001    // Copyright 2005 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    package org.apache.tapestry.portlet;
016    
017    import java.io.IOException;
018    
019    import javax.portlet.PortletRequest;
020    
021    import org.apache.tapestry.IRequestCycle;
022    import org.apache.tapestry.engine.IEngineService;
023    import org.apache.tapestry.engine.ILink;
024    import org.apache.tapestry.services.ServiceConstants;
025    
026    /**
027     * Responsible for rendering out a page; a Portlet render URL is built during
028     * action processing that stores the active page; this is the page that will be
029     * rendered. The render service is (typically) the only service that operates
030     * during a portlet RenderRequest. All other services will be an ActionRequest
031     * that (via {@link org.apache.tapestry.portlet.PortletResponseRenderer},
032     * writes query parameters to activate this service during the render request.
033     * <p>
034     * Problematic is is anything related to the portlet mode or window state. As
035     * per the Portlet spec, when the user clicks the "help" or "edit" buttons (or
036     * the minimize, maximize, etc.), this causes a new RenderRequest, but
037     * explicitly keeps the render parameters set by the most recent ActionRequest.
038     * But what Tapestry needs is to detect that the mode or state has changed and
039     * select a different page to render the response. So we store the mode and
040     * state in effect when the ActionRequest executed as two more query parameters,
041     * and detect changes to mode and state that way. If there is a change, then we
042     * ignore the page query parameter and use the {@link PortletPageResolver} to
043     * figure out the correct page to display instead.
044     * 
045     * @author Howard M. Lewis Ship
046     * @since 4.0
047     * @see org.apache.tapestry.services.impl.ResponseRendererImpl
048     */
049    public class RenderService implements IEngineService
050    {
051    
052        private PortletRequest _request;
053    
054        private PortletRenderer _portletRenderer;
055    
056        private PortletPageResolver _pageResolver;
057    
058        public ILink getLink(boolean post, Object parameter)
059        {
060            throw new UnsupportedOperationException(PortletMessages
061                    .unsupportedMethod("getLink"));
062        }
063    
064        public void service(IRequestCycle cycle)
065            throws IOException
066        {
067            String pageName = getPageNameToRender(cycle);
068    
069            _portletRenderer.renderPage(cycle, pageName);
070        }
071    
072        private String getPageNameToRender(IRequestCycle cycle)
073        {
074            if (isStateChange(cycle))
075                return _pageResolver.getPageNameForRequest(cycle);
076    
077            return cycle.getParameter(ServiceConstants.PAGE);
078        }
079    
080        /**
081         * Returns true if the portlet mode or the window state has changed since.
082         * The values stored previously (during an action request) are compared to
083         * the current values.
084         */
085    
086        boolean isStateChange(IRequestCycle cycle)
087        {
088            String expectedPortletMode = cycle
089                    .getParameter(PortletConstants.PORTLET_MODE);
090            String expectedWindowState = cycle
091                    .getParameter(PortletConstants.WINDOW_STATE);
092    
093            return !(_request.getPortletMode().toString().equals(
094                    expectedPortletMode) && _request.getWindowState().toString()
095                    .equals(expectedWindowState));
096    
097        }
098    
099        public String getName()
100        {
101            return PortletConstants.RENDER_SERVICE;
102        }
103    
104        public void setPortletRenderer(PortletRenderer portletRenderer)
105        {
106            _portletRenderer = portletRenderer;
107        }
108    
109        public void setRequest(PortletRequest request)
110        {
111            _request = request;
112        }
113    
114        public void setPageResolver(PortletPageResolver pageResolver)
115        {
116            _pageResolver = pageResolver;
117        }
118    }