blob: 0d770243634a3db72188f86fcc4b5af18e117517 [file] [log] [blame]
/*
* 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&ouml;rn L&uuml;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;
}
}