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/02/06 22:18:49 UTC

cvs commit: xml-cocoon2/src/scratchpad/src/org/apache/cocoon/transformation EncodeURLTransformer.java

huber       02/02/06 13:18:49

  Added:       src/scratchpad/src/org/apache/cocoon/transformation
                        EncodeURLTransformer.java
  Log:
  rewrite URLs, matching specified patterns
  using response.encodeURL()
  
  Revision  Changes    Path
  1.1                  xml-cocoon2/src/scratchpad/src/org/apache/cocoon/transformation/EncodeURLTransformer.java
  
  Index: EncodeURLTransformer.java
  ===================================================================
  package org.apache.cocoon.transformation;
  import java.io.IOException;
  import java.util.Map;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpSession;
  import org.apache.avalon.excalibur.pool.Poolable;
  import org.apache.avalon.excalibur.pool.Recyclable;
  import org.apache.avalon.framework.configuration.Configurable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.parameters.Parameters;
  import org.apache.cocoon.ProcessingException;
  import org.apache.cocoon.environment.SourceResolver;
  import org.apache.cocoon.environment.http.HttpEnvironment;
  import org.apache.cocoon.transformation.AbstractTransformer;
  import org.apache.regexp.RE;
  import org.apache.regexp.RESyntaxException;
  import org.xml.sax.Attributes;
  import org.xml.sax.SAXException;
  import org.xml.sax.helpers.AttributesImpl;
  
  /**
   * The encodeURL transformer emits encoded URLs.
   * <p>
   *   This transformer applies encodeURL method to URLs.
   *   You may want to use this transform to avoid doing the manually
   *   encodeURL() call.
   * </p>
   * <p>
   *   Usually this transformer is appended as last transformer before
   *   the serialization process. In this case it is possible to encode
   *   URLs introduced in the generator, and xslt transformer phase.
   * </p>
   * <p>
   *   You can specify which attributes hold URL values in order to restrict
   *   URL rewriting to specific attributes only.
   * </p>
   * <p>
   * Usage in a sitemap:
   * </p>
   * <pre><tt>
   *   <map:composition>
   *   ...
   *     <map:transformers>
   *     ...
   *       <map:transformer type="encodeURL" 
   *         src="org.apache.cocoon.optional.transformation.EncodeURLTransformer">
   *         <exclude-name>img/@src</exclude-name>
   *         <include-name>.&asterik;/@href|.&asterik;/@src|.&asterik;/@action</include-name>
   *       </map:transformer>
   *   ...
   *   <map:pipelines>
   *     <map:pipeline>
   *       ...
   *       <map:transform type="encodeURL"/>
   *       ...
   * </pre></tt>
   *
   * @author     <a href="mailto:bh22351@i-one.at">Bernhard Huber</a>
   * @version    CVS $Id: EncodeURLTransformer.java,v 1.1 2002/02/06 21:18:49 huber Exp $
   *
   * @cocoon:name encodeURL
   * @cocoon:status scratchpad
   * @cocoon:parameter name="exclude-name" 
   *   default-value="img/@src"
   *   description="RE pattern for excluding attributes from encode URL rewriting"
   * @cocoon:parameter name="include-name"
   *   default-value=".&asterik;/@href|.&asterik;/@src|.&asterik;/@action"
   *   description="RE pattern for including attributes from encode URL rewriting"
   *
   */
  
  public class EncodeURLTransformer extends AbstractTransformer implements Configurable, Recyclable {
  
      /**
       * Configuration name for specifying excluding patterns,
       * ie exclude-name.
       *
       * @since
       */
      public final static String EXCLUDE_NAME = "exclude-name";
      /**
       * Configuration name for specifying including patterns,
       * ie include-name.
       *
       * @since
       */
      public final static String INCLUDE_NAME = "include-name";
  
      /**
       * Configuration default exclude pattern, 
       * ie img/@src
       *
       * @since
       */
      public final static String EXCLUDE_NAME_DEFAULT = "img/@src";
      /**
       * Configuration default exclude pattern, 
       * ie .*\/@href|.*\/@action|frame/@src
       *
       * @since
       */
      public final static String INCLUDE_NAME_DEFAULT = ".*/@href|.*/@action|frame/@src";
  
      private String includeNameConfigure = INCLUDE_NAME_DEFAULT;
      private String excludeNameConfigure = EXCLUDE_NAME_DEFAULT;
  
      private String includeName;
      private String excludeName;
  
      private ElementAttributeMatching elementAttributeMatching;
      private HttpServletResponse response;
      private HttpServletRequest request;
  
  
      /**
       * Setup the transformer.
       * <p>
       *   Setup include, and exclude patterns from the parameters
       * </p>
       *
       * @param resolver source resolver
       * @param objectModel sitemap objects
       * @param parameters request parameters
       *
       */
      public void setup(SourceResolver resolver, Map objectModel, String source, Parameters parameters)
               throws ProcessingException, SAXException, IOException {
  
          includeName = parameters.getParameter(EncodeURLTransformer.INCLUDE_NAME, this.includeNameConfigure);
          excludeName = parameters.getParameter(EncodeURLTransformer.EXCLUDE_NAME, this.excludeNameConfigure);
  
          try {
              elementAttributeMatching = new ElementAttributeMatching(includeName, excludeName);
          } catch (RESyntaxException reex) {
              String message = "Cannot parse include-name: " + includeName + " " +
                      "or exclude-name: " + excludeName + "!";
              throw new ProcessingException(message, reex);
          }
  
          response =
                  (HttpServletResponse) objectModel.get(HttpEnvironment.HTTP_RESPONSE_OBJECT);
          request =
                  (HttpServletRequest) objectModel.get(HttpEnvironment.HTTP_REQUEST_OBJECT);
      }
  
  
      /**
       * BEGIN SitemapComponent methods
       *
       * @param  configuration               Description of Parameter
       * @exception  ConfigurationException  Description of Exception
       * @since
       */
      public void configure(Configuration configuration) throws ConfigurationException {
          if (configuration != null) {
              Configuration child;
  
              child = configuration.getChild(EncodeURLTransformer.INCLUDE_NAME);
              this.includeNameConfigure = child.getValue(INCLUDE_NAME_DEFAULT);
  
              child = configuration.getChild(EncodeURLTransformer.EXCLUDE_NAME);
              this.excludeNameConfigure = child.getValue(EXCLUDE_NAME_DEFAULT);
          }
          if (this.includeNameConfigure == null) {
              String message = "Configure " + INCLUDE_NAME + "!";
              throw new ConfigurationException(message);
          }
          if (this.excludeNameConfigure == null) {
              String message = "Configure " + EXCLUDE_NAME + "!";
              throw new ConfigurationException(message);
          }
      }
  
  
      /**
       *Description of the Method
       *
       * @since
       */
      public void recycle() {
          response = null;
          request = null;
          elementAttributeMatching = null;
      }
  
  
      /**
       * Start parsing an element
       *
       * @param  uri               of the element
       * @param  name              of the element
       * @param  raw               name of the element
       * @param  attributes        list
       * @exception  SAXException  Description of Exception
       * @since
       */
      public void startElement(String uri, String name, String raw, Attributes attributes)
               throws SAXException {
          String lname = name;
  
          if (response != null && elementAttributeMatching != null) {
              if (attributes != null && attributes.getLength() > 0) {
                  AttributesImpl new_attributes = new AttributesImpl(attributes);
                  for (int i = 0; i < new_attributes.getLength(); i++) {
                      String attr_lname = new_attributes.getLocalName(i);
  
                      String value = new_attributes.getValue(i);
  
                      if (elementAttributeMatching.matchesElementAttribute(lname, attr_lname)) {
                          String new_value = encodeURL(value, request, response);
                          if (getLogger().isDebugEnabled()) {
                              this.getLogger().debug("element/@attribute matches: " + name + "/@" + attr_lname);
                              this.getLogger().debug("encodeURL: " + value + " -> " + new_value);
                          }
                          new_attributes.setValue(i, new_value);
                      }
                  }
                  // parent handles element using encoded attribute values
                  super.contentHandler.startElement(uri, name, raw, new_attributes);
                  return;
              }
          }
          // no match, parent handles element as-is
          super.contentHandler.startElement(uri, name, raw, attributes);
      }
  
  
      /**
       * Encode a URL.
       * <p>
       *   This method calculates from a given url the encoded url
       * </p>
       *
       * @param  url       the URL probably without sessionid.
       * @param  request   the http request
       * @param  response  the http response
       * @return           String the original url inclusive the sessionid
       * @since
       */
      private String encodeURL(String url, HttpServletRequest request, HttpServletResponse response) {
          String encoded_url;
          if (response != null) {
              // As some servlet-engine does not check if url has been already rewritten
              HttpSession session = request.getSession(false);
              if (session != null && url.indexOf(session.getId()) > -1) {
                  encoded_url = url;
              } else {
                  encoded_url = response.encodeURL(url);
              }
          } else {
              encoded_url = url;
          }
          return encoded_url;
      }
  
  
      /**
       * A helper class for matching element names, and attribute names.
       *
       * <p>
       *  For given include-name, exclude-name decide if element-attribute pair
       *  matches. This class defines the precedence and matching algorithm.
       * </p>
       *
       * @author     <a href="mailto:bh22351@i-one.at">Bernhard Huber</a>
       * @version    CVS $Id: EncodeURLTransformer.java,v 1.1 2002/02/06 21:18:49 huber Exp $
       */
      public class ElementAttributeMatching {
          /**
           * Regular expression of including patterns
           *
           * @since
           */
          protected RE includeNameRE;
          /**
           * Regular expression of excluding patterns
           *
           * @since
           */
          protected RE excludeNameRE;
  
  
          /**
           *Constructor for the ElementAttributeMatching object
           *
           * @param  includeName            Description of Parameter
           * @param  excludeName            Description of Parameter
           * @exception  RESyntaxException  Description of Exception
           * @since
           */
          public ElementAttributeMatching(String includeName, String excludeName) throws RESyntaxException {
              includeNameRE = new RE(includeName, RE.MATCH_CASEINDEPENDENT);
              excludeNameRE = new RE(excludeName, RE.MATCH_CASEINDEPENDENT);
          }
  
  
          /**
           * Return true iff element_name attr_name pair is not matched by exclude-name,
           * but is matched by include-name
           *
           * @param  element_name
           * @param  attr_name
           * @return               boolean true iff value of attribute_name should get rewritten, else
           *   false.
           * @since
           */
          public boolean matchesElementAttribute(String element_name, String attr_name) {
              String element_attr_name = canonicalizeElementAttribute(element_name, attr_name);
  
              if (excludeNameRE != null && includeNameRE != null) {
                  return !matchesExcludesElementAttribute(element_attr_name) &&
                          matchesIncludesElementAttribute(element_attr_name);
              } else {
                  return false;
              }
          }
  
  
          /**
           * Build from elementname, and attribute name a single string.
           * <p>
           *   String concatenated <code>element name + "/@" + attribute name</code>
           *   is matched against the include and excluding patterns.
           * </p>
           *
           * @param  element_name  Description of Parameter
           * @param  attr_name     Description of Parameter
           * @return               Description of the Returned Value
           * @since
           */
          String canonicalizeElementAttribute(String element_name, String attr_name) {
              StringBuffer element_attr_name = new StringBuffer();
              element_attr_name.append(element_name);
              element_attr_name.append("/@");
              element_attr_name.append(attr_name);
              return element_attr_name.toString();
          }
  
  
          /**
           * Return true iff element_name attr_name pair is matched by exclude-name.
           *
           * @param  element_attr_name
           * @return                    boolean true iff exclude-name matches element_name, attr_name, else
           *   false.
           * @since
           */
          private boolean matchesExcludesElementAttribute(String element_attr_name) {
              boolean match = excludeNameRE.match(element_attr_name);
              return match;
          }
  
  
          /**
           * Return true iff element_name attr_name pair is matched by include-name.
           *
           * @param  element_attr_name
           * @return                    boolean true iff include-name matches element_name, attr_name, else
           *   false.
           * @since
           */
          private boolean matchesIncludesElementAttribute(String element_attr_name) {
              boolean match = includeNameRE.match(element_attr_name);
              return match;
          }
      }
  }
  
  
  
  

----------------------------------------------------------------------
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