001 // Copyright 2004, 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.engine;
016
017 import java.io.IOException;
018 import java.util.HashMap;
019 import java.util.Map;
020
021 import org.apache.hivemind.ApplicationRuntimeException;
022 import org.apache.hivemind.util.Defense;
023 import org.apache.tapestry.IComponent;
024 import org.apache.tapestry.IDirect;
025 import org.apache.tapestry.IPage;
026 import org.apache.tapestry.IRequestCycle;
027 import org.apache.tapestry.StaleSessionException;
028 import org.apache.tapestry.Tapestry;
029 import org.apache.tapestry.services.LinkFactory;
030 import org.apache.tapestry.services.ResponseRenderer;
031 import org.apache.tapestry.services.ServiceConstants;
032 import org.apache.tapestry.web.WebRequest;
033 import org.apache.tapestry.web.WebSession;
034
035 /**
036 * Implementation of the direct service, which encodes the page and component id in the service
037 * context, and passes application-defined parameters as well.
038 *
039 * @author Howard Lewis Ship
040 * @since 1.0.9
041 */
042
043 public class DirectService implements IEngineService
044 {
045 /** @since 4.0 */
046 protected ResponseRenderer _responseRenderer;
047
048 /** @since 4.0 */
049 protected LinkFactory _linkFactory;
050
051 /** @since 4.0 */
052 protected WebRequest _request;
053
054 /** @since 4.0 */
055 private IRequestCycle _requestCycle;
056
057 public ILink getLink(boolean post, Object parameter)
058 {
059 Defense.isAssignable(parameter, DirectServiceParameter.class, "parameter");
060
061 DirectServiceParameter dsp = (DirectServiceParameter) parameter;
062
063 IComponent component = dsp.getDirect();
064
065 // New since 1.0.1, we use the component to determine
066 // the page, not the cycle. Through the use of tricky
067 // things such as Block/InsertBlock, it is possible
068 // that a component from a page different than
069 // the response page will render.
070 // In 1.0.6, we start to record *both* the render page
071 // and the component page (if different).
072
073 IPage activePage = _requestCycle.getPage();
074 IPage componentPage = component.getPage();
075
076 Map parameters = new HashMap();
077
078 boolean stateful = _request.getSession(false) != null;
079
080 parameters.put(ServiceConstants.PAGE, activePage.getPageName());
081 parameters.put(ServiceConstants.COMPONENT, component.getIdPath());
082 parameters.put(ServiceConstants.CONTAINER, componentPage == activePage ? null
083 : componentPage.getPageName());
084 parameters.put(ServiceConstants.SESSION, stateful ? "T" : null);
085 parameters.put(ServiceConstants.PARAMETER, dsp.getServiceParameters());
086
087 return _linkFactory.constructLink(this, post, parameters, true);
088 }
089
090 public void service(IRequestCycle cycle) throws IOException
091 {
092 String componentId = cycle.getParameter(ServiceConstants.COMPONENT);
093 String componentPageName = cycle.getParameter(ServiceConstants.CONTAINER);
094 String activePageName = cycle.getParameter(ServiceConstants.PAGE);
095 boolean activeSession = cycle.getParameter(ServiceConstants.SESSION) != null;
096
097 IPage page = cycle.getPage(activePageName);
098
099 cycle.activate(page);
100
101 IPage componentPage = componentPageName == null ? page : cycle.getPage(componentPageName);
102
103 IComponent component = componentPage.getNestedComponent(componentId);
104
105 IDirect direct = null;
106
107 try
108 {
109 direct = (IDirect) component;
110 }
111 catch (ClassCastException ex)
112 {
113 throw new ApplicationRuntimeException(EngineMessages.wrongComponentType(
114 component,
115 IDirect.class), component, null, ex);
116 }
117
118 // Check for a StaleSession only when the session was stateful when
119 // the link was created.
120
121 if (activeSession && direct.isStateful())
122 {
123 WebSession session = _request.getSession(false);
124
125 if (session == null || session.isNew())
126 throw new StaleSessionException(EngineMessages.requestStateSession(direct),
127 componentPage);
128 }
129
130 Object[] parameters = _linkFactory.extractListenerParameters(cycle);
131
132 triggerComponent(cycle, direct, parameters);
133
134 // Render the response. This will be the active page
135 // unless the direct component (or its delegate) changes it.
136
137 _responseRenderer.renderResponse(cycle);
138 }
139
140 /** @since 4.0 */
141
142 protected void triggerComponent(IRequestCycle cycle, IDirect direct, Object[] parameters)
143 {
144 cycle.setListenerParameters(parameters);
145
146 direct.trigger(cycle);
147 }
148
149 public String getName()
150 {
151 return Tapestry.DIRECT_SERVICE;
152 }
153
154 /** @since 4.0 */
155 public void setResponseRenderer(ResponseRenderer responseRenderer)
156 {
157 _responseRenderer = responseRenderer;
158 }
159
160 /** @since 4.0 */
161 public void setLinkFactory(LinkFactory linkFactory)
162 {
163 _linkFactory = linkFactory;
164 }
165
166 /** @since 4.0 */
167 public void setRequest(WebRequest request)
168 {
169 _request = request;
170 }
171
172 /** @since 4.0 */
173 public void setRequestCycle(IRequestCycle requestCycle)
174 {
175 _requestCycle = requestCycle;
176 }
177 }