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 action processing that
028     * stores the active page; this is the page that will be rendered. The render service is (typically)
029     * the only service that operates during a portlet RenderRequest. All other services will be an
030     * ActionRequest that (via {@link org.apache.tapestry.portlet.PortletResponseRenderer}, writes
031     * query parameters to activate this service during the render request.
032     * <p>
033     * Problematic is is anything related to the portlet mode or window state. As per the Portlet spec,
034     * when the user clicks the "help" or "edit" buttons (or the minimize, maximize, etc.), this causes
035     * a new RenderRequest, but explicitly keeps the render parameters set by the most recent
036     * ActionRequest. But what Tapestry needs is to detect that the mode or state has changed and select
037     * a different page to render the response. So we store the mode and state in effect when the
038     * ActionRequest executed as two more query parameters, and detect changes to mode and state that
039     * way. If there is a change, then we ignore the page query parameter and use the
040     * {@link PortletPageResolver} to figure out the correct page to display instead.
041     * 
042     * @author Howard M. Lewis Ship
043     * @since 4.0
044     * @see org.apache.tapestry.services.impl.ResponseRendererImpl
045     */
046    public class RenderService implements IEngineService
047    {
048        private PortletRequest _request;
049    
050        private PortletRenderer _portletRenderer;
051    
052        private PortletPageResolver _pageResolver;
053    
054        public ILink getLink(boolean post, Object parameter)
055        {
056            throw new UnsupportedOperationException(PortletMessages.unsupportedMethod("getLink"));
057        }
058    
059        public void service(IRequestCycle cycle) throws IOException
060        {
061            String pageName = getPageNameToRender(cycle);
062    
063            _portletRenderer.renderPage(cycle, pageName);
064        }
065    
066        private String getPageNameToRender(IRequestCycle cycle)
067        {
068            if (isStateChange(cycle))
069                return _pageResolver.getPageNameForRequest(cycle);
070    
071            return cycle.getParameter(ServiceConstants.PAGE);
072        }
073    
074        /**
075         * Returns true if the portlet mode or the window state has changed since. The values stored
076         * previously (during an action request) are compared to the current values.
077         */
078    
079        boolean isStateChange(IRequestCycle cycle)
080        {
081            String expectedPortletMode = cycle.getParameter(PortletConstants.PORTLET_MODE);
082            String expectedWindowState = cycle.getParameter(PortletConstants.WINDOW_STATE);
083    
084            return !(_request.getPortletMode().toString().equals(expectedPortletMode) && _request
085                    .getWindowState().toString().equals(expectedWindowState));
086    
087        }
088    
089        public String getName()
090        {
091            return PortletConstants.RENDER_SERVICE;
092        }
093    
094        public void setPortletRenderer(PortletRenderer portletRenderer)
095        {
096            _portletRenderer = portletRenderer;
097        }
098    
099        public void setRequest(PortletRequest request)
100        {
101            _request = request;
102        }
103    
104        public void setPageResolver(PortletPageResolver pageResolver)
105        {
106            _pageResolver = pageResolver;
107        }
108    }