Package nexj.core.meta.integration.format.xml

Source Code of nexj.core.meta.integration.format.xml.RootXMLMessagePartMapping

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

import java.net.URL;
import java.util.Iterator;
import java.util.Set;

import nexj.core.meta.MetadataException;
import nexj.core.meta.MetadataLookupException;
import nexj.core.meta.integration.CompositeMessagePartRef;
import nexj.core.meta.integration.Message;
import nexj.core.meta.integration.MessagePart;
import nexj.core.meta.integration.MessagePartMapping;
import nexj.core.rpc.xml.XML;
import nexj.core.util.HashTab;
import nexj.core.util.HashTab2D;
import nexj.core.util.IdentityHashHolder;
import nexj.core.util.LinkedHashTab;
import nexj.core.util.Lookup;
import nexj.core.util.Lookup2D;
import nexj.core.util.LookupDeque;

/**
* The XML message part mapping for the root message part.
* Contains the namespace definitions.
*/
public class RootXMLMessagePartMapping extends XMLMessagePartMapping
{
   // constants

   /**
    * The namespace URI representing no namespace.
    */
   protected final static String NO_NAMESPACE = "";

   /**
    * Plain XML message.
    */
   public final static byte ENVELOPE_NONE = 1;

   /**
    * SOAP 1.1 envelope.
    */
   public final static byte ENVELOPE_SOAP = 2;

   /**
    * SOAP 1.2 envelope.
    */
   public final static byte ENVELOPE_SOAP12 = 4;

   // attributes

   /**
    * The SOAP action.
    */
   protected String m_sAction;

   /**
    * The WSDL operation name.
    */
   protected String m_sOperation;

   /**
    * The XSD type name of this message's root element.
    */
   protected String m_sXSDType;

   /**
    * The envelope type, one of the ENVELOPE_* constants.
    */
   protected byte m_nEnvelope = ENVELOPE_NONE;

   // associations

   /**
    * The message of this part.
    */
   protected final Message m_message;

   /**
    * The namespace map: XMLNamespace[String].
    */
   protected Lookup m_namespaceMap = new HashTab(4);

   /**
    * The map of schema URLs to local URLs. When the schemas are being processed,
    * this map will be used to resolve any imported or included schemas to their
    * local URLs.
    */
   protected LookupDeque m_schemaResourceLookupDeque;

   /**
    * The envelope header part.
    */
   protected MessagePart m_headerPart;

   /**
    * xsdType to Message map. Populated only on the mapping on the root base message
    * in an inheritance hierarchy.
    */
   protected Lookup2D m_xsdTypeMessageMap;

   /**
    * Map of reserved namespace name to URI: String[String].
    */
   protected final static Lookup s_reservedNamespaceMap = new HashTab(7);

   static
   {
      s_reservedNamespaceMap.put(XML.NS_TAG_XML, XML.NS_URI_XML);
      s_reservedNamespaceMap.put(XMLNamespace.XSD_NAME, XMLNamespace.XSD);
      s_reservedNamespaceMap.put(XMLNamespace.XSI_NAME, XMLNamespace.XSI);
      s_reservedNamespaceMap.put(XMLNamespace.SOAP_NAME, XMLNamespace.SOAP);
      s_reservedNamespaceMap.put(XMLNamespace.SOAP12_NAME, XMLNamespace.SOAP12);
      s_reservedNamespaceMap.put(XMLNamespace.WSDL_NAME, XMLNamespace.WSDL);
      s_reservedNamespaceMap.put(XMLNamespace.WSDL_SOAP_NAME, XMLNamespace.WSDL_SOAP);
   }

   // constructors

   public RootXMLMessagePartMapping(Message root)
   {
      m_message = root;
   }
  
   // operations

   /**
    * Adds a namespace to the mapping or looks up an existing one.
    * @param sName The namespace name.
    * @param sURI The namespace URI.
    * @param sSchema The namespace schema document URL, if any.
    * @param bDeclaredByEnvelope True iff the namespace must be marked as being declared by the envelope.
    * @return The XML namespace.
    * @throws MetadataException if a namespace
    * with the same name but with different URL already exists.
    */
   public XMLNamespace addNamespace(String sName, String sURI, String sSchema, boolean bDeclaredByEnvelope)
   {
      verifyNotReadOnly();

      XMLNamespace namespace = (XMLNamespace)m_namespaceMap.get(sName);

      if (namespace != null)
      {
         String sNamespaceURI = namespace.getURI();

         if (sNamespaceURI == null && sURI != null)
         {
            namespace.setURI(sURI);
            namespace.setSchema(sSchema);
         }

         if (sNamespaceURI != null && sURI != null && !sNamespaceURI.equals(sURI))
         {
            throw new MetadataException("err.meta.integration.xml.namespaceDup",
               new Object[]{sName, getRootMessage().getRoot().getFullPath()});
         }

         if (bDeclaredByEnvelope)
         {
            namespace.setDeclaredByEnvelope(true);
         }

         return namespace;
      }

      String sReservedURI = (String)s_reservedNamespaceMap.get(sName);

      if (sURI != null)
      {
         if (sReservedURI != null && !sURI.equals(sReservedURI))
         {
            throw new MetadataException("err.meta.integration.xml.reservedNamespaceRedefinition",
               new Object[]{sName, getRootMessage().getRoot().getFullPath()});
         }
      }
      else
      {
         sURI = sReservedURI;
      }

      namespace = new XMLNamespace(sName, sURI, sSchema, bDeclaredByEnvelope);
      m_namespaceMap.put(sName, namespace);

      return namespace;
   }

   /**
    * Adds a new namespace to the mapping.
    * @param namespace The namespace to add.
    * @throws MetadataException if a namespace
    * with the same name already exists.
    */
   public void addNamespace(XMLNamespace namespace)
   {
      verifyNotReadOnly();

      Object oldNamespace = m_namespaceMap.put(namespace.getName(), namespace);

      if (oldNamespace != null)
      {
         if (namespace.isDeclaredByEnvelope())
         {
            ((XMLNamespace)oldNamespace).setDeclaredByEnvelope(true);
         }
        
         m_namespaceMap.put(namespace.getName(), oldNamespace);

         throw new MetadataException("err.meta.integration.xml.namespaceDup", new Object[]
         {
            namespace.getName(),
            getRootMessage().getRoot().getFullPath()
         });
      }
   }

   /**
    * Gets the URI of a reserved (well-known) namespace by name.
    * @param sName The namespace name.
    * @return The namespace URI.
    * @throws MetadataLookupException if the namespace does not exist.
    */
   public String getReservedNamespaceURI(String sName)
   {
      String sURI = (String)s_reservedNamespaceMap.get(sName);

      if (sURI != null)
      {
         return sURI;
      }

      throw new MetadataLookupException("err.meta.integration.xml.namespaceLookup", sName, getRootMessage());
   }

   /**
    * Gets a namespace by name.
    * @param sName The namespace name.
    * @return The namespace object.
    * @throws MetadataLookupException if the namespace does not exist.
    */
   public XMLNamespace getNamespace(String sName)
   {
      XMLNamespace namespace = findNamespace(sName);

      if (namespace != null)
      {
         return namespace;
      }

      throw new MetadataLookupException("err.meta.integration.xml.namespaceLookup", sName, getRootMessage());
   }

   /**
    * Gets a namespace by name.
    * @param sName The namespace name.
    * @return The namespace object; null if not found.
    */
   public XMLNamespace findNamespace(String sName)
   {
      return (XMLNamespace)m_namespaceMap.get(sName);
   }

   /**
    * @return The namespace count.
    */
   public int getNamespaceCount()
   {
      return m_namespaceMap.size();
   }

   /**
    * @return An iterator for the contained namespace objects.
    */
   public Iterator getNamespaceIterator()
   {
      return m_namespaceMap.valueIterator();
   }

   /**
    * Adds a mapping from a schema URL to a local URL. When a schema is imported or
    * included, this mapping will be used to take the schema from a local file. If
    * there is already a mapping for a given source URL, then it is not replaced.
    * @param sSourceURL The source URL to match.
    * @param destination The URL to the local file.
    */
   public void addSchemaResourceMapping(String sSourceURL, URL destination)
   {
      verifyNotReadOnly();

      if (m_schemaResourceLookupDeque == null)
      {
         m_schemaResourceLookupDeque = new LinkedHashTab();
      }

      Object oldDestination = m_schemaResourceLookupDeque.put(sSourceURL, destination);

      if (oldDestination != null)
      {
         m_schemaResourceLookupDeque.put(sSourceURL, oldDestination);
      }
   }

   /**
    * @return The map of schema URLs to local URLs.
    */
   public LookupDeque getSchemaResourceMap()
   {
      return m_schemaResourceLookupDeque;
   }

   /**
    * @return the root message
    */
   public Message getRootMessage()
   {
      return m_message;
   }

   /**
    * Sets the SOAP action.
    * @param sAction The SOAP action to set.
    */
   public void setAction(String sAction)
   {
      verifyNotReadOnly();
      m_sAction = sAction;
   }

   /**
    * @return The SOAP action.
    */
   public String getAction()
   {
      return m_sAction;
   }

   /**
    * Sets the WSDL operation name.
    * @param sOperation The WSDL operation name to set.
    */
   public void setOperation(String sOperation)
   {
      verifyNotReadOnly();
      m_sOperation = sOperation;
   }

   /**
    * @return The WSDL operation name; null if not set.
    */
   public String getOperation()
   {
      return m_sOperation;
   }

   /**
    * Sets the XSD type name of this message's root element.
    * @param sXSDType The XSD type name of the root element.
    */
   public void setXSDType(String sXSDType)
   {
      verifyNotReadOnly();
      m_sXSDType = sXSDType;
   }

   /**
    * Gets the XSD type name of this message's root element.
    * @return The XSD type name of the root element.
    */
   public String getXSDType()
   {
      return m_sXSDType;
   }

   /**
    * Adds a mapping for the type "sNamespaceURI:sXSDType" to message, on the
    * root of the message inheritance hierarchy.
    * @param sNamespaceURI The namespace of the type; null if none.
    * @param sXSDType The type name.
    * @param message The message.
    */
   public void addXSDTypeMessage(String sNamespaceURI, String sXSDType, Message message)
   {
      verifyNotReadOnly();
      assert message != null;

      if (sNamespaceURI == null)
      {
         sNamespaceURI = NO_NAMESPACE;
      }

      Message rootBaseMessage = m_message.getRootBaseMessage();
      RootXMLMessagePartMapping rsmMapping = (RootXMLMessagePartMapping)rootBaseMessage.getRoot().getMapping();

      if (rsmMapping.m_xsdTypeMessageMap == null)
      {
         rsmMapping.m_xsdTypeMessageMap = new HashTab2D();
      }

      Message oldMessage = (Message)rsmMapping.m_xsdTypeMessageMap.put(sNamespaceURI, sXSDType, message);

      if (oldMessage != null && message != oldMessage)
      {
         rsmMapping.m_xsdTypeMessageMap.put(sNamespaceURI, sXSDType, oldMessage);

         throw new MetadataException("err.meta.integration.xml.duplicateXSDTypeMapping", new Object[]
         {
            sNamespaceURI, sXSDType, message, oldMessage
         });
      }
   }

   /**
    * Looks in the root of the message inheritance hierarchy for the message that
    * represents the type "sNamespaceURI:sXSDType".
    * @param sNamespaceURI The namespace of the type; null if none.
    * @param sXSDType The type name.
    * @return The message; null if not found.
    */
   public Message getXSDTypeMessage(String sNamespaceURI, String sXSDType)
   {
      if (sNamespaceURI == null)
      {
         sNamespaceURI = NO_NAMESPACE;
      }

      Message rootBaseMessage = m_message.getRootBaseMessage();
      RootXMLMessagePartMapping rsmMapping = (RootXMLMessagePartMapping)rootBaseMessage.getRoot().getMapping();

      return (Message)rsmMapping.m_xsdTypeMessageMap.get(sNamespaceURI, sXSDType);
   }

   /**
    * Sets the envelope type, one of the ENVELOPE_* constants.
    * @param nEnvelope The envelope type, one of the ENVELOPE_* constants to set.
    */
   public void setEnvelope(byte nEnvelope)
   {
      verifyNotReadOnly();
      m_nEnvelope = nEnvelope;
     
      switch (m_nEnvelope)
      {
         case ENVELOPE_SOAP:
            addNamespace(XMLNamespace.SOAP_NAME, XMLNamespace.SOAP, null, true);
            addNamespace(XMLNamespace.XSI_NAME, XMLNamespace.XSI, null, true);
            break;

         case ENVELOPE_SOAP12:
            addNamespace(XMLNamespace.SOAP12_NAME, XMLNamespace.SOAP12, null, true);
            addNamespace(XMLNamespace.XSI_NAME, XMLNamespace.XSI, null, true);
            break;
      }
   }

   /**
    * @return The envelope type, one of the ENVELOPE_* constants.
    */
   public byte getEnvelope()
   {
      return m_nEnvelope;
   }

   /**
    * Gets the envelope header part.
    *
    * @return The envelope header part; null if no header specified.
    */
   public MessagePart getHeaderPart()
   {
      return m_headerPart;
   }

   /**
    * Sets the envelope header part.
    *
    * @param part The envelope header part to set; null for no header.
    */
   public void setHeaderPart(MessagePart part)
   {
      verifyNotReadOnly();
      m_headerPart = part;
   }
  
   /**
    * @see nexj.core.meta.integration.format.xml.XMLMessagePartMapping#finish(nexj.core.meta.integration.MessagePart)
    */
   public void finish(MessagePart part)
   {
      verifyNotReadOnly();

      Message baseMessage = m_message.getBaseMessage();

      for (Iterator itr = m_namespaceMap.valueIterator(); itr.hasNext(); )
      {
         XMLNamespace namespace = (XMLNamespace)itr.next();

         // Resolve namespaces with no URI.
         if (namespace.getURI() == null)
         {
            String sName = namespace.getName();
            XMLNamespace uriNamespace = null;

            if (baseMessage != null)
            {
               uriNamespace = ((RootXMLMessagePartMapping)baseMessage.getRoot().getMapping()).findNamespace(
                     sName);
            }

            if (uriNamespace == null)
            {
               throw new MetadataException("err.meta.integration.xml.missingURI",
                  new Object[]{part.getFullPath()});
            }

            namespace.setURI(uriNamespace.getURI());
            namespace.setSchema(uriNamespace.getSchema());
         }

         if (namespace.getSchema() != null)
         {
            addNamespace(XMLNamespace.XSI_NAME, XMLNamespace.XSI, null, false);

            break;
         }
      }

      // Propagate namespaces from this mapping to the base recursively
      propagateNamespaces();

      super.finish(part);

      if (m_sXSDType != null)
      {
         String sURI = (m_namespace == null) ? null : m_namespace.getURI();

         addXSDTypeMessage(sURI, m_sXSDType, m_message);
      }

      if (baseMessage != null)
      {
         RootXMLMessagePartMapping baseRootMapping = (RootXMLMessagePartMapping)baseMessage.getRoot().getMapping();

         if (baseRootMapping.m_schemaResourceLookupDeque != null)
         {
            if (m_schemaResourceLookupDeque == null)
            {
               m_schemaResourceLookupDeque = new LinkedHashTab();
            }

            for (Lookup.Iterator itr = baseRootMapping.m_schemaResourceLookupDeque.iterator(); itr.hasNext(); )
            {
               String sSrcURL = (String)itr.next();
               URL dst = (URL)itr.getValue();
               URL oldDst = (URL)m_schemaResourceLookupDeque.put(sSrcURL, dst);

               if (oldDst != null && !oldDst.equals(dst))
               {
                  throw new MetadataException("err.meta.integration.xml.schemaResourceMismatch",
                     new Object[]{sSrcURL, m_message.getName(), baseRootMapping.m_message.getName()});
               }
            }
         }
      }
   }

   /**
    * @see nexj.core.meta.integration.format.xml.XMLMessagePartMapping#refer(nexj.core.meta.integration.CompositeMessagePartRef)
    */
   public void refer(CompositeMessagePartRef ref)
   {
      super.refer(ref);

      // Handle message whose root is a reference to a message with a header
      if (ref.getRoot() == ref)
      {
         setHeaderPart(((RootXMLMessagePartMapping)ref.getRefPart().getMapping()).getHeaderPart());
      }
   }

   /**
    * @see nexj.core.meta.MetadataObject#clone()
    */
   public Object clone()
   {
      RootXMLMessagePartMapping copy = (RootXMLMessagePartMapping)super.clone();

      copy.m_headerPart = null;
      copy.m_namespaceMap = (Lookup)m_namespaceMap.clone();

      if (m_schemaResourceLookupDeque != null)
      {
         copy.m_schemaResourceLookupDeque = (LookupDeque)m_schemaResourceLookupDeque.clone();
      }

      return copy;
   }

   /**
    * Copies namespaces from base message to derived message.
    * @see nexj.core.meta.integration.format.xml.XMLMessagePartMapping#resolveInheritance(nexj.core.meta.integration.MessagePartMapping)
    */
   public void resolveInheritance(MessagePartMapping baseMapping)
   {
      super.resolveInheritance(baseMapping);

      Message baseMessage = m_message.getBaseMessage();

      if (baseMessage != null)
      {
         RootXMLMessagePartMapping baseRootMapping = (RootXMLMessagePartMapping)baseMessage.getRoot().getMapping();

         for (Iterator itr = baseRootMapping.getNamespaceIterator(); itr.hasNext(); )
         {
            XMLNamespace namespace = (XMLNamespace)itr.next();

            if (findNamespace(namespace.getName()) == null)
            {
               addNamespace(namespace);
            }
         }
      }
   }

   /**
    * Propagate namespaces from this root mapping to root mappings of bases, referrers to bases, bases of
    * referrers and so on.
    */
   protected void propagateNamespaces()
   {
      Message baseMessage = m_message.getBaseMessage();

      if (baseMessage != null && baseMessage.getDerivation() != Message.DERIVATION_FINAL)
      {
         Set visitedSet = new IdentityHashHolder();

         visitedSet.add(this);
         ((RootXMLMessagePartMapping)baseMessage.getRoot().getMapping()).addNamespaces(m_namespaceMap,
               visitedSet);
      }
   }

   /**
    * Recursive step of propagateNamespaces().
    * @param namespaceMap Namespaces to add.
    * @param visitedSet Set of visited root mappings.
    */
   protected void addNamespaces(Lookup namespaceMap, Set visitedSet)
   {
      if (!visitedSet.add(this))
      {
         return;
      }

      for (Iterator itr = namespaceMap.valueIterator(); itr.hasNext(); )
      {
         XMLNamespace namespace = (XMLNamespace)itr.next();

         addNamespace(namespace.getName(), namespace.getURI(), namespace.getSchema(),
               namespace.isDeclaredByEnvelope());
      }

      Message baseMessage = m_message.getBaseMessage();

      if (baseMessage != null && baseMessage.getDerivation() != Message.DERIVATION_FINAL)
      {
         ((RootXMLMessagePartMapping)baseMessage.getRoot().getMapping()).addNamespaces(namespaceMap,
               visitedSet);
      }

      for (Iterator itr = m_message.getReferrerListIterator(); itr.hasNext(); )
      {
         Message message = (Message)itr.next();

         ((RootXMLMessagePartMapping)message.getRoot().getMapping()).addNamespaces(namespaceMap, visitedSet);
      }
   }
}
TOP

Related Classes of nexj.core.meta.integration.format.xml.RootXMLMessagePartMapping

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.