001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.environment.portlet;
018:
019: import org.apache.cocoon.environment.AbstractEnvironment;
020: import org.apache.cocoon.environment.Context;
021: import org.apache.cocoon.environment.ObjectModelHelper;
022: import org.apache.cocoon.environment.PermanentRedirector;
023: import org.apache.cocoon.environment.Redirector;
024: import org.apache.cocoon.environment.Session;
025:
026: import javax.portlet.PortletContext;
027: import java.io.IOException;
028: import java.io.OutputStream;
029:
030: /**
031: * Implements {@link org.apache.cocoon.environment.Environment} interface for the JSR-168
032: * Portlet environment.
033: *
034: * @author <a href="mailto:alex.rudnev@dc.gov">Alex Rudnev</a>
035: * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
036: * @version CVS $Id: PortletEnvironment.java 433543 2006-08-22 06:22:54Z crossley $
037: */
038: public class PortletEnvironment extends AbstractEnvironment implements
039: Redirector, PermanentRedirector {
040:
041: /**
042: * As portlets do not have a pathInfo in the request, we can simulate this by passing
043: * a parameter. If parameter is null, this will translate to the absent pathInfo,
044: * and portlets will be matched in the sitemap using only servletPath.
045: */
046: public static final String PARAMETER_PATH_INFO = "cocoon-portlet-path";
047:
048: /**
049: * This header can be read from any portlet request,
050: * and can be set on action response.
051: */
052: public static final String HEADER_PORTLET_MODE = "X-Portlet-Mode";
053:
054: /**
055: * This header can be read from any portlet request,
056: * and can be set on action response.
057: */
058: public static final String HEADER_WINDOW_STATE = "X-Window-State";
059:
060: /**
061: * This header can be set only, and only on render response.
062: */
063: public static final String HEADER_PORTLET_TITLE = "X-Portlet-Title";
064:
065: /**
066: * This is the prefix for application scope session attributes.
067: */
068: public static final String SESSION_APPLICATION_SCOPE = "portlet-application-";
069:
070: /**
071: * This is the prefix for portlet scope session attributes.
072: */
073: public static final String SESSION_PORTLET_SCOPE = "portlet-portlet-";
074:
075: /**
076: * The PortletRequest
077: */
078: private PortletRequest request;
079:
080: /**
081: * The PortletResponse
082: */
083: private PortletResponse response;
084:
085: /**
086: * The PortletContext
087: */
088: private Context context;
089:
090: /**
091: * Cache content type as there is no getContentType()
092: * method on reponse object
093: */
094: private String contentType;
095:
096: /**
097: * Did we redirect?
098: */
099: private boolean hasRedirected;
100:
101: /**
102: * @see #getDefaultSessionScope()
103: */
104: private int defaultSessionScope;
105:
106: /**
107: * Constructs a PortletEnvironment object from a PortletRequest
108: * and PortletResponse objects
109: */
110: public PortletEnvironment(String servletPath, String pathInfo,
111: String uri, String root,
112: javax.portlet.ActionRequest request,
113: javax.portlet.ActionResponse response,
114: PortletContext portletContext, Context context,
115: String containerEncoding, String defaultFormEncoding,
116: int defaultSessionScope) throws IOException {
117: super (uri, null, root, null);
118:
119: this .request = new ActionRequest(servletPath, pathInfo,
120: request, this );
121: this .request.setCharacterEncoding(defaultFormEncoding);
122: this .request.setContainerEncoding(containerEncoding);
123: this .response = new ActionResponse(response, request
124: .getPreferences(), (ActionRequest) this .request, uri);
125: this .context = context;
126: this .defaultSessionScope = defaultSessionScope;
127:
128: setView(extractView(this .request));
129: setAction(extractAction(this .request));
130:
131: initObjectModel(request, response, portletContext);
132: }
133:
134: /**
135: * Constructs a PortletEnvironment object from a PortletRequest
136: * and PortletResponse objects
137: */
138: public PortletEnvironment(String servletPath, String pathInfo,
139: String uri, String root,
140: javax.portlet.RenderRequest request,
141: javax.portlet.RenderResponse response,
142: PortletContext portletContext, Context context,
143: String containerEncoding, String defaultFormEncoding,
144: int defaultSessionScope) throws IOException {
145: super (uri, null, root, null);
146:
147: this .request = new RenderRequest(servletPath, pathInfo,
148: request, this );
149: this .request.setCharacterEncoding(defaultFormEncoding);
150: this .request.setContainerEncoding(containerEncoding);
151: this .response = new RenderResponse(response, request
152: .getPreferences());
153: this .context = context;
154: this .defaultSessionScope = defaultSessionScope;
155:
156: setView(extractView(this .request));
157: setAction(extractAction(this .request));
158:
159: initObjectModel(request, response, portletContext);
160: }
161:
162: private void initObjectModel(
163: javax.portlet.PortletRequest portletRequest,
164: javax.portlet.PortletResponse portletResponse,
165: PortletContext portletContext) {
166: this .objectModel.put(ObjectModelHelper.REQUEST_OBJECT,
167: this .request);
168: this .objectModel.put(ObjectModelHelper.RESPONSE_OBJECT,
169: this .response);
170: this .objectModel.put(ObjectModelHelper.CONTEXT_OBJECT,
171: this .context);
172:
173: // This is a kind of a hack for the components that need
174: // the real portlet objects to pass them along to other
175: // libraries.
176: PortletObjectModelHelper.setPortletRequest(this .objectModel,
177: portletRequest);
178: PortletObjectModelHelper.setPortletResponse(this .objectModel,
179: portletResponse);
180: PortletObjectModelHelper.setPortletContext(this .objectModel,
181: portletContext);
182: }
183:
184: public void redirect(boolean sessionmode, String newURL)
185: throws IOException {
186: this .hasRedirected = true;
187:
188: // check if session mode shall be activated
189: if (sessionmode) {
190: if (getLogger().isDebugEnabled()) {
191: String s = request.getRequestedSessionId();
192: if (s != null) {
193: getLogger()
194: .debug(
195: "Session ID in request = "
196: + s
197: + (request
198: .isRequestedSessionIdValid() ? " (valid)"
199: : " (invalid)"));
200: }
201: }
202:
203: // get session from request, or create new session
204: Session session = request.getSession(true);
205: if (getLogger().isDebugEnabled()) {
206: getLogger().debug("Session ID = " + session.getId());
207: }
208: }
209:
210: // redirect
211: String redirect = newURL;
212: if (getLogger().isDebugEnabled()) {
213: getLogger().debug("Sending redirect to '" + redirect + "'");
214: }
215:
216: this .response.sendRedirect(redirect);
217: }
218:
219: /**
220: * In portlet environment this is the same as {@link #redirect(boolean, String)}
221: */
222: public void permanentRedirect(boolean sessionmode, String newURL)
223: throws IOException {
224: redirect(sessionmode, newURL);
225: }
226:
227: public boolean hasRedirected() {
228: return this .hasRedirected;
229: }
230:
231: /**
232: * Portlet environment does not support response status code.
233: */
234: public void setStatus(int statusCode) {
235: }
236:
237: /**
238: * Portlet environment does not support response status code.
239: */
240: public void sendStatus(int sc) {
241: throw new AbstractMethodError("Not Implemented");
242: }
243:
244: /**
245: * Set the ContentType
246: */
247: public void setContentType(String contentType) {
248: this .response.setContentType(contentType);
249: this .contentType = contentType;
250: }
251:
252: /**
253: * Get the ContentType
254: */
255: public String getContentType() {
256: return this .contentType;
257: }
258:
259: /**
260: * Portlet environment does not support response content length.
261: * This method does nothing.
262: */
263: public void setContentLength(int length) {
264: }
265:
266: /**
267: * This method always returns true because portlet environment
268: * does not support response codes.
269: */
270: public boolean isResponseModified(long lastModified) {
271: return true;
272: }
273:
274: /**
275: * Portlet environment does not support response status code.
276: * This method does nothing.
277: */
278: public void setResponseIsNotModified() {
279: }
280:
281: /**
282: * Reset the response if possible. This allows error handlers to have
283: * a higher chance to produce clean output if the pipeline that raised
284: * the error has already output some data.
285: *
286: * @return true if the response was successfully reset
287: */
288: public boolean tryResetResponse() throws IOException {
289: if (!super .tryResetResponse()) {
290: try {
291: if (!this .response.isCommitted()) {
292: this .response.reset();
293: if (getLogger().isDebugEnabled()) {
294: getLogger()
295: .debug("Response successfully reset");
296: }
297: return true;
298: }
299: } catch (Exception e) {
300: // Log the error, but don't transmit it
301: getLogger().warn("Problem resetting response", e);
302: }
303: if (getLogger().isDebugEnabled()) {
304: getLogger().debug("Response wasn't reset");
305: }
306: return false;
307: }
308: return true;
309: }
310:
311: /**
312: * Get the output stream where to write the generated resource.
313: * The returned stream is buffered by the environment. If the
314: * buffer size is -1 then the complete output is buffered.
315: * If the buffer size is 0, no buffering takes place.
316: * This method replaces {@link #getOutputStream()}.
317: */
318: public OutputStream getOutputStream(final int bufferSize)
319: throws IOException {
320: if (this .outputStream == null) {
321: this .outputStream = this .response.getOutputStream();
322: }
323: return super .getOutputStream(bufferSize);
324: }
325:
326: /**
327: * Always return <code>true</code>.
328: */
329: public boolean isExternal() {
330: return true;
331: }
332:
333: /**
334: * Default scope for the session attributes, either
335: * {@link javax.portlet.PortletSession#PORTLET_SCOPE} or
336: * {@link javax.portlet.PortletSession#APPLICATION_SCOPE}.
337: */
338: int getDefaultSessionScope() {
339: return this.defaultSessionScope;
340: }
341: }
|