/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cocoon.environment.wrapper; import java.io.IOException; import java.io.OutputStream; import java.net.MalformedURLException; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.apache.avalon.framework.component.ComponentManager; import org.apache.avalon.framework.logger.Logger; import org.apache.cocoon.Constants; import org.apache.cocoon.environment.AbstractEnvironment; import org.apache.cocoon.environment.Environment; import org.apache.cocoon.environment.ObjectModelHelper; import org.apache.cocoon.environment.PermanentRedirector; import org.apache.cocoon.environment.Redirector; import org.apache.cocoon.environment.Request; import org.apache.cocoon.environment.Response; import org.apache.cocoon.util.BufferedOutputStream; /** * This is a wrapper class for the <code>Environment</code> object. * It has the same properties except that the object model * contains a <code>RequestWrapper</code> object. * * @author <a href="mailto:bluetkemeier@s-und-n.de">Björn Lütkemeier</a> * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a> * @version $Id$ */ public class EnvironmentWrapper extends AbstractEnvironment implements Redirector, PermanentRedirector { /** The wrapped environment */ protected Environment environment; /** The object model */ protected Map objectModel; /** The redirect url */ protected String redirectURL; /** The request object */ protected Request request; /** The stream to output to */ protected OutputStream outputStream; protected String contentType; protected boolean internalRedirect = false; protected boolean hasRedirected; protected boolean permanentRedirection; /** * Constructs an EnvironmentWrapper object from a Request * and Response objects */ public EnvironmentWrapper(Environment env, String requestURI, String queryString, Logger logger) throws MalformedURLException { this(env, requestURI, queryString, logger, false); } /** * Constructs an EnvironmentWrapper object from a Request * and Response objects */ public EnvironmentWrapper(Environment env, String requestURI, String queryString, Logger logger, boolean rawMode) throws MalformedURLException { this(env, requestURI, queryString, logger, null, rawMode); } /** * Constructs an EnvironmentWrapper object from a Request * and Response objects */ public EnvironmentWrapper(Environment env, String requestURI, String queryString, Logger logger, ComponentManager manager, boolean rawMode) throws MalformedURLException { this(env, requestURI, queryString, logger, null, rawMode,env.getView(), true); } /** * Constructs an EnvironmentWrapper object from a Request * and Response objects */ public EnvironmentWrapper(Environment env, String requestURI, String queryString, Logger logger, ComponentManager manager, boolean rawMode, String view) throws MalformedURLException { this(env, requestURI, queryString, logger, manager, rawMode, view, true); } /** * Constructs an EnvironmentWrapper object from a Request * and Response objects */ public EnvironmentWrapper(Environment env, String requestURI, String queryString, Logger logger, ComponentManager manager, boolean rawMode, String view, boolean wrapResponse) throws MalformedURLException { super(env.getURI(), view, env.getContext(), env.getAction()); init(env, requestURI, queryString, logger, manager, rawMode, view, wrapResponse); } private void init(Environment env, String requestURI, String queryString, Logger logger, ComponentManager manager, boolean rawMode, String view, boolean wrapResponse) throws MalformedURLException { // super(env.getURI(), view, env.getContext(), env.getAction()); this.rootContext = env.getRootContext(); this.enableLogging(logger); this.environment = env; this.view = view; this.prefix = new StringBuffer(env.getURIPrefix()); // create new object model and replace the request object Map oldObjectModel = env.getObjectModel(); if (oldObjectModel instanceof HashMap) { this.objectModel = (Map)((HashMap)oldObjectModel).clone(); } else { this.objectModel = new HashMap(oldObjectModel.size()*2); Iterator entries = oldObjectModel.entrySet().iterator(); Map.Entry entry; while (entries.hasNext()) { entry = (Map.Entry)entries.next(); this.objectModel.put(entry.getKey(), entry.getValue()); } } this.request = new RequestWrapper(ObjectModelHelper.getRequest(oldObjectModel), requestURI, queryString, this, rawMode); this.objectModel.put(ObjectModelHelper.REQUEST_OBJECT, this.request); if (wrapResponse) { Response response = new ResponseWrapper(ObjectModelHelper.getResponse(oldObjectModel)); this.objectModel.put(ObjectModelHelper.RESPONSE_OBJECT, response); } } public EnvironmentWrapper(Environment env, ComponentManager manager, String uri, Logger logger, boolean wrapResponse) throws MalformedURLException { super(env.getURI(), env.getView(), env.getContext(), env.getAction()); // FIXME(SW): code stolen from SitemapSource. Factorize somewhere... boolean rawMode = false; // remove the protocol int position = uri.indexOf(':') + 1; if (position != 0) { // this.protocol = uri.substring(0, position-1); // check for subprotocol if (uri.startsWith("raw:", position)) { position += 4; rawMode = true; } } else { throw new MalformedURLException("No protocol found for sitemap source in " + uri); } // does the uri point to this sitemap or to the root sitemap? String prefix; if (uri.startsWith("//", position)) { position += 2; // try { // this.processor = (Processor)this.manager.lookup(Processor.ROLE); // } catch (ComponentException e) { // throw new MalformedURLException("Cannot get Processor instance"); // } prefix = ""; // start at the root } else if (uri.startsWith("/", position)) { position ++; prefix = null; // this.processor = CocoonComponentManager.getCurrentProcessor(); } else { throw new MalformedURLException("Malformed cocoon URI: " + uri); } // create the queryString (if available) String queryString = null; int queryStringPos = uri.indexOf('?', position); if (queryStringPos != -1) { queryString = uri.substring(queryStringPos + 1); uri = uri.substring(position, queryStringPos); } else if (position > 0) { uri = uri.substring(position); } // determine if the queryString specifies a cocoon-view String view = null; if (queryString != null) { int index = queryString.indexOf(Constants.VIEW_PARAM); if (index != -1 && (index == 0 || queryString.charAt(index-1) == '&') && queryString.length() > index + Constants.VIEW_PARAM.length() && queryString.charAt(index+Constants.VIEW_PARAM.length()) == '=') { String tmp = queryString.substring(index+Constants.VIEW_PARAM.length()+1); index = tmp.indexOf('&'); if (index != -1) { view = tmp.substring(0,index); } else { view = tmp; } } else { view = env.getView(); } } else { view = env.getView(); } // build the request uri which is relative to the context String requestURI = (prefix == null ? env.getURIPrefix() + uri : uri); // // create system ID // this.systemId = queryString == null ? // this.protocol + "://" + requestURI : // this.protocol + "://" + requestURI + "?" + queryString; this.init(env, requestURI, queryString, logger, manager, rawMode, view, wrapResponse); this.setURI(prefix, uri); } /** * Redirect the client to a new URL is not allowed */ public void redirect(boolean sessionmode, String newURL) throws IOException { this.redirectURL = newURL; this.hasRedirected = true; // check if session mode shall be activated if (sessionmode) { // get session from request, or create new session request.getSession(true); } } /** * Permanentlty redirect the client to a new URL is not allowed */ public void permanentRedirect(boolean sessionmode, String newURL) throws IOException { this.redirect(sessionmode, newURL); this.permanentRedirection = true; } public boolean hasRedirected() { return this.hasRedirected; } /** * Has a permanent redirection been asked */ public boolean isPermanentRedirection() { return this.permanentRedirection; } public void sendStatus(int sc) { this.setStatus(sc); this.hasRedirected = true; } /** * Redirect in the first non-wrapped environment */ public void globalRedirect(boolean sessionmode, String newURL) throws IOException { if (environment instanceof EnvironmentWrapper) { ((EnvironmentWrapper)environment).globalRedirect(sessionmode, newURL); } else if ( environment instanceof MutableEnvironmentFacade ) { ((MutableEnvironmentFacade)environment).getDelegate().globalRedirect(sessionmode, newURL); } else { environment.redirect(sessionmode,newURL); } } /** * Get the output stream */ public OutputStream getOutputStream(int bufferSize) throws IOException { return this.outputStream == null ? this.environment.getOutputStream(bufferSize) : this.outputStream; } /** * Set the output stream for this environment. It hides the one of the * wrapped environment. */ public void setOutputStream(OutputStream stream) { this.outputStream = stream; } /** * Reset the response if possible. This allows error handlers to have * a higher chance to produce clean output if the pipeline that raised * the error has already output some data. * * @return true if the response was successfully reset */ public boolean tryResetResponse() throws IOException { final OutputStream outputStream = getOutputStream(-1); if (outputStream instanceof BufferedOutputStream && ((BufferedOutputStream) outputStream).isResettable()) { ((BufferedOutputStream)outputStream).reset(); return true; } // return false return super.tryResetResponse(); } /** * Commit the response */ public void commitResponse() throws IOException { final OutputStream outputStream = getOutputStream(-1); if (outputStream != null) { outputStream.flush(); } else { // no action super.commitResponse(); } } /** * if a redirect should happen this returns the url, * otherwise <code>null</code> is returned */ public String getRedirectURL() { return this.redirectURL; } public void reset() { this.redirectURL = null; } /** * Set the StatusCode */ public void setStatus(int statusCode) { // ignore this } public void setContentLength(int length) { // ignore this } /** * Set the ContentType */ public void setContentType(String contentType) { this.contentType = contentType; } /** * Get the ContentType */ public String getContentType() { return this.contentType; } /** * Get the underlying object model */ public Map getObjectModel() { return this.objectModel; } /** * Set a new URI for processing. If the prefix is null the * new URI is inside the current context. * If the prefix is not null the context is changed to the root * context and the prefix is set. */ public void setURI(String prefix, String uris) { if(getLogger().isDebugEnabled()) { getLogger().debug("Setting uri (prefix=" + prefix + ", uris=" + uris + ")"); } if ( !this.initializedComponents) { this.initComponents(); } if (prefix != null) { setContext(getRootContext()); setURIPrefix(prefix); } this.uris = uris; } /** * Lookup an attribute in this instance, and if not found search it * in the wrapped environment. * * @param name a <code>String</code>, the name of the attribute to * look for * @return an <code>Object</code>, the value of the attribute or * null if no such attribute was found. */ public Object getAttribute(String name) { Object value = super.getAttribute(name); // get it from the wrapped env only if it's not defined here with a null value if (value == null && !hasAttribute(name)) { value = this.environment.getAttribute(name); } return value; } /** * Always return <code>false</code>. */ public boolean isExternal() { return false; } public void setInternalRedirect(boolean flag) { this.internalRedirect = flag; if ( flag ) { ((RequestWrapper)this.request).setRequestURI(this.prefix.toString(), this.uris); } } /* (non-Javadoc) * @see org.apache.cocoon.environment.Environment#isInternRedirect() */ public boolean isInternalRedirect() { return this.internalRedirect; } }