Package org.jboss.xb.binding.metadata.unmarshalling.impl

Source Code of org.jboss.xb.binding.metadata.unmarshalling.impl.XsdBinder$ParentElement

/*
* 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.metadata.unmarshalling.impl;

import org.jboss.xb.binding.JBossXBRuntimeException;
import org.jboss.xb.binding.SimpleTypeBindings;
import org.jboss.xb.binding.Util;
import org.jboss.xb.binding.metadata.unmarshalling.AttributeBinding;
import org.jboss.xb.binding.metadata.unmarshalling.BasicElementBinding;
import org.jboss.xb.binding.metadata.unmarshalling.DocumentBinding;
import org.jboss.xb.binding.metadata.unmarshalling.ElementBinding;
import org.jboss.xb.binding.metadata.unmarshalling.NamespaceBinding;
import org.jboss.xb.binding.metadata.unmarshalling.TopElementBinding;
import org.jboss.xb.binding.metadata.unmarshalling.XmlValueBinding;
import org.jboss.logging.Logger;
import org.apache.xerces.xs.XSImplementation;
import org.apache.xerces.xs.XSModel;
import org.apache.xerces.xs.XSLoader;
import org.apache.xerces.xs.StringList;
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.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.w3c.dom.bootstrap.DOMImplementationRegistry;

import javax.xml.namespace.QName;
import java.util.Collection;
import java.util.Map;
import java.util.HashMap;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
* @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 XsdBinder()
   {
   }

   public static DocumentBinding bindXsd(String xsdUrl)
   {
      return bindXsd(xsdUrl, null);
   }

   public static DocumentBinding bindXsd(String xsdUrl, DocumentBinding delegate)
   {
      DocumentBindingImpl localDoc;
      if(delegate instanceof DocumentBindingImpl)
      {
         localDoc = (DocumentBindingImpl)delegate;
      }
      else
      {
         localDoc = new DocumentBindingImpl(delegate);
      }

      XSModel model = loadSchema(xsdUrl);
      StringList namespaces = model.getNamespaces();
      for(int i = 0; i < namespaces.getLength(); ++i)
      {
         String namespaceUri = namespaces.item(i);
         NamespaceBindingImpl ns = localDoc.bindNamespace(namespaceUri);

         XSNamedMap components = model.getComponentsByNamespace(XSConstants.ELEMENT_DECLARATION, namespaceUri);
         for(int j = 0; j < components.getLength(); ++j)
         {
            XSElementDeclaration element = (XSElementDeclaration)components.item(j);
            bindTopElement(localDoc, ns, element);
         }
      }

      return localDoc;
   }

   private static final void bindTopElement(DocumentBinding doc,
                                            NamespaceBindingImpl ns,
                                            XSElementDeclaration element)
   {
      TopElementBindingImpl top = new TopElementBindingImpl(ns, element);
      ns.addTopElement(top);

      bindComplexElement(element, doc, top);
   }

   private static void bindComplexElement(XSElementDeclaration elementDecl,
                                          DocumentBinding doc,
                                          ParentElement parentBinding)
   {
      XSTypeDefinition type = elementDecl.getTypeDefinition();
      if(type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
      {
         XSComplexTypeDefinition complexType = (XSComplexTypeDefinition)type;
         XSParticle particle = complexType.getParticle();
         if(particle != null)
         {
            bindParticle(doc, parentBinding, particle);
         }

         /* todo attributes
         XSObjectList attributeUses = complexType.getAttributeUses();
         for(int i = 0; i < attributeUses.getLength(); ++i)
         {
            XSAttributeUse attrUse = (XSAttributeUse)attributeUses.item(i);
            XSAttributeDeclaration attrDec = attrUse.getAttrDeclaration();

            String baseFieldName = Util.xmlNameToClassName(elementDecl.getName(), true);
            String fieldName = Character.toLowerCase(baseFieldName.charAt(0)) + baseFieldName.substring(1);

            NamespaceBinding ns = doc.getNamespace(elementDecl.getNamespace());
            String fqClsName = ns.getJavaPackage() +
               "." +
               Util.xmlNameToClassName(getBaseForClassName(elementDecl), true);

            Class javaType;
            try
            {
               javaType = Thread.currentThread().getContextClassLoader().loadClass(fqClsName);
            }
            catch(ClassNotFoundException e)
            {
               javaType = null;
            }

            factory.bindAttribute(parentBinding, attrDec.getNamespace(), attrDec.getName(), fieldName, javaType);
         }
         */
      }
   }

   private static void bindParticle(DocumentBinding doc,
                                    ParentElement parent,
                                    XSParticle particle)
   {
      XSTerm term = particle.getTerm();
      switch(term.getType())
      {
         case XSConstants.MODEL_GROUP:
            bindModelGroup(doc, parent, (XSModelGroup)term);
            break;
         case XSConstants.WILDCARD:
            // todo bindWildcard((XSWildcard)term);
            break;
         case XSConstants.ELEMENT_DECLARATION:
            bindElement(doc, parent, (XSElementDeclaration)term);
            break;
         default:
            throw new IllegalStateException("Unexpected term type: " + term.getType());
      }
   }

   private static void bindElement(DocumentBinding doc,
                                   ParentElement parent,
                                   XSElementDeclaration elementDecl)
   {
      ElementBindingImpl child = new ElementBindingImpl(parent, elementDecl);
      parent.addChild(child);
      bindComplexElement(elementDecl, doc, child);
   }

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

   // Private

   private static XSModel loadSchema(String 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 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";
         Class c = 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

   public static final class DocumentBindingImpl
      extends DocumentBindingFactoryImpl.AbstractDocumentBinding
   {
      private final Map namespaces = new HashMap();

      public DocumentBindingImpl(DocumentBinding doc)
      {
         super(doc);
      }

      NamespaceBindingImpl bindNamespace(String namespaceUri)
      {
         NamespaceBindingImpl ns = new NamespaceBindingImpl(doc, namespaceUri);
         namespaces.put(namespaceUri, ns);
         return ns;
      }

      protected NamespaceBinding getNamespaceLocal(String namespaceUri)
      {
         return (NamespaceBinding)namespaces.get(namespaceUri);
      }
   }

   private static final class NamespaceBindingImpl
      extends DocumentBindingFactoryImpl.AbstractNamespaceBinding
   {
      private final Map tops = new HashMap();

      public NamespaceBindingImpl(DocumentBinding doc, String namespaceUri)
      {
         super(doc, namespaceUri);
      }

      protected String getJavaPackageLocal()
      {
         return Util.xmlNamespaceToJavaPackage(namespaceUri);
      }

      protected TopElementBinding getTopElementLocal(String elementName)
      {
         return (TopElementBinding)tops.get(elementName);
      }

      void addTopElement(TopElementBindingImpl top)
      {
         tops.put(top.getName().getLocalPart(), top);
      }
   }

   private static final class ElementBindingImpl
      extends DocumentBindingFactoryImpl.AbstractElementBinding
      implements ParentElement
   {
      private final XSElementDeclaration elementDecl;
      private final Map children = new HashMap();
      private Class javaType;
      private Class fieldType;
      private Method getter;
      private Method setter;
      private Field field;

      public ElementBindingImpl(BasicElementBinding parent, XSElementDeclaration elementDecl)
      {
         super(parent, new QName(elementDecl.getNamespace(), elementDecl.getName()));
         this.elementDecl = elementDecl;
      }

      private void init()
      {
         DocumentBinding doc = parent.getDocument();

         // first try to use XSD type
         XSTypeDefinition typeDef = elementDecl.getTypeDefinition();
         String typeBasedClsName = null;
         if("http://www.w3.org/2001/XMLSchema".equals(typeDef.getNamespace()))
         {
            javaType = SimpleTypeBindings.classForType(typeDef.getName());
         }
         else if(typeDef.getName() != null)
         {
            NamespaceBinding ns = doc.getNamespace(typeDef.getNamespace());
            typeBasedClsName = ns.getJavaPackage() + "." + Util.xmlNameToClassName(typeDef.getName(), true);
            try
            {
               javaType = Thread.currentThread().getContextClassLoader().loadClass(typeBasedClsName);
            }
            catch(ClassNotFoundException e)
            {
            }
         }

         String elBasedClsName = Util.xmlNameToClassName(elementDecl.getName(), true);
         if(javaType == null)
         {
            NamespaceBinding ns = doc.getNamespace(elementDecl.getNamespace());
            // using type didn't help, let's try element's name
            // note: here we use element's namespace, not type's one
            try
            {
               javaType =
                  Thread.currentThread().getContextClassLoader().loadClass(ns.getJavaPackage() + "." + elBasedClsName);
            }
            catch(ClassNotFoundException e1)
            {
               // this also didn't work
            }
         }

         Class parentType = parent.getJavaType();
         if(Collection.class.isAssignableFrom(parentType))
         {
            if(javaType == null)
            {
               javaType = String.class;
            }
         }
         else
         {
            try
            {
               getter = parentType.getMethod("get" + elBasedClsName, null);
               fieldType = getter.getReturnType();
               try
               {
                  setter = parentType.getMethod("set" + elBasedClsName, new Class[]{getter.getReturnType()});
               }
               catch(NoSuchMethodException e)
               {
                  // todo immutable!!!
                  setter = null;
               }
            }
            catch(NoSuchMethodException e)
            {
               String fieldName = Util.xmlNameToFieldName(elementDecl.getName(), true);
               try
               {
                  field = parentType.getField(fieldName);
                  fieldType = field.getType();
               }
               catch(NoSuchFieldException e1)
               {
               }
            }

            if(fieldType != null)
            {
               if(Modifier.isFinal(fieldType.getModifiers()) ||
                  javaType == null &&
                  !Modifier.isInterface(fieldType.getModifiers()) &&
                  !Modifier.isAbstract(fieldType.getModifiers()))
               {
                  javaType = fieldType;
               }
               else if(fieldType == Collection.class || Collection.class.isAssignableFrom(fieldType))
               {
                  if(javaType == null)
                  {
                     // todo: other collection types
                     javaType = java.util.ArrayList.class;
                  }
               }
               else if(javaType != null)
               {
                  if(javaType != fieldType && !fieldType.isAssignableFrom(javaType))
                  {
                     javaType = null;
                  }
               }
            }
         }

         if(javaType == null)
         {
            throw new JBossXBRuntimeException("Failed to bind element " +
               name +
               " to any non-abstract Java type. Parent is " +
               parentType +
               ", field is " +
               fieldType
               + ", base=" + elBasedClsName
            );
         }
      }

      protected Field getFieldLocal()
      {
         if(javaType == null)
         {
            init();
         }
         return field;
      }

      protected Method getGetterLocal()
      {
         if(javaType == null)
         {
            init();
         }
         return getter;
      }

      protected Method getSetterLocal()
      {
         if(javaType == null)
         {
            init();
         }
         return setter;
      }

      protected Class getFieldTypeLocal()
      {
         if(javaType == null)
         {
            init();
         }
         return fieldType;
      }

      protected Class getJavaTypeLocal()
      {
         if(javaType == null)
         {
            init();
         }
         return javaType;
      }

      protected ElementBinding getElementLocal(QName elementName)
      {
         return (ElementBinding)children.get(elementName);
      }

      protected AttributeBinding getAttributeLocal(QName attributeName)
      {
         String fieldName = Util.xmlNameToClassName(attributeName.getLocalPart(), true);
         fieldName = Character.toLowerCase(fieldName.charAt(0)) + fieldName.substring(1);
         return new AttributeBindingImpl(attributeName, null, getJavaType(), fieldName);
      }

      protected XmlValueBinding getValueLocal()
      {
         // todo: implement getValueLocal
         throw new UnsupportedOperationException("getValueLocal is not implemented.");
      }

      public void addChild(BasicElementBinding child)
      {
         children.put(child.getName(), child);
      }
   }

   private static class TopElementBindingImpl
      extends DocumentBindingFactoryImpl.AbstractTopElementBinding
      implements ParentElement
   {
      private final XSElementDeclaration elementDecl;
      private final Map children = new HashMap();
      protected Class javaType;

      public TopElementBindingImpl(NamespaceBinding ns, XSElementDeclaration elementDecl)
      {
         super(ns, elementDecl.getName());
         this.elementDecl = elementDecl;
      }

      private void init()
      {
         DocumentBinding doc = ns.getDocument();

         // first try to use XSD type
         XSTypeDefinition typeDef = elementDecl.getTypeDefinition();
         String typeBasedClsName = null;
         if("http://www.w3.org/2001/XMLSchema".equals(typeDef.getNamespace()))
         {
            javaType = SimpleTypeBindings.classForType(typeDef.getName());
         }
         else if(typeDef.getName() != null)
         {
            NamespaceBinding ns = doc.getNamespace(typeDef.getNamespace());
            typeBasedClsName = ns.getJavaPackage() + "." + Util.xmlNameToClassName(typeDef.getName(), true);
            try
            {
               javaType = Thread.currentThread().getContextClassLoader().loadClass(typeBasedClsName);
            }
            catch(ClassNotFoundException e)
            {
            }
         }

         if(javaType == null)
         {
            // using type didn't help, let's try element's name
            // note: here we use element's namespace, not type's one
            NamespaceBinding ns = doc.getNamespace(elementDecl.getNamespace());
            String elBasedClsName = ns.getJavaPackage() + "." + Util.xmlNameToClassName(elementDecl.getName(), true);
            try
            {
               javaType = Thread.currentThread().getContextClassLoader().loadClass(elBasedClsName);
            }
            catch(ClassNotFoundException e1)
            {
               throw new JBossXBRuntimeException("Failed to bind element " +
                  name +
                  " using XSD type (" +
                  typeBasedClsName +
                  ") and element name (" +
                  elBasedClsName +
                  "): classes not found."
               );
            }
         }
      }

      protected Class getJavaTypeLocal()
      {
         if(javaType == null)
         {
            init();
         }
         return javaType;
      }

      protected ElementBinding getElementLocal(QName elementName)
      {
         return (ElementBinding)children.get(elementName);
      }

      protected AttributeBinding getAttributeLocal(QName attributeName)
      {
         String fieldName = Util.xmlNameToClassName(attributeName.getLocalPart(), true);
         fieldName = Character.toLowerCase(fieldName.charAt(0)) + fieldName.substring(1);
         return new AttributeBindingImpl(attributeName, null, getJavaType(), fieldName);
      }

      protected XmlValueBinding getValueLocal()
      {
         // todo: implement getValueLocal
         throw new UnsupportedOperationException("getValueLocal is not implemented.");
      }

      public void addChild(BasicElementBinding child)
      {
         children.put(child.getName(), child);
      }
   }

   interface ParentElement
      extends BasicElementBinding
   {
      void addChild(BasicElementBinding child);
   }
}
TOP

Related Classes of org.jboss.xb.binding.metadata.unmarshalling.impl.XsdBinder$ParentElement

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.