Package org.apache.cocoon.transformation

Source Code of org.apache.cocoon.transformation.DASLTransformer

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.transformation;

import java.io.IOException;
import java.io.Serializable;
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;

import javax.xml.transform.OutputKeys;

import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.caching.CacheableProcessingComponent;
import org.apache.cocoon.caching.validity.EventValidity;
import org.apache.cocoon.components.webdav.WebDAVEventFactory;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.xml.XMLUtils;
import org.apache.cocoon.xml.dom.DOMStreamer;
import org.apache.commons.httpclient.HttpConnection;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.HttpURL;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.excalibur.source.SourceValidity;
import org.apache.excalibur.source.impl.validity.AggregatedValidity;
import org.apache.webdav.lib.BaseProperty;
import org.apache.webdav.lib.WebdavResource;
import org.apache.webdav.lib.methods.OptionsMethod;
import org.apache.webdav.lib.methods.SearchMethod;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

/**
* This transformer performs DASL queries on DASL-enabled WebDAV servers.
* It expects a "query" element in the  "http://cocoon.apache.org/webdav/dasl/1.0"
* namespace containing the DASL query to execute, with a "target" attribute specifiyng
* the webdav:// or http:// URL for the target WebDAV server. It will then replace
* it  with a "query-result" element containing the WebDAV results.
*
* Each result will be contained in a "result"  element with a "path" attribute pointing at it
* and all WebDAV properties presented as (namespaced) children elements.
*
* Sample invocation:
* lt;dasl:query xmlns:dasl="http://cocoon.apache.org/webdav/dasl/1.0"
*   target="webdav://localhost/repos/"gt;
* lt;D:searchrequest xmlns:D="DAV:"gt;
*   lt;D:basicsearchgt;
*     lt;D:selectgt;
*       lt;D:allprop/gt;
*     lt;/D:selectgt;
*     lt;D:fromgt;
*       lt;D:scopegt;
*         lt;D:hrefgt;/repos/lt;/D:hrefgt;
*         lt;D:depthgt;infinitylt;/D:depthgt;
*       lt;/D:scopegt;
*     lt;/D:fromgt;
*     lt;D:wheregt;
*       lt;D:eqgt;
*         lt;D:propgt;lt;D:getcontenttype/gt;lt;/D:propgt;
*         lt;D:literalgt;text/htmllt;/D:literalgt;
*       lt;/D:eqgt;
*     lt;/D:wheregt;
*     lt;D:orderbygt;
*       lt;D:ordergt;
*         lt;D:propgt;
*           lt;D:getcontentlength/gt;
*         lt;/D:propgt;
*         lt;D:ascending/gt;
*       lt;/D:ordergt;
*       lt;D:ordergt;
*         lt;D:propgt;
*           lt;D:href/gt;
*         lt;/D:propgt;
*         lt;D:ascending/gt;
*       lt;/D:ordergt;
*     lt;/D:orderbygt;
*   lt;/D:basicsearchgt;
* lt;/D:searchrequestgt;
* lt;/dasl:querygt;
*
* Features
* - Substitution of a value: with this feature it's possible to pass value from sitemap
* that are substituted into a query.
* sitemap example:
*        lt;map:transformer type="dasl"gt;
*          lt;parameter name="repos" value="/repos/"gt;
*        lt;/map:transformergt;
* query example:
*        ....
*        lt;D:hrefgt;lt;substitute-value name="repos"/gt;lt;/D:hrefgt;
*        ....
* This feature is like substitute-value of SQLTransformer
*
* TODO: the SWCL Search method doesn't preserve the result order, which makes
* order-by clauses useless.
*
* TODO: *much* better error handling.
*
* @author <a href="mailto: gianugo@apache.org">Gianugo Rabellino</a>
* @author <a href="mailto:d.madama@pro-netics.com>Daniele Madama</a>
* @version $Id: DASLTransformer.java 433543 2006-08-22 06:22:54Z crossley $
*/
public class DASLTransformer extends AbstractSAXTransformer implements CacheableProcessingComponent {

    /** The prefix for tag */
    static final String PREFIX = "dasl";
    /** The tag name identifying the query */
    static final String QUERY_TAG = "query";
    /** The tag namespace */
    static final String DASL_QUERY_NS =
        "http://cocoon.apache.org/webdav/dasl/1.0";
    /** The URL namespace */
    static final String TARGET_URL = "target";
    /** The WebDAV scheme*/
    static final String WEBDAV_SCHEME = "webdav://";
    /** The tag name of root_tag for result */
    static final String RESULT_ROOT_TAG = "query-result";
    /** The tag name of root_tag for errors */
    static final String ERROR_ROOT_TAG = "error";
    /** The tag name for substitution of query parameter */
    static final String SUBSTITUTE_TAG = "substitute-value";
    /** The tag name for substitution of query parameter */
    static final String SUBSTITUTE_TAG_NAME_ATTRIBUTE = "name";

    protected static final String PATH_NODE_NAME = "path";
    protected static final String RESOURCE_NODE_NAME = "resource";

    /** The target HTTP URL */
    String targetUrl;
   
    /** The validity of this dasl transformation run */
  private AggregatedValidity m_validity = null;
 
  /** The WebdavEventFactory to abstract Event creation */
  private WebDAVEventFactory m_eventfactory = null;
 
 
    /**
     *  Intercept the <dasl:query> start tag.
     *
     * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes)
     */
    public void startElement(
        String uri,
        String name,
        String raw,
        Attributes attr)
        throws SAXException {
        if (name.equals(QUERY_TAG) && uri.equals(DASL_QUERY_NS)) {
            this.startRecording();
            if ((targetUrl = attr.getValue(TARGET_URL)) == null) {
                throw new IllegalStateException("The query element must contain a \"target\" attribute");
            }
            //Sanityze target
            if (targetUrl.startsWith(WEBDAV_SCHEME))
                targetUrl =
                    "http://" + targetUrl.substring(WEBDAV_SCHEME.length());
            if (!targetUrl.startsWith("http"))
                throw new SAXException("Illegal value for target, must be an http:// or webdav:// URL");
        } else if (name.equals(SUBSTITUTE_TAG) && uri.equals(DASL_QUERY_NS)) {
            String parName = attr.getValue( DASL_QUERY_NS, SUBSTITUTE_TAG_NAME_ATTRIBUTE );
            if ( parName == null ) {
                throw new IllegalStateException( "Substitute value elements must have a " +
                                           SUBSTITUTE_TAG_NAME_ATTRIBUTE + " attribute" );
            }
            String substitute = this.parameters.getParameter( parName, null );
            if (getLogger().isDebugEnabled()) {
                getLogger().debug( "SUBSTITUTE VALUE " + substitute );
            }
            super.characters(substitute.toCharArray(), 0, substitute.length());
        } else {
            super.startElement(uri, name, raw, attr);
        }
    }

    /**
     * Intercept the <dasl:query> end tag, convert buffered input to a String, build and execute the
     * DASL query.
     *
     * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String)
     */
    public void endElement(String uri, String name, String raw)
        throws SAXException {
        String query;
        if (name.equals(QUERY_TAG) && uri.equals(DASL_QUERY_NS)) {
            DocumentFragment frag = this.endRecording();
            try {
                Properties props = XMLUtils.createPropertiesForXML(false);
                props.put(OutputKeys.ENCODING, "ISO-8859-1");
                query = XMLUtils.serializeNode(frag, props);
                // Perform the DASL query
                this.performSearchMethod(query);
            } catch (ProcessingException e) {
                throw new SAXException("Unable to fetch the query data:", e);
            }
        } else if (name.equals(SUBSTITUTE_TAG) && uri.equals(DASL_QUERY_NS)) {
            //Do nothing!!!!
        } else {
            super.endElement(uri, name, raw);
        }
    }

    protected void performSearchMethod(String query) throws SAXException {
      OptionsMethod optionsMethod = null;
      SearchMethod searchMethod = null;
        try {
            DOMStreamer propertyStreamer = new DOMStreamer(this.xmlConsumer);
            optionsMethod = new OptionsMethod(this.targetUrl);
            searchMethod = new SearchMethod(this.targetUrl, query);
            HttpURL url = new HttpURL(this.targetUrl);
            HttpState state = new HttpState();
            state.setCredentials(null, new UsernamePasswordCredentials(
                    url.getUser(),
                    url.getPassword()));
            HttpConnection conn = new HttpConnection(url.getHost(), url.getPort());
           
            // eventcaching stuff
            SourceValidity extraValidity = makeWebdavEventValidity(url);
            if(extraValidity!=null && m_validity!=null)
              m_validity.add(extraValidity);
            // end eventcaching stuff
           
            WebdavResource resource = new WebdavResource(new HttpURL(this.targetUrl));
            if(!resource.exists()) {
                throw new SAXException("The WebDAV resource don't exist");
            }
            optionsMethod.execute(state, conn);
            if(!optionsMethod.isAllowed("SEARCH")) {
                throw new SAXException("The server doesn't support the SEARCH method");
            }
            int httpstatus = searchMethod.execute(state, conn);
           
           
            this.contentHandler.startElement(DASL_QUERY_NS,
                                             RESULT_ROOT_TAG,
                                             PREFIX + ":" + RESULT_ROOT_TAG,
                                             XMLUtils.EMPTY_ATTRIBUTES);
           
            // something might have gone wrong, report it
            // 207 = multistatus webdav response
            if(httpstatus != 207) {
             
              this.contentHandler.startElement(DASL_QUERY_NS,
                        ERROR_ROOT_TAG,
                        PREFIX + ":" + ERROR_ROOT_TAG,
                        XMLUtils.EMPTY_ATTRIBUTES);
             
              // dump whatever the server said
              propertyStreamer.stream(searchMethod.getResponseDocument());
             
              this.contentHandler.endElement(DASL_QUERY_NS,
                  ERROR_ROOT_TAG,
                        PREFIX + ":" + ERROR_ROOT_TAG);
             
            } else {
              // show results
             
              Enumeration enumeration = searchMethod.getAllResponseURLs();
             
              while (enumeration.hasMoreElements()) {
                  String path = (String) enumeration.nextElement();
                  Enumeration properties = searchMethod.getResponseProperties(path);
                  AttributesImpl attr = new AttributesImpl();
                  attr.addAttribute(DASL_QUERY_NS, PATH_NODE_NAME, PREFIX + ":" + PATH_NODE_NAME, "CDATA",path);
 
                  this.contentHandler.startElement(DASL_QUERY_NS,
                      RESOURCE_NODE_NAME,
                      PREFIX + ":" + RESOURCE_NODE_NAME,
                      attr);
                  while(properties.hasMoreElements()) {
                      BaseProperty metadata = (BaseProperty) properties.nextElement();
                      Element propertyElement = metadata.getElement();
                      propertyStreamer.stream(propertyElement);
                  }
 
                  this.contentHandler.endElement(DASL_QUERY_NS,
                      RESOURCE_NODE_NAME,
                      PREFIX + ":" + RESOURCE_NODE_NAME);
              }
            }
           
            this.contentHandler.endElement(DASL_QUERY_NS,
                                           RESULT_ROOT_TAG,
                                           PREFIX + ":" + RESULT_ROOT_TAG);
        } catch (SAXException e) {
            throw new SAXException("Unable to fetch the query data:", e);
        } catch (HttpException e1) {
            this.getLogger().error("Unable to contact Webdav server", e1);
            throw new SAXException("Unable to connect with server: ", e1);
        } catch (IOException e2) {
            throw new SAXException("Unable to connect with server: ", e2);
        } catch (NullPointerException e) {
            throw new SAXException("Unable to fetch the query data:", e);
        } catch (Exception e) {
            throw new SAXException("Generic Error:", e);
        } finally {
          // cleanup
          if(searchMethod!=null)
            searchMethod.releaseConnection();
          if(optionsMethod!=null)
            optionsMethod.releaseConnection();
        }
    }
   
    /**
     * Helper method to do event caching
     *
     * @param methodurl The url to create the EventValidity for
     * @return an EventValidity object or null
     */
    private SourceValidity makeWebdavEventValidity(HttpURL methodurl) {
     
      if(m_eventfactory == null) {
        return null;
      }
     
      SourceValidity evalidity = null;
      try {
       
        evalidity = new EventValidity(m_eventfactory.createEvent(methodurl));
       
        if(getLogger().isDebugEnabled())
          getLogger().debug("Created eventValidity for dasl: "+evalidity);
     
      } catch (Exception e) {
        if(getLogger().isErrorEnabled())
          getLogger().error("could not create EventValidity!",e);
      }
      return evalidity;
    }
   
    public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par)
    throws ProcessingException, SAXException, IOException {
      super.setup(resolver, objectModel, src, par);
     
      if(m_eventfactory == null) {
        try {
          m_eventfactory = (WebDAVEventFactory)manager.lookup(WebDAVEventFactory.ROLE);
        } catch (Exception e) {
          if(getLogger().isErrorEnabled())
            getLogger().error("Couldn't look up WebDAVEventFactory, event caching will not work!", e);
      }
      }
    }
   
    /**
     * Forget about previous aggregated validity object
     */
    public void recycle() {
      super.recycle();
      m_validity = null;
    }
   
    /**
     * generates the cachekey, which is the classname plus any possible COCOON parameters
     */
  public Serializable getKey() {
    if(this.parameters.getNames().length == 0) {
      return getClass().getName();
    } else {
      StringBuffer buf = new StringBuffer();
      buf.append(getClass().getName());
     
      // important for substitution
      // we don't know yet which ones are relevant, so include all
      String[] names = this.parameters.getNames();
      for(int i=0; i<names.length; i++) {
        buf.append(";");
        buf.append(names[i]);
        buf.append("=");
        try {
          buf.append(this.parameters.getParameter(names[i]));
        } catch (Exception e) {
          if(getLogger().isErrorEnabled())
              getLogger().error("Could not read parameter '"+names[i]+"'!",e);
        }
      }
     
      return buf.toString();
    }
  }

  /**
   * returns the validity which will be filled during processing of the requests
   */
  public SourceValidity getValidity() {
    if(getLogger().isDebugEnabled())
      getLogger().debug("getValidity() called!");
   
    // dont do any caching when no event caching is set up
    if (m_eventfactory == null) {
      return null;
    }
   
        if (m_validity == null) {
            m_validity = new AggregatedValidity();
        }
        return m_validity;
    }

}
TOP

Related Classes of org.apache.cocoon.transformation.DASLTransformer

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