Package nexj.core.rpc.xml

Source Code of nexj.core.rpc.xml.WADLGenerator

// Copyright 2010 NexJ Systems Inc. This software is licensed under the terms of the Eclipse Public License 1.0
package nexj.core.rpc.xml;

import java.io.IOException;
import java.util.Iterator;
import java.util.Set;

import javax.xml.namespace.QName;

import nexj.core.meta.Argument;
import nexj.core.meta.Event;
import nexj.core.meta.Member;
import nexj.core.meta.Metaclass;
import nexj.core.meta.Primitive;
import nexj.core.meta.Selector;
import nexj.core.meta.Type;
import nexj.core.util.HashHolder;
import nexj.core.util.HashTab2D;
import nexj.core.util.Lookup2D;

/**
* Class to generate WADL API
*/
public class WADLGenerator extends XSDGenerator
{
   // constants

   protected final static XMLMetatype NIL_TYPE =
      new XMLMetatype(XML.getTNSType(XML.BASE_PREFIX + "Nil"));

   // associations

   /**
    * Cache of results from computeElementType.
    */
   protected Lookup2D/*<Type, Boolean, QName>*/ m_elementMap =
      new HashTab2D/*<Type, Boolean, QName>*/();

   /**
    * Set of types that require an array element defined,
    * as opposed to just the complexType requirements tracked via setRequiredType(...).
    */
   protected Set/*<Type>*/ m_requiredArrayTypeSet;

   // operations

   /**
    * @see nexj.core.rpc.xml.XSDGenerator#addEventDependencies(nexj.core.meta.Metaclass)
    */
   protected void addEventDependencies(Metaclass meta)
   {
      super.addEventDependencies(meta);

      // exported events require that all <element> types are defined, need to define "-array" types
      for (int i = 0, nCount = meta.getEventCount(); i < nCount; ++i)
      {
         Event event = meta.getEvent(i);

         if (isExportedEvent(event))
         {
            Argument result = event.getResult();

            // check if array <element> required for return type
            if (result != null && result.isCollection())
            {
               m_requiredArrayTypeSet.add(result.getType());
            }
         }
      }
   }

   /**
    * Compute the proper qualified element type to use for this type.
    * @param type The type to compute qualified element for (not null).
    * @param bArray This is a collection element.
    * @return The computed element type.
    */
   public static QName computeElementType(Type type, boolean bArray)
   {
      QName qType = XML.getQualifiedType(type, false);

      if (qType.getNamespaceURI() == XML.XSD_URI) // elements for XSD types are in TNS NS
      {
         return XML.getTNSType(XML.BASE_PREFIX + qType.getLocalPart(), bArray);
      }

      return (bArray) ? XML.getQualifiedType(type, bArray) : qType;
   }

   /**
    * @see nexj.core.rpc.xml.XSDGenerator#generate(java.lang.String)
    */
   protected void generate(String sURI) throws IOException
   {
      m_writer.openElement("application");
         m_writer.writeAttribute(XML.XML_NS, XML.NS_URI_WADL);
         m_writer.setNamespace(XML.XML_NS);
            m_writer.writeAttribute(XML.XSD_NS,  XML.XSD_URI);
            m_writer.writeAttribute(XML.NS_TAG_WADL, XML.NS_URI_WADL);
            m_writer.writeAttribute(XML.TNS_NS,  XML.NS_URI_TNS);
         m_writer.setNamespace(null);
         m_writer.writeAttribute("targetNamespace", XML.NS_URI_TNS);
      m_writer.closeElement();

         m_writer.startElement("grammars");

            m_writer.openElement("schema");
               m_writer.writeAttribute(XML.XML_NS, XML.XSD_URI);
               m_writer.writeAttribute("targetNamespace", XML.NS_URI_TNS);
               m_writer.writeAttribute("elementFormDefault", "qualified");
            m_writer.closeElement();

               writeTNSXSD();

               // add elements for all XSD types since that is how primitives will be marshalled
               for (int i = 0; i <= Primitive.MAX_COUNT; ++i)
               {
                  Primitive type = Primitive.get(i);
                  QName qType = getQualifiedTypeCached(type, false);

                  if (qType.getNamespaceURI() == XML.XSD_URI) // only consider XSD types
                  {
                     QName element = getElementTypeCached(type, false);

                     writeElement(element.getLocalPart(), null, null, qType);//marshalled non-arrays
                     qType = getQualifiedTypeCached(type, true);
                     element = getElementTypeCached(type, true);
                     writeElement(element.getLocalPart(), null, null, qType); // marshalled arrays
                  }
               }

               writeElement(
                  XML.BASE_PREFIX, "Exception", null, XML.TNS_NS, XML.BASE_PREFIX, "Exception");
               writeElement(
                  XML.BASE_PREFIX, "Request", null, XML.TNS_NS, XML.BASE_PREFIX, "Request");
               writeElement(
                  XML.BASE_PREFIX, "Response", null, XML.TNS_NS, XML.BASE_PREFIX, "Response");
               writeElement(
                  XML.BASE_PREFIX, "Collection", null, XML.TNS_NS, XML.BASE_PREFIX, "Collection");
               writeElement(XML.BASE_PREFIX, "Nil", null, NIL_TYPE.getType());

            m_writer.endElement("schema");
         m_writer.endElement("grammars");

         m_writer.openElement("resources");
            m_writer.writeAttribute("base", sURI);
         m_writer.closeElement();

            m_writer.openElement("resource");
               m_writer.writeAttribute("queryType", "text/xml");
            m_writer.closeElement();

               m_writer.openElement("param");
                  m_writer.writeAttribute("href", "#authorization");
               m_writer.closeEmptyElement();

               m_writer.openElement("method");
                  m_writer.writeAttribute("name", "GET");
               m_writer.closeElement();

                  m_writer.startElement("request");
                     writeParam("xsd", XML.getQualifiedType(Primitive.BOOLEAN));
                  m_writer.endElement("request");

                  m_writer.startElement("response");
                     m_writer.openElement("representation");
                        m_writer.writeAttribute("mediaType", "application/vnd.sun.wadl+xml");
                     m_writer.closeEmptyElement();
                  m_writer.endElement("response");

               m_writer.endElement("method");

               m_writer.openElement("method");
                  m_writer.writeAttribute("name", "POST");
               m_writer.closeElement();

                  m_writer.startElement("request");
                     writeRepresentation(XML.TNS_NS, XML.BASE_PREFIX, "Request", null, null);
                  m_writer.endElement("request");

                  m_writer.startElement("response");

                     writeRepresentation(XML.TNS_NS, XML.BASE_PREFIX, "Response", null, null);

                     m_writer.openElement("fault");
                     m_writer.writeAttribute("href", "#exception");
                  m_writer.closeEmptyElement();

                  m_writer.endElement("response");

               m_writer.endElement("method");

            m_writer.endElement("resource");

            // output metaclass specific resources here
            for (int i = 0; i < m_metaclassArray.length; ++i)
            {
               if (isExportedMetaclass(m_metaclassArray[i]))
               {
                  writeResource(m_metaclassArray[i]);
               }
            }

         m_writer.endElement("resources");

         // definitions referenced elsewhere in the document

         m_writer.openElement("param");
            m_writer.writeAttribute("id", "authorization");
            m_writer.writeAttribute("name", "Authorization");
            m_writer.writeAttribute("style", "header");
         m_writer.closeEmptyElement();

         m_writer.openElement("method");
            m_writer.writeAttribute("id", "read-request");
            m_writer.writeAttribute("name", "GET");
         m_writer.closeElement();

            m_writer.startElement("request");

               writeParam("attributes", null);
               writeParam("where", null);
               writeParam("orderBy", null);

               m_writer.openElement("param");
                  m_writer.writeAttribute("name", "count");
                  m_writer.writeAttribute("style", "query");
                  // @see http://www.w3.org/TR/xmlschema-2/ for list of built-in types
                  m_writer.writeAttribute("type", XML.XSD_NS, ":int");
                  m_writer.writeAttribute("default", "8");
               m_writer.closeEmptyElement();

               writeParam("offset", XML.getQualifiedType(Primitive.INTEGER));

            m_writer.endElement("request");

            m_writer.startElement("response");

               writeRepresentation(XML.TNS_NS, XML.BASE_PREFIX, "Collection", null, null);

               m_writer.openElement("fault");
                  m_writer.writeAttribute("href", "#exception");
               m_writer.closeEmptyElement();
            m_writer.endElement("response");

         m_writer.endElement("method");

         m_writer.openElement("fault");
            m_writer.writeAttribute("id", "exception");
            m_writer.writeAttribute("mediaType", "text/xml");
            m_writer.writeAttribute("element", XML.TNS_NS, ":", XML.BASE_PREFIX, "Exception");
            m_writer.writeAttribute("status", "500");
         m_writer.closeEmptyElement();

      m_writer.endElement("application");
   }

   /**
    * Provide caching for element types.
    * @see XML#getQualifiedType(nexj.core.meta.Type, boolean)
    */
   protected QName getElementTypeCached(Type type, boolean bArray)
   {
      assert type != null;

      QName qType = (QName)m_elementMap.get(type, Boolean.valueOf(bArray));

      if (qType == null)
      {
         qType = computeElementType(type, bArray);
         m_elementMap.put(type, Boolean.valueOf(bArray), qType);
      }

      return qType;
   }

   /**
    * @see nexj.core.rpc.xml.XSDGenerator#getMIMEType()
    */
   public String getMIMEType()
   {
      return "application/vnd.sun.wadl+xml; charset=UTF-8";
   }

   /**
    * @see nexj.core.rpc.xml.XSDGenerator#isExportedEvent(nexj.core.meta.Event)
    */
   protected boolean isExportedEvent(Event event)
   {
      return super.isExportedEvent(event) && event.getTransactionMode() != Event.TX_REQUIRED;
   }

   /**
    * Output WADL doc XML.
    * @param sCaption The parameter caption.
    * @param sDescription The parameter description.
    * @return If a doc element was output.
    * @throws IOException On IO error.
    */
   protected void writeDoc(String sCaption, String sDescription) throws IOException
   {
      m_writer.openElement("doc");
         m_writer.writeAttribute("xml:lang", "en");

         if (sCaption != null)
         {
            m_writer.writeAttribute("title", sCaption);
         }

      if (sDescription != null)
      {
         m_writer.closeElement();
            m_writer.writeValue(sDescription);
         m_writer.endElement("doc");
      }
      else
      {
         m_writer.closeEmptyElement();
      }
   }

   /**
    * Output event method declaration for a given event.
    * @param event The event to output (not null).
    * @param sName The event name to use, (null == XML.BASE_PREFIX + event.getName()).
    * @throws IOException On IO error.
    */
   protected void writeEventMethod(Event event, String sName) throws IOException
   {
      assert event != null;

      m_writer.openElement("method");

         if (sName != null)
         {
            m_writer.writeAttribute("name", sName);
         }
         else
         {
            m_writer.writeAttribute("name", XML.BASE_PREFIX, event.getName());
         }

      m_writer.closeElement();

         if (m_bIncludeDocumentation)
         {
            writeDoc(event.getName(), event.getDescription());
         }

         m_writer.startElement("request");

            for (int i = 0, nCount = event.getArgumentCount(); i < nCount; ++i)
            {
               Argument arg = event.getArgument(i);
               Type type = arg.getType();
               boolean bVarArg = event.isVarArg() && i == nCount - 1;

               if (type instanceof Metaclass)
               {
                  type = Primitive.STRING; // OID parameter
               }

               writeParam(arg.getName(), getQualifiedTypeCached(type, bVarArg),
                          arg.isRequired(), arg.isCollection(),
                          arg.getSymbol().getName(), arg.getDescription());
            }

         m_writer.endElement("request");

         m_writer.startElement("response");

            Argument result = event.getResult();

            if (result != null)
            {
               QName qType = getElementTypeCached(result.getType(), result.isCollection());

               writeRepresentation(qType.getPrefix(), qType.getLocalPart(), null,
                                   null, result.getDescription());
            }

            m_writer.openElement("fault");
               m_writer.writeAttribute("href", "#exception");
            m_writer.closeEmptyElement();

         m_writer.endElement("response");

      m_writer.endElement("method");
   }

   /**
    * Output event resource declaration for a given event.
    * @param meta The metaclass for which to output events (not null).
    * @param bStatic Output only static events (false == output only non-static events)
    * @throws IOException On IO error.
    */
   protected void writeEventResources(Metaclass meta, boolean bStatic) throws IOException
   {
      assert meta != null;

      for (Iterator/*<Selector>*/ selItr = meta.getSelectorIterator(); selItr.hasNext();)
      {
         boolean bStarted = false;
         Selector selector = (Selector)selItr.next();

         for (Iterator/*<Member>*/ memItr = selector.getMemberIterator(); memItr.hasNext();)
         {
            Member member = (Member)memItr.next();

            if (!(member instanceof Event) ||
                bStatic != member.isStatic() ||
                !isExportedEvent((Event)member))
            {
               continue;
            }

            if (!bStarted)
            {
               // add each event as a resource
               m_writer.openElement("resource");
                  m_writer.writeAttribute("path", member.getName());
                  m_writer.writeAttribute("queryType", "text/xml");
               m_writer.closeElement();

               m_writer.openElement("param");
                  m_writer.writeAttribute("href", "#authorization");
               m_writer.closeEmptyElement();

               bStarted = true;
            }

            writeEventMethod((Event)member, "POST");
         }

         if (bStarted)
         {
            m_writer.endElement("resource");
         }
      }
   }

   /**
    * @see nexj.core.rpc.xml.XSDGenerator#writeMetaclass(nexj.core.meta.Metaclass)
    */
   protected void writeMetaclass(Metaclass meta) throws IOException
   {
      // must execute what the parent's method too so that XSD is generated
      super.writeMetaclass(meta);

      if (meta.getVisibility() == Metaclass.PUBLIC)
      {
         writeElement(meta.getName(), null, null, XML.TNS_NS, meta.getName(), null);
      }

      // add an array element if one is required
      // Note: has to be element around array complex type or wadl2java has resolution issues
      if (m_requiredArrayTypeSet.contains(meta))
      {
         writeElement(getElementTypeCached(meta, true).getLocalPart(), null, null,
                      getQualifiedTypeCached(meta, true));
      }
   }

   /**
    * Convenience method for writeParam(...) with default values.
    * @see WADLGenerator#writeParam(String, QName, boolean, boolean, String, String)
    * @param bRequired == false
    * @param bCollection == false
    * @param sCaption == null
    * @param sDescription = null
    */
   protected void writeParam(String sName, QName type) throws IOException
   {
      writeParam(sName, type, false, false, null, null);
   }

   /**
    * Output WADL param XML for a type.
    * @param sName The parameter name (not null).
    * @param type The type of param.
    * @param bRequired Is this parameter required to be present.
    * @param bCollection Does this parameter represent a collection.
    * @param sCaption The parameter caption.
    * @param sDescription The parameter description.
    * @throws IOException On IO error.
    */
   protected void writeParam(String sName, QName type, boolean bRequired, boolean bCollection,
                             String sCaption, String sDescription) throws IOException
   {
      assert sName != null;

      m_writer.openElement("param");
         m_writer.writeAttribute("name", sName);
         m_writer.writeAttribute("style", "query");

         if (type != null)
         {
            m_writer.writeAttribute("type", type.getPrefix(), ":", type.getLocalPart());
         }

         if (bRequired) // ignore default value to minimize XML output
         {
            m_writer.writeAttribute("required", "true");
         }

         if (bCollection) // ignore default value to minimize XML output
         {
            m_writer.writeAttribute("repeating", "true");
         }

      if (m_bIncludeDocumentation && (sCaption != null || sDescription != null))
      {
         m_writer.closeElement();
            writeDoc(sCaption, sDescription);
         m_writer.endElement("param");
      }
      else
      {
         m_writer.closeEmptyElement();
      }
   }

   /**
    * Output WADL representation XML for a type.
    * @param sTypePrefix The element type namespace prefix (not null).
    * @param sType0 The first part of the element type (not null).
    * @param sType1 The second part of the element type, concatenated with first, (null == ignore)
    * @param sCaption The parameter caption.
    * @param sDescription The parameter description.
    * @throws IOException On IO error.
    */
   protected void writeRepresentation(
      String sTypePrefix, String sType0, String sType1,
      String sCaption, String sDescription)
      throws IOException
   {
      assert sTypePrefix != null;
      assert sType0 != null;

      m_writer.openElement("representation");
         m_writer.writeAttribute("mediaType", "text/xml");
         m_writer.writeAttribute("element", sTypePrefix, ":", sType0, sType1);

      if (m_bIncludeDocumentation && (sCaption != null || sDescription != null))
      {
         m_writer.closeElement();
            writeDoc(sCaption, sDescription);
         m_writer.endElement("representation");
      }
      else
      {
         m_writer.closeEmptyElement();
      }
   }

   /**
    * Output WADL resource XML for a metaclass.
    * @param metaclass The metaclass to process.
    * @throws IOException On IO error.
    */
   protected void writeResource(Metaclass metaclass) throws IOException
   {
      m_writer.openElement("resource");
         m_writer.writeAttribute("path", metaclass.getName());
         m_writer.writeAttribute("queryType", "text/xml");
      m_writer.closeElement();

         m_writer.openElement("param");
            m_writer.writeAttribute("href", "#authorization");
         m_writer.closeEmptyElement();

         m_writer.openElement("method");
            m_writer.writeAttribute("href", "#read-request");
         m_writer.closeEmptyElement();

         m_writer.openElement("method");
            m_writer.writeAttribute("name", "POST");
         m_writer.closeElement();

            m_writer.startElement("request");
               writeParam("attributes", null);
               writeRepresentation(XML.TNS_NS, metaclass.getName(), null, null, null);
            m_writer.endElement("request");

            m_writer.startElement("response");

               writeRepresentation(XML.TNS_NS, metaclass.getName(), null, null, null);
               writeRepresentation(XML.TNS_NS, XML.BASE_PREFIX, "Nil", null, null);

               m_writer.openElement("fault");
                  m_writer.writeAttribute("href", "#exception");
               m_writer.closeEmptyElement();
            m_writer.endElement("response");

         m_writer.endElement("method");

         // output static event method hooks
         for (int i = 0, nCount = metaclass.getEventCount(); i < nCount; ++i)
         {
            Event event = metaclass.getEvent(i);

            if (event.isStatic() && isExportedEvent(event))
            {
               writeEventMethod(event, null);
            }
         }

         writeEventResources(metaclass, true); // output static event resource hooks

         m_writer.openElement("resource");
            m_writer.writeAttribute("path", "{oid}");
            m_writer.writeAttribute("queryType", "text/xml");
         m_writer.closeElement();

            m_writer.openElement("param");
               m_writer.writeAttribute("href", "#authorization");
            m_writer.closeEmptyElement();

            m_writer.openElement("param");
               m_writer.writeAttribute("name", "oid");
               m_writer.writeAttribute("style", "template");
               m_writer.writeAttribute("type", XML.XSD_NS, ":hexBinary");
            m_writer.closeEmptyElement();

            m_writer.openElement("method");
               m_writer.writeAttribute("href", "#read-request");
            m_writer.closeEmptyElement();

            m_writer.openElement("method");
               m_writer.writeAttribute("name", "POST");
            m_writer.closeElement();

               m_writer.startElement("request");
                  writeParam("attributes", null);
                  writeRepresentation(XML.TNS_NS, metaclass.getName(), null, null, null);
               m_writer.endElement("request");

               m_writer.startElement("response");

                  writeRepresentation(XML.TNS_NS, metaclass.getName(), null, null, null);
                  writeRepresentation(XML.TNS_NS, XML.BASE_PREFIX, "Nil", null, null);

                  m_writer.openElement("fault");
                     m_writer.writeAttribute("href", "#exception");
                  m_writer.closeEmptyElement();
               m_writer.endElement("response");
            m_writer.endElement("method");

            m_writer.openElement("method");
               m_writer.writeAttribute("name", "PUT");
            m_writer.closeElement();

               m_writer.startElement("request");
                  writeParam("attributes", null);
                  writeRepresentation(XML.TNS_NS, metaclass.getName(), null, null, null);
               m_writer.endElement("request");

               m_writer.startElement("response");

                  writeRepresentation(XML.TNS_NS, metaclass.getName(), null, null, null);

                  m_writer.openElement("fault");
                     m_writer.writeAttribute("href", "#exception");
                  m_writer.closeEmptyElement();
               m_writer.endElement("response");

            m_writer.endElement("method");


            m_writer.openElement("method");
               m_writer.writeAttribute("name", "DELETE");
            m_writer.closeElement();

               m_writer.startElement("request");
               m_writer.endElement("request");

               m_writer.startElement("response");
                  m_writer.openElement("fault");
                     m_writer.writeAttribute("href", "#exception");
                  m_writer.closeEmptyElement();
               m_writer.endElement("response");

            m_writer.endElement("method");

            // output non-static event method hooks
            for (int i = 0, nCount = metaclass.getEventCount(); i < nCount; ++i)
            {
               Event event = metaclass.getEvent(i);

               if (!event.isStatic() && isExportedEvent(event))
               {
                  writeEventMethod(event, null);
               }
            }

            writeEventResources(metaclass, false); // output static event resource hooks

         m_writer.endElement("resource");

      m_writer.endElement("resource");
   }

   /**
    * Reset all member caches.
    * Any classes overriding this function will have to call this function as well
    * (i.e. their parent's function).
    */
   protected void reset()
   {
      super.reset();

      setRequiredType(NIL_TYPE); // add required static NIL type used by response representations
      m_requiredArrayTypeSet = new HashHolder/*<Metaclass>*/();
   }
}
TOP

Related Classes of nexj.core.rpc.xml.WADLGenerator

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.