You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by hu...@apache.org on 2002/11/03 21:26:50 UTC

cvs commit: xml-cocoon2/src/scratchpad/src/org/apache/cocoon/ant CocoonCrawling.java CocoonProcessorDelegate.java CocoonTask.java DelayedFileOutputStream.java DelayedFileSavingEnvironment.java NullOutputStream.java UriType.java readme.txt

huber       2002/11/03 12:26:50

  Added:       src/scratchpad/src/org/apache/cocoon/ant CocoonCrawling.java
                        CocoonProcessorDelegate.java CocoonTask.java
                        DelayedFileOutputStream.java
                        DelayedFileSavingEnvironment.java
                        NullOutputStream.java UriType.java readme.txt
  Log:
  A simple ant task for launching cocoon. see readme.txt for additional descriptions
  
  Revision  Changes    Path
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/ant/CocoonCrawling.java
  
  Index: CocoonCrawling.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.ant;
  
  import java.io.*;
  import java.util.*;
  import org.apache.avalon.framework.activity.*;
  import org.apache.avalon.framework.configuration.*;
  import org.apache.avalon.framework.context.*;
  
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.parameters.*;
  
  import org.apache.cocoon.*;
  import org.apache.cocoon.environment.*;
  import org.apache.cocoon.environment.commandline.*;
  import org.apache.cocoon.util.NetUtils;
  
  /**
   *   A simple Cocoon crawler
   *
   * @author    huber@apache.org
   */
  public class CocoonCrawling extends AbstractLogEnabled {
      private Set visitedAlready;
      private List stillNotVisited;
      private String root;
  
  
      /**
       * Constructor for the CocoonCrawling object
       */
      public CocoonCrawling() {
          visitedAlready = Collections.synchronizedSet(new HashSet());
          stillNotVisited = Collections.synchronizedList(new ArrayList());
      }
  
  
      /**
       *   Sets the root attribute of the CocoonCrawling object
       *
       * @param  uriType  The new root value
       */
      public void setRoot(UriType uriType) {
          this.root = uriType.getPath();
          add(uriType);
      }
  
  
      /**
       *   Description of the Method
       *
       * @param  uriType  Description of Parameter
       */
      public void add(UriType uriType) {
          if (root != null) {
              String normalizedUriType = NetUtils.normalize(uriType.getUri());
              if (!normalizedUriType.startsWith(root)) {
                  getLogger().warn("Uri " + String.valueOf(normalizedUriType) + " does not match root " + String.valueOf(root));
                  return;
              }
          }
          if (!visitedAlready.contains(uriType)) {
              if (!stillNotVisited.contains(uriType)) {
                  if (getLogger().isDebugEnabled()) {
                      getLogger().debug("Add uri " + String.valueOf(uriType.getUri()) + " for visiting");
                  }
                  stillNotVisited.add(uriType);
              }
          }
      }
  
  
      /**
       *   Description of the Method
       *
       * @return    Description of the Returned Value
       */
      public Iterator iterator() {
          return new CocoonCrawlingIterator(visitedAlready, stillNotVisited);
      }
  
  
      /**
       *   Description of the Method
       *
       * @return    Description of the Returned Value
       */
      public Iterator visitedAlreadyIterator() {
          return visitedAlready.iterator();
      }
  
  
      /**
       *   An Iterator iterating over URIs which are not visited already,
       *   visited URIs are moved immediatly to a set of visited URIs
       *
       * @author    huber@apache.org
       */
      public static class CocoonCrawlingIterator implements Iterator {
          /**
           * List of URIs waiting to get visited
           */
          private List stillNotVisited;
          /**
           * List of all visited URIs
           */
          private Set visitedAlready;
  
  
          /**
           * Constructor for the CocoonCrawlingIterator object
           *
           * @param  visitedAlready   Description of Parameter
           * @param  stillNotVisited  Description of Parameter
           */
          public CocoonCrawlingIterator(Set visitedAlready, List stillNotVisited) {
              this.visitedAlready = visitedAlready;
              this.stillNotVisited = stillNotVisited;
          }
  
  
          /**
           *   Check if list of not visited URIs is empty
           *
           * @return    boolean true iff list of not visited URIs is not empty
           */
          public boolean hasNext() {
              return !stillNotVisited.isEmpty();
          }
  
  
          /**
           *   Get next not visited URIs
           *
           * @return    object from list of not visited URIs, move it immediatly
           *   to set of visited URIs
           */
          public Object next() {
              Object nextElement = stillNotVisited.remove(0);
              visitedAlready.add(nextElement);
              return nextElement;
          }
  
  
          /**
           *   Removing objects is not supported, and will always throw
           *   a <code>UnsupportedOperationException</code>.
           */
          public void remove() {
              throw new UnsupportedOperationException();
          }
      }
  }
  
  
  
  
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/ant/CocoonProcessorDelegate.java
  
  Index: CocoonProcessorDelegate.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.ant;
  
  import java.io.*;
  import java.util.*;
  import org.apache.avalon.framework.activity.*;
  import org.apache.avalon.framework.configuration.*;
  import org.apache.avalon.framework.context.*;
  
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.avalon.framework.parameters.*;
  
  import org.apache.cocoon.*;
  import org.apache.cocoon.environment.*;
  import org.apache.cocoon.environment.commandline.*;
  import org.apache.cocoon.util.NetUtils;
  
  /**
   * A facade for Cocoon processing
   *
   * @author    huber@apache.org
   */
  public class CocoonProcessorDelegate extends AbstractLogEnabled
           implements Contextualizable, Configurable, Initializable {
  
      private Cocoon cocoon;
  
      private org.apache.avalon.framework.context.Context context;
  
      private CommandlineContext clContext;
      private File contextDir;
      private File destDir;
  
      private boolean followLinks;
  
      private CocoonCrawling cocoonCrawling;
  
  
      /**
       * Constructor for the CocoonProcessorDelegate object
       *
       * @param  cocoon  Description of Parameter
       */
      public CocoonProcessorDelegate(Cocoon cocoon) {
          this.cocoon = cocoon;
  
      }
  
  
      /**
       *   Description of the Method
       *
       * @param  context               Description of Parameter
       * @exception  ContextException  Description of Exception
       */
      public void contextualize(org.apache.avalon.framework.context.Context context) throws ContextException {
          this.context = new DefaultContext(context);
      }
  
  
      /**
       *   Description of the Method
       *
       * @param  configuration               Description of Parameter
       * @exception  ConfigurationException  Description of Exception
       */
      public void configure(Configuration configuration) throws ConfigurationException {
          Configuration child;
          Configuration[] children;
  
          child = configuration.getChild("follow-links");
          this.followLinks = child.getValueAsBoolean();
  
          child = configuration.getChild("headers");
          Parameters headers = Parameters.fromConfiguration(child);
      }
  
  
      /**
       *   Description of the Method
       *
       * @exception  Exception  Description of Exception
       */
      public void initialize() throws Exception {
          clContext = (CommandlineContext) this.context.get(Constants.CONTEXT_ENVIRONMENT_CONTEXT);
          contextDir = new File(clContext.getRealPath("/"));
  
          destDir = (File) this.context.get("dest-dir");
  
          cocoonCrawling = new CocoonCrawling();
          cocoonCrawling.enableLogging(getLogger());
      }
  
  
      /**
       *   Description of the Method
       *
       * @param  uris                     Description of Parameter
       * @exception  ProcessingException  Description of Exception
       */
      public void processAllUris(Set uris) throws ProcessingException {
          Iterator i = uris.iterator();
          while (i.hasNext()) {
              Object uriObjRef = i.next();
  
              UriType uriType = null;
              if (uriObjRef instanceof String) {
                  uriType = new UriType((String) uriObjRef);
              } else if (uriObjRef instanceof UriType) {
                  uriType = (UriType) uriObjRef;
              } else {
                  // skip it don't know how to handle it
                  continue;
              }
  
              if (uriType != null) {
                  processUri(uriType);
              }
          }
      }
  
  
      /**
       * process a single Uri, resolve followingLink internally
       *
       * @param  uriType                  Description of Parameter
       * @exception  ProcessingException  Description of Exception
       */
      public void processUri(UriType uriType) throws ProcessingException {
          int maxIterations = -1;
          int iterations = 0;
  
          // get the links of the page
          if (!followLinks) {
              maxIterations = 1;
          }
  
          cocoonCrawling.setRoot(uriType);
          if (getLogger().isDebugEnabled()) {
              getLogger().debug("Crawling root " + String.valueOf(uriType.getPath()));
          }
  
          for (Iterator cocoonCrawlingIterator = cocoonCrawling.iterator();
                  (maxIterations > -1 ? iterations < maxIterations : true) &&
                  cocoonCrawlingIterator.hasNext();
                  iterations++) {
  
              UriType crawlingUriType = (UriType) cocoonCrawlingIterator.next();
              
              //
              // fix crawlingUriType append 'index.html' if uri ends with '/'
              //
              String uri = crawlingUriType.getUri();
              if (uri.charAt(uri.length() - 1) == '/') {
                crawlingUriType = new UriType( Constants.INDEX_URI + ".html" );
              }
  
              if (getLogger().isDebugEnabled()) {
                  getLogger().debug("processUri uri " + String.valueOf(crawlingUriType.getUri()));
              }
  
              Map parameters = crawlingUriType.getParameters();
              Map rewriteLinks = new HashMap();
  
              // get the page
              DelayedFileOutputStream dfos = new DelayedFileOutputStream();
              try {
                  //
                  // get a page, URI is defined by crawlingUriType
                  //
                  getPage(crawlingUriType, parameters, rewriteLinks, dfos);
              } catch (ResourceNotFoundException rnfe) {
                  String message = "Unavailable resource of uri " + String.valueOf(crawlingUriType.getUri());
                  getLogger().warn(message, rnfe);
                  // continue, as fetch links for unavailable uri
                  // will throw again a ResourceNotFoundException
                  continue;
              } catch (Exception e) {
                  String message = "Processing error of uri " + String.valueOf(crawlingUriType.getUri());
                  getLogger().warn(message, e);
  
                  // being optimistic that fetching of links
                  // may work
              } finally {
                  try {
                      dfos.flush();
                      dfos.close();
                  } catch (IOException ioe) {
                      String message = "Cannot close output " + String.valueOf(crawlingUriType.getDestFile()) + ", " +
                              "for URI " + String.valueOf(crawlingUriType.getUri());
                      getLogger().warn(message, ioe);
                  }
              }
  
              //
              // being more restrictive about for which uri links are requestes
              // fetch links if content type is not defined
              // or iff content type is of form text/* is this okay?
              //
              String contentType = crawlingUriType.getContentType();
              if (contentType == null || (contentType != null && contentType.startsWith("text"))) {
                  // get the links
                  try {
                      //
                      // get links of URI crawlingUriType
                      //
                      Collection links = getLinks(crawlingUriType, parameters);
                      if (links != null) {
                          for (Iterator i = links.iterator();
                                  i.hasNext(); ) {
                              String linkUri = (String) i.next();
                              if (getLogger().isDebugEnabled()) {
                                  getLogger().debug("processUri linkUri " + String.valueOf(linkUri));
                              }
  
                              UriType linkUriType = new UriType(crawlingUriType, linkUri);
                              if (getLogger().isDebugEnabled()) {
                                  getLogger().debug("parent Uri " + String.valueOf(crawlingUriType.getUri()) + ", " +
                                          String.valueOf(crawlingUriType.getPath()));
                              }
  
                              if (getLogger().isDebugEnabled()) {
                                  getLogger().debug("add uri " + String.valueOf(linkUriType.getUri()));
                              }
                              cocoonCrawling.add(linkUriType);
  
                              crawlingUriType.addLink(linkUriType);
                          }
                      }
                  } catch (ResourceNotFoundException rnfe) {
                      String message = "Failed fetching links of unavailable resource uri " + String.valueOf(crawlingUriType.getUri());
                      getLogger().warn(message, rnfe);
  
                  } catch (Exception e) {
                      String message = "Processing error while fetching links of uri " + String.valueOf(crawlingUriType.getUri());
                      getLogger().warn(message, e);
                  }
              }
          }
      }
  
  
      /**
       *   dump a list of all visited uris, its content-type, and its outbound links
       */
      public void dumpVisitedLinks() {
          // dump visited Links
          for (Iterator visitedAlreadyIterator = cocoonCrawling.visitedAlreadyIterator();
                  visitedAlreadyIterator.hasNext(); ) {
              UriType visitedAlreadyUriType = (UriType) visitedAlreadyIterator.next();
  
              getLogger().info("Visited Uri " + String.valueOf(visitedAlreadyUriType.getUri()) + ", " +
                      "contentType " + String.valueOf(visitedAlreadyUriType.getContentType()));
  
              // get outbound links of visitedAlreadyUriType
              Collection linksFromVisitedAlreadyUriType = visitedAlreadyUriType.getLinks();
              if (linksFromVisitedAlreadyUriType != null) {
                  for (Iterator linksFromvisitedAlreadyIterator = linksFromVisitedAlreadyUriType.iterator();
                          linksFromvisitedAlreadyIterator.hasNext(); ) {
                      UriType linkFromVisitedAlreadyUriType = (UriType) linksFromvisitedAlreadyIterator.next();
                      getLogger().info("Visited Uri links " + String.valueOf(linkFromVisitedAlreadyUriType.getUri()));
                  }
              }
          }
      }
  
  
      /**
       * Processes an Uri for its content.
       *
       * @param  parameters     a <code>Map</code> value containing request parameters
       * @param  links          a <code>Map</code> value
       * @param  uriType        Description of Parameter
       * @param  dfos           Description of Parameter
       * @exception  Exception  Description of Exception
       */
      protected void getPage(UriType uriType, Map parameters, Map links, DelayedFileOutputStream dfos) throws Exception {
          Map attributes = null;
  
          DelayedFileSavingEnvironment env = new DelayedFileSavingEnvironment(
                  uriType,
                  this.contextDir,
                  attributes,
                  parameters,
                  links,
                  dfos,
                  getLogger());
          env.setDestDir(destDir);
          cocoon.process(env);
  
          uriType.setContentType(env.getContentType());
      }
  
  
      /**
       *   Gets the links attribute of the CocoonProcessorDelegate object
       *
       * @param  uriType        Description of Parameter
       * @param  parameters     Description of Parameter
       * @return                The links value
       * @exception  Exception  Description of Exception
       */
      protected Collection getLinks(UriType uriType, Map parameters) throws Exception {
          Map attributes = null;
  
          LinkSamplingEnvironment env = new LinkSamplingEnvironment(
                  uriType.getDeparameterizedUri(),
                  this.contextDir,
                  attributes,
                  parameters,
                  getLogger());
          cocoon.process(env);
          return env.getLinks();
      }
  
  }
  
  
  
  
  
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/ant/CocoonTask.java
  
  Index: CocoonTask.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.ant;
  
  import java.io.*;
  import java.util.*;
  
  import org.apache.avalon.excalibur.logger.*;
  import org.apache.avalon.framework.configuration.*;
  import org.apache.avalon.framework.context.*;
  
  //import org.apache.avalon.framework.logger.Logger;
  import org.apache.avalon.framework.logger.*;
  
  import org.apache.cocoon.*;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.components.notification.DefaultNotifyingBuilder;
  import org.apache.cocoon.components.notification.Notifier;
  import org.apache.cocoon.components.notification.Notifying;
  import org.apache.cocoon.components.notification.SimpleNotifyingBean;
  import org.apache.cocoon.environment.Environment;
  import org.apache.cocoon.environment.commandline.CommandlineContext;
  import org.apache.cocoon.environment.commandline.FileSavingEnvironment;
  import org.apache.cocoon.environment.commandline.LinkSamplingEnvironment;
  import org.apache.cocoon.util.IOUtils;
  import org.apache.cocoon.util.MIMEUtils;
  import org.apache.cocoon.util.NetUtils;
  
  import org.apache.tools.ant.*;
  import org.apache.tools.ant.types.*;
  
  /**
   * Ant task for running Cocoon.
   *
   * @author    huber@apache.org
   */
  public class CocoonTask extends Task {
  
      /**
       *   User-agent header used in the Cocoon processing stage
       */
      protected final static String DEFAULT_USER_AGENT = Constants.COMPLETE_NAME;
      /**
       *   Accept header used in the Cocoon processing stage
       */
      protected final static String DEFAULT_ACCEPT = "text/html, */*";
  
      /**
       * logkit xconf file, ie logkit.xconf
       */
      private File logkitXconf;
      /**
       * cocoon destination directory
       */
      private File destDir;
      /**
       * cocoon work directory
       */
      private File workDir;
      /**
       * Cocoon context directory
       */
      private File contextDir;
      /**
       * Cocoon config file, ie cocoon.xconf
       */
      private File configFile;
      /**
       *LoggerCategory
       */
      private String logger;
      /**
       *loglevel, ie DEBUG, INFO, WARN, or ERROR
       */
      private String logLevel;
  
      private String acceptHeader;
      private String agentHeader;
      private Boolean preCompileOnly;
      private Boolean followLinks;
  
      /**
       * A list of targets processed by Cocoon
       */
      private List targets;
  
      private Path cocoonClasspath;
  
  
      /**
       * Creates a new instance of CocoonTask
       */
      public CocoonTask() {
          this.logkitXconf = null;
  
          this.destDir = null;
          File workDirParent = new File((String) System.getProperty("java.io.tmpdir", "."));
          this.workDir = new File(workDirParent, "work");
  
          this.contextDir = null;
          this.logLevel = "INFO";
          this.logger = "cocoon";
          this.acceptHeader = DEFAULT_ACCEPT;
          this.agentHeader = DEFAULT_USER_AGENT;
          this.preCompileOnly = new Boolean(false);
          this.followLinks = new Boolean(true);
          this.targets = new ArrayList();
      }
  
  
      /**
       *   Sets the logkitXconf attribute of the CocoonTask object
       *
       * @param  logkitXconf  The new logkitXconf value
       */
      public void setLogkitXconf(File logkitXconf) {
          this.logkitXconf = logkitXconf;
      }
  
  
      /**
       *   Sets the logger attribute of the CocoonTask object
       *
       * @param  logger  The new logger value
       */
      public void setLogger(String logger) {
          this.logger = logger;
      }
  
  
      /**
       *   Sets the logLevel attribute of the CocoonTask object
       *
       * @param  logLevelOption  The new logLevel value
       */
      public void setLogLevel(LogLevelOption logLevelOption) {
          this.logLevel = logLevelOption.getValue();
      }
  
  
      /**
       *   Sets the acceptHeader attribute of the CocoonTask object
       *
       * @param  acceptHeader  The new acceptHeader value
       */
      public void setAcceptHeader(String acceptHeader) {
          this.acceptHeader = acceptHeader;
      }
  
  
      /**
       *   Sets the agentHeader attribute of the CocoonTask object
       *
       * @param  agentHeader  The new agentHeader value
       */
      public void setAgentHeader(String agentHeader) {
          this.agentHeader = agentHeader;
      }
  
  
      /**
       *   Sets the precompileOnly attribute of the CocoonTask object
       *
       * @param  preCompileOnly  The new precompileOnly value
       */
      public void setPrecompileOnly(boolean preCompileOnly) {
          this.preCompileOnly = new Boolean(preCompileOnly);
      }
  
  
      /**
       *   Sets the followLinks attribute of the CocoonTask object
       *
       * @param  followLinks  The new followLinks value
       */
      public void setFollowLinks(boolean followLinks) {
          this.followLinks = new Boolean(followLinks);
      }
  
  
      /**
       *   Sets the targets attribute of the CocoonTask object
       *
       * @param  targets  The new targets value
       */
      public void setTargets(String targets) {
          this.targets = new ArrayList();
  
          // split target delimited by DEFAULT_DELIM characters
          final String DEFAULT_DELIM = " ,;";
          final String delimiter = DEFAULT_DELIM;
          StringTokenizer st = new StringTokenizer(targets, delimiter);
          while (st.hasMoreTokens()) {
              String target = (String) st.nextToken();
              this.targets.add(target);
          }
      }
  
  
      /**
       *   Sets the destDir attribute of the CocoonTask object
       *
       * @param  destDir  The new destDir value
       */
      public void setDestDir(File destDir) {
          this.destDir = getDir(destDir.toString(), true, "dest-dir");
      }
  
  
      /**
       *   Sets the workDir attribute of the CocoonTask object
       *
       * @param  workDir  The new workDir value
       */
      public void setWorkDir(File workDir) {
          this.workDir = getDir(workDir.toString(), true, "work-dir");
      }
  
  
      /**
       *   Sets the contextDir attribute of the CocoonTask object
       *
       * @param  contextDir  The new contextDir value
       */
      public void setContextDir(File contextDir) {
          this.contextDir = getDir(contextDir.toString(), false, "context-dir");
      }
  
  
      /**
       *   Sets the configFile attribute of the CocoonTask object
       *
       * @param  configFile  The new configFile value
       */
      public void setConfigFile(File configFile) {
          this.configFile = configFile;
      }
  
  
      /**
       * Adds a reference to a CLASSPATH defined elsewhere.
       *
       * @param  r  The new classpathRef value
       */
      public void setClasspathRef(Reference r) {
          createClasspath().setRefid(r);
      }
  
  
      /**
       * Creates a nested classpath element.
       *
       * @return        Path created
       * @deprecated    no need for creating an additional classloader
       */
      public Path createClasspath() {
          if (cocoonClasspath == null) {
              cocoonClasspath = new Path(project);
          }
          return cocoonClasspath.createPath();
      }
  
  
  
      // MatchingTask implementation
      /**
       *   Execute the ant task launching Cocoon
       *
       * @exception  BuildException  thrown iff Cocoon processing fails
       */
      public void execute() throws BuildException {
  
          // try check some well known places for configFile, and logkitXconf
          if (contextDir != null) {
              if (configFile == null) {
                  configFile = getContextDirFile(contextDir, "cocoon.xconf");
              }
              if (logkitXconf == null) {
                  logkitXconf = getContextDirFile(contextDir, "logkit.xconf");
              }
          }
  
          // Check validity of members
          checkValidity();
  
          DefaultContext rootCtx = new DefaultContext();
          DefaultConfiguration configuration = new DefaultConfiguration("root", "");
          Cocoon cocoon = null;
          CocoonFactory cocoonFactory = null;
  
          try {
              // fill rootCtx
              rootCtx.put("dest-dir", destDir);
              rootCtx.put("context-root", this.contextDir);
              rootCtx.put(Constants.CONTEXT_WORK_DIR, this.workDir);
              rootCtx.put(Constants.CONTEXT_CONFIG_URL, configFile.toURL());
  
              ClassLoader classLoader = null;
              if (this.cocoonClasspath != null) {
                  //
                  // I think there is no real need for creating an additional
                  // AntClassLoader
                  // CocoonTask was already loaded via an AntClassLoader by Ant
                  //
                  AntClassLoader antClassLoader = new AntClassLoader(this.project, this.cocoonClasspath, false);
  
                  log("Using Class Loader having classpath " + String.valueOf(this.cocoonClasspath), Project.MSG_INFO);
                  classLoader = antClassLoader;
              } else {
                  classLoader = this.getClass().getClassLoader();
              }
              rootCtx.put(Constants.CONTEXT_CLASS_LOADER, classLoader);
  
              // set classloader explicitly
              // this is very important otherwise ClassUtils.loadClass(), et al.
              // will use the system classloader for loading classes, and resources
              // but only this class (the CocoonTask) was loaded via an
              // AntClassLoader
              Thread.currentThread().setContextClassLoader(classLoader);
  
              // build a configuration from the ant attributes....
              // add configuration elements
              DefaultConfiguration child;
              if (logkitXconf != null) {
                  child = new DefaultConfiguration("logkit", "");
                  child.setValue(logkitXconf.toString());
                  configuration.addChild(child);
              }
              child = new DefaultConfiguration("log-level", "");
              child.setValue(this.logLevel);
              configuration.addChild(child);
  
              child = new DefaultConfiguration("follow-links", "");
              child.setValue(this.followLinks.toString());
              configuration.addChild(child);
  
              DefaultConfiguration headers = new DefaultConfiguration("headers", "");
              child = new DefaultConfiguration("parameter", "");
              child.setAttribute("name", "accept");
              child.setAttribute("value", this.acceptHeader);
              headers.addChild(child);
  
              child = new DefaultConfiguration("parameter", "");
              child.setAttribute("name", "user-agent");
              child.setAttribute("value", this.agentHeader);
              headers.addChild(child);
  
              configuration.addChild(headers);
  
              // create a Cocoon instance
              cocoonFactory = new CocoonFactory();
              cocoonFactory.enableLogging(new ConsoleLogger());
              cocoonFactory.contextualize(rootCtx);
              cocoonFactory.configure(configuration);
  
          } catch (Exception e) {
              String message = "Cannot create cocoon factory";
              throw new BuildException(message, e);
          }
  
          try {
              cocoon = cocoonFactory.createCocoon();
          } catch (Exception e) {
              String message = "Cannot create cocoon object";
              throw new BuildException(message, e);
          }
  
          // loop over all targets
          try {
              Set uniqueTargets = new HashSet();
              uniqueTargets.addAll(targets);
              CocoonProcessorDelegate cpd = cocoonFactory.createCocoonProcessorDelegate(cocoon, configuration);
              cpd.processAllUris(uniqueTargets);
              //cpd.dumpVisitedLinks();
          } catch (Exception e) {
              String message = "Cannot process Uri(s) by Cocoon";
              throw new BuildException(message, e);
          } finally {
  
              cocoonFactory.disposeCocoon(cocoon);
          }
      }
  
  
      /**
       *   Gets the contextDirFile attribute of the CocoonTask object.
       *   Try to locate a file name relative to Cocoon's context directory.
       *   Check ${contextDir}/WEB-INF, ${contextDir}/ locations iff
       *   there is a file named name.
       *
       * @param  contextDir  Cocoon's context directory
       * @param  name        a pure file name
       * @return             File full path of an existing file name, or null
       */
      protected File getContextDirFile(File contextDir, String name) {
  
          // 1 try ${contextDir}/WEB-INF/${name}
          final File fullName1 = new File(contextDir, "WEB-INF/" + name);
          if (fullName1.exists() && fullName1.canRead()) {
              return fullName1;
          }
  
          // 2 try ${contextDir}/${name}
          final File fullName2 = new File(contextDir, name);
          if (fullName2.exists() && fullName2.canRead()) {
              return fullName2;
          }
          String message = "Cannot find, or access file " + String.valueOf(name) + " " +
                  "neither " + String.valueOf(fullName1) + ", " +
                  "nor " + String.valueOf(fullName2);
          log(message, Project.MSG_INFO);
          return null;
      }
  
  
      /**
       * Get a <code>File</code> representing a directory.
       * Create, and check existance, read- writeability of a directory.
       *
       * @param  dir                 a <code>String</code> with a directory name
       * @param  type                a <code>String</code> describing the type of directory
       * @param  create              true iff directory should be created
       * @return                     a <code>File</code> value
       * @exception  BuildException  throw iff checks fails
       */
      protected File getDir(String dir, boolean create, String type) throws BuildException {
  
          log("Getting handle to " + type + " directory '" + dir + "'", Project.MSG_INFO);
  
          File d = new File(dir);
          if (!d.exists()) {
              if (create && !d.mkdirs()) {
                  String message = "Error creating " + type + " directory '" + d + "'";
                  throw new BuildException(message);
              }
          }
          if (!d.isDirectory()) {
              String message = "'" + d + "' is not a directory.";
              throw new BuildException(message);
          }
  
          if (!(d.canRead() && d.canWrite())) {
              String message = "Directory '" + d + "' is not readable/writable";
              throw new BuildException(message);
          }
          return d;
      }
  
  
      /**
       *   Check if all parameters for running Cocoon are set properly
       *
       * @exception  BuildException  is thrown iff at least one parameter is invalid
       */
      protected void checkValidity() throws BuildException {
          if (destDir == null) {
              throw new BuildException("Set attribute destDir!");
          } else {
              destDir = getDir(destDir.toString(), true, "dest-dir");
          }
  
          if (workDir == null) {
              throw new BuildException("Set attribute workDir!");
          } else {
              workDir = getDir(workDir.toString(), true, "work-dir");
          }
          if (contextDir == null) {
              throw new BuildException("Set attribute contextDir!");
          } else {
              contextDir = getDir(contextDir.toString(), false, "contex-dir");
          }
  
          if (configFile == null) {
              throw new BuildException("Set attribute configFile!");
          }
          if (logger == null) {
              throw new BuildException("Set attribute logger!");
          }
          if (logLevel == null) {
              throw new BuildException("Set attribute logLevel!");
          }
          if (acceptHeader == null) {
              throw new BuildException("Set attribute acceptHeader!");
          }
          if (agentHeader == null) {
              throw new BuildException("Set attribute agentHeader!");
          }
  
          if (!destDir.exists() || !destDir.isDirectory()) {
              throw new BuildException("Attribute destDir directory " + String.valueOf(destDir) +
                      " does not exists, or is not a directory!");
          }
          if (!contextDir.exists() || !contextDir.isDirectory()) {
              throw new BuildException("Attribute contextDir directory " + String.valueOf(contextDir) +
                      " does not exists, or is not a directory!");
          }
          if (!workDir.exists() || !workDir.isDirectory()) {
              throw new BuildException("Attribute worktDir directory " + String.valueOf(workDir) +
                      " does not exists, or is not a directory!");
          }
      }
  
  
      /**
       * A factory creating Cocoon objects.
       * This class encapsulates creation, disposing of Cocoon objects, and
       * creating of classes for using Cocoon in some task, subtask execution
       *
       * @author    huber@apache.org
       */
      public static class CocoonFactory extends AbstractLogEnabled
               implements Contextualizable, Configurable {
  
          private DefaultLogKitManager logKitManager;
          private org.apache.log.Logger logger;
          private DefaultContext ctx;
          private ClassLoader classLoader;
  
  
          /**
           * Constructor for the CocoonFactory object
           */
          public CocoonFactory() { }
  
  
          /**
           * contextualize the CocoonFactory
           *
           * Expecting at least following context entries
           *
           * <ul>
           *  <li>context-root</li>
           *  <li>CONTEXT_CLASSPATH</li>
           *  <li>CONTEXT_CLASS_LOADER</li>
           *  <li>CONTEXT_ENVIRONMENT_CONTEXT</li>
           *  <li>CONTEXT_WORK_DIR</li>
           *  <li>CONTEXT_CONFIG_URL</li>
           * </ul>
           *
           * @param  context               parent context
           * @exception  ContextException  thrown iff parent context fails to provide
           *   mandadory context entries
           */
          public void contextualize(Context context) throws ContextException {
              this.ctx = new DefaultContext(context);
  
              classLoader = (ClassLoader) this.ctx.get(Constants.CONTEXT_CLASS_LOADER);
              File contextDir = (File) this.ctx.get("context-root");
              File workDir = (File) this.ctx.get(Constants.CONTEXT_WORK_DIR);
  
              CommandlineContext clContext = new CommandlineContext(contextDir.toString());
              clContext.enableLogging(getLogger());
              this.ctx.put(Constants.CONTEXT_ENVIRONMENT_CONTEXT, clContext);
              this.ctx.put(Constants.CONTEXT_CLASSPATH, getClassPath(contextDir));
  
              this.ctx.put(Constants.CONTEXT_UPLOAD_DIR, new File(contextDir, "upload-dir"));
              this.ctx.put(Constants.CONTEXT_CACHE_DIR, new File(workDir, "cache-dir"));
          }
  
  
          /**
           *   Configure the Cocoon factory
           *
           * @param  configuration               Cocoon factory configuration
           * @exception  ConfigurationException  thrown iff configuration fails
           */
          public void configure(Configuration configuration) throws ConfigurationException {
              Configuration child;
  
              // configure logLevel
              String logLevel = "WARN";
              child = configuration.getChild("log-level", false);
              if (child != null) {
                  logLevel = child.getValue();
              } else {
                  logLevel = "WARN";
              }
  
              // configure the logKitManager, either by using a logkit.xconf file,
              // or by a logger
              final org.apache.log.Priority priority = org.apache.log.Priority.getPriorityForName(logLevel);
              org.apache.log.Hierarchy.getDefaultHierarchy().setDefaultPriority(priority);
              logger = org.apache.log.Hierarchy.getDefaultHierarchy().getLoggerFor("");
  
              child = configuration.getChild("logKit", false);
              if (child != null) {
                  String logKit = child.getValue();
                  String logKitLogCategory = child.getAttribute("category", "cocoon");
  
                  if (logKit != null) {
                      try {
                          final DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
                          final Configuration logKitConf = builder.buildFromFile(logKit);
                          logKitManager = new DefaultLogKitManager(org.apache.log.Hierarchy.getDefaultHierarchy());
  
                          final DefaultContext subcontext = new DefaultContext(this.ctx);
                          File contextDir = (File) this.ctx.get("context-root");
                          subcontext.put("context-root", contextDir);
                          logKitManager.contextualize(subcontext);
                          logKitManager.configure(logKitConf);
                          logger = logKitManager.getLogger(logKitLogCategory);
                      } catch (Exception e) {
                          getLogger().error("Cannot initialize log-kit-manager from logkit-xconf " + String.valueOf(logKit));
  
                          // clean logKitManager, try init it without the logkit-xconf
                          logKitManager = null;
                      }
                  }
              }
  
              if (logKitManager == null) {
                  logKitManager = new DefaultLogKitManager(org.apache.log.Hierarchy.getDefaultHierarchy());
                  logKitManager.setLogger(logger);
              }
          }
  
  
          /**
           * create a new Cocoon instance
           *
           * @return                             Cocoon the Cocoon instance
           * @exception  ContextException        thrown iff configuring of Cocoon instance fails
           * @exception  ConfigurationException  thrown iff contextualizing of Cocoon instance fails
           * @exception  Exception               thrown iff initializing of Cocoon instance fails
           */
          public Cocoon createCocoon() throws Exception, ContextException, ConfigurationException {
              Cocoon cocoon = new Cocoon();
              cocoon.enableLogging(new LogKitLogger(logger));
              cocoon.contextualize(this.ctx);
              cocoon.setLogKitManager(logKitManager);
              cocoon.initialize();
              return cocoon;
          }
  
  
          /**
           *  Dispose a cocoon instance.
           *  Don't forget to invoke this method iff you have retrieved a Cocoon
           *  instance via <code>createCocoon()</code>.
           *
           * @param  cocoon  the Cocoon instance
           */
          public void disposeCocoon(Cocoon cocoon) {
              if (cocoon != null) {
                  cocoon.dispose();
              }
          }
  
  
          /**
           *   Create a CocoonProcessorDelegate for performing some Cocoon relevant
           *   operations.
           *
           * @param  cocoon         Cocoon instance
           * @param  configuration  of the CocoonProcessorDelegate
           * @return                CocoonProcessorDelegate instance
           * @exception  Exception  thrown iff contextualizing, configuring, or creating
           *   of CocoonProcessorDelegate instance fails.
           */
          public CocoonProcessorDelegate createCocoonProcessorDelegate(Cocoon cocoon, Configuration configuration) throws Exception {
              CocoonProcessorDelegate cpd = new CocoonProcessorDelegate(cocoon);
              cpd.enableLogging(new LogKitLogger(logger));
              cpd.contextualize(this.ctx);
              cpd.configure(configuration);
              cpd.initialize();
              return cpd;
          }
  
  
          /**
           * This builds the important ClassPath used by this class.  It
           * does so in a neutral way.
           * It iterates in alphabetical order through every file in the
           * lib directory and adds it to the classpath.
           *
           * Also, we add the files to the ClassLoader for the Cocoon system.
           * In order to protect ourselves from skitzofrantic classloaders,
           * we need to work with a known one.
           *
           * @param  contextDir  Description of Parameter
           * @return             a <code>String</code> value
           */
          protected String getClassPath(final File contextDir) {
              StringBuffer buildClassPath = new StringBuffer();
              File classDir = new File(contextDir, "WEB-INF/classes");
              File root = new File(contextDir, "WEB-INF/lib");
  
              buildClassPath.append(classDir);
  
              if (root.isDirectory()) {
                  File[] libraries = root.listFiles();
                  Arrays.sort(libraries);
                  for (int i = 0; i < libraries.length; i++) {
                      buildClassPath.append(File.pathSeparatorChar)
                              .append(IOUtils.getFullFilename(libraries[i]));
                  }
              }
  
              buildClassPath.append(File.pathSeparatorChar)
                      .append(System.getProperty("java.class.path"));
  
              if (getLogger().isDebugEnabled()) {
                  getLogger().debug("Context classpath: " + buildClassPath.toString());
              }
  
              return buildClassPath.toString();
          }
      }
  
  
      /**
       * Enumerated attribute with the values "DEBUG", "INFO", "WARN", "ERROR",
       * and "FATAL_ERROR"
       *
       * @author    huber@apache.org
       */
      public static class LogLevelOption extends EnumeratedAttribute {
          /**
           *   Gets the values attribute of the LogLevelOption object
           *
           * @return    The values value
           */
          public String[] getValues() {
              final String[] values = {
                      "DEBUG", "INFO", "WARN", "ERROR", "FATAL_ERROR"
                      };
              return values;
          }
      }
  
  }
  
  
  
  
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/ant/DelayedFileOutputStream.java
  
  Index: DelayedFileOutputStream.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.ant;
  
  import java.io.*;
  
  /**
   *   A output stream writing to a ByteArrayOutputStream, until FilOutputStream target is defined.
   *
   * @author    huber@apache.org
   */
  public class DelayedFileOutputStream extends OutputStream {
      /**
       * write to baos as long as fos member is still null,
       * create a ByteArrayOutputStream only
       */
      private ByteArrayOutputStream baos;
      /**
       * If fos is defined write into fos, dump content of
       * baos to fos first
       */
      private OutputStream fos;
  
  
      /**
       * Constructor for the DelayedFileOutputStream object,
       * create a ByteArrayOutputStream only
       */
      public DelayedFileOutputStream() {
          baos = new ByteArrayOutputStream();
          fos = null;
      }
  
  
      /**
       * Creates a file output stream to write to the file represented by the specified File object.
       *
       * @param  file                       The new fileOutputStream value
       * @exception  FileNotFoundException  thrown if creating of FileOutputStream fails
       */
      public void setFileOutputStream(File file) throws FileNotFoundException {
          if (fos == null) {
              fos = new FileOutputStream(file);
          }
      }
  
  
      /**
       * Creates a file output stream to write to the file represented by the specified File object.
       *
       * @param  file                       The new fileOutputStream value
       * @param  append                     The new fileOutputStream value
       * @exception  FileNotFoundException  thrown if creating of FileOutputStream fails
       */
      public void setFileOutputStream(File file, boolean append) throws FileNotFoundException {
          if (fos == null) {
              fos = new FileOutputStream(file, append);
          }
      }
  
  
      /**
       * Creates an output file stream to write to the specified file descriptor, which represents an existing connection to an actual file in the file system.
       *
       * @param  fdObj  The new fileOutputStream value
       */
      public void setFileOutputStream(FileDescriptor fdObj) {
          if (fos == null) {
              fos = new BufferedOutputStream(new FileOutputStream(fdObj));
          }
      }
  
  
      /**
       * Creates an output file stream to write to the file with the specified name.
       *
       * @param  name                       The new fileOutputStream value
       * @exception  FileNotFoundException  thrown if creating of FileOutputStream fails
       */
      public void setFileOutputStream(String name) throws FileNotFoundException {
          if (fos == null) {
              fos = new FileOutputStream(name);
          }
      }
  
  
      /**
       * Creates an output file stream to write to the file with the specified name.
       *
       * @param  name                       The new fileOutputStream value
       * @param  append                     The new fileOutputStream value
       * @exception  FileNotFoundException  thrown if creating of FileOutputStream fails
       */
      public void setFileOutputStream(String name, boolean append) throws FileNotFoundException {
          if (fos == null) {
              fos = new FileOutputStream(name, append);
          }
      }
  
  
  
      /**
       *   Write into ByteArrayOutputStrem, or FileOutputStream, depending on inner
       *   state of this stream
       *
       * @param  b                Description of Parameter
       * @exception  IOException  thrown iff implicitly flush of baos to fos fails, or writing
       *   of baos, or fos fails
       */
      public void write(int b) throws IOException {
          OutputStream os = getTargetOutputStream();
          os.write(b);
      }
  
  
      /**
       *   Write into ByteArrayOutputStrem, or FileOutputStream, depending on inner
       *   state of this stream
       *
       * @param  b                Description of Parameter
       * @exception  IOException  thrown iff implicitly flush of baos to fos fails, or writing
       *   of baos, or fos fails
       */
      public void write(byte b[]) throws IOException {
          OutputStream os = getTargetOutputStream();
          os.write(b);
      }
  
  
      /**
       *   Write into ByteArrayOutputStrem, or FileOutputStream, depending on inner
       *   state of this stream
       *
       * @param  b                Description of Parameter
       * @param  off              Description of Parameter
       * @param  len              Description of Parameter
       * @exception  IOException  thrown iff implicitly flush of baos to fos fails, or writing
       *   of baos, or fos fails
       */
      public void write(byte b[], int off, int len) throws IOException {
          OutputStream os = getTargetOutputStream();
          os.write(b, off, len);
      }
  
  
      /**
       *   Close ByteArrayOutputStrem, and FileOutputStream, depending on inner
       *   state of this stream
       *
       * @exception  IOException  thrown iff implicitly flush of baos to fos fails, or closing
       *   of baos, or fos fails
       */
      public void close() throws IOException {
          IOException ioexception = null;
  
          getTargetOutputStream();
          
          // close baos
          try {
              if (baos != null) {
                  baos.close();
              }
          } catch (IOException ioe) {
              if (ioexception == null) {
                  ioexception = ioe;
              }
          } finally {
              baos = null;
          }
          
          // close fos
          try {
              if (fos != null) {
                  fos.close();
              }
          } catch (IOException ioe) {
              if (ioexception == null) {
                  ioexception = ioe;
              }
          } finally {
              fos = null;
          }
  
          if (ioexception != null) {
              throw ioexception;
          }
      }
  
  
      /**
       *   Flush ByteArrayOutputStrem, writing content to FileOutputStream,
       *   flush FileOutputStream
       *
       * @exception  IOException  thrown iff implicitly flush of baos to fos fails, or flushing
       *   of baos, or fos fails
       */
      public void flush() throws IOException {
          IOException ioexception = null;
  
          // flush baos, writing to fos, if neccessary
          getTargetOutputStream();
  
          // flush baos
          try {
              if (baos != null) {
                  baos.flush();
              }
          } catch (IOException ioe) {
              if (ioexception == null) {
                  ioexception = ioe;
              }
          }
  
          // flush fos
          try {
              if (fos != null) {
                  fos.flush();
              }
          } catch (IOException ioe) {
              if (ioexception == null) {
                  ioexception = ioe;
              }
          }
          if (ioexception != null) {
              throw ioexception;
          }
      }
  
  
      /**
       *   Gets the targetOutputStream attribute of the DelayedFileOutputStream object
       *
       * @return                  The targetOutputStream value
       * @exception  IOException  thrown iff implicitly flush of baos to fos fails
       */
      private OutputStream getTargetOutputStream() throws IOException {
          if (baos != null && fos == null) {
              
              // no fos is defined, just write to baos in the mean time
              return baos;
          } else if (baos != null && fos != null) {
              // fos is defined, flush boas to fos, and destroy baos
              IOException ioexception = null;
              
              try {
                  baos.flush();
                  baos.writeTo(fos);
                  baos.close();
              } catch (IOException ioe) {
                  ioexception = ioe;
              } finally {
                  baos = null;
              }
              
              if (ioexception != null) {
                  throw ioexception;
              }
             
              return fos;
          } else if (baos == null && fos != null) {
              // no more temporary baos writing, write directly to fos
              return fos;
          } else {
              // neither baos, nor fos are valid
              throw new IOException("No outputstream available!");
          }
      }
  }
  
  
  
  
  
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/ant/DelayedFileSavingEnvironment.java
  
  Index: DelayedFileSavingEnvironment.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.ant;
  
  import java.io.*;
  import java.net.*;
  import java.util.*;
  
  import org.apache.avalon.framework.logger.Logger;
  import org.apache.cocoon.Constants;
  import org.apache.cocoon.environment.ObjectModelHelper;
  import org.apache.cocoon.environment.commandline.*;
  
  import org.apache.cocoon.util.*;
  
  /**
   *   A command line file saving environment writing files in a delayed mode.
   *   File writing is delayed until the content-type is clear, until then
   *   output is written into temporary buffer
   *
   *
   * @author    huber@apache.org
   */
  public class DelayedFileSavingEnvironment extends AbstractCommandLineEnvironment {
  
      private DelayedFileOutputStream dfos;
      private UriType uriType;
      private File destDir;
  
  
      /**
       * Constructor for the DelayedFileSavingEnvironment object
       * It uses the default view
       *
       * @param  context                    Cocoon's context directory
       * @param  attributes                 Description of Parameter
       * @param  links                      Description of Parameter
       * @param  log                        Logger of this environment
       * @param  parameters                 Description of Parameter
       * @param  uriType                    uri of this environment
       * @param  dfos                       Description of Parameter
       * @exception  MalformedURLException  Description of Exception
       */
      public DelayedFileSavingEnvironment(
              UriType uriType,
              File context,
              Map attributes,
              Map parameters,
              Map links,
              DelayedFileOutputStream dfos,
              Logger log) throws MalformedURLException {
          super(uriType.getDeparameterizedUri(), null, context, dfos, log);
  
          this.uriType = uriType;
          String deparameterizedUri = uriType.getDeparameterizedUri();
  
          this.dfos = dfos;
          if (getLogger().isDebugEnabled()) {
              this.getLogger().debug("DelayedFileSavingEnvironment: uri = " + deparameterizedUri);
          }
          this.objectModel.put(Constants.LINK_OBJECT, links);
          this.objectModel.put(ObjectModelHelper.REQUEST_OBJECT, new CommandLineRequest(this, null, deparameterizedUri, null, attributes, parameters));
          this.objectModel.put(ObjectModelHelper.RESPONSE_OBJECT, new CommandLineResponse());
      }
  
  
      /**
       * Constructor for the DelayedFileSavingEnvironment object
       * Cocoon's view is explictly set.
       *
       * @param  context                    Cocoon's context directory
       * @param  attributes                 Description of Parameter
       * @param  links                      Description of Parameter
       * @param  log                        Logger of this environment
       * @param  parameters                 Description of Parameter
       * @param  uriType                    uri of this environment
       * @param  view                       Description of Parameter
       * @param  dfos                       Description of Parameter
       * @exception  MalformedURLException  Description of Exception
       */
      public DelayedFileSavingEnvironment(
              UriType uriType,
              String view,
              File context,
              Map attributes,
              Map parameters,
              Map links,
              DelayedFileOutputStream dfos,
              Logger log) throws MalformedURLException {
  
          super(uriType.getDeparameterizedUri(), view, context, dfos, log);
  
          this.uriType = uriType;
          String deparameterizedUri = uriType.getDeparameterizedUri();
  
          this.dfos = dfos;
  
          if (getLogger().isDebugEnabled()) {
              this.getLogger().debug("DelayedFileSavingEnvironment: uri = " + deparameterizedUri);
          }
          this.objectModel.put(Constants.LINK_OBJECT, links);
          this.objectModel.put(ObjectModelHelper.REQUEST_OBJECT, new CommandLineRequest(this, null, deparameterizedUri, null, attributes, parameters));
          this.objectModel.put(ObjectModelHelper.RESPONSE_OBJECT, new CommandLineResponse());
      }
  
  
      /**
       *   Sets the destDir attribute of the DelayedFileSavingEnvironment object
       *
       * @param  destDir   The new destDir value
       */
      public void setDestDir(File destDir) {
          this.destDir = destDir;
      }
  
  
      /**
       *   Gets the destDir attribute of the DelayedFileSavingEnvironment object
       *
       * @return     The destDir value
       */
      public File getDestDir() {
          return this.destDir;
      }
  
  
      /**
       * Commit the response
       *
       * @exception  IOException  Description of Exception
       */
      public void commitResponse()
               throws IOException {
  
          final File file = getFile();
          if (getLogger().isDebugEnabled()) {
              this.getLogger().debug("DelayedFileSavingEnvironment: filename = " + String.valueOf(file));
          }
          dfos.setFileOutputStream(file);
  
          uriType.setDestFile(file);
  
          super.commitResponse();
      }
  
  
      /**
       *   Gets the filename attribute of the DelayedFileSavingEnvironment object
       *
       * @return    The filename value
       */
      protected File getFile() {
          // calculate filename
          String filename = uriType.getFilename();
          String type = contentType;
          String ext = uriType.getExtension();
          String defaultExt = MIMEUtils.getDefaultExtension(type);
  
          if ((ext == null) || (!ext.equals(defaultExt))) {
              filename += defaultExt;
          }
          File file = IOUtils.createFile(destDir, NetUtils.decodePath(filename));
          return file;
      }
  
  }
  
  
  
  
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/ant/NullOutputStream.java
  
  Index: NullOutputStream.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.ant;
  
  import java.io.*;
  /**
   *   A OutputStream writting no bytes at all.
   *
   * @author    huber@apache.org
   */
  public class NullOutputStream extends OutputStream {
      /**
       *   Description of the Method
       *
       * @param  b                Description of Parameter
       * @exception  IOException  Description of Exception
       */
      public void write(int b) throws IOException { }
  
  
      /**
       *   Description of the Method
       *
       * @param  b                Description of Parameter
       * @exception  IOException  Description of Exception
       */
      public void write(byte b[]) throws IOException { }
  
  
      /**
       *   Description of the Method
       *
       * @param  b                Description of Parameter
       * @param  off              Description of Parameter
       * @param  len              Description of Parameter
       * @exception  IOException  Description of Exception
       */
      public void write(byte b[], int off, int len) throws IOException { }
  }
  
  
  
  
  
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/ant/UriType.java
  
  Index: UriType.java
  ===================================================================
  /*
  
   ============================================================================
                     The Apache Software License, Version 1.1
   ============================================================================
  
   Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved.
  
   Redistribution and use in source and binary forms, with or without modifica-
   tion, are permitted provided that the following conditions are met:
  
   1. Redistributions of  source code must  retain the above copyright  notice,
      this list of conditions and the following disclaimer.
  
   2. Redistributions in binary form must reproduce the above copyright notice,
      this list of conditions and the following disclaimer in the documentation
      and/or other materials provided with the distribution.
  
   3. The end-user documentation included with the redistribution, if any, must
      include  the following  acknowledgment:  "This product includes  software
      developed  by the  Apache Software Foundation  (http://www.apache.org/)."
      Alternately, this  acknowledgment may  appear in the software itself,  if
      and wherever such third-party acknowledgments normally appear.
  
   4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
      used to  endorse or promote  products derived from  this software without
      prior written permission. For written permission, please contact
      apache@apache.org.
  
   5. Products  derived from this software may not  be called "Apache", nor may
      "Apache" appear  in their name,  without prior written permission  of the
      Apache Software Foundation.
  
   THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
   APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
   INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
   DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
   OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
   ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
   (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  
   This software  consists of voluntary contributions made  by many individuals
   on  behalf of the Apache Software  Foundation and was  originally created by
   Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
   Software Foundation, please see <http://www.apache.org/>.
  
  */
  package org.apache.cocoon.ant;
  
  import java.io.*;
  import java.util.*;
  
  import org.apache.cocoon.util.NetUtils;
  
  /**
   *   Encapsulate URI arithmetic.
   * A simple class for encapsultating URI computations,
   * avoiding to use extensive String operation spread
   * over all classes.
   *
   * @author    huber@apache.org
   */
  public class UriType {
      private String uri;
      private Map parameters;
      private String deparameterizedUri;
      private String sUri;
      private String mangledUri;
      private String path;
  
      /**
       * optionally set iff content type of a uri is determinable
       */
      private String contentType;
      /**
       * optionally set iff Uri has some destination file associated with
       */
      private File destFile;
  
      /**
       * optionally set iff links has been calculated for this Uri
       */
      private Set links;
  
  
      /**
       * Constructor for the UriType object
       *
       * @param  uri  String representation of a Uri
       */
      public UriType(String uri) {
          // normalize uri
          final String normalizedUri = NetUtils.normalize(uri);
          this.uri = normalizedUri;
          init();
      }
  
  
      /**
       * Constructor for the UriType object
       *
       * @param  parent  Parent context of a Uri
       * @param  uri     String representation of a Uri
       */
      public UriType(UriType parent, String uri) {
          if (parent != null) {
              // absolutize it relative to parent
              final String parentPath = parent.getPath();
              final String absolutizedUri = NetUtils.absolutize(parentPath, uri);
              // normalize
              this.uri = NetUtils.normalize(absolutizedUri);
          } else {
              // normalize
              final String normalizedUri = NetUtils.normalize(uri);
              this.uri = normalizedUri;
          }
          init();
      }
  
  
      /**
       *   Sets the destFile attribute of the UriType object
       *
       * @param  destFile   The new destFile value
       */
      public void setDestFile(File destFile) {
          this.destFile = destFile;
      }
  
  
      /**
       *   Sets the contentType attribute of the UriType object
       *
       * @param  contentType  The new contentType value
       */
      public void setContentType(String contentType) {
          this.contentType = contentType;
      }
  
  
      /**
       *   Gets the destFile attribute of the UriType object
       *
       * @return     The destFile value
       */
      public File getDestFile() {
          return this.destFile;
      }
  
  
      /**
       *   Gets the contentType attribute of the UriType object
       *
       * @return    The contentType value
       */
      public String getContentType() {
          return this.contentType;
      }
  
  
      /**
       *   Gets the links attribute of the UriType object
       *
       * @return    The links value
       */
      public Collection getLinks() {
          return this.links;
      }
  
  
      /**
       * Constructor for the getURI object
       *
       * @return    The uRI value
       */
      public String getUri() {
          return uri;
      }
  
  
      /**
       *   Gets the parameters attribute of the UriType object
       *
       * @return    The parameters value
       */
      public Map getParameters() {
          return parameters;
      }
  
  
      /**
       *   Gets the deparameterizedURI attribute of the UriType object
       *
       * @return    The deparameterizedURI value
       */
      public String getDeparameterizedUri() {
          return this.deparameterizedUri;
      }
  
  
      /**
       *   Gets the sURI attribute of the UriType object
       *
       * @return    The sURI value
       */
      public String getSUri() {
          return this.sUri;
      }
  
  
      /**
       *   Gets the mangledURI attribute of the UriType object
       *
       * @return    The mangledURI value
       */
      public String getMangledUri() {
          return this.mangledUri;
      }
  
  
      /**
       *   Gets the path attribute of the UriType object
       *
       * @return    The path value
       */
      public String getPath() {
          return this.path;
      }
  
  
      /**
       *   Gets the filename attribute of the UriType object
       *
       * @return    The filename value
       */
      public String getFilename() {
          return this.mangledUri;
      }
  
  
      /**
       *   Gets the extension attribute of the UriType object
       *
       * @return    The extension value
       */
      public String getExtension() {
          final String filename = getFilename();
          return NetUtils.getExtension(filename);
      }
  
  
      /**
       *   Gets the parameterizedURI attribute of the UriType object
       *
       * @param  addOriginalParameters    Description of Parameter
       * @param  addAdditionalParameters  Description of Parameter
       * @param  additionalParameters     Description of Parameter
       * @return                          The parameterizedURI value
       */
      public String getParameterizedUri(boolean addOriginalParameters,
              boolean addAdditionalParameters,
              Map additionalParameters) {
          Map mergedParameters = new HashMap();
          if (addOriginalParameters) {
              mergedParameters.putAll(parameters);
          }
          if (addAdditionalParameters && additionalParameters != null) {
              mergedParameters.putAll(additionalParameters);
          }
  
          final String parameterizedUri = NetUtils.parameterize(deparameterizedUri, mergedParameters);
          return parameterizedUri;
      }
  
  
      /**
       *   Gets the mergedParameterizedURI attribute of the UriType object
       *
       * @param  additionalParameters  Description of Parameter
       * @return                       The mergedParameterizedURI value
       */
      public String getMergedParameterizedUri(Map additionalParameters) {
          return getParameterizedUri(false, true, additionalParameters);
      }
  
  
      /**
       *   Gets the originalParameterizedURI attribute of the UriType object
       *
       * @return    The originalParameterizedURI value
       */
      public String getOriginalParameterizedUri() {
          return getParameterizedUri(true, false, null);
      }
  
  
      /**
       *   Adds a feature to the Link attribute of the UriType object
       *
       * @param  uriType  The feature to be added to the Link attribute
       */
      public void addLink(UriType uriType) {
          if (links == null) {
              links = new HashSet();
          }
          this.links.add(uriType);
      }
  
  
      /**
       *   Compute equality of Uri objects.
       *   Two uri objects are equal iff non-null, and
       *   uri member is non null, and uri member are equal.
       *
       * @param  o  Checked against this for equality
       * @return    boolean true if URIType objects are equal else false
       */
      public boolean equals(Object o) {
          if (o != null && o instanceof UriType) {
              UriType uriType = (UriType) o;
              if (uriType.uri != null && this.uri != null) {
                  return uriType.uri.equals(this.uri);
              }
          }
          return false;
      }
  
  
      /**
       *   Compute hash code of this object
       *
       * @return    HashCode of uri member
       */
      public int hashCode() {
          return this.uri.hashCode();
      }
  
  
      /**
       * Mangle a URI.
       *
       * @param  uri  the Uri value
       * @return      mangled Uri
       */
      protected String mangledUri(String uri) {
          uri = uri.replace('"', '\'');
          uri = uri.replace('?', '_');
          uri = uri.replace(':', '_');
  
          return uri;
      }
  
  
      /**
       *   Calculate all member values depending on the uri member value
       */
      protected void init() {
          if (uri != null) {
              parameters = new HashMap();
              deparameterizedUri = NetUtils.deparameterize(uri, parameters);
              sUri = NetUtils.parameterize(deparameterizedUri, parameters);
              mangledUri = mangledUri(sUri);
              path = NetUtils.getPath(uri);
              
              if (path.length() == 0) {
                  path = "/";
              }
          }
      }
  }
  
  
  
  
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/ant/readme.txt
  
  Index: readme.txt
  ===================================================================
   This directory implements a Cocoon Ant Task.
   
   The basic attributes of this ant task are taken from org.apache.cocoon.Main
   Beside implementing launching Cocoon via ant the number of Cocoon
   invocation should be reduced compared to the Main implementation.
   
   Another trigger for implementing an Ant task:
   I wanted to exploit a bit launching cocoon from a different environment
   than servlet, and main-commandline environment.
   
   Side Note:
     Main invokes Cocoon for getting the links for a URI, it
     invokes Cocoon for getting the content type of a URI, and
     finally it invokes Cocoon for getting the page content itself.
   
   This implementation skips getting the content type of a URI,
   by implementing a DelayedFileSavingEnvironment. This class
   write the content of a page into a ByteArrayBuffer till the content type
   of page has been settled. This should and will save time generating
   off-line pages.
   Moreover getting links of an URI is reduced to URIs having content type text/*.
   This should speed up the page generation a bit more. This feature should
   be made configurable... 
  
   Classloader Note:
     I struggled a bit making Cocoon running as an Ant task, the 
     the classpath for loading the cocoon task should include all 
     classes need for running cocoon too.
     In the CocoonTask java code itself the Thread.currentThred().setContextClassLoader()
     is absolutly important, otherwise Cocoon will fail configuring using
     it starup manager.
     Of course you can define all Cocoon classes in your java classpath commandline
     environment, but i wanted to avoid this. Defining all needed classes only
     in the ant script.
   
   Cocoon Ant task usage:
   <project basedir="." default="cocoon-docs" name="cocoon-docs">
     <property name="cocoon.dir" value="your-cocoon-directory"/>
   
     <path id="cocoon.classpath">
       <fileset dir="${cocoon.dir}/lib">
       <include name="core/jvm1.4/*.jar"/>
       <include name="core/*.jar"/>
       <include name="optional/*.jar"/>
       </fileset>
       <fileset dir="${cocoon.dir}/build/cocoon">
       <include name="*.jar"/>
       </fileset>
     </path>
  
     <target 
       name="prepare-cocoon-docs"
       description="[internal] define the task for launching Cocoon">
       
       <taskdef name="cocoon" classname="org.apache.cocoon.ant.CocoonTask" 
         classpathref="cocoon.classpath"/>
     </target>
  
     <target name="cocoon-docs" depends="prepare-cocoon-docs"
       description="* build cocoon documentation">
       
       <property name="contextDir" value="${cocoon.dir}/build/cocoon/documentation"/>
       <property name="workDir" value="${cocoon.dir}/build/cocoon-ant-work"/>
       <property name="destDir" value="${cocoon.dir}/build/cocoon-ant-docs"/>
       
       <cocoon
         contextDir="${contextDir}"
         workDir="${workDir}"
         destDir="${destDir}"
         targets="/index.html"
         logLevel="WARN"
       />
     </target>
   </project>
  
   CocoonTask Attributes
  
   Cocoon Creation
   ---------------
  
   contextDir - Cocoon's context directory, mandatory
   configFile - specifies cocoon xconf file, by default try using ${contextDir}/WEB-INF/cocoon.xconf,
   ${contextDir}/cocoon.xconf
  
   workDir - Cocoon's work directory, by default sub directory work of directory specified
   by system property java.io.tmpdir
  
   Cocoon Logging
   --------------
   logLevel - log level option DEBUG, INFO, WARN, ERROR, by default INFO
   logger - logger category, by default "cocoon"
   logkitXconf - logkit xconf file, by default try using ${contextDir}/WEB-INF/logkit.xconf,
   ${contextDir}/cocoon.xconf
  
   Processing Cocoon options
   -------------------------
   targets - comma, space, or semicolon seperated list of target URIs, eg. /index.html,
   mandatory
  
   acceptHeader - accept header, by default text/html, * / *
   agentHeader - agent header, by default Apache Cocoon 2.1-dev
  
   Processing Cocoon File Generation
   ---------------------------------
   destDir - destination directory of generated targets, mandatory
  
   Processing Cocoon Modes
   -----------------------
   followLinks - boolean value, iff following links should be processed, by default true
   precompileOnly - boolean value, iff xsp precompile should be performed, by default false,
   not evaluted - yet
  
   Processing Cocoon Link Generation
   ---------------------------------
   to-do
  
   Processing Cocoon Index Generation
   ----------------------------------
   to-do
  
  
  Future Plans
   I think about creating some ant inner classes for specifying some more subtask
   Subtask ideas:
     Offline index generation
     Offline xsp compilation
     Offline link generation
  
   Ideas are welcome
   Have fun.
   
  
  
  

----------------------------------------------------------------------
In case of troubles, e-mail:     webmaster@xml.apache.org
To unsubscribe, e-mail:          cocoon-cvs-unsubscribe@xml.apache.org
For additional commands, e-mail: cocoon-cvs-help@xml.apache.org