Package org.apache.xindice.core.request

Source Code of org.apache.xindice.core.request.URIMapper

/*
* 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.
*
* $Id: URIMapper.java 511426 2007-02-25 03:25:02Z vgritsenko $
*/

package org.apache.xindice.core.request;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xindice.core.Collection;
import org.apache.xindice.core.Container;
import org.apache.xindice.core.DBException;
import org.apache.xindice.core.Database;
import org.apache.xindice.core.FaultCodes;
import org.apache.xindice.util.ObjectPool;
import org.apache.xindice.util.Poolable;
import org.apache.xindice.util.XindiceException;
import org.apache.xindice.xml.TextWriter;

import org.w3c.dom.Document;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Properties;

/**
* URIMapper maps a URI (from whence it came) to a Xindice object.  Xindice
* URIs can identify any of several different object types, each of which
* exposes a different (or slightly different) interface to the outside
* world.
*
* @version $Revision: 511426 $, $Date: 2007-02-24 22:25:02 -0500 (Sat, 24 Feb 2007) $
*/
public final class URIMapper extends URLConnection implements Poolable {

    private static final Log log = LogFactory.getLog(URIMapper.class);

    public static final int UNKNOWN = -1;
    public static final int APPLICATION = 1;
    public static final int COLLECTION = 2;
    public static final int DOCUMENT = 3;

    public static final String DEFAULT_ENCODING = "UTF-8";

    private ObjectPool pool = null;
    private String uri = null;
    private int type = 0;

    private byte[] buf = null;
    private int pos = 0;
    private char lastChar = 0;

    private Database db = null;
    private Collection collection = null;
    private Document document = null;
    private String method = null;
    private Container container = null;

    private Properties params = null;
    private String[] args = null;

    private String urlresult = null; // Holds the value of the URL resolution results (XML doc or XMLObject call results )
    private boolean inputstreamset = false; // Flag to tell if the input stream has been initialized

    /**
     * Constructor for creating URIMapper instance using a standard URL
     */
    public URIMapper(URL u) {
        super(u);
        try {
            setURI(u.toString());
        } catch (Exception e) {
            // Put error code here!
            if (log.isWarnEnabled()) {
                log.warn("ignored exception", e);
            }
        }
    }

    /**
     * Constructor for older URIMapper instances
     */
    public URIMapper(String uri) throws XindiceException {
        super(null);
        setURI(uri);
    }

    /**
     * Constructor for older URIMapper instances
     */
    public URIMapper() {
        super(null);
    }

    /**
     * Opens a communications link to the resource referenced by this URL,
     * if such a connection has not already been established.
     */
    public void connect() {
        this.connected = true;
    }

    /**
     * Returns an input stream that reads from this open connection.
     */
    public InputStream getInputStream() throws IOException {

        String output = null;

        // Check if the inputstream has already been initialized, if not do now, else return the contents of urlresult
        if (!inputstreamset) {
            try {
                switch (type) {

                    case URIMapper.DOCUMENT:
                        output = TextWriter.toString(getDocument());
                        break;

                    default :
                        //  Document type not found, output error message
                        throw new Exception("Content type unsupported");
                }
            } catch (Exception e) {
                if (log.isWarnEnabled()) {
                    log.warn("ignored exception", e);
                }
            }
        }
        // Inputstream already initialized, set output to be value of urlresult
        else {
            output = urlresult;
        }

        // Save the value of output into local variable urlresult
        urlresult = output;
        // Set inpustreamset flag to signal that url has already been resolved
        inputstreamset = true;

        // Send the result to the client, sending blank string if NULL
        if (output == null) {
            return new ByteArrayInputStream(new byte[0]);
        } else {
            return new ByteArrayInputStream(output.getBytes(DEFAULT_ENCODING));
        }
    }

    /**
     * Returns the value of the content-encoding header field.
     * @return the content encoding of the resource that the URL references, or null if not known.
     */
    public String getContentEncoding() {
        return DEFAULT_ENCODING;
    }

    /**
     * Returns the value of the content-type header field.
     * @return the content type of the resource that the URL references, or null if not known.
     */
    public String getContentType() {
        // Return the docuement's content type, for now this can only be "text/xml"
        return "text/xml";
    }

    /**
     * Returns the value of the content-length header field.
     * @return the content length of the resource that this connection's URL references, or -1 if the content length is not known.
     */
    public int getContentLength() {
        // Check to see if this document has already been resolved, if not call getInputStream
        if (!inputstreamset) {
            try {
                this.getInputStream();
            } catch (IOException e) {
                return 0;
            }
        }

        // Return the lenght of this document/XMLObject call
        return urlresult.length();
    }

    /**
     * Returns the value of the last-modified header field. The result is the number of milliseconds since January 1, 1970 GMT.
     * @return the date the resource referenced by this URLConnection was last modified, or 0 if not known.
     */
    public long getLastModified() {
        // For now this functionality is not available, return 0
        return 0;
    }

    public void setPool(ObjectPool pool) {
        this.pool = pool;
    }

    public void reclaim() {
        reset();
        if (pool != null) {
            pool.putObject(this);
        }
    }

    /**
     * reset resets the state of the URIMapper.
     */
    private void reset() {
        type = UNKNOWN;
        lastChar = 0;
        method = "";
        db = null;
        collection = null;
        document = null;
        params = null;
        args = null;
        container = null;

        // reset urlresult and inputstreamset
        urlresult = null;
        inputstreamset = false;
    }

    /**
     * setURI sets the URI for the URIMapper and parses it.  The parsed
     * components of a URI can be retrieved using getObjectType and any
     * of the get<component> methods.
     *
     * @param uri The URI
     */
    public void setURI(String uri) throws XindiceException {
        this.uri = uri;
        reset();
        parse();
    }

    /**
     * parseName parses an identifier up to any of the specified delimiters.
     *
     * @param delims The delimiters to use
     * @return The parsed name
     */
    private String parseName(String delims) {
        int start = pos;
        while (pos < buf.length) {
            lastChar = (char) buf[pos++];
            if (delims.indexOf(lastChar) != -1) {
                break;
            }
        }
        if (pos == buf.length && delims.indexOf(lastChar) == -1) {
            pos++;
        }
       
        return pos > start ? new String(buf, start, pos - start - 1) : "";
    }

    /**
     * parseParams parses a parameter set and produces either a Properties or
     * String[] Object representing those parameters.
     */
    private void parseParams() {
        if (lastChar == '?') {
            // Query String param list
            params = new Properties();
            String name;
            String value;
            String temp;
            while (true) {
                name = parseName("=");
                if (name.length() == 0) {
                    break;
                }
                value = parseName("?&;");
                temp = params.getProperty(name);
                if (temp != null) {
                    StringBuffer sb = new StringBuffer(32);
                    sb.append(temp);
                    sb.append('\u0001');
                    sb.append(value);
                    value = sb.toString();
                }
                params.setProperty(name, value);
            }
        } else
            params = new Properties();
    }

    /**
     * parse parses the URI.
     */
    private void parse() throws XindiceException {
        buf = uri.getBytes();
        pos = 0;
        String tmp;

        if (buf.length == 0) {
            throw new DBException(FaultCodes.URI_EMPTY);
        }

        // TODO: Be Able To Handle Remote URIs
        if ((char) buf[0] != '/') {
            parseName(":"); // Ignore Protocol
            parseName("/"); // Ignore Slash
            parseName("/"); // Ignore Slash
            parseName("/:"); // Ignore Host (For Now)
            if (lastChar == ':') {
                parseName("/"); // Ignore Port
            }
        } else {
            pos = 1;
        }

        // Database check
        tmp = parseName("/");
        if (tmp == null) {
            return;
        }

        db = Database.getDatabase(tmp);
        if (db == null) {
            return;
        }

        type = APPLICATION;
        tmp = parseName("/(?");

        int objType = getParsedObjectType(db, tmp);
        // If unknown then this URI just points to db and we're done.
        // Otherwise we need to keep walking down the URI.
        if (objType != UNKNOWN) {
            type = walkURI(db, tmp, objType);
        }

        if (lastChar == '?') {
            parseParams();
            return;
        }
    }

    /**
     * Recursive method to handle the parse of the URI and setup the instance
     * objects.
     */
    protected int walkURI(Collection col, String name, int objType) throws XindiceException {
        switch (objType) {
            case DOCUMENT:
                container = col.getContainer(name);
                document = container.getDocument();
                return DOCUMENT;

            case COLLECTION:
                Collection c = col.getCollection(name);
                if (c != null) {
                    collection = c;
                    String tmp = parseName("/(?");
                    // If we have another name recurse to handle it.
                    if (!tmp.equals("")) {
                        return walkURI(c, tmp, getParsedObjectType(c, tmp));
                    }

                    return COLLECTION;
                }

            default:
                if (log.isWarnEnabled()) {
                    log.warn("invalid object type : " + objType);
                }
        }

        return UNKNOWN;
    }

    /**
     * Determine the type of object. If more then one object has the same name
     * the order of precedence is COLLECTION - XMLOBJECT - DOCUMENT
     */
    protected int getParsedObjectType(Collection col, String name) throws XindiceException {

        if (col.getCollection(name) != null) {
            return COLLECTION;
        } else if ((col.getFiler() != null) && (col.getContainer(name) != null)) {
            return DOCUMENT;
        } else {
            return UNKNOWN;
        }
    }

    /**
     * getObjectType returns the type of Object that was identified in the
     * parsing of the URI.  This method will return one of the following
     * values: UNKNOWN, APPLICATION, DATABASE, COLLECTION, DOCUMENT or
     * XMLOBJECT.
     *
     * @return The object type
     */
    public int getObjectType() {
        return type;
    }

    /**
     * getDatabase returns the Database that was resolved in the
     * parsing of this URI.
     *
     * @return The Database
     */
    public Database getDatabase() {
        return db;
    }

    /**
     * getCollection returns the Collection object that was resolved in the
     * parsing of the URI.  If no Collection was resolved, this method will
     * return null.
     *
     * @return The Collection
     */
    public Collection getCollection() {
        return collection;
    }

    /**
     * getDocument returns the Document object that was resolved in the
     * parsing of the URI.  If no Document was resolved, this method will
     * return null.
     *
     * @return The Document
     */
    public Document getDocument() {
        return document;
    }

    /**
     * getContainer returns the Document Container that was resolved in
     * the parsing of the URI.  If no Container was resolved, this method
     * will return null.
     *
     * @return The Container
     */
    public Container getContainer() {
        return container;
    }

    /**
     * getMethod returns the method name that was resolved in the parsing
     * of the URI.  Method names are associated with XMLObjects.
     * If no method name was resolved, this method will return null.
     *
     * @return The method name
     */
    public String getMethod() {
        return method;
    }

    /**
     * getProperties returns the Properties object that was produced in
     * parsing the URI's Query String.  Properties are passed into methods
     * that are associated with XMLObjects.  This method will return null if
     * no Properties were resolved.
     *
     * @return The Query String Properties
     */
    public Properties getProperties() {
        return params;
    }

    /**
     * getArguments returns method arguments in the form of a String array.
     * Method arguments are passed to a method in the order that they are
     * specified in the URI.  If no arguments were parsed, this method will
     * return null.
     *
     * @return The method arguments
     */
    public String[] getArguments() {
        return args;
    }
}
TOP

Related Classes of org.apache.xindice.core.request.URIMapper

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.