Package org.apache.cocoon.environment

Source Code of org.apache.cocoon.environment.AbstractEnvironment

/*
* 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;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

import org.apache.avalon.framework.CascadingRuntimeException;
import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.cocoon.Constants;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.components.CocoonComponentManager;
import org.apache.cocoon.components.source.SourceUtil;
import org.apache.cocoon.util.BufferedOutputStream;
import org.apache.cocoon.util.ClassUtils;
import org.apache.cocoon.util.Deprecation;
import org.apache.commons.collections.iterators.IteratorEnumeration;
import org.apache.excalibur.source.SourceException;
import org.xml.sax.SAXException;

/**
* Base class for any environment
*
* @author <a href="mailto:bluetkemeier@s-und-n.de">Bj&ouml;rn L&uuml;tkemeier</a>
* @author <a href="mailto:Giacomo.Pati@pwr.ch">Giacomo Pati</a>
* @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
* @version $Id: AbstractEnvironment.java 665954 2008-06-10 02:40:16Z joerg $
*/
public abstract class AbstractEnvironment extends AbstractLogEnabled implements Environment {

    /** The current uri in progress */
    protected String uris;

    /** The current prefix to strip off from the request uri */
    protected StringBuffer prefix = new StringBuffer();

    /** The View requested */
    protected String view;

    /** The Action requested */
    protected String action;

     /** The Context path */
    protected String context;

    /** The context path stored temporarily between constructor and initComponents */
    private String tempInitContext;

    /** The root context path */
    protected String rootContext;

    /** The servlet object model */
    protected HashMap objectModel;

    /** The real source resolver */
    protected org.apache.excalibur.source.SourceResolver sourceResolver;

    /** The component manager */
    protected ComponentManager manager;

    /** The attributes */
    private Map attributes = new HashMap();

    /** The secure Output Stream */
    protected BufferedOutputStream secureOutputStream;

    /** The real output stream */
    protected OutputStream outputStream;

    /** The AvalonToCocoonSourceWrapper (this is for the deprecated support) */
    static protected Method avalonToCocoonSourceWrapper;

    /** Do we have our components ? */
    protected boolean initializedComponents = false;

    /**
     * Constructs the abstract environment
     */
    public AbstractEnvironment(String uri, String view, File file)
    throws MalformedURLException {
        this(uri, view, file, null);
    }

    /**
     * Constructs the abstract environment
     */
    public AbstractEnvironment(String uri, String view, File file, String action)
    throws MalformedURLException {
        this(uri, view, file.toURL().toExternalForm(), action);
    }

    /**
     * Constructs the abstract environment
     */
    public AbstractEnvironment(String uri, String view, String context, String action)
    throws MalformedURLException {
        this.uris = uri;
        this.view = view;
        this.tempInitContext = context;
        this.action = action;
        this.objectModel = new HashMap();
    }

    /**
     * Allow implementations to set view later than in super() constructor.
     * View can be set only once, and should be set in implementation's constructor.
     */
    protected void setView(String view) {
        if (this.view != null) {
            throw new IllegalStateException("View was already set on this environment");
        }
        this.view = view;
    }

    /**
     * Allow implementations to set action later than in super() constructor
     * Action can be set only once, and should be set in implementation's constructor.
     */
    protected void setAction(String action) {
        if (this.action != null) {
            throw new IllegalStateException("Action was already set on this environment");
        }
        this.action = action;
    }

    /**
     * Helper method to extract the view name from the request.
     */
    protected static String extractView(Request request) {
        return request.getParameter(Constants.VIEW_PARAM);
    }

    /**
     * Helper method to extract the action name from the request.
     */
     protected static String extractAction(Request req) {
         String action = req.getParameter(Constants.ACTION_PARAM);
         if (action != null) {
             /* TC: still support the deprecated syntax */
             return action;
         } else {
             for(Enumeration e = req.getParameterNames(); e.hasMoreElements(); ) {
                 String name = (String)e.nextElement();
                 if (name.startsWith(Constants.ACTION_PARAM_PREFIX)) {
                     if (name.endsWith(".x") || name.endsWith(".y")) {
                         return name.substring(Constants.ACTION_PARAM_PREFIX.length(),name.length()-2);
                     } else {
                         return name.substring(Constants.ACTION_PARAM_PREFIX.length());
                     }
                 }
             }
             return null;
         }
     }

    // Sitemap methods

    /**
     * Returns the uri in progress. The prefix is stripped off
     */
    public String getURI() {
        return this.uris;
    }

    /**
     * Get the Root Context
     */
    public String getRootContext() {
        if ( !this.initializedComponents) {
            this.initComponents();
        }
        return this.rootContext;
    }

    /**
     * Get the current Context
     */
    public String getContext() {
        if (!this.initializedComponents) {
            this.initComponents();
        }
        return this.context;
    }

    /**
     * Get the prefix of the URI in progress
     */
    public String getURIPrefix() {
        return this.prefix.toString();
    }

    /**
     * Set the prefix of the URI in progress
     */
    protected void setURIPrefix(String prefix) {
        if (this.getLogger().isDebugEnabled()) {
            this.getLogger().debug("Set the URI Prefix (OLD=" + this.getURIPrefix() + ", NEW=" +  prefix + ")");
        }
        this.prefix = new StringBuffer(prefix);
    }

    /**
     * Set the context.
     */
    protected void setContext(String context) {
        this.context = context;
    }

    /**
     * Set the context. This is similar to changeContext()
     * except that it is absolute.
     */
    public void setContext(String prefix, String uri, String context) {
        this.setContext(context);
        this.setURIPrefix(prefix == null ? "" : prefix);
        this.uris = uri;
        if (this.getLogger().isDebugEnabled()) {
            this.getLogger().debug("Reset context to " + this.context);
        }
    }

    /**
     * Adds an prefix to the overall stripped off prefix from the request uri
     */
    public void changeContext(String newPrefix, String newContext)
    throws IOException {
        if (!this.initializedComponents) {
            this.initComponents();
        }

        if (this.getLogger().isDebugEnabled()) {
            this.getLogger().debug("Changing Cocoon context");
            this.getLogger().debug("  from context(" + this.context + ") and prefix(" + this.prefix + ")");
            this.getLogger().debug("  to context(" + newContext + ") and prefix(" + newPrefix + ")");
            this.getLogger().debug("  at URI " + this.uris);
        }

        int l = newPrefix.length();
        if (l >= 1) {
            if (!this.uris.startsWith(newPrefix)) {
                String message = "The current URI (" + this.uris +
                                 ") doesn't start with given prefix (" + newPrefix + ")";
                this.getLogger().error(message);
                throw new RuntimeException(message);
            }
            this.prefix.append(newPrefix);
            this.uris = this.uris.substring(l);

            // check for a slash at the beginning to avoid problems with subsitemaps
            if (this.uris.startsWith("/")) {
                this.uris = this.uris.substring(1);
                this.prefix.append('/');
            }
        }

        if (this.context.startsWith("zip:")) {
            // if the resource is zipped into a war file (e.g. Weblogic temp deployment)
            // FIXME (VG): Is this still required? Better to unify both cases.
            if (this.getLogger().isDebugEnabled()) {
                this.getLogger().debug("Base context is zip: " + this.context);
            }

            org.apache.excalibur.source.Source source = null;
            try {
                source = this.sourceResolver.resolveURI(this.context + newContext);
                this.context = source.getURI();
            } finally {
                this.sourceResolver.release(source);
            }
        } else if (newContext.length() > 0){
            String sContext;
            // if we got a absolute context or one with a protocol resolve it
            if (newContext.charAt(0) == '/') {
                // context starts with the '/' - absolute file URL
                sContext = "file:" + newContext;
            } else if (newContext.indexOf(':') > 1) {
                // context have ':' - absolute URL
                sContext = newContext;
            } else {
                // context is relative to old one
                sContext = this.context + '/' + newContext;
            }

            // Cut the file name part from context (if present)
            int i = sContext.lastIndexOf('/');
            if (i != -1 && i + 1 < sContext.length()) {
                sContext = sContext.substring(0, i + 1);
            }

            org.apache.excalibur.source.Source source = null;
            try {
                source = this.sourceResolver.resolveURI(sContext);
                this.context = source.getURI();
            } finally {
                this.sourceResolver.release(source);
            }
        }

        if (this.getLogger().isDebugEnabled()) {
            this.getLogger().debug("New context is " + this.context);
        }
    }

    public void globalRedirect(boolean sessionmode, String newURL) throws IOException {
        this.redirect(sessionmode, newURL);
    }

    // Request methods

    /**
     * Returns the request view
     */
    public String getView() {
        return this.view;
    }

    /**
     * Returns the request action
     */
    public String getAction() {
        return this.action;
    }

    // Response methods

    /**
     * Set a status code
     */
    public void setStatus(int statusCode) {
    }

    // Object model method

    /**
     * Returns a Map containing environment specific objects
     */
    public Map getObjectModel() {
        return this.objectModel;
    }

    /**
     * Resolve an entity.
     * @deprecated Use the resolveURI methods instead
     */
    public Source resolve(String systemId)
    throws ProcessingException, SAXException, IOException {
        Deprecation.logger.warn("The method SourceResolver.resolve(String) is "
                              + "deprecated. Use resolveURI(String) instead.");
        if (!this.initializedComponents) {
            this.initComponents();
        }

        if (this.getLogger().isDebugEnabled()) {
            this.getLogger().debug("Resolving '" + systemId + "' in context '" + this.context + "'");
        }

        if (systemId == null) {
            throw new SAXException("Invalid System ID");
        }

        // get the wrapper class - we don't want to import the wrapper directly
        // to avoid a direct dependency from the core to the deprecation package
        Class clazz;
        try {
            clazz = ClassUtils.loadClass("org.apache.cocoon.components.source.impl.AvalonToCocoonSourceInvocationHandler");
        } catch (Exception e) {
            throw new ProcessingException("The deprecated resolve() method of the environment was called."
                                          +"Please either update your code to use the new resolveURI() method or"
                                          +" install the deprecation support.", e);
        }

        if (null == avalonToCocoonSourceWrapper) {
            synchronized (this.getClass()) {
                try {
                    avalonToCocoonSourceWrapper = clazz.getDeclaredMethod("createProxy",
                           new Class[] {ClassUtils.loadClass("org.apache.excalibur.source.Source"),
                                        ClassUtils.loadClass("org.apache.excalibur.source.SourceResolver"),
                                        ClassUtils.loadClass(Environment.class.getName()),
                                        ClassUtils.loadClass(ComponentManager.class.getName())});
                } catch (Exception e) {
                    throw new ProcessingException("The deprecated resolve() method of the environment was called."
                                                  +"Please either update your code to use the new resolveURI() method or"
                                                  +" install the deprecation support.", e);
                }
            }
        }

        try {
            org.apache.excalibur.source.Source source = this.resolveURI(systemId);
            Source wrappedSource = (Source)avalonToCocoonSourceWrapper.invoke(
                    clazz,
                    new Object[] {source, this.sourceResolver, this, this.manager});
            return wrappedSource;
        } catch (SourceException se) {
            throw SourceUtil.handle(se);
        } catch (Exception e) {
            throw new ProcessingException("Unable to create source wrapper.", e);
        }
    }

    /**
     * Check if the response has been modified since the same
     * "resource" was requested.
     * The caller has to test if it is really the same "resource"
     * which is requested.
     * @return true if the response is modified or if the
     *         environment is not able to test it
     */
    public boolean isResponseModified(long lastModified) {
        return true; // always modified
    }

    /**
     * Mark the response as not modified.
     */
    public void setResponseIsNotModified() {
        // does nothing
    }

    public Object getAttribute(String name) {
        return this.attributes.get(name);
    }

    public void setAttribute(String name, Object value) {
        this.attributes.put(name, value);
    }

    protected boolean hasAttribute(String name) {
        return this.attributes.containsKey(name);
    }

    public void removeAttribute(String name) {
        this.attributes.remove(name);
    }

    public Enumeration getAttributeNames() {
        return new IteratorEnumeration(this.attributes.keySet().iterator());
    }

    /**
     * Get the output stream where to write the generated resource.
     * @deprecated Use {@link #getOutputStream(int)} instead.
     */
    public OutputStream getOutputStream() throws IOException {
        Deprecation.logger.warn("The method Environment.getOutputStream() " +
                              "is deprecated. Use getOutputStream(-1) instead.");
        // by default we use the complete buffering output stream
        return this.getOutputStream(-1);
    }

    /**
     * Get the output stream where to write the generated resource.
     * The returned stream is buffered by the environment. If the
     * buffer size is -1 then the complete output is buffered.
     * If the buffer size is 0, no buffering takes place.
     *
     * <br>This method replaces {@link #getOutputStream()}.
     */
    public OutputStream getOutputStream(int bufferSize) throws IOException {
        // This method could be called several times during request processing
        // with differing values of bufferSize and should handle this situation
        // correctly.
        // FIXME (JH): Question is what "correctly" means. The current behavior
        // seems to be inconsistent: On a second call with bufferSize == 0 we
        // discard whatever the first called set up. With a bufferSize != 0 the
        // first call's setup is preserved. Why not always creating new
        // BufferedOutputStream in the else block replacing a potentially
        // existing one?
        if (bufferSize == 0) {
            // Discard secure output stream if it was created before.
            if (this.secureOutputStream != null) {
                this.secureOutputStream = null;
            }
            return this.outputStream;
        } else {
            if (this.secureOutputStream == null) {
                this.secureOutputStream = new BufferedOutputStream(this.outputStream, bufferSize);
            }
            return this.secureOutputStream;
        }
    }

    /**
     * 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 {
        if (this.secureOutputStream != null && this.secureOutputStream.isResettable()) {
            this.secureOutputStream.reset();
            return true;
        }
        return false;
    }

    /**
     * Commit the response
     */
    public void commitResponse()
    throws IOException {
        if (this.secureOutputStream != null) {
            if (this.secureOutputStream.isResettable()) {
                this.setContentLength(this.secureOutputStream.getCount());
            }
            this.secureOutputStream.flush();
        } else if (this.outputStream != null) {
            this.outputStream.flush();
        }
    }

    /**
     * Get a <code>Source</code> object.
     */
    public org.apache.excalibur.source.Source resolveURI(final String location)
    throws MalformedURLException, IOException, SourceException {
        return this.resolveURI(location, null, null);
    }

    /**
     * Get a <code>Source</code> object.
     */
    public org.apache.excalibur.source.Source resolveURI(final String location,
                                                         String baseURI,
                                                         final Map parameters)
    throws MalformedURLException, IOException, SourceException {
        if (!this.initializedComponents) {
            this.initComponents();
        }
        return this.sourceResolver.resolveURI(location, baseURI, parameters);
    }

    /**
     * Releases a resolved resource
     */
    public void release(final org.apache.excalibur.source.Source source) {
        if (null != source) {
            this.sourceResolver.release(source);
        }
    }

    /**
     * Initialize the components for the environment
     * This gets the source resolver and the xmlizer component
     */
    protected void initComponents() {
        this.initializedComponents = true;
        try {
            this.manager = CocoonComponentManager.getSitemapComponentManager();
            this.sourceResolver = (org.apache.excalibur.source.SourceResolver)this.manager.lookup(org.apache.excalibur.source.SourceResolver.ROLE);
            if (this.tempInitContext != null) {
                org.apache.excalibur.source.Source source = null;
                try {
                    source = this.sourceResolver.resolveURI(this.tempInitContext);
                    this.context = source.getURI();

                    if (this.rootContext == null) // hack for EnvironmentWrapper
                        this.rootContext = this.context;
                } finally {
                    this.sourceResolver.release(source);
                }
                this.tempInitContext = null;
            }
        } catch (ComponentException ce) {
            // this should never happen!
            throw new CascadingRuntimeException("Unable to lookup component.", ce);
        } catch (IOException ie) {
            throw new CascadingRuntimeException("Unable to resolve URI: "+this.tempInitContext, ie);
        }
    }

    /**
     * Notify that the processing starts.
     */
    public void startingProcessing() {
        // do nothing here
    }

    /**
     * Notify that the processing is finished
     * This can be used to cleanup the environment object
     */
    public void finishingProcessing() {
        if (null != this.manager) {
            this.manager.release((Component)this.sourceResolver);
            this.manager = null;
            this.sourceResolver = null;
        }
        this.initializedComponents = false;
    }

    /* (non-Javadoc)
     * @see org.apache.cocoon.environment.Environment#isInternRedirect()
     */
    public boolean isInternalRedirect() {
        return false;
    }
}
TOP

Related Classes of org.apache.cocoon.environment.AbstractEnvironment

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.