Package org.jboss.xb.binding.sunday.unmarshalling

Source Code of org.jboss.xb.binding.sunday.unmarshalling.XsdBinder

/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.xb.binding.sunday.unmarshalling;

import java.util.LinkedList;
import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
import java.io.Reader;
import java.io.InputStream;
import javax.xml.namespace.QName;

import org.w3c.dom.bootstrap.DOMImplementationRegistry;

import org.jboss.logging.Logger;
import org.jboss.xb.binding.Constants;
import org.jboss.xb.binding.JBossXBRuntimeException;
import org.jboss.xb.binding.metadata.AddMethodMetaData;
import org.jboss.xb.binding.metadata.CharactersMetaData;
import org.jboss.xb.binding.metadata.ClassMetaData;
import org.jboss.xb.binding.metadata.MapEntryMetaData;
import org.jboss.xb.binding.metadata.PackageMetaData;
import org.jboss.xb.binding.metadata.PropertyMetaData;
import org.jboss.xb.binding.metadata.PutMethodMetaData;
import org.jboss.xb.binding.metadata.SchemaMetaData;
import org.jboss.xb.binding.metadata.ValueMetaData;
import org.jboss.xb.binding.metadata.XsdAnnotation;
import org.jboss.xb.binding.metadata.XsdAppInfo;
import org.jboss.xb.binding.sunday.unmarshalling.impl.runtime.RtAttributeHandler;
import org.apache.xerces.xs.XSModel;
import org.apache.xerces.xs.XSImplementation;
import org.apache.xerces.xs.XSLoader;
import org.apache.xerces.xs.XSNamedMap;
import org.apache.xerces.xs.XSConstants;
import org.apache.xerces.xs.XSElementDeclaration;
import org.apache.xerces.xs.XSTypeDefinition;
import org.apache.xerces.xs.XSSimpleTypeDefinition;
import org.apache.xerces.xs.XSComplexTypeDefinition;
import org.apache.xerces.xs.XSParticle;
import org.apache.xerces.xs.XSTerm;
import org.apache.xerces.xs.XSModelGroup;
import org.apache.xerces.xs.XSObjectList;
import org.apache.xerces.xs.XSModelGroupDefinition;
import org.apache.xerces.xs.XSAttributeDeclaration;
import org.apache.xerces.xs.XSAttributeUse;
import org.apache.xerces.xs.XSAnnotation;
import org.apache.xerces.xs.XSWildcard;

/**
* @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
* @version <tt>$Revision: 1455 $</tt>
*/
public class XsdBinder
{
   private static final Logger log = Logger.getLogger(XsdBinder.class);

   private static final ThreadLocal xsdBinding = new ThreadLocal()
   {
      protected Object initialValue()
      {
         return new XsdBinding();
      }
   };

   private static XsdBinding getXsdBinding()
   {
      return (XsdBinding)xsdBinding.get();
   }

   private XsdBinder()
   {
   }

   /**
    * Create a SchemaBinding from and xsd url/uri.
    * @param xsdUrl
    * @return SchemaBinding mapping
    */
   public static final SchemaBinding bind(String xsdUrl)
   {
      XSModel model = loadSchema(xsdUrl);
      return bind(model, xsdUrl);
   }

   /**
    * Create a SchemaBinding from and xsd stream.
    * @param xsdStream - the xsd InputStream
    * @param encoding - optional stream encoding
    * @return SchemaBinding mapping
    */
   public static final SchemaBinding bind(InputStream xsdStream, String encoding, String baseURI)
   {
      XSModel model = loadSchema(xsdStream, encoding, baseURI);
      return bind(model, baseURI);
   }

   /**
    * Create a SchemaBinding from and xsd reader.
    * @param xsdReader - xsd reader
    * @param encoding - optional reader encoding
    * @return SchemaBinding mapping
    */
   public static final SchemaBinding bind(Reader xsdReader, String encoding, String baseURI)
   {
      XSModel model = loadSchema(xsdReader, encoding, baseURI);
      return bind(model, baseURI);
   }

   /**
    * Create a SchemaBinding from and xsd string.
    * @param xsd - xsd string
    * @param encoding - optional string encoding
    * @return SchemaBinding mapping
    */
   public static final SchemaBinding bind(String xsd, String encoding)
   {
      XSModel model = loadSchema(xsd, encoding);
      return bind(model);
   }

   public static final SchemaBinding bind(XSModel model)
   {
      return bind(model, null);
   }

   public static final SchemaBinding bind(XSModel model, String baseURI)
   {
      DefaultSchemaResolver resolver = new DefaultSchemaResolver();
      resolver.setBaseURI(baseURI);
      SchemaBinding schema = getXsdBinding().schemaBinding;
      schema.setSchemaResolver(resolver);

      // read annotations. for now just log the ones that are going to be used
      XSObjectList annotations = model.getAnnotations();
      for(int i = 0; i < annotations.getLength(); ++i)
      {
         XSAnnotation annotation = (XSAnnotation)annotations.item(i);
         XsdAnnotation an = XsdAnnotation.unmarshal(annotation.getAnnotationString());
         XsdAppInfo appinfo = an.getAppInfo();
         if(appinfo != null)
         {
            SchemaMetaData schemaBindings = appinfo.getSchemaMetaData();
            if(schemaBindings != null)
            {
               // Get the ignoreUnresolvedFieldOrClass
               schema.setIgnoreUnresolvedFieldOrClass(schemaBindings.isIgnoreUnresolvedFieldOrClass());
               // Get the ignoreUnresolvedFieldOrClass
               schema.setReplacePropertyRefs(schemaBindings.isReplacePropertyRefs());
               // Get the default package
               PackageMetaData packageMetaData = schemaBindings.getPackage();
               if(packageMetaData != null)
               {
                  if(log.isTraceEnabled())
                  {
                     log.trace("schema default package: " + packageMetaData.getName());
                  }
                  schema.setPackageMetaData(packageMetaData);
               }
            }
         }
      }

      /*
      XSTypeDefinition anyType = model.getTypeDefinition(Constants.QNAME_ANYTYPE.getLocalPart(),
         Constants.QNAME_ANYTYPE.getNamespaceURI()
      );
      if(anyType == null)
      {
         throw new JBossXBRuntimeException("Unable to get a refence to " + Constants.QNAME_ANYTYPE);
      }
      */

      SharedElements sharedElements = new SharedElements();
      // this is just caching of the reference to easier compare types at runtime
      //sharedElements.anyType = anyType;

      XSNamedMap groups = model.getComponents(XSConstants.MODEL_GROUP_DEFINITION);
      for(int i = 0; i < groups.getLength(); ++i)
      {
         XSModelGroupDefinition groupDef = (XSModelGroupDefinition)groups.item(i);
         XSModelGroup group = groupDef.getModelGroup();
         XSObjectList particles = group.getParticles();
         for(int j = 0; j < particles.getLength(); ++j)
         {
            XSParticle particle = (XSParticle)particles.item(j);
            XSTerm term = particle.getTerm();
            switch(term.getType())
            {
               case XSConstants.ELEMENT_DECLARATION:
                  XSElementDeclaration element = ((XSElementDeclaration)term);
                  sharedElements.add(element);
                  break;
               case XSConstants.WILDCARD:
                  break;
               case XSConstants.MODEL_GROUP:
               default:
                  throw new JBossXBRuntimeException(
                     "For now we don't support anything but elements in global model groups"
                  );
            }

         }
      }

      XSNamedMap types = model.getComponents(XSConstants.TYPE_DEFINITION);
      for(int i = 0; i < types.getLength(); ++i)
      {
         XSTypeDefinition type = (XSTypeDefinition)types.item(i);
         if(!Constants.NS_XML_SCHEMA.equals(type.getNamespace()))
         {
            bindType(schema, type, sharedElements);
         }
      }

      XSNamedMap elements = model.getComponents(XSConstants.ELEMENT_DECLARATION);
      for(int i = 0; i < elements.getLength(); ++i)
      {
         XSElementDeclaration element = (XSElementDeclaration)elements.item(i);
         bindElement(schema, element, sharedElements, false);
      }

      return schema;
   }

   private static final TypeBinding bindType(SchemaBinding doc,
                                             XSTypeDefinition type,
                                             SharedElements sharedElements)
   {
      TypeBinding binding;
      switch(type.getTypeCategory())
      {
         case XSTypeDefinition.SIMPLE_TYPE:
            binding = bindSimpleType(doc, (XSSimpleTypeDefinition)type);
            break;
         case XSTypeDefinition.COMPLEX_TYPE:
            binding = bindComplexType(doc, (XSComplexTypeDefinition)type, sharedElements);
            break;
         default:
            throw new JBossXBRuntimeException("Unexpected type category: " + type.getTypeCategory());
      }
      return binding;
   }

   private static final TypeBinding bindSimpleType(SchemaBinding doc, XSSimpleTypeDefinition type)
   {
      QName typeName = type.getName() == null ? null : new QName(type.getNamespace(), type.getName());
      TypeBinding binding = typeName == null ? null : doc.getType(typeName);
      if(binding == null)
      {
         XSTypeDefinition baseTypeDef = type.getBaseType();
         TypeBinding baseType = baseTypeDef == null ? null : bindType(doc, baseTypeDef, null);

         binding = baseType == null ? new TypeBinding(typeName) : new TypeBinding(typeName, baseType);

         if(typeName != null)
         {
            doc.addType(binding);
         }

         if(log.isTraceEnabled())
         {
            String msg = typeName == null ? "simple anonymous type" : "simple type " + typeName;
            if(baseType != null)
            {
               msg += " inherited binding metadata from " + baseType.getQName();
            }
            log.trace(msg);
         }

         // customize binding with annotations
         XSObjectList annotations = type.getAnnotations();
         if(annotations != null)
         {
            for(int i = 0; i < annotations.getLength(); ++i)
            {
               XSAnnotation an = (XSAnnotation)annotations.item(i);
               XsdAnnotation xsdAn = XsdAnnotation.unmarshal(an.getAnnotationString());
               XsdAppInfo appInfo = xsdAn.getAppInfo();
               if(appInfo != null)
               {
                  ClassMetaData classMetaData = appInfo.getClassMetaData();
                  if(classMetaData != null)
                  {
                     if(log.isTraceEnabled())
                     {
                        log.trace("simple type " +
                           type.getName() +
                           ": impl=" +
                           classMetaData.getImpl()
                        );
                     }
                     binding.setClassMetaData(classMetaData);
                  }

                  ValueMetaData valueMetaData = appInfo.getValueMetaData();
                  if(valueMetaData != null)
                  {
                     if(log.isTraceEnabled())
                     {
                        log.trace("simple type " +
                           type.getName() +
                           ": unmarshalMethod=" +
                           valueMetaData.getUnmarshalMethod() +
                           ", marshalMethod=" +
                           valueMetaData.getMarshalMethod()
                        );
                     }
                     binding.setValueMetaData(valueMetaData);
                  }
               }
            }
         }

         binding.setSchemaBinding(doc);
      }
      return binding;
   }

   private static final TypeBinding bindComplexType(SchemaBinding doc,
                                                    XSComplexTypeDefinition type,
                                                    SharedElements sharedElements)
   {
      QName typeName = type.getName() == null ? null : new QName(type.getNamespace(), type.getName());
      TypeBinding binding = typeName == null ? null : doc.getType(typeName);
      if(binding == null)
      {
         //XSTypeDefinition baseTypeDef = type.getBaseType();
         // anyType is the parent of all the types, even the parent of itself according to xerces :)
         TypeBinding baseType = null; /* todo: review binding inheritance for complex types
         (baseTypeDef == sharedElements.anyType ?
            null :
            bindType(doc, baseTypeDef, sharedElements));*/
         binding = (baseType == null ? new TypeBinding(typeName) : new TypeBinding(typeName, baseType));

         if(typeName != null)
         {
            doc.addType(binding);
         }

         if(log.isTraceEnabled())
         {
            String msg = typeName == null ? "complex anonymous type" : "complex type " + typeName;
            if(baseType != null)
            {
               msg += " inherited binding metadata from " + baseType.getQName();
            }
            log.trace(msg);
         }

         binding.setSchemaBinding(doc);

         XSObjectList attrs = type.getAttributeUses();
         for(int i = 0; i < attrs.getLength(); ++i)
         {
            XSAttributeUse attr = (XSAttributeUse)attrs.item(i);
            bindAttributes(doc, binding, attr);
         }

         // customize binding with xsd annotations
         XSObjectList annotations = type.getAnnotations();
         if(annotations != null)
         {
            for(int i = 0; i < annotations.getLength(); ++i)
            {
               XSAnnotation an = (XSAnnotation)annotations.item(i);
               XsdAnnotation xsdAn = XsdAnnotation.unmarshal(an.getAnnotationString());
               XsdAppInfo appInfo = xsdAn.getAppInfo();
               if(appInfo != null)
               {
                  ClassMetaData classMetaData = appInfo.getClassMetaData();
                  if(classMetaData != null)
                  {
                     if(log.isTraceEnabled())
                     {
                        log.trace("complex type " +
                           type.getName() +
                           ": impl=" +
                           classMetaData.getImpl()
                        );
                     }
                     binding.setClassMetaData(classMetaData);
                  }

                  CharactersMetaData charactersMetaData = appInfo.getCharactersMetaData();
                  if(charactersMetaData != null)
                  {
                     if(log.isTraceEnabled())
                     {
                        PropertyMetaData propertyMetaData = charactersMetaData.getProperty();
                        if(propertyMetaData != null)
                        {
                           log.trace("complex type " +
                              type.getName() +
                              ": characters bound to " + propertyMetaData.getName()
                           );
                        }

                        ValueMetaData valueMetaData = charactersMetaData.getValue();
                        if(valueMetaData != null)
                        {
                           log.trace("complex type " +
                              type.getName() +
                              ": characters unmarshalMethod=" +
                              valueMetaData.getUnmarshalMethod() +
                              ", marshalMethod=" + valueMetaData.getMarshalMethod()
                           );
                        }

                        boolean mapEntryKey = appInfo.isMapEntryKey();
                        if(mapEntryKey)
                        {
                           log.trace("complex type " +
                              type.getName() +
                              ": characters are bound as a key in a map entry"
                           );
                        }

                        boolean mapEntryValue = appInfo.isMapEntryValue();
                        if(mapEntryValue)
                        {
                           log.trace("complex type " +
                              type.getName() +
                              ": characters are bound as a value in a map entry"
                           );
                        }
                     }
                     binding.setCharactersMetaData(charactersMetaData);
                  }

                  MapEntryMetaData mapEntryMetaData = appInfo.getMapEntryMetaData();
                  if(mapEntryMetaData != null)
                  {
                     if(log.isTraceEnabled())
                     {
                        log.trace("complex type " +
                           type.getName() +
                           " is bound to a map entry: impl=" +
                           mapEntryMetaData.getImpl() +
                           ", getKeyMethod=" +
                           mapEntryMetaData.getGetKeyMethod() +
                           ", setKeyMethod=" +
                           mapEntryMetaData.getSetKeyMethod() +
                           ", getValueMethod=" +
                           mapEntryMetaData.getGetValueMethod() +
                           ", setValueMethod=" +
                           mapEntryMetaData.getSetValueMethod() +
                           ", valueType=" +
                           mapEntryMetaData.getValueType() +
                           ", nonNullValue=" + mapEntryMetaData.isNonNullValue()
                        );
                     }

                     if(classMetaData != null)
                     {
                        throw new JBossXBRuntimeException("Illegal binding: both jbxb:class and jbxb:mapEntry are specified for complex type " +
                           type.getName()
                        );
                     }
                     binding.setMapEntryMetaData(mapEntryMetaData);
                  }

                  boolean skip = appInfo.isSkip();
                  if(skip)
                  {
                     if(log.isTraceEnabled())
                     {
                        log.trace("complex type " +
                           type.getName() +
                           ": elements of this type will be skipped; their attrs, character content " +
                           "and elements will be set the parent."
                        );
                     }
                     binding.setSkip(skip);
                  }

                  PropertyMetaData propertyMetaData = appInfo.getPropertyMetaData();
                  if(propertyMetaData != null)
                  {
                     if(log.isTraceEnabled())
                     {
                        log.trace("complex type " +
                           type.getName() +
                           ": the content of elements of this type is bound to property " + propertyMetaData.getName()
                        );
                     }
                     binding.setPropertyMetaData(propertyMetaData);
                  }

                  AddMethodMetaData addMethodMetaData = appInfo.getAddMethodMetaData();
                  if(addMethodMetaData != null)
                  {
                     if(log.isTraceEnabled())
                     {
                        log.trace("complex type " + type.getName() +
                           ": elements of this type will be added to parent objects with addMethod=" +
                           addMethodMetaData.getMethodName() + ", valueType=" + addMethodMetaData.getValueType());
                     }
                     binding.setAddMethodMetaData(addMethodMetaData);
                  }
               }
            }
         }

         XSParticle particle = type.getParticle();
         if(particle != null)
         {
            pushType(binding);
            bindParticle(doc, particle, sharedElements);
            popType();
         }
      }
      return binding;
   }

   private static void bindAttributes(SchemaBinding doc,
                                      TypeBinding type,
                                      XSAttributeUse attrUse)
   {
      XSAttributeDeclaration attr = attrUse.getAttrDeclaration();
      XSSimpleTypeDefinition attrType = attr.getTypeDefinition();
      TypeBinding typeBinding = bindSimpleType(doc, attrType);
      QName attrName = new QName(attr.getNamespace(), attr.getName());
      AttributeBinding binding = type.addAttribute(attrName, typeBinding, RtAttributeHandler.INSTANCE);
      if( attrUse.getConstraintType() == XSConstants.VC_DEFAULT )
      {
         // Associate the default value with the binding
         binding.setDefaultConstraint(attrUse.getConstraintValue());
      }

      XSAnnotation an = attr.getAnnotation();
      if(an != null)
      {
         XsdAnnotation xsdAn = XsdAnnotation.unmarshal(an.getAnnotationString());
         XsdAppInfo appInfo = xsdAn.getAppInfo();
         if(appInfo != null)
         {
            PropertyMetaData propertyMetaData = appInfo.getPropertyMetaData();
            if(propertyMetaData != null)
            {
               binding.setPropertyMetaData(propertyMetaData);
            }

            boolean mapEntryKey = appInfo.isMapEntryKey();
            if(mapEntryKey)
            {
               binding.setMapEntryKey(mapEntryKey);
            }

            boolean mapEntryValue = appInfo.isMapEntryValue();
            if(mapEntryValue)
            {
               binding.setMapEntryValue(mapEntryValue);
            }
         }
      }

      if(log.isTraceEnabled())
      {
         String msg = "attribute " +
            new QName(attr.getNamespace(), attr.getName()) +
            ": ";

         if(binding.getPropertyMetaData() != null)
         {
            msg += " property=" +
               binding.getPropertyMetaData().getName() +
               ", collectionType=" + binding.getPropertyMetaData().getCollectionType();
         }
         else if(binding.isMapEntryKey())
         {
            msg += "bound as a key in a map entry";
         }
         else if(binding.isMapEntryValue())
         {
            msg += "bound as a value in a map entry";
         }
         else
         {
            msg += " type=" + attrType.getName() + ", owner type=" + type.getQName();
         }

         if(binding.getDefaultConstraint() != null)
         {
            msg += ", default=" + binding.getDefaultConstraint();
         }

         log.trace(msg);
      }
   }

   private static void bindParticle(SchemaBinding schema, XSParticle particle, SharedElements sharedElements)
   {
      XSTerm term = particle.getTerm();
      switch(term.getType())
      {
         case XSConstants.MODEL_GROUP:
            bindModelGroup(schema, (XSModelGroup)term, sharedElements);
            break;
         case XSConstants.WILDCARD:
            bindWildcard(schema, (XSWildcard)term);
            break;
         case XSConstants.ELEMENT_DECLARATION:
            bindElement(schema,
               (XSElementDeclaration)term,
               sharedElements,
               particle.getMaxOccursUnbounded() || particle.getMaxOccurs() > 1
            );
            break;
         default:
            throw new IllegalStateException("Unexpected term type: " + term.getType());
      }
   }

   private static void bindWildcard(SchemaBinding schema, XSWildcard wildcard)
   {
      TypeBinding typeBinding = peekType();

      XSAnnotation annotation = wildcard.getAnnotation();
      if(annotation != null)
      {
         XsdAnnotation xsdAn = XsdAnnotation.unmarshal(annotation.getAnnotationString());
         XsdAppInfo appInfo = xsdAn.getAppInfo();
         if(appInfo != null)
         {
            PropertyMetaData propertyMetaData = appInfo.getPropertyMetaData();
            if(propertyMetaData != null)
            {
               if(log.isTraceEnabled())
               {
                  log.trace("wildcard is bound to property: " + propertyMetaData.getName() +
                     ", collectionType=" + propertyMetaData.getCollectionType());
               }
            }
            typeBinding.setWildcardPropertyMetaData(propertyMetaData);
         }
      }
   }

   private static void bindElement(SchemaBinding doc,
                                   XSElementDeclaration element,
                                   SharedElements sharedElements,
                                   boolean multiOccurs)
   {
      QName qName = new QName(element.getNamespace(), element.getName());

      TypeBinding parentType = peekType();
      ElementBinding binding = parentType == null ? null : parentType.getLocalElement(qName);

      if(binding == null)
      {
         TypeBinding type = null;

         boolean shared = sharedElements.isShared(element);
         if(shared)
         {
            type = sharedElements.getTypeBinding(element);
         }

         if(type == null)
         {
            type = bindType(doc, element.getTypeDefinition(), sharedElements);
            if(shared)
            {
               sharedElements.setTypeBinding(element, type);
            }
         }

         boolean global = element.getScope() == XSConstants.SCOPE_GLOBAL;
         if(global)
         {
            binding = doc.getElement(qName);
         }

         if(binding == null)
         {
            binding = new ElementBinding(doc, type);
            binding.setMultiOccurs(multiOccurs);
            if(global)
            {
               doc.addElement(qName, binding);
            }

            // customize binding with annotations
            XSAnnotation an = element.getAnnotation();
            if(an != null)
            {
               XsdAnnotation xsdAn = XsdAnnotation.unmarshal(an.getAnnotationString());
               XsdAppInfo appInfo = xsdAn.getAppInfo();
               if(appInfo != null)
               {
                  ClassMetaData classMetaData = appInfo.getClassMetaData();
                  if(classMetaData != null)
                  {
                     log.trace("element: name=" +
                        new QName(element.getNamespace(), element.getName()) +
                        ", class=" +
                        classMetaData.getImpl()
                     );
                     binding.setClassMetaData(classMetaData);
                  }

                  PropertyMetaData propertyMetaData = appInfo.getPropertyMetaData();
                  if(propertyMetaData != null)
                  {
                     if(log.isTraceEnabled())
                     {
                        log.trace("element: name=" +
                           new QName(element.getNamespace(), element.getName()) +
                           ", property=" +
                           propertyMetaData.getName() +
                           ", collectionType=" + propertyMetaData.getCollectionType()
                        );
                     }
                     binding.setPropertyMetaData(propertyMetaData);
                  }

                  MapEntryMetaData mapEntryMetaData = appInfo.getMapEntryMetaData();
                  if(mapEntryMetaData != null)
                  {
                     if(propertyMetaData != null)
                     {
                        throw new JBossXBRuntimeException("An element can be bound either as a property or as a map" +
                           " entry but not both: " +
                           new QName(element.getNamespace(), element.getName())
                        );
                     }

                     if(log.isTraceEnabled())
                     {
                        log.trace("element name=" +
                           new QName(element.getNamespace(), element.getName()) +
                           " is bound to a map entry: impl=" +
                           mapEntryMetaData.getImpl() +
                           ", getKeyMethod=" +
                           mapEntryMetaData.getGetKeyMethod() +
                           ", setKeyMethod=" +
                           mapEntryMetaData.getSetKeyMethod() +
                           ", getValueMethod=" +
                           mapEntryMetaData.getGetValueMethod() +
                           ", setValueMethod=" +
                           mapEntryMetaData.getSetValueMethod() +
                           ", valueType=" +
                           mapEntryMetaData.getValueType() +
                           ", nonNullValue=" + mapEntryMetaData.isNonNullValue()
                        );
                     }

                     if(classMetaData != null)
                     {
                        throw new JBossXBRuntimeException("Invalid binding: both jbxb:class and jbxb:mapEntry are specified for element " +
                           new QName(element.getNamespace(), element.getName())
                        );
                     }
                     binding.setMapEntryMetaData(mapEntryMetaData);
                  }

                  PutMethodMetaData putMethodMetaData = appInfo.getPutMethodMetaData();
                  if(putMethodMetaData != null)
                  {
                     if(log.isTraceEnabled())
                     {
                        log.trace("element: name=" +
                           new QName(element.getNamespace(), element.getName()) +
                           ", putMethod=" +
                           putMethodMetaData.getName() +
                           ", keyType=" +
                           putMethodMetaData.getKeyType() +
                           ", valueType=" + putMethodMetaData.getValueType()
                        );
                     }
                     binding.setPutMethodMetaData(putMethodMetaData);
                  }

                  AddMethodMetaData addMethodMetaData = appInfo.getAddMethodMetaData();
                  if(addMethodMetaData != null)
                  {
                     if(log.isTraceEnabled())
                     {
                        log.trace("element: name=" +
                           new QName(element.getNamespace(), element.getName()) +
                           ", addMethod=" +
                           addMethodMetaData.getMethodName() +
                           ", valueType=" +
                           addMethodMetaData.getValueType() +
                           ", isChildType=" + addMethodMetaData.isChildType()
                        );
                     }
                     binding.setAddMethodMetaData(addMethodMetaData);
                  }

                  ValueMetaData valueMetaData = appInfo.getValueMetaData();
                  if(valueMetaData != null)
                  {
                     if(log.isTraceEnabled())
                     {
                        log.trace("element " +
                           new QName(element.getNamespace(), element.getName()) +
                           ": unmarshalMethod=" + valueMetaData.getUnmarshalMethod()
                        );
                     }
                     binding.setValueMetaData(valueMetaData);
                  }

                  boolean mapEntryKey = appInfo.isMapEntryKey();
                  if(mapEntryKey)
                  {
                     if(log.isTraceEnabled())
                     {
                        log.trace("element name=" +
                           new QName(element.getNamespace(), element.getName()) +
                           ": is bound to a key in a map entry"
                        );
                     }
                     binding.setMapEntryKey(mapEntryKey);
                  }

                  boolean mapEntryValue = appInfo.isMapEntryValue();
                  if(mapEntryValue)
                  {
                     if(log.isTraceEnabled())
                     {
                        log.trace("element name=" +
                           new QName(element.getNamespace(), element.getName()) +
                           ": is bound to a value in a map entry"
                        );
                     }
                     binding.setMapEntryValue(mapEntryValue);
                  }

                  boolean skip = appInfo.isSkip();
                  if(skip)
                  {
                     if(log.isTraceEnabled())
                     {
                        log.trace(
                           "element name=" +
                           new QName(element.getNamespace(), element.getName()) +
                           ": will be skipped, it's attributes, character content and children will be set on the parent"
                        );
                     }
                     binding.setSkip(skip);
                  }
               }
            }
         }

         if(parentType != null)
         {
            parentType.addElement(qName, binding);
            if(log.isTraceEnabled())
            {
               log.trace("element: name=" +
                  qName +
                  ", type=" +
                  type.getQName() +
                  ", multiOccurs=" +
                  binding.isMultiOccurs() +
                  ", owner type=" +
                  parentType.getQName()
               );
            }
         }
      }
   }

   private static void bindModelGroup(SchemaBinding doc, XSModelGroup modelGroup, SharedElements sharedElements)
   {
      XSObjectList particles = modelGroup.getParticles();
      for(int i = 0; i < particles.getLength(); ++i)
      {
         XSParticle particle = (XSParticle)particles.item(i);
         bindParticle(doc, particle, sharedElements);
      }
   }

   // Private

   private static XSModel loadSchema(String xsdURL)
   {
      log.debug("loading xsd: " + xsdURL);

      XSImplementation impl = getXSImplementation();
      XSLoader schemaLoader = impl.createXSLoader(null);
      XSModel model = schemaLoader.loadURI(xsdURL);
      if(model == null)
      {
         throw new IllegalArgumentException("Invalid URI for schema: " + xsdURL);
      }

      return model;
   }

   private static XSModel loadSchema(InputStream is, String encoding, String baseURI)
   {
      log.debug("loading xsd from InputStream");
      LSInputAdaptor input = new LSInputAdaptor(is, encoding, baseURI);

      XSImplementation impl = getXSImplementation();
      XSLoader schemaLoader = impl.createXSLoader(null);
      XSModel model = schemaLoader.load(input);
      return model;
   }

   private static XSModel loadSchema(Reader reader, String encoding, String baseURI)
   {
      log.debug("loading xsd from Reader");
      LSInputAdaptor input = new LSInputAdaptor(reader, encoding, baseURI);

      XSImplementation impl = getXSImplementation();
      XSLoader schemaLoader = impl.createXSLoader(null);
      XSModel model = schemaLoader.load(input);
      return model;
   }

   private static XSModel loadSchema(String data, String encoding)
   {
      log.debug("loading xsd from string");
      LSInputAdaptor input = new LSInputAdaptor(data, encoding);

      XSImplementation impl = getXSImplementation();
      XSLoader schemaLoader = impl.createXSLoader(null);
      XSModel model = schemaLoader.load(input);
      return model;
   }

   private static XSImplementation getXSImplementation()
   {
      // Get DOM Implementation using DOM Registry
      ClassLoader loader = Thread.currentThread().getContextClassLoader();
      try
      {
         // Try the 2.6.2 version
         String name = "org.apache.xerces.dom.DOMXSImplementationSourceImpl";
         loader.loadClass(name);
         System.setProperty(DOMImplementationRegistry.PROPERTY, name);
      }
      catch(ClassNotFoundException e)
      {
         // Try the 2.7.0 version
         String name = "org.apache.xerces.dom.DOMXSImplementationSourceImpl";
         System.setProperty(DOMImplementationRegistry.PROPERTY, name);
      }

      XSImplementation impl;
      try
      {
         DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
         impl = (XSImplementation)registry.getDOMImplementation("XS-Loader");
      }
      catch(Exception e)
      {
         log.error("Failed to create schema loader.", e);
         throw new IllegalStateException("Failed to create schema loader: " + e.getMessage());
      }
      return impl;
   }

   private static void popType()
   {
      getXsdBinding().typeStack.removeLast();
   }

   private static void pushType(TypeBinding binding)
   {
      getXsdBinding().typeStack.addLast(binding);
   }

   private static TypeBinding peekType()
   {
      LinkedList typeStack = getXsdBinding().typeStack;
      return (TypeBinding)(typeStack.isEmpty() ? null : typeStack.getLast());
   }

   private static final class SharedElements
   {
      private Map elements = Collections.EMPTY_MAP;
      //private XSTypeDefinition anyType;

      public void add(XSElementDeclaration element)
      {
         switch(elements.size())
         {
            case 0:
               elements = Collections.singletonMap(element, null);
               break;
            case 1:
               elements = new HashMap(elements);
            default:
               elements.put(element, null);
         }
      }

      public boolean isShared(XSElementDeclaration element)
      {
         return elements.containsKey(element);
      }

      public TypeBinding getTypeBinding(XSElementDeclaration element)
      {
         return (TypeBinding)elements.get(element);
      }

      public void setTypeBinding(XSElementDeclaration element, TypeBinding type)
      {
         elements.put(element, type);
      }
   }

   // Inner

   private static final class XsdBinding
   {
      public final LinkedList typeStack = new LinkedList();
      public final SchemaBinding schemaBinding = new SchemaBinding();
   }
}
TOP

Related Classes of org.jboss.xb.binding.sunday.unmarshalling.XsdBinder

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.