Looking to use Struts2 with Serlvet 3.0 Async support.
My first approach was to just handle to writing to the outputstream in the action and returning null. This however returns with a 404 "resource not available". I am attempting to adapt a Bosh servlet inside of a struts action, using ServletRequestAware, ServletResponseAware interfaces to inject the response.
I am using the struts filter dispatcher. Not entirely sure if this is doable,but would be sure happy if someone else has managed to get async to work within a struts action. Perhaps here is an AsyncResult type or someother magic to make this work.
Make sure the struts filter allows async. Here's what that looks like in the web.xml file:
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
<async-supported>true</async-supported>
</filter>
Then from within an Action obtain the HttpServletRequest and HttpServletResponse and use the AsyncContext as you would within a servlet:
public String execute() {
HttpServletRequest req = ServletActionContext.getRequest();
HttpServletResponse res = ServletActionContext.getResponse();
final AsyncContext asyncContext = req.startAsync(req, res);
asyncContext.start(new Runnable() {
#Override
public void run() {
try {
// doing some work asynchronously ...
}
finally {
asyncContext.complete();
}
}
});
return Action.SUCCESS;
}
Related
I am doing a project for school. I am using JSF and Primefaces. But to check authorization with Servlet Filter when HTML5 file called in JSF project. Because JSF doesn't support HTML5.
Project has a HTML5 page. It is necessary to login to reach this page.
However, I can't open Pop-Up or Message or Growl when HTML5 file called without login.
Can I use FacesMessage in LoginFilter ?
Code:
#WebFilter(urlPatterns = { "/design.html" , "/demodesign.html" } )
public class LoginFilter implements Filter{
#Override
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
UserBean userBean = (UserBean) ((session != null) ? session.getAttribute("userBean") : null);
User member = null;
if ( !(userBean == null) )
member = userBean.getMember();
if (member != null) {
chain.doFilter(request, response);
} else {
response.sendRedirect(welcomeURL);
}
}
}
Because JSF doesn't support HTML5
This is complete nonsense. JSF is just a HTML code producer. It can produce legit HTML5 code without trouble. You can just place "plain vanilla" HTML5 elements like <canvas> in a JSF page. It will just untouch it and output it as-is. All what JSF can do more for you is to wrap it in a custom/composite component like <my:canvas> so that the submitted values are immediately updated as bean properties and that you can perform validation and attach listeners on it without any additional effort.
Just rename those HTML files to .xhtml and add/use a *.xhtml mapping on the FacesServlet. This way you'll be able to use JSF components on those so-called HTML5 pages.
See also:
Is it possible to use JSF+Facelets with HTML 4/5?
I've been trying to cache and handle viewExpiredexception where if a `viewExpiredexceptionviewExpiredexception is throw, i have written a custom viewExpiredexception Handler which is suppose to redirect back to the page where the Exception is thrown, i also insert a boolean into session which is used in the redicted page to show "page was refreshed" message.
Below is the relevant part of my ViewExpiredException Handler:
public void handle() throws FacesException {
for (Iterator<ExceptionQueuedEvent> i = getUnhandledExceptionQueuedEvents().iterator(); i.hasNext();) {
ExceptionQueuedEvent event = i.next();
ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();
Throwable t = context.getException();
if (t instanceof ViewExpiredException) {
ViewExpiredException vee = (ViewExpiredException) t;
FacesContext fc = FacesContext.getCurrentInstance();
Map<String, Object> requestMap = fc.getExternalContext().getRequestMap();
NavigationHandler nav = fc.getApplication().getNavigationHandler();
try {
requestMap.put("currentViewId", vee.getViewId());
HttpServletRequest orgRequest = (HttpServletRequest) fc.getExternalContext().getRequest();
fc.getExternalContext().redirect(orgRequest.getRequestURI());
Map<String, Object> sessionMap = FacesContext.getCurrentInstance().getExternalContext().getSessionMap();
sessionMap.put("refreshedMaxSesion",true);
fc.renderResponse();
}
catch(IOException e){ }
finally { i.remove(); }
}
}
// here queue will not contain any ViewExpiredEvents, let the parent handle them.
getWrapped().handle();
}
and the Navigation case
<navigation-rule>
<navigation-case>
<from-outcome>/app/ord1</from-outcome>
<to-view-id>/jsp/orderHist.jsp</to-view-id>
<redirect />
</navigation-case>
</navigation-rule>
I had limited success with the above, it would work in some cases but in other cases the page wouldn't redirect at all. It works mostly in chrome but in IE it didn't work at all.
I tried making few changes such as using
HttpServletResponse response = (HttpServletResponse) fc.getExternalContext().getResponse();
response.sendRedirect(vee.getViewId());
but i was getting the 500 error pages with exception saying View must Exists... so i stopped experimenting to find out what i am doing wrong first. How can this goal of cahcing a ViewExpiredException, and Redirectign back to the page where the error was thrown be archived?
I'm on myFaces (2.1.7) and richFaces (3.3.3). Thanks
There is some work already done inside MyFaces Community to deal with ViewExpiredException in a graceful way. Some issues has been solved in MyFaces Core (see MYFACES-3530 and MYFACES-3531) Maybe you should try the latest snapshot HERE.
Currently I am using a Transaction View pattern to make lazy-loading of collections possible in views.
I have the following in web.xml
<filter>
<filter-name>view</filter-name>
<filter-class>com.jasoni.ViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>view</filter-name>
<url-pattern>*.xhtml</url-pattern>
</filter-mapping>
And the Filter class has the following...
public class ViewFilter implements Filter {
#Resource UserTransaction tx;
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
tx.begin();
chain.doFilter(request, response);
}
//catch here
finally {
//another try-catch
tx.commit();
}
}
}
Then assuming I have the following (rather contrived) backing bean
#ManagedBean
#RequestScoped
public class DepartmentEmployees {
#EJB
private DepartmentServiceBean deptService;
#ManagedProperty(value="#{param.deptId}")
private Integer deptId;
private Department dept;
#PostConstruct
public String init() {
dept = deptService.findById(deptId);
}
}
I can do something like this in my view (.xhtml file)
<ul>
<c:forEach var="emp" items="#{departmentEmployees.dept.employees}">
<li>#{emp.firstName} #{emp.lastName}</li>
</c:forEach>
</ul>
Just wondering if anybody knows of a different way to accomplish the same thing without using filters (or servlets).
This approach ("open session in view") has a couple of major disadvantages. Besides being kind of hacky (it's certainly not the design idea of a servlet filter to control a business session) you don't have many options to appropriately process any "real" exception that occurs while rendering the JSF page.
You don't write much about your infrastructure / technology stack, but I assume that you are on a Java EE 6 server.
I usually use the EntityManger in Extended Mode and flush it with transactions which I control explicitly by annotating only certain methods of my business facade. Have a look at this example (taken from Adam Bien - Real World Java EE Patterns, Rethinking Best Practices):
#Stateful
#TransactionAttribute(TransactionAttributeType.NEVER)
public class BookFacadeBean implements BookFacade {
#PersistenceContext(type=PersistenceContextType.EXTENDED)
private EntityManager em;
private Book currentBook;
public Book find(long id){
this.currentBook = this.em.find(Book.class, id);
return this.currentBook;
}
public void create(Book book){
this.em.persist(book);
this.currentBook = book;
}
public Book getCurrentBook() {
return currentBook;
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void save(){
//nothing to do here
}
}
A next level in this approach would be to bind the EntityManager to a CDI conversation scope. Have a look at (a) Weld (b) Seam 3 Persistence for further discussions on that topic.
This is rather a rough sketch of an alternative than a detailed how-to. I hope this level of information is what you were asking about - feel free to ask further questions. :-)
I cannot seem to inject a simple bean into my #WebService. With Spring on the classpath and javax.inject dependencies defined, I created a simple JAX-WS webservice with some underlying interface-driven DAOs etc:
#Named
#WebService(name = "NoteStorage", serviceName = "NoteStorageWS")
public class NoteStorageWS implements NoteStore {
private static final Log l = LogFactory.getLog(NoteStorageWS.class);
#Named("NoteDAO")
#Inject
private NoteDAO noteDAO;
public NoteStorageWS() {
super();
}
#Override
#WebMethod
public StorageState takeNote(String note) {
try {
l.info(format("Service received message: '%s'", note));
Note n = new Note();
n.setContent(note);
noteDAO.store(n);
} catch (Exception e) {
l.error(e);
return StorageState.FAILURE;
}
return StorageState.SUCCESS;
}
#WebMethod(exclude = true)
public void setNoteDAO(NoteDAO noteDAO) {
this.noteDAO = noteDAO;
}
}
NoteDAOhas just implementation: FlatFileNoteDAO which is defined as follows:
#Named("NoteDAO")
public class FlatFileNoteDAO implements NoteDAO {
private static final Log l = LogFactory.getLog(FlatFileNoteDAO.class);
#Override
public void store(Note n) {
if (n == null) {
throw new IllegalArgumentException("Note was null");
}
try {
l.info(format("Storing note '%s'", n));
FileWriter fileWriter = new FileWriter(new File("Note"));
fileWriter.write(format("%s\n", n.getContent()));
fileWriter.close();
} catch (IOException e) {
throw new DataAccessException(e);
}
}
}
My web.xml says:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<resource-env-ref>
<description>Object factory for the CDI Bean Manager</description>
<resource-env-ref-name>BeanManager</resource-env-ref-name>
<resource-env-ref-type>javax.enterprise.inject.spi.BeanManager</resource-env-ref-type>
</resource-env-ref>
</web-app>
I deploy the application to Glassfish by pointing it to the target/note-ws/ directory and execute the simple takeNote method via the ?Tester page.
Upon submission of the tester form I get a NullPointerException at the line noteDAO.store(n);, presumably because noteDAO wasn't injected.
I can confirm that Spring has been invoked by the logs from glassfish on context initialisation (the Java EE context):
[#|2011-12-04T16:57:24.970+0000|INFO|glassfish3.1.1|org.springframework.context.annotation.ClassPathBeanDefinitionScanner|_ThreadID=256;_ThreadName=Thread-2;|JSR-330 'javax.inject.Named' annotation found and supported for component scanning|#]
[#|2011-12-04T16:57:25.653+0000|INFO|glassfish3.1.1|org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor|_ThreadID=256;_ThreadName=Thread-2;|JSR-330 'javax.inject.Inject' annotation found and supported for autowiring|#]
[#|2011-12-04T16:57:25.757+0000|INFO|glassfish3.1.1|org.springframework.beans.factory.support.DefaultListableBeanFactory|_ThreadID=256;_ThreadName=Thread-2;|Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#9e39146: defining beans [noteStorageWS,NoteDAO,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor]; root of factory hierarchy|#]
which says my beans are defined: noteStorageWS, NoteDAO and so-on.
Any ideas?
Edit
to clarify, I'm using Spring to provide JSR 330 -- dependency injection -- functionality.
I never got this solved, so I ended up removing the DI-features as the codebase was small and relied on manual dependency resolution - plain old new IFaceImpl(); for now.
JAX-WS and Guice require a specific integration via #GuiceManaged annotation. More info here.
Move the business logic to a separate bean and annotate it with #Configurable so that Spring can handle the lifecycle of the bean. Now use that bean in NoteStorageWS
#Configurable
public class NoteStorageUtil{
#Named("NoteDAO")
#Inject
private NoteDAO noteDAO;
public StorageState takeNote(String note) {
try {
l.info(format("Service received message: '%s'", note));
Note n = new Note();
n.setContent(note);
noteDAO.store(n);
} catch (Exception e) {
l.error(e);
return StorageState.FAILURE;
}
return StorageState.SUCCESS;
}
}
#WebService(name = "NoteStorage", serviceName = "NoteStorageWS")
public class NoteStorageWS implements NoteStore {
public StorageState takeNote(String note) {
return new NoteStorageUtil().takeNote(note)
}
}
Or please check if your end point configuration is proper, so that the web service end point is a spring-managed bean also.
Eg:-
<bean id="hello" class="demo.spring.service.HelloWorldImpl" />
<jaxws:endpoint id="helloWorld" implementor="#hello" address="/HelloWorld" />
check the link
I'm trying to use the authenticate() in a preRenderView listener method, in order to trigger authentication conditionally, depending on view parameters in the page. I tried adding a simple method:
#Named
#RequestScoped
public class PermissionBean implements java.io.Serializable {
public void preRender() {
System.out.println("IN PRERENDER");
HttpServletRequest request = (HttpServletRequest)FacesContext.getCurrentInstance().getExternalContext().getRequest();
HttpServletResponse response = (HttpServletResponse)FacesContext.getCurrentInstance().getExternalContext().getResponse();
try {
request.authenticate(response);
} catch (Exception e) { // may throw ServletException or IOException
e.printStackTrace();
}
}
The authenticate method itself doesn't throw an exception, it triggers the redirect to Login.xhtml as expected. However, I'm getting in my server log, I get this exception:
enter code here
INFO: IN PRERENDER
FINEST: GET /Login.xhtml previous[3]
INFO: Exception when handling error trying to reset the response.
java.lang.NullPointerException
at com.sun.faces.facelets.tag.jsf.core.DeclarativeSystemEventListener.processEvent(EventHandler.java:126)
at javax.faces.component.UIComponent$ComponentSystemEventListenerAdapter.processEvent(UIComponent.java:2508)
at javax.faces.event.SystemEvent.processListener(SystemEvent.java:106)
at com.sun.faces.application.ApplicationImpl.processListeners(ApplicationImpl.java:2129)
at com.sun.faces.application.ApplicationImpl.invokeComponentListenersFor(ApplicationImpl.java:2077)
at com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:286)
at com.sun.faces.application.ApplicationImpl.publishEvent(ApplicationImpl.java:244)
at javax.faces.application.ApplicationWrapper.publishEvent(ApplicationWrapper.java:670)
at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:108)
at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:139)
at javax.faces.webapp.FacesServlet.service(FacesServlet.java:594)
So my request is not redirected to Login.xhtml.
My question is - is this something that should work within a JSF managed bean, or is it only legal outside of JSF request lifecycle? I tried calling authenticate() from a WebFilter, and it works as exptected.
Thanks,
Ellen
You need to tell JSF to not render the response which it was initially asked to do, whenever the request has been redirected. You can do that by checking if HttpServletRequest#authenticate() returns false and then invoke FacesContext#responseComplete() accordingly.
if (!request.authenticate(response)) {
FacesContext.getCurrentInstance().responseComplete();
}