Announcement Announcement Module
Collapse
No announcement yet.
Webflow with JSP/Tiles - Portlet has no content Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Webflow with JSP/Tiles - Portlet has no content

    Hi all,

    I am creating a portlet application with Spring Webflow (2.2.1) and JSP/Tiles (2.2.2).

    Everything works without any error. The problem I have is that the portlet does not show any content.
    I only see the title and no content (see attached picutre).
    And the console output of the liferay/tomcat server is:
    10:15:08.330 [http-8080-2] DEBUG o.s.w.c.i.SessionBindingConversationManager - Unlocking conversation 1
    10:15:08.330 [http-8080-2] DEBUG o.s.web.portlet.DispatcherPortlet - Null ModelAndView returned to DispatcherPortlet with name 'testproject': assuming HandlerAdapter completed request handling
    10:15:08.330 [http-8080-2] DEBUG o.s.web.portlet.DispatcherPortlet - Successfully completed request


    Here are my config files:

    web.xml:
    Code:
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
    	version="2.4">
    
    	<!-- - Location of the XML file that defines the root application context 
    		- Applied by ContextLoaderListener. -->
    	<context-param>
    		<param-name>contextConfigLocation</param-name>
    		<param-value>
    			classpath:/config/applicationContext.xml
    		</param-value>
    	</context-param>
    
    	<!-- - Loads the root application context of this web app at startup. - 
    		The application context is then available via - WebApplicationContextUtils.getWebApplicationContext(servletContext). -->
    	<listener>
    		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    	</listener>
    
    	<!-- Supports view rendering -->
    	<servlet> <!-- ViewRendererServlet is a bridge servlet, mainly for the Portlet MVC 
    			support. -->
    		<servlet-name>ViewRendererServlet</servlet-name>
    		<servlet-class>org.springframework.web.servlet.ViewRendererServlet</servlet-class>
    	</servlet>
    
    	<servlet-mapping>
    		<servlet-name>ViewRendererServlet</servlet-name>
    		<url-pattern>/WEB-INF/servlet/view</url-pattern>
    	</servlet-mapping>
    
    	<jsp-config>
    		<taglib id="PortletTLD">
    			<taglib-uri>http://java.sun.com/portlet</taglib-uri>
    			<taglib-location>META-INF/sun-portlet_2_0.tld</taglib-location>
    		</taglib>
    	</jsp-config>
    </web-app>
    portlet.xml:
    Code:
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <portlet-app
    	xmlns="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd"
    	version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd http://java.sun.com/xml/ns/portlet/portlet-app_1_0.xsd">
    
    	<portlet>
    		<portlet-name>testportlet</portlet-name>
    		<display-name>testportlet</display-name>
    
    		<portlet-class>
    			org.springframework.web.portlet.DispatcherPortlet
    		</portlet-class>
    
    		<init-param>
    			<name>contextConfigLocation</name>
    			<value>
    				classpath:/config/portlet-config.xml
    			</value>
    		</init-param>
    
    		<init-param>
    			<name>viewRendererUrl</name>
    			<value>/WEB-INF/servlet/view</value>
    		</init-param>
    
    		<expiration-cache>0</expiration-cache>
    
    		<supports>
    			<mime-type>text/html</mime-type>
    			<portlet-mode>view</portlet-mode>
    		</supports>
    
    		<portlet-info>
    			<title>Test Portlet</title>
    		</portlet-info>
    
    	</portlet>
    
    </portlet-app>
    applicationCtx portlet-config.xml:
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:webflow="http://www.springframework.org/schema/webflow-config"
    	xmlns:mvc="http://www.springframework.org/schema/mvc"
    	xsi:schemaLocation="
               http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
               http://www.springframework.org/schema/webflow-config
               http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd
               http://www.springframework.org/schema/mvc
               http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
    
    	<!-- Maps portlet modes to handlers -->
    	<bean id="portletModeHandlerMapping"
    		class="org.springframework.web.portlet.handler.PortletModeHandlerMapping">
    		<property name="portletModeMap">
    			<map>
    				<entry key="view">
    					<bean
    						class="testproject.portlet.flowHandler.ViewFlowHandler" />
    				</entry>
    			</map>
    		</property>
    	</bean>
    
    	<bean id="tilesViewResolver" class="org.springframework.js.ajax.AjaxUrlBasedViewResolver">
    		<property name="viewClass"
    			value="org.springframework.webflow.mvc.view.FlowAjaxTilesView" />
    	</bean>
    
    	<!-- Plugs in a custom creator for Web Flow views -->
    	<webflow:flow-builder-services id="flowBuilderServices"
    		view-factory-creator="mvcViewFactoryCreator" />
    
    	<!-- Configures Web Flow to use Tiles to create views for rendering; Tiles 
    		allows for applying consistent layouts to your views -->
    	<bean id="mvcViewFactoryCreator"
    		class="org.springframework.webflow.mvc.builder.MvcViewFactoryCreator">
    		<property name="viewResolvers" ref="tilesViewResolver" />
    	</bean>
    
    	<bean class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
    		<property name="definitions">
    			<list>
    				<value>/WEB-INF/tiles/tiles-def.xml</value>
    			</list>
    		</property>
    	</bean>
    
    
    	<!-- Enables FlowHandlers -->
    	<bean class="org.springframework.webflow.mvc.portlet.FlowHandlerAdapter">
    		<property name="flowExecutor" ref="flowExecutor" />
    	</bean>
    
    	<!-- Default flow executor -->
    	<webflow:flow-executor id="flowExecutor"
    		flow-registry="flowRegistry" />
    
    	<!-- The registry of executable flow definitions -->
    	<webflow:flow-registry id="flowRegistry"
    		flow-builder-services="flowBuilderServices" base-path="/WEB-INF/flows">
    		<webflow:flow-location-pattern value="/**/*-flow.xml" />
    	</webflow:flow-registry>
    
    
    	<!-- Validators -->
    	<bean id="personValidator"
    		class="testporject.portlet.validator.PersonValidator" />
    
    </beans>
    Application Ctx applicationContext.xml:
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"      
           xmlns:tx="http://www.springframework.org/schema/tx"
           xsi:schemaLocation="
               http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
               http://www.springframework.org/schema/context
               http://www.springframework.org/schema/context/spring-context-3.0.xsd           
               http://www.springframework.org/schema/tx
               http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    
    	<bean id="personService" class="testproject.service.impl.PersonServiceImpl" />
    
    </beans>
    tiles-def.xml:
    Code:
    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE tiles-definitions PUBLIC
           "-//Apache Software Foundation//DTD Tiles Configuration 2.1//EN"
           "http://tiles.apache.org/dtds/tiles-config_2_1.dtd">
    <tiles-definitions>
    	<definition name="portletgreet" template="/WEB-INF/tiles/layouts/refarchgreet.jsp">
    		<put-attribute name="input" value="/WEB-INF/tiles/layout/input.jsp" />
    		<put-attribute name="greet" value="/WEB-INF/tiles/layout/greet.jsp" />
    	</definition>
    	
    	<definition name="portletclone" template="/WEB-INF/tiles/layouts/refarchclone.jsp">
    		<put-attribute name="input" value="/WEB-INF/tiles/layout/input.jsp" />
    		<put-attribute name="cloned" value="/WEB-INF/tiles/layout/cloned.jsp" />
    	</definition>
    </tiles-definitions>
    main-flow.xml:
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <flow xmlns="http://www.springframework.org/schema/webflow"
    	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow-2.0.xsd"
    	start-state="createPerson">
    
    	<var name="person" class="testproject.model.Person" />
    
    	<view-state id="createPerson" model="person" view="portletgreet">
    		<transition on="clone" to="clonePerson">
    			<evaluate expression="personService.clone(person)" result="flowScope.pers" />
    		</transition>
    		<transition on="greet" to="greetPersonAction" validate="false" />
    
    		<transition on-exception="java.lang.RuntimeException" to="createPerson" />
    	</view-state>
    
    	<action-state id="greetPersonAction">
    		<evaluate expression="personService.greet(person)" result="flowScope.greeting" />
    		<transition to="greetPerson" />
    	</action-state>
    
    	<view-state id="greetPerson"  view="portletgreet" >
    		<on-render>
    			<render fragments="greet" />
    		</on-render>
    		<transition on="cancel" to="cancel" />
    	</view-state>
    
    	<view-state id="clonePerson" view="portletclone">
    		<transition on="cancel" to="cancel" />
    	</view-state>
    
    	<end-state id="cancel" view="portletgreet"/>
    </flow>
    refarchgreet.jsp (refarchclone.jsp looks the same):
    Code:
    <%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%>
    
    <portlet:actionURL var="actionUrl">
    	<portlet:param name="execution" value="${flowExecutionKey}" />
    </portlet:actionURL>
    
    <h1>Tiles Portlet Example</h1>
    <table>
    	<tr>
    		<td><tiles:insertAttribute name="input" /></td>
    	</tr>
    	<tr>
    		<td>
    		<hr />
    		</td>
    	</tr>
    	<tr>
    		<td><tiles:insertAttribute name="greet" /></td>
    	</tr>
    </table>

    I really have no idea how to get that thing run.
    Does anybody has a hint?

    Regards,
    Florian

  • #2
    Can you show the earlier parts of the log output from about where the PortletDispatcherServlet delgates to Web Flow? Your configurations looks ok. Maybe some exception occurs during view rendering that's not visible in the logs? Try turning up the default logging level.

    Comment


    • #3
      Hi,

      Thx for your reply.
      Log Level is now on DEBUG.

      While deployment of the portlet the following output is produced:
      see attached file: deployment.txt (in "Log Output.zip")

      While adding the portlet to the page (liferay) the following output is produced:
      see attached file: adding.txt (in "Log Output.zip")

      While reloading the page/portlet (CTRL+F5) the following output is produced:
      see attached file: reloading.txt (in "Log Output.zip")


      For me everything looks fine.
      Would be great if you could help me. I could also offer to send you a zip containing the eclipse-maven project, so that you could try reproducing the error on your site.

      Regards,
      Florian

      Comment


      • #4
        From what I can see the request processing goes correctly to Tiles:

        Code:
        15:40:05.851 [http-8080-1] DEBUG o.s.webflow.engine.ViewState - Rendering + [PortletMvcView@10b39c5 view = org.springframework.webflow.mvc.view.FlowAjaxTilesView: n
        ame 'portletgreet'; URL [portletgreet]]
        
        ...
        
        15:40:05.856 [http-8080-1] DEBUG o.s.w.mvc.view.FlowAjaxTilesView - Added model object 'viewScope' of type [org.springframework.webflow.core.collection.LocalAttribu
        teMap] to request in view with name 'portletgreet'
        15:40:05.857 [http-8080-1] DEBUG o.a.tiles.impl.BasicTilesContainer - Render request recieved for definition 'portletgreet'
        So my guess is that it's something to do with processing inside the Tiles container. You can try debugging. Or use simple JSP rendering to see if it works without Tiles.

        Comment


        • #5
          Hi,

          Without tiles it works.
          It must have something to do with it.

          Debugging is a problem, means I don't have an idea how I could debug a Portlet within Eclipse. Do you have an idea?

          Comment


          • #6
            I add the Pluto container as a regular Tomcat instance to my Servers view but you could also start your server with remote debugging options and then attach with the Eclipse debugger to the debugging port.

            Comment


            • #7
              I got the remote-debugging in Tomcat/Liferay working.

              I debugged through Tiles, especially through BaiscTilesContainer.java (there are all those render(...) methods)

              Unfortunately I do not see anything that goes wrong.

              But I have a suspicion:
              While debugging I saw some used classes like "ServletTilesRequestContext". I saw in the tiles-portlet project that there are special classes like "PortletTilesRequestContext". Might it be that it has something to do with this? "Servlet..." would be for "normal" webapps, "Portlet..." for "portlet" webapps?

              Does anybody have an idea what else I could try?

              Comment


              • #8
                Originally posted by huof View Post
                But I have a suspicion:
                While debugging I saw some used classes like "ServletTilesRequestContext". I saw in the tiles-portlet project that there are special classes like "PortletTilesRequestContext". Might it be that it has something to do with this? "Servlet..." would be for "normal" webapps, "Portlet..." for "portlet" webapps?
                The ViewRendererServlet you've configured in web.xml serves as a bridge that allows re-using servlet based View classes (see docs).

                Web Flow's PortletMvcView does include on the PortletRequestDispatcher requesting the fixed view "/WEB-INF/servlet/view", which is what the ViewRendererServlet is mapped to. This causes the Portlet container to wrap the Portlet request/response and invoke a regular Servlet. In short Tiles should be unaware of the Portlet environment in this scenario.

                Comment


                • #9
                  So we can't use the tiles in portlet environemnt?!
                  Any one tried?

                  Comment


                  • #10
                    As per log it is going to BasicTilesContainer.

                    org.apache.tiles.impl.BasicTilesContainer - Render request recieved for definition 'xxx'

                    But the corresponding jsp never called!! I put some System.out in jsp.

                    Comment


                    • #11
                      Hi spsaran,

                      I did exactly the same.
                      So you have the same problem?

                      I am currently very frustrated .
                      I debugged Tiles and I do not find a small hint what may go wrong.

                      Regards,
                      Florian

                      Comment


                      • #12
                        Yeah. The problem is in TilesConfigurer which is only ServletAware not PorletAware.

                        I try to create the PortletTilesRequestContext through factory but there is no portlet tiles context. TilesCongurer creates only ServletTilesApplicationContext. I am not sure whether we can extend the TilesConfigurer as a PorletAware and use it. It may lead some other problem.

                        For quick fix i extended FlowAjaxTilesView and used in tilesViewResolver as a view class, but rendering fragments is not working as expected.

                        Code:
                        public class PortletFlowAjaxTilesView extends FlowAjaxTilesView {
                        
                        	protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response)
                        	throws Exception {
                        		ServletUtil.setForceInclude(request, true);
                        		super.renderMergedOutputModel(model, request, response);
                        	}
                        	
                        }
                        Fragment is not working because of ajaxSource is missing in render phase!

                        Comment


                        • #13
                          Tiles should not have to be aware of the Portlet environment when running withing Spring Portlet MVC. Please see the documentation on the ViewRendererServlet especially the comments about the reuse of all the existing Servlet-based view types.

                          Comment


                          • #14
                            Since it is ServletAware, the ServletTilesRequestContext is initialized and used and its dispatch is,

                            Code:
                                public void dispatch(String path) throws IOException {
                                    if (response.isCommitted() || ServletUtil.isForceInclude(request)) {
                                        include(path);
                                    } else {
                                        forward(path);
                                    }
                                }
                            The dispatch method calls forward(path) when its portlet and its return empty content. I have set the forceInclude true in PortletFlowAjaxTilesView and include called. The include is working.

                            Then the issue in fragment rendering also. SpringJavascriptAjaxHandler checks isAjaxRequest based on ajaxSource request parameter. Since portlet is in rendering phase this parameter is not availble and failed to consider as Ajax request!

                            So Spring Webflow + Tiles in Portlet env is not working

                            Please let us know if we missed any configuration or need to do any custom coding to achieve this!

                            Note: I am using Spring 3.0.3 + Webflow 2.1.0 and Tiles 2.1.2 in WebLogic Portal 10.3.2 environment.

                            Comment


                            • #15
                              I did a test by modifying the booking-portlet-mvc sample. TilesView exposes a few standard forward request attributes in case the servlet container doesn't properly do that itself. This is based on the flag exposeForwardAttributes, which is set to true for pre-2.5 servlet container.

                              When TilesView exposes these attributes the forward works ok. So my guess is that the container I'm using Pluto 2.x does not do that itself. You can try to set this flag to true by overriding TilesView.initServletContext(ServletContext).

                              Comment

                              Working...
                              X