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.wrapper;
018:
019: import java.io.IOException;
020: import java.io.OutputStream;
021: import java.net.MalformedURLException;
022: import java.util.HashMap;
023: import java.util.Iterator;
024: import java.util.Map;
025:
026: import org.apache.avalon.framework.component.ComponentManager;
027: import org.apache.avalon.framework.logger.Logger;
028: import org.apache.cocoon.Constants;
029: import org.apache.cocoon.environment.AbstractEnvironment;
030: import org.apache.cocoon.environment.Environment;
031: import org.apache.cocoon.environment.ObjectModelHelper;
032: import org.apache.cocoon.environment.Request;
033: import org.apache.cocoon.environment.Response;
034: import org.apache.cocoon.util.BufferedOutputStream;
035: import org.apache.cocoon.util.Deprecation;
036:
037: /**
038: * This is a wrapper class for the <code>Environment</code> object.
039: * It has the same properties except that the object model
040: * contains a <code>RequestWrapper</code> object.
041: *
042: * @author <a href="mailto:bluetkemeier@s-und-n.de">Björn Lütkemeier</a>
043: * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
044: * @version $Id: EnvironmentWrapper.java 433543 2006-08-22 06:22:54Z crossley $
045: */
046: public class EnvironmentWrapper extends AbstractEnvironment {
047:
048: /** The wrapped environment */
049: protected Environment environment;
050:
051: /** The object model */
052: protected Map objectModel;
053:
054: /** The redirect url */
055: protected String redirectURL;
056:
057: /** The request object */
058: protected Request request;
059:
060: /** The stream to output to */
061: protected OutputStream outputStream;
062:
063: protected String contentType;
064:
065: protected boolean internalRedirect = false;
066:
067: /**
068: * Constructs an EnvironmentWrapper object from a Request
069: * and Response objects
070: */
071: public EnvironmentWrapper(Environment env, String requestURI,
072: String queryString, Logger logger)
073: throws MalformedURLException {
074: this (env, requestURI, queryString, logger, false);
075: }
076:
077: /**
078: * Constructs an EnvironmentWrapper object from a Request
079: * and Response objects
080: */
081: public EnvironmentWrapper(Environment env, String requestURI,
082: String queryString, Logger logger, boolean rawMode)
083: throws MalformedURLException {
084: this (env, requestURI, queryString, logger, null, rawMode);
085: }
086:
087: /**
088: * Constructs an EnvironmentWrapper object from a Request
089: * and Response objects
090: */
091: public EnvironmentWrapper(Environment env, String requestURI,
092: String queryString, Logger logger,
093: ComponentManager manager, boolean rawMode)
094: throws MalformedURLException {
095: this (env, requestURI, queryString, logger, null, rawMode, env
096: .getView(), true);
097: }
098:
099: /**
100: * Constructs an EnvironmentWrapper object from a Request
101: * and Response objects
102: */
103: public EnvironmentWrapper(Environment env, String requestURI,
104: String queryString, Logger logger,
105: ComponentManager manager, boolean rawMode, String view)
106: throws MalformedURLException {
107: this (env, requestURI, queryString, logger, manager, rawMode,
108: view, true);
109: }
110:
111: /**
112: * Constructs an EnvironmentWrapper object from a Request
113: * and Response objects
114: */
115: public EnvironmentWrapper(Environment env, String requestURI,
116: String queryString, Logger logger,
117: ComponentManager manager, boolean rawMode, String view,
118: boolean wrapResponse) throws MalformedURLException {
119: super (env.getURI(), view, env.getContext(), env.getAction());
120: init(env, requestURI, queryString, logger, manager, rawMode,
121: view, wrapResponse);
122: }
123:
124: private void init(Environment env, String requestURI,
125: String queryString, Logger logger,
126: ComponentManager manager, boolean rawMode, String view,
127: boolean wrapResponse) throws MalformedURLException {
128: // super(env.getURI(), view, env.getContext(), env.getAction());
129: this .rootContext = env.getRootContext();
130:
131: this .enableLogging(logger);
132: this .environment = env;
133: this .view = view;
134:
135: this .prefix = new StringBuffer(env.getURIPrefix());
136:
137: // create new object model and replace the request object
138: Map oldObjectModel = env.getObjectModel();
139: if (oldObjectModel instanceof HashMap) {
140: this .objectModel = (Map) ((HashMap) oldObjectModel).clone();
141: } else {
142: this .objectModel = new HashMap(oldObjectModel.size() * 2);
143: Iterator entries = oldObjectModel.entrySet().iterator();
144: Map.Entry entry;
145: while (entries.hasNext()) {
146: entry = (Map.Entry) entries.next();
147: this .objectModel.put(entry.getKey(), entry.getValue());
148: }
149: }
150: this .request = new RequestWrapper(ObjectModelHelper
151: .getRequest(oldObjectModel), requestURI, queryString,
152: this , rawMode);
153: this .objectModel.put(ObjectModelHelper.REQUEST_OBJECT,
154: this .request);
155: if (wrapResponse) {
156: Response response = new ResponseWrapper(ObjectModelHelper
157: .getResponse(oldObjectModel));
158: this .objectModel.put(ObjectModelHelper.RESPONSE_OBJECT,
159: response);
160: }
161: }
162:
163: public EnvironmentWrapper(Environment env,
164: ComponentManager manager, String uri, Logger logger,
165: boolean wrapResponse) throws MalformedURLException {
166: super (env.getURI(), env.getView(), env.getContext(), env
167: .getAction());
168:
169: // FIXME(SW): code stolen from SitemapSource. Factorize somewhere...
170: boolean rawMode = false;
171:
172: // remove the protocol
173: int position = uri.indexOf(':') + 1;
174: if (position != 0) {
175: // this.protocol = uri.substring(0, position-1);
176: // check for subprotocol
177: if (uri.startsWith("raw:", position)) {
178: position += 4;
179: rawMode = true;
180: }
181: } else {
182: throw new MalformedURLException(
183: "No protocol found for sitemap source in " + uri);
184: }
185:
186: // does the uri point to this sitemap or to the root sitemap?
187: String prefix;
188: if (uri.startsWith("//", position)) {
189: position += 2;
190: // try {
191: // this.processor = (Processor)this.manager.lookup(Processor.ROLE);
192: // } catch (ComponentException e) {
193: // throw new MalformedURLException("Cannot get Processor instance");
194: // }
195: prefix = ""; // start at the root
196: } else if (uri.startsWith("/", position)) {
197: position++;
198: prefix = null;
199: // this.processor = CocoonComponentManager.getCurrentProcessor();
200: } else {
201: throw new MalformedURLException("Malformed cocoon URI: "
202: + uri);
203: }
204:
205: // create the queryString (if available)
206: String queryString = null;
207: int queryStringPos = uri.indexOf('?', position);
208: if (queryStringPos != -1) {
209: queryString = uri.substring(queryStringPos + 1);
210: uri = uri.substring(position, queryStringPos);
211: } else if (position > 0) {
212: uri = uri.substring(position);
213: }
214:
215: // determine if the queryString specifies a cocoon-view
216: String view = null;
217: if (queryString != null) {
218: int index = queryString.indexOf(Constants.VIEW_PARAM);
219: if (index != -1
220: && (index == 0 || queryString.charAt(index - 1) == '&')
221: && queryString.length() > index
222: + Constants.VIEW_PARAM.length()
223: && queryString.charAt(index
224: + Constants.VIEW_PARAM.length()) == '=') {
225:
226: String tmp = queryString.substring(index
227: + Constants.VIEW_PARAM.length() + 1);
228: index = tmp.indexOf('&');
229: if (index != -1) {
230: view = tmp.substring(0, index);
231: } else {
232: view = tmp;
233: }
234: } else {
235: view = env.getView();
236: }
237: } else {
238: view = env.getView();
239: }
240:
241: // build the request uri which is relative to the context
242: String requestURI = (prefix == null ? env.getURIPrefix() + uri
243: : uri);
244:
245: // // create system ID
246: // this.systemId = queryString == null ?
247: // this.protocol + "://" + requestURI :
248: // this.protocol + "://" + requestURI + "?" + queryString;
249:
250: this .init(env, requestURI, queryString, logger, manager,
251: rawMode, view, wrapResponse);
252: this .setURI(prefix, uri);
253:
254: }
255:
256: /**
257: * Redirect the client to a new URL is not allowed
258: */
259: public void redirect(boolean sessionmode, String newURL)
260: throws IOException {
261: this .redirectURL = newURL;
262:
263: // check if session mode shall be activated
264: if (sessionmode) {
265: // get session from request, or create new session
266: request.getSession(true);
267: }
268: }
269:
270: /**
271: * Redirect in the first non-wrapped environment
272: */
273: public void globalRedirect(boolean sessionmode, String newURL)
274: throws IOException {
275: if (environment instanceof EnvironmentWrapper) {
276: ((EnvironmentWrapper) environment).globalRedirect(
277: sessionmode, newURL);
278: } else if (environment instanceof MutableEnvironmentFacade) {
279: ((MutableEnvironmentFacade) environment).getDelegate()
280: .globalRedirect(sessionmode, newURL);
281: } else {
282: environment.redirect(sessionmode, newURL);
283: }
284: }
285:
286: /**
287: * Get the output stream
288: * @deprecated use {@link #getOutputStream(int)} instead.
289: */
290: public OutputStream getOutputStream() throws IOException {
291: Deprecation.logger
292: .warn("The method Environment.getOutputStream() "
293: + "is deprecated. Use getOutputStream(-1) instead.");
294: // by default we use the complete buffering output stream
295: return getOutputStream(-1);
296: }
297:
298: /**
299: * Get the output stream
300: */
301: public OutputStream getOutputStream(int bufferSize)
302: throws IOException {
303: return this .outputStream == null ? this .environment
304: .getOutputStream(bufferSize) : this .outputStream;
305: }
306:
307: /**
308: * Set the output stream for this environment. It hides the one of the
309: * wrapped environment.
310: */
311: public void setOutputStream(OutputStream stream) {
312: this .outputStream = stream;
313: }
314:
315: /**
316: * Reset the response if possible. This allows error handlers to have
317: * a higher chance to produce clean output if the pipeline that raised
318: * the error has already output some data.
319: *
320: * @return true if the response was successfully reset
321: */
322: public boolean tryResetResponse() throws IOException {
323: final OutputStream outputStream = getOutputStream(-1);
324: if (outputStream != null
325: && outputStream instanceof BufferedOutputStream) {
326: ((BufferedOutputStream) outputStream).clearBuffer();
327: return true;
328: } else {
329: return super .tryResetResponse();
330: }
331: }
332:
333: /**
334: * Commit the response
335: */
336: public void commitResponse() throws IOException {
337: final OutputStream outputStream = getOutputStream(-1);
338: if (outputStream != null
339: && outputStream instanceof BufferedOutputStream) {
340: ((BufferedOutputStream) outputStream).realFlush();
341: } else {
342: super .commitResponse();
343: }
344: }
345:
346: /**
347: * if a redirect should happen this returns the url,
348: * otherwise <code>null</code> is returned
349: */
350: public String getRedirectURL() {
351: return this .redirectURL;
352: }
353:
354: public void reset() {
355: this .redirectURL = null;
356: }
357:
358: /**
359: * Set the StatusCode
360: */
361: public void setStatus(int statusCode) {
362: // ignore this
363: }
364:
365: public void setContentLength(int length) {
366: // ignore this
367: }
368:
369: /**
370: * Set the ContentType
371: */
372: public void setContentType(String contentType) {
373: this .contentType = contentType;
374: }
375:
376: /**
377: * Get the ContentType
378: */
379: public String getContentType() {
380: return this .contentType;
381: }
382:
383: /**
384: * Get the underlying object model
385: */
386: public Map getObjectModel() {
387: return this .objectModel;
388: }
389:
390: /**
391: * Set a new URI for processing. If the prefix is null the
392: * new URI is inside the current context.
393: * If the prefix is not null the context is changed to the root
394: * context and the prefix is set.
395: */
396: public void setURI(String prefix, String uris) {
397: if (getLogger().isDebugEnabled()) {
398: getLogger().debug(
399: "Setting uri (prefix=" + prefix + ", uris=" + uris
400: + ")");
401: }
402: if (!this .initializedComponents) {
403: this .initComponents();
404: }
405: if (prefix != null) {
406: setContext(getRootContext());
407: setURIPrefix(prefix);
408: }
409: this .uris = uris;
410: }
411:
412: /**
413: * Lookup an attribute in this instance, and if not found search it
414: * in the wrapped environment.
415: *
416: * @param name a <code>String</code>, the name of the attribute to
417: * look for
418: * @return an <code>Object</code>, the value of the attribute or
419: * null if no such attribute was found.
420: */
421: public Object getAttribute(String name) {
422: Object value = super .getAttribute(name);
423:
424: // get it from the wrapped env only if it's not defined here with a null value
425: if (value == null && !hasAttribute(name)) {
426: value = this .environment.getAttribute(name);
427: }
428:
429: return value;
430: }
431:
432: /**
433: * Always return <code>false</code>.
434: */
435: public boolean isExternal() {
436: return false;
437: }
438:
439: public void setInternalRedirect(boolean flag) {
440: this .internalRedirect = flag;
441: if (flag) {
442: ((RequestWrapper) this .request).setRequestURI(this .prefix
443: .toString(), this .uris);
444: }
445: }
446:
447: /* (non-Javadoc)
448: * @see org.apache.cocoon.environment.Environment#isInternRedirect()
449: */
450: public boolean isInternalRedirect() {
451: return this.internalRedirect;
452: }
453: }
|