View Javadoc

    1   package org.codehaus.xfire.util;
    2
    3   import java.io.InputStream;
    4   import java.lang.reflect.Constructor;
    5   import java.lang.reflect.Method;
    6   import java.util.ArrayList;
    7   import java.util.Collection;
    8   import java.util.Collections;
    9   import java.util.HashMap;
    10  import java.util.List;
    11  import java.util.Map;
    12
    13  import javax.xml.stream.XMLInputFactory;
    14  import javax.xml.stream.XMLStreamException;
    15  import javax.xml.stream.XMLStreamReader;
    16
    17  import org.apache.commons.logging.Log;
    18  import org.apache.commons.logging.LogFactory;
    19  import org.codehaus.xfire.XFire;
    20  import org.codehaus.xfire.XFireRuntimeException;
    21  import org.codehaus.xfire.handler.Handler;
    22  import org.codehaus.xfire.service.Service;
    23  import org.codehaus.xfire.service.ServiceRegistry;
    24  import org.codehaus.xfire.service.binding.BindingProvider;
    25  import org.codehaus.xfire.service.binding.ObjectInvoker;
    26  import org.codehaus.xfire.service.binding.ObjectServiceFactory;
    27  import org.codehaus.xfire.soap.Soap11;
    28  import org.codehaus.xfire.soap.Soap12;
    29  import org.codehaus.xfire.soap.SoapVersion;
    30  import org.codehaus.xfire.transport.TransportManager;
    31  import org.codehaus.yom.Document;
    32  import org.codehaus.yom.Element;
    33  import org.codehaus.yom.Elements;
    34  import org.codehaus.yom.stax.StaxBuilder;
    35
    36  /***
    37   * Builds services from an xml configuration file.
    38   *
    39   * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
    40   */
    41  public class XMLServiceBuilder
    42  {
    43      private static final Log log = LogFactory.getLog(XMLServiceBuilder.class);
    44
    45      private static final Object DEFAULT_FACTORY_INSTANCE = new DefaultFactory();
    46
    47      private static Method DEFAULT_FACTORY_METHOD = null;
    48
    49      /***
    50       * It's likely that the same factory object will be used for creation for more then only 1 object, so cache it.
    51       */
    52      private Map factoryCache = new HashMap();
    53
    54      private XFire xfire;
    55
    56      public XMLServiceBuilder(XFire xfire)
    57      {
    58          this.xfire = xfire;
    59          try
    60          {
    61              DEFAULT_FACTORY_METHOD = DefaultFactory.class.getMethod("create",new Class[]{String.class});
    62          }
    63          catch (SecurityException e)
    64          {
    65              //  Imposible :)
    66              log.error(e);
    67          }
    68          catch (NoSuchMethodException e)
    69          {
    70              // Imposible :)
    71              log.error(e);
    72          }
    73      }
    74
    75      protected XFire getXFire()
    76      {
    77          return xfire;
    78      }
    79
    80      /***
    81       * Returns a collection of SOAP services.
    82       * <p>
    83       * This method takes an input stream and for each service element
    84       * builds a SOAP service.  The stream is interrogated for the following
    85       * element values:  name, namespace, style, use, serviceClass,
    86       * implementationClass, bindingProvider, and
    87       * property (a repeatable element) using attribute 'key'
    88       * <p>
    89       * @param  stream      A xml-based resource bundle
    90       * @return Collection  A collection of services prescribed in the bundle
    91       */
    92      public Collection buildServices(InputStream stream)
    93          throws Exception
    94      {
    95          try
    96          {
    97              XMLInputFactory ifactory = XMLInputFactory.newInstance();
    98              XMLStreamReader reader = ifactory.createXMLStreamReader(stream);
    99              StaxBuilder builder = new StaxBuilder();
    100             Document doc = builder.build(reader);
    101             Element root = doc.getRootElement();
    102
    103             List serviceList = new ArrayList();
    104             Elements contents = root.getChildElements("services");
    105             for (int i = 0; i < contents.size(); i++)
    106             {
    107                 Element element = contents.get(i);
    108                 Elements services = element.getChildElements();
    109                 for (int n = 0; n < services.size(); n++)
    110                 {
    111                     Element service = services.get(n);
    112
    113                     serviceList.add(loadService(service));
    114                 }
    115             }
    116             return serviceList;
    117         }
    118         catch (XMLStreamException e1)
    119         {
    120             log.error("Could not parse META-INF/xfire/services.xml!", e1);
    121             throw e1;
    122         }
    123     }
    124
    125     /***
    126      * Keeps data about object factory.
    127      * @author <a href="mailto:tsztelak@gmail.com">Tomasz Sztelak</a>
    128      *
    129      */
    130     private class ObjectFactory
    131     {
    132         /***
    133          * Instance of object declared as factory.
    134          */
    135         private Object factoryInstance;
    136
    137         /***
    138          * Method declared as factory method.
    139          */
    140         private Method factoryMethod;
    141
    142         /***
    143          * @param factory
    144          * @param method
    145          */
    146         public ObjectFactory(final Object factory,final Method method){
    147             factoryInstance = factory;
    148             factoryMethod = method;
    149         }
    150
    151         /***
    152          * Creates object given by className param using factory object instance @see factoryInstance.
    153          * @param className
    154          * @return created object.
    155          * @throws Exception
    156          */
    157         public Object createObject(String className)
    158             throws Exception
    159         {
    160             try{
    161             return factoryMethod.invoke(factoryInstance, new Object[] { className });
    162             }catch(Exception e){
    163                 throw new XFireRuntimeException("Coundn't create instance of object :"+className,e);
    164             }
    165         }
    166
    167
    168     }
    169
    170     /***
    171      * Returns ObjectFactory object created from values defined as attribues for given Element or null if no required
    172      * attributes are not present.
    173      * @param element
    174      * @return
    175      * @throws Exception
    176      */
    177     private ObjectFactory getObjectFactory(Element element)
    178         throws Exception
    179     {
    180
    181         Method factoryMethod  = null;
    182         Object factoryInstance = null;
    183
    184         String factoryClassName = element.getAttributeValue("factory-class");
    185         String factoryMethodName = element.getAttributeValue("factory-method");
    186
    187         // Both factoryClassName and factoryNethodName must be provided.
    188         if (factoryClassName != null && factoryClassName.length() > 0 && factoryMethodName != null
    189                 && factoryMethodName.length() > 0)
    190         {
    191
    192             // Check if factory instance was created before..
    193             factoryInstance = factoryCache.get(factoryClassName);
    194             if (factoryInstance == null)
    195             {
    196                 factoryInstance = loadClass(factoryClassName).newInstance();
    197                 factoryCache.put(factoryClassName, factoryInstance);
    198             }
    199
    200          factoryMethod  = factoryInstance.getClass().getMethod(factoryMethodName,new Class[]{String.class});
    201
    202         }else{
    203
    204             // No data for factory is provied so use default to avoid if(factory == null ) new MyClass() code
    205             factoryInstance = DEFAULT_FACTORY_INSTANCE;
    206             factoryMethod = DEFAULT_FACTORY_METHOD;
    207         }
    208
    209         return new ObjectFactory(factoryInstance, factoryMethod);
    210     }
    211
    212     protected Service loadService(Element service)
    213         throws Exception
    214     {
    215         ServiceRegistry registry = getXFire().getServiceRegistry();
    216
    217         String name = getElementValue(service, "name", null);
    218         String namespace = getElementValue(service, "namespace", null);
    219         String style = getElementValue(service, "style", "");
    220         String use = getElementValue(service, "use", "");
    221         String serviceClass = getElementValue(service, "serviceClass", "");
    222         String implClassName = getElementValue(service, "implementationClass", "");
    223         String bindingProviderName = getElementValue(service, "bindingProvider", "");
    224
    225         String soapVersionValue = getElementValue(service, "soapVersion", "1.1");
    226         SoapVersion soapVersion;
    227         if (soapVersionValue.equals("1.2"))
    228         {
    229             soapVersion = Soap12.getInstance();
    230         }
    231         else
    232         {
    233             soapVersion = Soap11.getInstance();
    234         }
    235
    236         Class clazz = null;
    237         try
    238         {
    239             clazz = loadClass(serviceClass);
    240         }
    241         catch (Exception e)
    242         {
    243             throw new XFireRuntimeException("Could not load service class: " + serviceClass, e);
    244         }
    245
    246         BindingProvider bindingProvider = loadBindingProvider(bindingProviderName);
    247
    248         String serviceFactory = getElementValue(service, "serviceFactory", "");
    249         ObjectServiceFactory factory;
    250         if (serviceFactory.equals("jsr181") || serviceFactory.equals("commons-attributes"))
    251             factory = getAnnotationServiceFactory(serviceFactory, bindingProvider);
    252         else
    253             factory = loadServiceFactory(bindingProvider, serviceFactory);
    254
    255         if (style.length() > 0)
    256             factory.setStyle(style);
    257         if (use.length() > 0)
    258             factory.setUse(use);
    259
    260         factory.setSoapVersion(soapVersion);
    261
    262         Service svc = null;
    263         if (name != null || namespace != null)
    264         {
    265             svc = factory.create(clazz, name, namespace, null);
    266         }
    267         else
    268         {
    269             svc = factory.create(clazz);
    270         }
    271
    272         if (implClassName.length() > 0)
    273         {
    274             Class implClazz = null;
    275             try
    276             {
    277                 implClazz = loadClass(implClassName);
    278             }
    279             catch (Exception e)
    280             {
    281                 throw new XFireRuntimeException("Could not load implementation class: "
    282                         + serviceClass, e);
    283             }
    284
    285             svc.setProperty(ObjectInvoker.SERVICE_IMPL_CLASS, implClazz);
    286
    287             if (log.isInfoEnabled())
    288             {
    289                 log.info("Created Service " + name + " with impl " + implClazz + ", soap version: "
    290                         + soapVersionValue + ", style: " + style + ", use: " + use + ", namespace "
    291                         + svc.getServiceInfo().getName().getNamespaceURI());
    292             }
    293         }
    294         else
    295         {
    296             if (log.isInfoEnabled())
    297             {
    298                 log.info("Created Service " + name + " with impl " + clazz + ", soap version: "
    299                         + soapVersionValue + ", style: " + style + ", use: " + use + ", namespace "
    300                         + svc.getServiceInfo().getName().getNamespaceURI());
    301             }
    302         }
    303
    304         loadServiceProperties(svc,service);
    305
    306         svc.getInHandlers().addAll(createHandlers(service.getFirstChildElement("inHandlers")));
    307         svc.getOutHandlers().addAll(createHandlers(service.getFirstChildElement("outHandlers")));
    308         svc.getFaultHandlers().addAll(createHandlers(service.getFirstChildElement("faultHandlers")));
    309
    310         registry.register(svc);
    311
    312         return svc;
    313     }
    314
    315     protected ObjectServiceFactory loadServiceFactory(BindingProvider bindingProvider,
    316                                                       String serviceFactoryName)
    317     {
    318         ObjectServiceFactory factory = null;
    319         if (serviceFactoryName.length() > 0)
    320         {
    321             // Attempt to load a ServiceFactory for the user.
    322             try
    323             {
    324                 Class clz = loadClass(serviceFactoryName);
    325                 TransportManager tman = getXFire().getTransportManager();
    326
    327                 Constructor con = null;
    328                 Object[] arguments = null;
    329
    330                 try
    331                 {
    332                     con = clz.getConstructor(new Class[] { TransportManager.class,
    333                             BindingProvider.class });
    334                     arguments = new Object[] { tman, bindingProvider };
    335                 }
    336                 catch (NoSuchMethodException e)
    337                 {
    338                     try
    339                     {
    340                         con = clz.getConstructor(new Class[] { TransportManager.class });
    341                         arguments = new Object[] { tman };
    342                     }
    343                     catch (NoSuchMethodException e1)
    344                     {
    345                         con = clz.getConstructor(new Class[0]);
    346                         arguments = new Object[0];
    347                     }
    348                 }
    349
    350                 return (ObjectServiceFactory) con.newInstance(arguments);
    351             }
    352             catch (Exception e)
    353             {
    354                 throw new XFireRuntimeException("Could not load service factory: "
    355                         + serviceFactoryName, e);
    356             }
    357         }
    358         else
    359         {
    360             factory = new ObjectServiceFactory(getXFire().getTransportManager(), bindingProvider);
    361         }
    362
    363         return factory;
    364     }
    365
    366     protected ObjectServiceFactory getAnnotationServiceFactory(String annotationType,
    367                                                                BindingProvider bindingProvider)
    368         throws Exception
    369     {
    370         Class annotsClz = null;
    371         Class clz = loadClass("org.codehaus.xfire.annotations.AnnotationServiceFactory");
    372
    373         if (annotationType.equals("jsr181"))
    374         {
    375             annotsClz = loadClass("org.codehaus.xfire.annotations.jsr181.Jsr181WebAnnotations");
    376         }
    377         else if (annotationType.equals("commons-attributes"))
    378         {
    379             annotsClz = loadClass("org.codehaus.xfire.annotations.commons.CommonsWebAttributes");
    380         }
    381
    382         Class webAnnot = loadClass("org.codehaus.xfire.annotations.WebAnnotations");
    383
    384         Constructor con = clz.getConstructor(new Class[] { webAnnot, TransportManager.class,
    385                 BindingProvider.class });
    386
    387         return (ObjectServiceFactory) con.newInstance(new Object[] { annotsClz.newInstance(),
    388                 getXFire().getTransportManager(), bindingProvider });
    389     }
    390
    391     protected BindingProvider loadBindingProvider(String bindingProviderName)
    392     {
    393         BindingProvider bindingProvider = null;
    394         if (bindingProviderName.length() > 0)
    395         {
    396             try
    397             {
    398                 bindingProvider = (BindingProvider) loadClass(bindingProviderName).newInstance();
    399             }
    400             catch (Exception e)
    401             {
    402                 throw new XFireRuntimeException("Could not load binding provider: "
    403                         + bindingProvider, e);
    404             }
    405         }
    406         return bindingProvider;
    407     }
    408
    409     private List createHandlers(Element child)
    410         throws Exception
    411     {
    412         if (child == null)
    413             return Collections.EMPTY_LIST;
    414
    415         Elements handlers = child.getChildElements("handler");
    416         if (handlers.size() == 0)
    417             return Collections.EMPTY_LIST;
    418
    419         List pipe = new ArrayList();
    420
    421         for (int i = 0; i < handlers.size(); i++)
    422         {
    423             pipe.add(getHandler(handlers.get(i)));
    424         }
    425
    426         return pipe;
    427     }
    428
    429     /***
    430      * @param element
    431      * @return
    432      * @throws Exception
    433      */
    434     protected Handler getHandler(Element element)
    435         throws Exception
    436     {
    437         String handlerClassName = element.getValue();
    438         return (Handler) getObjectFactory(element).createObject(handlerClassName);
    439     }
    440
    441     public String getElementValue(Element root, String name, String def)
    442     {
    443         Element child = root.getFirstChildElement(name);
    444         if (child != null)
    445         {
    446             String value = child.getValue();
    447             if (value != null && value.length() > 0)
    448                 return value;
    449         }
    450
    451         return def;
    452     }
    453
    454     private void loadServiceProperties(Service svc, Element child)
    455     {
    456         Elements elements = child.getChildElements("property");
    457         if (elements.size() == 0)
    458             return;
    459         for (int i = 0; i < elements.size(); i++)
    460         {
    461             Element element = (Element) elements.get(i);
    462             String key = element.getAttributeValue("key");
    463             String value = element.getValue();
    464             if (key.length() > 1 && value.length() > 1)
    465                 svc.setProperty(key, value);
    466         }
    467     }
    468
    469     /***
    470      * Load a class from the class loader.
    471      *
    472      * @param className
    473      *            The name of the class.
    474      * @return The class.
    475      * @throws Exception
    476      */
    477     protected Class loadClass(String className)
    478         throws Exception
    479     {
    480         // Handle array'd types.
    481         if (className.endsWith("[]"))
    482         {
    483             className = "[L" + className.substring(0, className.length() - 2) + ";";
    484         }
    485
    486         return ClassLoaderUtils.loadClass(className, getClass());
    487     }
    488
    489     private static class DefaultFactory
    490     {
    491         public Object create(String className)
    492             throws Exception
    493         {
    494             // Handle array'd types.
    495             if (className.endsWith("[]"))
    496             {
    497                 className = "[L" + className.substring(0, className.length() - 2) + ";";
    498             }
    499
    500             return ClassLoaderUtils.loadClass(className, getClass()).newInstance();
    501
    502         }
    503     }
    504 }
    505