I created a ApplicationScoped bean that have a PostConstruct method named start.
Whenever i want to get instance of FacesContext in the start method and it returns null:
#ManagedBean
#ApplicationScoped
public class RemoveOldFilesScheduler implements Serializable {
#PostConstruct
private void start() {
final FacesContext facesContext = FacesContext.getCurrentInstance();
if(facesContext != null) {
String realDownloadDirName = facesContext.getExternalContext().getRealPath("/") + DOWNLOAD_DIRECTORY;
File downloadDir = new File(realDownloadDirName);
if (downloadDir.exists()) {
removeOldFiles(downloadDir.listFiles());
}
}
}
How can i access to facesContext in this situation?
I want to get real path of my download directory in the start method and i don't know how to get path of my directory without using FaceContext.
Is there another way to do it?
I implementing my class as Listener and it worked and i can access to ServletContext in contextInitialized method :
public class RemoveOldFilesListener implements ServletContextListener {
public ServletContext servletContext;
#Override
public void contextInitialized(ServletContextEvent sce) {
servletContext = sce.getServletContext();
String realDownloadDirName = servletContext.getRealPath("/") + DOWNLOAD_DIRECTORY;
File downloadDir = new File(realDownloadDirName);
if (downloadDir.exists()) {
removeOldFiles(downloadDir.listFiles());
}
}
Related
This is how I'm rendering my composite component inside a loop, it works, but when I switch to edit mode and sumbmit new values I can't retrieve them from the InputText.
#FacesComponent("customComponent")
public class CustomComponent extends UIInput implements NamingContainer, Serializable {
private static final long serialVersionUID = 1L;
#Override
public String getFamily() {
return UINamingContainer.COMPONENT_FAMILY;
}
private UIComponent component;
private HtmlInputText inputTextValue;
#Override
public void encodeBegin(FacesContext context) throws IOException {
AttributeObject attrObject = (AttributeObject) getAttributes().get("value");
Boolean enableInput = (Boolean) getAttributes().get("enableInput");
if (attrObject.getAttributeValue() != null) {
if (attrObject.getAttributeDescriptor().getDataType() == DataTypeConstants.TEXT && enableInput) {
InputText inputText = new InputText();
inputText.setRequired(true);
inputText.setValueExpression("binding",
createValueExpression("#{searchController.myComponent}", UIComponent.class));
inputText.setId("editableTextId");
inputText.encodeAll(context);
inputText.setParent(this);
component = inputText;
} else if (attrObject.getAttributeDescriptor().getDataType() == DataTypeConstants.TEXT
&& enableInput == false) {
OutputLabel outputLabel = new OutputLabel();
outputLabel.setValue(attrObject.getAttributeValue());
outputLabel.encodeAll(context);
outputLabel.setId("nonEditatbleId");
component = outputLabel;
}
}
}
private ValueExpression createValueExpression(String valueExpression, Class<?> valueType) {
FacesContext facesContext = FacesContext.getCurrentInstance();
return facesContext.getApplication().getExpressionFactory()
.createValueExpression(facesContext.getELContext(), valueExpression, valueType);
}
Ok I think I found what caused all that mad performance problems. I did some logic inside a getter and because that getter was getting called multiple times that caused performance issues.
I'm having a problem regarding actionlistener in my project. I'm creating a website but my problem is at the login and I'm using composite and JSF. Whenever I try to login I get a nullpointer pointing at the actionlistener class line 30 which is in the if statement.
ActionListener class
public class LoginActionListener implements ActionListener {
#Inject private Service service;
#Override
public void processAction(ActionEvent event) throws AbortProcessingException {
UIComponent container = event.getComponent().getNamingContainer();
String username = (String) ((UIInput)
container.findComponent("form:username")).getValue();
String pwd = (String) ((UIInput)
container.findComponent("form:password")).getValue();
if(service.isRegistered(username, pwd))
return;
FacesContext context = FacesContext.getCurrentInstance();
context.addMessage(container.getClientId(),
new FacesMessage("Username and password are invalid. Please try again."));
throw new AbortProcessingException("Invalid credentials");
}
}
Service class
public boolean isRegistered(String username, String password){
for (User u : users) {
if (u.getUserName().equals(username) && u.getPassword().equals(password))
return true;
}
return false;
}
Composite login xhtml file
http://blg.nikonsrc.com/image/4nEwBZn2a6VnBoCaET-wUiU_iwnRwLBaMfMR67ypIKVyameRSjNcbAmtoKug6n4_PWUXZcEFpp8/item.JPG?rot=0
http://blg.nikonsrc.com/image/4nEwBZn2a6VnBoCaET-wUiU_iwnRwLBaMfMR67ypIKU7KIV8XlnDFQmtoKug6n4_PWUXZcEFpp8/item.JPG?rot=0
Best regards
Jakob
If your service is null it seems to be a problem with injecting your Service class. Check if the Service class has proper annotations which allows that class to be injected. Be aware that you should use annotations form one package:
For CDI-based bean definitions
javax.enterprise.context.SessionScoped
javax.inject.Named
javax.inject.Inject
For JSF-based bean definitions
javax.faces.bean.SessionScoped
javax.faces.bean.ManagedBean
javax.faces.bean.ManagedProperty
For example:
#Named
#SessionScoped
public class Service {
...
public boolean isRegistered(String username, String password){
for (User u : users) {
if (u.getUserName().equals(username) && u.getPassword().equals(password))
return true;
}
return false;
}
}
i have a junit test method that calls a backing bean method as follows:
myBackingBean.signup();
, in the backing bean method there's a call to Faces.getLocale() and it gives null pointer exception in the line
UIViewRoot viewRoot = context.getViewRoot();
please advise how to be able to set locale in test method and fix this error.
solution was as follows:
1- add the following class to project:
public abstract class FacesContextMocker extends FacesContext {
private FacesContextMocker() {
}
private static final Release RELEASE = new Release();
private static class Release implements Answer<Void> {
#Override
public Void answer(InvocationOnMock invocation) throws Throwable {
setCurrentInstance(null);
return null;
}
}
public static FacesContext mockFacesContext() {
FacesContext context = Mockito.mock(FacesContext.class);
setCurrentInstance(context);
Mockito.doAnswer(RELEASE).when(context).release();
return context;
}
}
2- In #Before for the test use the following code:
FacesContext facesContext = FacesContextMocker.mockFacesContext();
UIViewRoot uiViewRoot = Mockito.mock(UIViewRoot.class);
Mockito.when(facesContext.getCurrentInstance().getViewRoot())
.thenReturn(uiViewRoot);
Mockito.when(
facesContext.getCurrentInstance().getViewRoot().getLocale())
.thenReturn(new Locale("en"));
in my preRender code for a page i add faces message then make navigation to another page as follows:
if(error){
addMessageToComponent(null,"AN ERROR HAS OCCURRED");
FacesContext.getCurrentInstance().getExternalContext().getFlash()
.setKeepMessages(true);
navigateActionListener("myoutcome");
}
and the util methods for adding message and navigation are:
public static String getClientId(String componentId)
{
FacesContext context = FacesContext.getCurrentInstance();
UIViewRoot root = context.getViewRoot();
UIComponent c = findComponent(root, componentId);
return c.getClientId(context);
}
public static UIComponent findComponent(UIComponent c, String id)
{
if (id.equals(c.getId())) { return c; }
Iterator<UIComponent> kids = c.getFacetsAndChildren();
while (kids.hasNext())
{
UIComponent found = findComponent(kids.next(), id);
if (found != null) { return found; }
}
return null;
}
/**
* #param componentId
* : the id for the jsf/primefaces component without formId:
* prefix. <br>
* if you use null then the message will be added to the
* h:messages component.
**/
public static void addMessageToComponent(String componentId, String message)
{
if (componentId != null)
componentId = GeneralUtils.getClientId(componentId);
FacesContext.getCurrentInstance().addMessage(componentId,
new FacesMessage(message));
}
public static void navigateActionListener(String outcome)
{
FacesContext context = FacesContext.getCurrentInstance();
NavigationHandler navigator = context.getApplication()
.getNavigationHandler();
navigator.handleNavigation(context, null, outcome);
}
but messages are not saved and so it doesn't appear after redirect.
please advise how to fix that.
The preRenderView event runs in the very beginning of the RENDER_RESPONSE phase. It's too late to instruct the Flash scope to keep the messages. You can do this at the latest during the INVOKE_APPLICATION phase.
Since there's no standard JSF component system event for this, you'd need to homebrew one:
#NamedEvent(shortName="postInvokeAction")
public class PostInvokeActionEvent extends ComponentSystemEvent {
public PostInvokeActionEvent(UIComponent component) {
super(component);
}
}
To publish this, you need a PhaseListener:
public class PostInvokeActionListener implements PhaseListener {
#Override
public PhaseId getPhaseId() {
return PhaseId.INVOKE_APPLICATION;
}
#Override
public void beforePhase(PhaseEvent event) {
// NOOP.
}
#Override
public void afterPhase(PhaseEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
context.getApplication().publishEvent(context, PostInvokeActionEvent.class, context.getViewRoot());
}
}
After registering it as follows in faces-config.xml:
<lifecycle>
<phase-listener>com.example.PostInvokeActionListener</phase-listener>
</lifecycle>
You'll be able to use the new event as follows:
<f:event type="postInvokeAction" listener="#{bean.init}" />
You only need to make sure that you've at least a <f:viewParam>, otherwise JSF won't enter the invoked phase at all.
The JSF utility library OmniFaces already supports this event and the preInvokeAction event out the box. See also the showcase page which also demonstrates setting a facesmessage for redirect.
(Java EE 6 with Glassfish 3.1)
I have a property file that I want to process only once at start up time, so I did this
public class Config implements ServletContextListener{
private static final String CONFIG_FILE_PATH = "C:\\dev\\harry\\core.cfg";
private static final String CONFIG_ATTRIBUTE_NAME = "config";
private long startupTime;
private ConfigRecord config;
#Override
public void contextInitialized(ServletContextEvent sce) {
this.startupTime = System.currentTimeMillis() / 1000;
this.config = new ConfigRecord(CONFIG_FILE_PATH); //Parse the property file
sce.getServletContext().setAttribute(CONFIG_ATTRIBUTE_NAME, this);
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
//Nothing to do here
}
public ConfigRecord getConfig() {
return config;
}
public long getStartupTime() {
return startupTime;
}
}
and in web.xml, i register it as follow
<listener>
<listener-class>com.wf.docsys.core.servlet.Config</listener-class>
</listener>
Now how do I access the ConfigRecord config from the managed bean. I try this
#ManagedBean
#RequestScoped
public class DisplayInbound {
#EJB
private CoreMainEJBLocal coreMainEJBLocal;
#javax.ws.rs.core.Context
private ServletContext servletContext;
public void test(){
Config config = (Config) servletContext.getAttribute("config")
ConfigRecord configRecord = config.getConfig();
}
}
I dont think it work. Got NullPointerException.
That #Context annotation is only applicable in a JAX-RS controller, not in a JSF managed bean. You have to use #ManagedProperty instead. The ServletContext is available by ExternalContext#getContext(). The FacesContext itself is available by #{facesContext}.
#ManagedProperty(value="#{facesContext.externalContext.context}")
private ServletContext context;
Or because you stored the listener as a servletcontext attribute, which is basically the same as the JSF application scope, you could also just set it as managed property by its attribute name:
#ManagedProperty(value="#{config}")
private Config config;
But since you're on JSF 2.0, I'd suggest to use an #ApplicationScoped #ManagedBean instead which is eagerly constructed. With #PostConstruct and #PreDestroy in such a bean you have similar hooks on webapp's startup and shutdown as in a ServletContextListener.
#ManagedBean(eager=true)
#ApplicationScoped
public void Config {
#PostConstruct
public void applicationInitialized() {
// ...
}
#PreDestroy
public void applicationDestroyed() {
// ...
}
}
You can inject it in another beans the usual #ManagedProperty way and access it in the views the usual EL way.