Package org.restlet.ext.wadl

Source Code of org.restlet.ext.wadl.WadlRepresentation

/**
* Copyright 2005-2011 Noelios Technologies.
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 or EPL 1.0 (the
* "Licenses"). You can select the license that you prefer but you may not use
* this file except in compliance with one of these Licenses.
*
* You can obtain a copy of the LGPL 3.0 license at
* http://www.opensource.org/licenses/lgpl-3.0.html
*
* You can obtain a copy of the LGPL 2.1 license at
* http://www.opensource.org/licenses/lgpl-2.1.php
*
* You can obtain a copy of the CDDL 1.0 license at
* http://www.opensource.org/licenses/cddl1.php
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://www.noelios.com/products/restlet-engine
*
* Restlet is a registered trademark of Noelios Technologies.
*/

package org.restlet.ext.wadl;

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;

import org.restlet.Context;
import org.restlet.data.Language;
import org.restlet.data.MediaType;
import org.restlet.data.Method;
import org.restlet.data.Reference;
import org.restlet.data.Status;
import org.restlet.engine.Engine;
import org.restlet.ext.xml.DomRepresentation;
import org.restlet.ext.xml.SaxRepresentation;
import org.restlet.ext.xml.TransformRepresentation;
import org.restlet.ext.xml.XmlRepresentation;
import org.restlet.ext.xml.XmlWriter;
import org.restlet.representation.InputRepresentation;
import org.restlet.representation.Representation;
import org.w3c.dom.Attr;
import org.w3c.dom.CDATASection;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.ext.LexicalHandler;
import org.xml.sax.helpers.DefaultHandler;

/**
* Root of a WADL description document. For the {@link #getHtmlRepresentation()}
* method to work properly, you will certainly have to update your classpath
* with a recent version of <a href="http://xml.apache.org/xalan-j/"> Apache
* Xalan XSLT engine</a> (version 2.7.1 has been successfully tested). This is
* due to the <a href="http://github.com/mnot/wadl_stylesheets/">XSLT
* stylesheet</a> bundled which relies on EXSLT features.<br>
*
* @author Jerome Louvel
*/
public class WadlRepresentation extends SaxRepresentation {

    // -------------------
    // Content reader part
    // -------------------
    private static class ContentReader extends DefaultHandler implements
            LexicalHandler {
        public enum MixedContentState {
            CDATA, COMMENT, ELEMENT, ENTITY, NONE, TEXT
        }

        public enum State {
            APPLICATION, DOCUMENTATION, FAULT, GRAMMARS, INCLUDE, LINK, METHOD, NONE, OPTION, PARAMETER, REPRESENTATION, REQUEST, RESOURCE, RESOURCES, RESOURCETYPE, RESPONSE
        }

        /** The current parsed "application" tag. */
        private ApplicationInfo currentApplication;

        /** The current parsed "documentation" tag. */
        private DocumentationInfo currentDocumentation;

        /** The current parsed "grammars" tag. */
        private GrammarsInfo currentGrammars;

        /** The current parsed "include" tag. */
        private IncludeInfo currentInclude;

        /** The current parsed "link" tag. */
        private LinkInfo currentLink;

        /** The current parsed "method" tag. */
        private MethodInfo currentMethod;

        /** The current mixed content CDataSection. */
        private CDATASection currentMixedContentCDataSection;

        /** The current mixed content node. */
        private Node currentMixedContentNode;

        /** The current parsed "option" tag. */
        private OptionInfo currentOption;

        /** The current parsed "param" tag. */
        private ParameterInfo currentParameter;

        /** The current parsed "representation" tag. */
        private RepresentationInfo currentRepresentation;

        /** The current parsed "request" tag. */
        private RequestInfo currentRequest;

        /** The current parsed "resources" tag. */
        private ResourcesInfo currentResources;

        /** The list of the current parsed "resource" tags. */
        private final List<ResourceInfo> currentResourcesList;

        /** The current parsed "resource_type" tag. */
        private ResourceTypeInfo currentResourceType;

        /** The current parsed "response" tag. */
        private ResponseInfo currentResponse;

        /** The document used to create the mixed content. */
        private Document mixedContentDocument;

        /** The stack of mixed content parser states. */
        private final List<MixedContentState> mixedContentStates;

        /** The top node of mixed content nodes. */
        private Node mixedContentTopNode;

        /**
         * Map of namespaces used in the WADL document. The key is the URI of
         * the namespace and the value, the prefix.
         */
        private Map<String, String> namespaces;

        /** The stack of parser states. */
        private final List<State> states;

        /** The WadlRepresentation instance that represents the parsed document. */
        private final WadlRepresentation wadlRepresentation;

        /**
         * Constructor
         *
         * @param wadlRepresentation
         *            The WadlRepresentation instance that represents the parsed
         *            document.
         */
        public ContentReader(WadlRepresentation wadlRepresentation) {
            this.states = new ArrayList<State>();
            this.states.add(State.NONE);
            this.mixedContentStates = new ArrayList<MixedContentState>();
            this.mixedContentStates.add(MixedContentState.NONE);
            this.currentApplication = null;
            this.currentDocumentation = null;
            this.currentGrammars = null;
            this.currentInclude = null;
            this.currentLink = null;
            this.currentMethod = null;
            this.currentOption = null;
            this.currentParameter = null;
            this.currentRepresentation = null;
            this.currentRequest = null;
            this.currentResourcesList = new ArrayList<ResourceInfo>();
            this.currentResources = null;
            this.currentResourceType = null;
            this.currentResponse = null;

            try {
                this.mixedContentDocument = new DomRepresentation(
                        MediaType.TEXT_XML).getDocument();
            } catch (IOException e) {
            }

            this.currentMixedContentCDataSection = null;
            this.namespaces = new HashMap<String, String>();
            this.wadlRepresentation = wadlRepresentation;
        }

        /**
         * Receive notification of character data.
         *
         * @param ch
         *            The characters from the XML document.
         * @param start
         *            The start position in the array.
         * @param length
         *            The number of characters to read from the array.
         */
        @Override
        public void characters(char[] ch, int start, int length)
                throws SAXException {
            if (getState() == State.DOCUMENTATION) {
                if (getMixedContentState() == MixedContentState.CDATA) {
                    this.currentMixedContentCDataSection.appendData(new String(
                            ch, start, length));
                } else if (getMixedContentState() != MixedContentState.ENTITY) {
                    this.currentMixedContentNode
                            .appendChild(this.mixedContentDocument
                                    .createTextNode(new String(ch, start,
                                            length)));
                }
            }
        }

        /**
         * Receive notification of a comment section.
         *
         * @param ch
         *            The characters from the XML document.
         * @param start
         *            The start position in the array.
         * @param length
         *            The number of characters to read from the array.
         */
        public void comment(char[] ch, int start, int length)
                throws SAXException {
            if (getState() == State.DOCUMENTATION) {
                this.currentMixedContentNode
                        .appendChild(this.mixedContentDocument
                                .createComment(new String(ch, start, length)));
            }
        }

        /**
         * Receive notification of the end of a CDATA sectionn.
         */
        public void endCDATA() throws SAXException {
            if (getState() == State.DOCUMENTATION) {
                popMixedContentState();
            }
        }

        /**
         * Receive notification of the end of a document.
         */
        @Override
        public void endDocument() throws SAXException {
            popState();
            if (this.namespaces != null && !this.namespaces.isEmpty()
                    && this.currentApplication != null) {
                this.currentApplication.setNamespaces(namespaces);
            }
            this.wadlRepresentation.setApplication(this.currentApplication);
        }

        public void endDTD() throws SAXException {
        }

        /**
         * Receive notification of the end of an element.
         *
         * @param uri
         *            The Namespace URI, or the empty string if the element has
         *            no Namespace URI or if Namespace processing is not being
         *            performed.
         * @param localName
         *            The local name (without prefix), or the empty string if
         *            Namespace processing is not being performed.
         * @param qName
         *            The qualified XML name (with prefix), or the empty string
         *            if qualified names are not available.
         */
        @Override
        public void endElement(String uri, String localName, String qName)
                throws SAXException {
            if (uri.equalsIgnoreCase(APP_NAMESPACE)) {
                if (localName.equals("application")) {
                    popState();
                } else if (localName.equals("doc")) {
                    this.currentDocumentation
                            .setMixedContent(mixedContentTopNode);
                    popState();
                } else if (localName.equals("fault")) {
                    popState();
                } else if (localName.equals("grammars")) {
                    popState();
                } else if (localName.equals("include")) {
                    popState();
                } else if (localName.equals("link")) {
                    popState();
                } else if (localName.equals("method")) {
                    popState();
                } else if (localName.equals("option")) {
                    popState();
                } else if (localName.equals("param")) {
                    popState();
                } else if (localName.equals("representation")) {
                    popState();
                } else if (localName.equals("request")) {
                    popState();
                } else if (localName.equals("resource")) {
                    this.currentResourcesList.remove(0);
                    popState();
                } else if (localName.equals("resources")) {
                    popState();
                } else if (localName.equals("resource_type")) {
                    popState();
                } else if (localName.equals("response")) {
                    popState();
                }
            } else {
                if (getState() == State.DOCUMENTATION) {
                    popMixedContentState();
                    this.currentMixedContentNode = this.currentMixedContentNode
                            .getParentNode();
                }
            }
        }

        /**
         * Receive notification of the end of an entity section.
         *
         * @param name
         *            The name of the entity.
         */
        public void endEntity(String name) throws SAXException {
            popMixedContentState();
        }

        /**
         * Returns the current state when processing mixed content sections.
         *
         * @return The current state when processing mixed content sections.
         */
        private MixedContentState getMixedContentState() {
            final MixedContentState result = this.mixedContentStates.get(0);
            return result;
        }

        /**
         * Returns a parameterStyle value according to the given string or null.
         *
         * @param parameterStyle
         *            The given string.
         * @return The parameterStyle value that corresponds to the given style
         *         name, or null otherwise.
         */
        public ParameterStyle getParameterStyle(String parameterStyle) {
            ParameterStyle result = null;
            if ("header".equalsIgnoreCase(parameterStyle)) {
                result = ParameterStyle.HEADER;
            } else if ("matrix".equalsIgnoreCase(parameterStyle)) {
                result = ParameterStyle.MATRIX;
            } else if ("plain".equalsIgnoreCase(parameterStyle)) {
                result = ParameterStyle.PLAIN;
            } else if ("query".equalsIgnoreCase(parameterStyle)) {
                result = ParameterStyle.QUERY;
            } else if ("template".equalsIgnoreCase(parameterStyle)) {
                result = ParameterStyle.TEMPLATE;
            }

            return result;
        }

        /**
         * Returns the current state when processing the WADL document.
         *
         * @return the current state when processing the WADL document.
         */
        private State getState() {
            final State result = this.states.get(0);
            return result;
        }

        /**
         * Drops the current state from the stack and returns it. This state
         * becomes the former current state.
         *
         * @return the former current state.
         */
        private MixedContentState popMixedContentState() {
            return this.mixedContentStates.remove(0);
        }

        /**
         * Drops the current state from the stack and returns it. This state
         * becomes the former current state.
         *
         * @return the former current state.
         */
        private State popState() {
            return this.states.remove(0);
        }

        /**
         * Adds the given state.
         *
         * @param state
         *            The given state.
         */
        private void pushMixedContentState(MixedContentState state) {
            this.mixedContentStates.add(0, state);
        }

        /**
         * Adds the given state.
         *
         * @param state
         *            The given state.
         */
        private void pushState(State state) {
            this.states.add(0, state);
        }

        /**
         * Receive notification of the beginning of a CDATA section.
         */
        public void startCDATA() throws SAXException {
            if (getState() == State.DOCUMENTATION) {
                pushMixedContentState(MixedContentState.CDATA);
                this.currentMixedContentCDataSection = this.mixedContentDocument
                        .createCDATASection("");
                this.currentMixedContentNode
                        .appendChild(this.currentMixedContentCDataSection);
            }
        }

        /**
         * Receive notification of the beginning of a document.
         */
        @Override
        public void startDocument() throws SAXException {
        }

        public void startDTD(String name, String publicId, String systemId)
                throws SAXException {
        }

        /**
         * Receive notification of the beginning of an element.
         *
         * @param uri
         *            The Namespace URI, or the empty string if the element has
         *            no Namespace URI or if Namespace processing is not being
         *            performed.
         * @param localName
         *            The local name (without prefix), or the empty string if
         *            Namespace processing is not being performed.
         * @param qName
         *            The qualified name (with prefix), or the empty string if
         *            qualified names are not available.
         * @param attrs
         *            The attributes attached to the element. If there are no
         *            attributes, it shall be an empty Attributes object. The
         *            value of this object after startElement returns is
         *            undefined.
         */
        @Override
        public void startElement(String uri, String localName, String qName,
                Attributes attrs) throws SAXException {

            if (uri.equalsIgnoreCase(APP_NAMESPACE)) {
                if (localName.equals("application")) {
                    this.currentApplication = new ApplicationInfo();
                    pushState(State.APPLICATION);
                } else if (localName.equals("doc")) {
                    this.currentDocumentation = new DocumentationInfo();
                    this.mixedContentTopNode = this.mixedContentDocument
                            .createDocumentFragment();
                    this.currentMixedContentNode = mixedContentTopNode;
                    this.currentMixedContentCDataSection = null;

                    if (attrs.getIndex("xml:lang") != -1) {
                        this.currentDocumentation.setLanguage(Language
                                .valueOf(attrs.getValue("xml:lang")));
                    }
                    if (attrs.getIndex("lang") != -1) {
                        this.currentDocumentation.setLanguage(Language
                                .valueOf(attrs.getValue("lang")));
                    }
                    if (attrs.getIndex("title") != -1) {
                        this.currentDocumentation.setTitle(attrs
                                .getValue("title"));
                    }
                    if (getState() == State.APPLICATION) {
                        this.currentApplication.getDocumentations().add(
                                this.currentDocumentation);
                    } else if (getState() == State.GRAMMARS) {
                        this.currentGrammars.getDocumentations().add(
                                this.currentDocumentation);
                    } else if (getState() == State.INCLUDE) {
                        this.currentInclude.getDocumentations().add(
                                this.currentDocumentation);
                    } else if (getState() == State.LINK) {
                        this.currentLink.getDocumentations().add(
                                this.currentDocumentation);
                    } else if (getState() == State.METHOD) {
                        this.currentMethod.getDocumentations().add(
                                this.currentDocumentation);
                    } else if (getState() == State.OPTION) {
                        this.currentOption.getDocumentations().add(
                                this.currentDocumentation);
                    } else if (getState() == State.PARAMETER) {
                        this.currentParameter.getDocumentations().add(
                                this.currentDocumentation);
                    } else if (getState() == State.REPRESENTATION) {
                        this.currentRepresentation.getDocumentations().add(
                                this.currentDocumentation);
                    } else if (getState() == State.REQUEST) {
                        this.currentRequest.getDocumentations().add(
                                this.currentDocumentation);
                    } else if (getState() == State.RESOURCE) {
                        this.currentResourcesList.get(0).getDocumentations()
                                .add(this.currentDocumentation);
                    } else if (getState() == State.RESOURCES) {
                        this.currentResources.getDocumentations().add(
                                this.currentDocumentation);
                    } else if (getState() == State.RESOURCETYPE) {
                        this.currentResourceType.getDocumentations().add(
                                this.currentDocumentation);
                    } else if (getState() == State.RESPONSE) {
                        this.currentResponse.getDocumentations().add(
                                this.currentDocumentation);
                    }
                    pushState(State.DOCUMENTATION);
                } else if (localName.equals("grammars")) {
                    this.currentGrammars = new GrammarsInfo();
                    if (getState() == State.APPLICATION) {
                        this.currentApplication
                                .setGrammars(this.currentGrammars);
                    }
                    pushState(State.GRAMMARS);
                } else if (localName.equals("include")) {
                    this.currentInclude = new IncludeInfo();
                    if (attrs.getIndex("href") != -1) {
                        this.currentInclude.setTargetRef(new Reference(attrs
                                .getValue("href")));
                    }
                    if (getState() == State.GRAMMARS) {
                        this.currentGrammars.getIncludes().add(
                                this.currentInclude);
                    }
                    pushState(State.INCLUDE);
                } else if (localName.equals("link")) {
                    this.currentLink = new LinkInfo();
                    if (attrs.getIndex("rel") != -1) {
                        this.currentLink.setRelationship(attrs.getValue("rel"));
                    }
                    if (attrs.getIndex("rev") != -1) {
                        this.currentLink.setReverseRelationship(attrs
                                .getValue("rev"));
                    }
                    if (attrs.getIndex("resource_type") != -1) {
                        this.currentLink.setResourceType(new Reference(attrs
                                .getValue("resource_type")));
                    }

                    if (getState() == State.PARAMETER) {
                        this.currentParameter.setLink(this.currentLink);
                    }
                    pushState(State.LINK);
                } else if (localName.equals("method")) {
                    this.currentMethod = new MethodInfo();
                    if (attrs.getIndex("href") != -1) {
                        this.currentMethod.setTargetRef(new Reference(attrs
                                .getValue("href")));
                    }
                    if (attrs.getIndex("id") != -1) {
                        this.currentMethod.setIdentifier(attrs.getValue("id"));
                    }
                    if (attrs.getIndex("name") != -1) {
                        this.currentMethod.setName(Method.valueOf(attrs
                                .getValue("name")));
                    }

                    if (getState() == State.APPLICATION) {
                        this.currentApplication.getMethods().add(
                                this.currentMethod);
                    } else if (getState() == State.RESOURCE) {
                        this.currentResourcesList.get(0).getMethods().add(
                                this.currentMethod);
                    } else if (getState() == State.RESOURCETYPE) {
                        this.currentResourceType.getMethods().add(
                                this.currentMethod);
                    }
                    pushState(State.METHOD);
                } else if (localName.equals("option")) {
                    this.currentOption = new OptionInfo();
                    if (attrs.getIndex("value") != -1) {
                        this.currentOption.setValue(attrs.getValue("value"));
                    }
                    if (getState() == State.PARAMETER) {
                        this.currentParameter.getOptions().add(
                                this.currentOption);
                    }
                    pushState(State.OPTION);
                } else if (localName.equals("param")) {
                    this.currentParameter = new ParameterInfo();
                    if (attrs.getIndex("default") != -1) {
                        this.currentParameter.setDefaultValue(attrs
                                .getValue("default"));
                    }
                    if (attrs.getIndex("fixed") != -1) {
                        this.currentParameter.setFixed(attrs.getValue("fixed"));
                    }
                    if (attrs.getIndex("id") != -1) {
                        this.currentParameter.setIdentifier(attrs
                                .getValue("id"));
                    }
                    if (attrs.getIndex("path") != -1) {
                        this.currentParameter.setPath(attrs.getValue("path"));
                    }
                    if (attrs.getIndex("style") != -1) {
                        this.currentParameter.setStyle(getParameterStyle(attrs
                                .getValue("style")));
                    }
                    if (attrs.getIndex("name") != -1) {
                        this.currentParameter.setName(attrs.getValue("name"));
                    }
                    if (attrs.getIndex("type") != -1) {
                        this.currentParameter.setType(attrs.getValue("type"));
                    }
                    if (attrs.getIndex("repeating") != -1) {
                        this.currentParameter.setRepeating(Boolean
                                .parseBoolean(attrs.getValue("repeating")));
                    }
                    if (attrs.getIndex("required") != -1) {
                        this.currentParameter.setRequired(Boolean
                                .parseBoolean(attrs.getValue("required")));
                    }

                    if (getState() == State.REPRESENTATION) {
                        this.currentRepresentation.getParameters().add(
                                this.currentParameter);
                    } else if (getState() == State.REQUEST) {
                        this.currentRequest.getParameters().add(
                                this.currentParameter);
                    } else if (getState() == State.RESOURCE) {
                        this.currentResourcesList.get(0).getParameters().add(
                                this.currentParameter);
                    } else if (getState() == State.RESOURCETYPE) {
                        this.currentRequest.getParameters().add(
                                this.currentParameter);
                    } else if (getState() == State.RESPONSE) {
                        this.currentRequest.getParameters().add(
                                this.currentParameter);
                    }

                    pushState(State.PARAMETER);
                } else if (localName.equals("representation")) {
                    this.currentRepresentation = new RepresentationInfo();
                    if (attrs.getIndex("id") != -1) {
                        this.currentRepresentation.setIdentifier(attrs
                                .getValue("id"));
                    }
                    if (attrs.getIndex("mediaType") != -1) {
                        this.currentRepresentation.setMediaType(MediaType
                                .valueOf(attrs.getValue("mediaType")));
                    }
                    if (attrs.getIndex("element") != -1) {
                        this.currentRepresentation.setXmlElement(attrs
                                .getValue("element"));
                    }
                    if (attrs.getIndex("profile") != -1) {
                        final String[] profiles = attrs.getValue("profile")
                                .split(" ");
                        for (final String string : profiles) {
                            this.currentRepresentation.getProfiles().add(
                                    new Reference(string));
                        }
                    }

                    if (getState() == State.APPLICATION) {
                        this.currentApplication.getRepresentations().add(
                                this.currentRepresentation);
                    } else if (getState() == State.REQUEST) {
                        this.currentRequest.getRepresentations().add(
                                this.currentRepresentation);
                    } else if (getState() == State.RESPONSE) {
                        this.currentResponse.getRepresentations().add(
                                this.currentRepresentation);
                    }
                    pushState(State.REPRESENTATION);
                } else if (localName.equals("request")) {
                    this.currentRequest = new RequestInfo();
                    if (getState() == State.METHOD) {
                        this.currentMethod.setRequest(this.currentRequest);
                    }
                    pushState(State.REQUEST);
                } else if (localName.equals("resource")) {
                    final ResourceInfo resourceInfo = new ResourceInfo();
                    if (attrs.getIndex("id") != -1) {
                        resourceInfo.setIdentifier(attrs.getValue("id"));
                    }
                    if (attrs.getIndex("path") != -1) {
                        resourceInfo.setPath(attrs.getValue("path"));
                    }
                    if (attrs.getIndex("queryType") != -1) {
                        resourceInfo.setQueryType(MediaType.valueOf(attrs
                                .getValue("queryType")));
                    }
                    if (attrs.getIndex("type") != -1) {
                        final String[] type = attrs.getValue("type").split(" ");
                        for (final String string : type) {
                            resourceInfo.getType().add(new Reference(string));
                        }
                    }

                    if (getState() == State.RESOURCE) {
                        this.currentResourcesList.get(0).getChildResources()
                                .add(resourceInfo);
                    } else if (getState() == State.RESOURCES) {
                        this.currentResources.getResources().add(resourceInfo);
                    }

                    this.currentResourcesList.add(0, resourceInfo);
                    pushState(State.RESOURCE);
                } else if (localName.equals("resources")) {
                    this.currentResources = new ResourcesInfo();
                    if (attrs.getIndex("base") != -1) {
                        this.currentResources.setBaseRef(new Reference(attrs
                                .getValue("base")));
                    }
                    if (getState() == State.APPLICATION) {
                        this.currentApplication
                                .setResources(this.currentResources);
                    }
                    pushState(State.RESOURCES);
                } else if (localName.equals("resource_type")) {
                    this.currentResourceType = new ResourceTypeInfo();
                    if (attrs.getIndex("id") != -1) {
                        this.currentResourceType.setIdentifier(attrs
                                .getValue("id"));
                    }

                    if (getState() == State.APPLICATION) {
                        this.currentApplication.getResourceTypes().add(
                                this.currentResourceType);
                    }
                    pushState(State.RESOURCETYPE);
                } else if (localName.equals("response")) {
                    this.currentResponse = new ResponseInfo();
                    if (attrs.getIndex("status") != -1) {
                        final String[] statuses = attrs.getValue("status")
                                .split(" ");
                        for (final String string : statuses) {
                            this.currentResponse.getStatuses().add(
                                    Status.valueOf(Integer.parseInt(string)));
                        }
                    }

                    if (getState() == State.METHOD) {
                        this.currentMethod.getResponses().add(
                                this.currentResponse);
                    }
                    pushState(State.RESPONSE);
                }
            } else {
                if (getState() == State.DOCUMENTATION) {
                    // We are handling a new element
                    pushMixedContentState(MixedContentState.ELEMENT);
                    Node node = null;
                    if (("".equals(qName) || qName == null)) {
                        node = this.mixedContentDocument.createElementNS(uri,
                                localName);
                    } else {
                        node = this.mixedContentDocument.createElementNS(uri,
                                qName);
                    }

                    for (int i = 0; i < attrs.getLength(); i++) {
                        Attr attr = this.mixedContentDocument
                                .createAttributeNS(attrs.getURI(i), attrs
                                        .getLocalName(i));
                        attr.setNodeValue(attrs.getValue(i));
                        node.getAttributes().setNamedItemNS(attr);
                    }
                    // This element becomes the current one and is added to its
                    // parent.
                    this.currentMixedContentNode.appendChild(node);
                    this.currentMixedContentNode = node;
                }
            }
        }

        /**
         * Receive notification of the beginning of an entity.
         *
         * @param name
         *            The name of the entity.
         */
        public void startEntity(String name) throws SAXException {
            pushMixedContentState(MixedContentState.ENTITY);
            this.currentMixedContentNode.appendChild(mixedContentDocument
                    .createEntityReference(name));
        }

        /**
         * Receive notification of the beginning of a prefix-URI Namespace
         * mapping.
         *
         * @param name
         *            The name of the entity.
         */
        @Override
        public void startPrefixMapping(String arg0, String arg1)
                throws SAXException {
            this.namespaces.put(arg1, arg0);
        }
    }

    /** Web Application Description Language namespace. */
    public static final String APP_NAMESPACE = "http://wadl.dev.java.net/2009/02";

    /** The root element of the WADL document. */
    private ApplicationInfo application;

    /**
     * Constructor.
     */
    public WadlRepresentation() {
        super(MediaType.APPLICATION_WADL);
    }

    /**
     * Constructor.
     *
     * @param application
     *            The root element of the WADL document.
     */
    public WadlRepresentation(ApplicationInfo application) {
        super(MediaType.APPLICATION_WADL);
        this.application = application;
    }

    /**
     * Constructor.
     *
     * @param xmlRepresentation
     *            The XML WADL document.
     * @throws IOException
     */
    public WadlRepresentation(Representation xmlRepresentation)
            throws IOException {
        super(xmlRepresentation);
        setMediaType(MediaType.APPLICATION_WADL);

        // Parse the given document using SAX to produce an ApplicationInfo
        // instance.
        parse(new ContentReader(this));
    }

    /**
     * Constructor. The title of the resource, that is to say the title of its
     * first documentation tag is transfered to the title of the first
     * documentation tag of the main application tag.
     *
     * @param resource
     *            The root element of the WADL document.
     */
    public WadlRepresentation(ResourceInfo resource) {
        super(MediaType.APPLICATION_WADL);
        this.application = resource.createApplication();
    }

    @Override
    public Object evaluate(String expression,
            javax.xml.namespace.QName returnType) throws Exception {
        return null;
    }

    /**
     * Returns the root element of the WADL document.
     *
     * @return The root element of the WADL document.
     */
    public ApplicationInfo getApplication() {
        return this.application;
    }

    /**
     * Returns an HTML representation. Note that the internal XSLT stylesheet
     * used comes from <a href="http://www.mnot.net/webdesc/">Mark
     * Nottingham</a>. This stylesheet requires advanced XSLT features,
     * including EXSLT extensions. Usage of a recent version of Xalan-J is
     * suggested. It has been tested successfully with Xalan-J 2.7.1.
     *
     * @return An HTML representation.
     */
    public Representation getHtmlRepresentation() {
        Representation representation = null;
        URL wadl2htmlXsltUrl = Engine
                .getResource("org/restlet/ext/wadl/wadl2html.xslt");

        if (wadl2htmlXsltUrl != null) {
            try {
                InputRepresentation xslRep = new InputRepresentation(
                        wadl2htmlXsltUrl.openStream(),
                        MediaType.APPLICATION_W3C_XSLT);
                representation = new TransformRepresentation(Context
                        .getCurrent(), this, xslRep);
                representation.setMediaType(MediaType.TEXT_HTML);
            } catch (IOException e) {
                Context.getCurrent().getLogger().log(Level.WARNING,
                        "Unable to generate the WADL HTML representation", e);
            }
        }

        return representation;
    }

    @Override
    public javax.xml.transform.sax.SAXSource getSaxSource() throws IOException {
        return XmlRepresentation.getSaxSource(this);
    }

    /**
     * Sets the root element of the WADL document.
     *
     * @param application
     *            The root element of the WADL document.
     */
    public void setApplication(ApplicationInfo application) {
        this.application = application;
    }

    @Override
    public void write(XmlWriter writer) throws IOException {
        try {
            writer.forceNSDecl(APP_NAMESPACE, "");
            writer.setDataFormat(true);
            writer.setIndentStep(3);
            writer.processingInstruction("xml",
                    "version=\"1.0\" standalone=\"yes\"");
            writer.processingInstruction("xml-stylesheet",
                    "type=\"text/xsl\" href=\"wadl2html.xslt\"");
            this.application.writeElement(writer);
            writer.endDocument();
        } catch (SAXException e) {
            Context.getCurrentLogger().log(Level.SEVERE,
                    "Error when writing the WADL Representation.", e);
        }
    }
}
TOP

Related Classes of org.restlet.ext.wadl.WadlRepresentation

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.