You are viewing a plain text version of this content. The canonical link for it is here.
Posted to muse-commits@ws.apache.org by wi...@apache.org on 2005/10/13 17:20:47 UTC
svn commit: r320783 - in
/webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic:
./ BodyWrapper.java DynamicSchemaClassBuilder.java DynamicSoapClient.java
EnvelopeWrapper.java HeaderWrapper.java
Author: wire
Date: Thu Oct 13 08:19:35 2005
New Revision: 320783
URL: http://svn.apache.org/viewcvs?rev=320783&view=rev
Log:
dynmaic soap client for previous release to this package
Added:
webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/
webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/BodyWrapper.java
webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/DynamicSchemaClassBuilder.java
webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/DynamicSoapClient.java
webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/EnvelopeWrapper.java
webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/HeaderWrapper.java
Added: webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/BodyWrapper.java
URL: http://svn.apache.org/viewcvs/webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/BodyWrapper.java?rev=320783&view=auto
==============================================================================
--- webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/BodyWrapper.java (added)
+++ webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/BodyWrapper.java Thu Oct 13 08:19:35 2005
@@ -0,0 +1,84 @@
+/*=============================================================================*
+ * Confidential Copyright (c) 2004 Hewlett-Packard Development Company, L.P. *
+ *=============================================================================*/
+package org.apache.ws.client.muse.client.impl.dynamic;
+
+import org.apache.xmlbeans.XmlCursor;
+import org.apache.xmlbeans.XmlObject;
+import org.xmlsoap.schemas.soap.envelope.Body;
+
+import javax.xml.namespace.QName;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Wraps an XmlBean generated Body to provide
+ * utility methods for getting at the XmlBean objects.
+ *
+ * @author Ian Springer, Sal Campana
+ */
+public class BodyWrapper
+{
+ private Body m_body;
+
+ /**
+ * Creates a new {@link BodyWrapper} object.
+ *
+ * @param body DOCUMENT_ME
+ */
+ public BodyWrapper( Body body )
+ {
+ m_body = body;
+ }
+
+ /**
+ * Returns the top-level elements from the Body as an XmlBean Object[].
+ *
+ * @return XmlObject[] body elements
+ */
+ public XmlObject[] getBodyElements( )
+ {
+ XmlCursor xmlCursor = m_body.newCursor( );
+ xmlCursor.toNextToken( );
+
+ //get the first child of the body i.e. the response message, or fault
+ XmlObject xmlBeanResponseMessage = xmlCursor.getObject( );
+ List xmlObjects = new ArrayList( );
+ xmlObjects.add( xmlBeanResponseMessage );
+
+ //add the rest of the top-level-elements to the list
+ while ( xmlCursor.toNextSibling( ) )
+ {
+ xmlObjects.add( xmlCursor.getObject( ) );
+ }
+
+ xmlCursor.dispose( );
+ return (XmlObject[]) xmlObjects.toArray( new XmlObject[0] );
+ }
+
+ /**
+ * Returns the top-level body elements with the specified name.
+ *
+ * @return the top-level body elements with the specified name
+ */
+ public XmlObject[] getBodyElements( QName qName )
+ {
+ if ( qName == null )
+ {
+ throw new IllegalArgumentException( "Null name is not allowed." );
+ }
+
+ XmlObject[] allBodyElems = getBodyElements( );
+ List bodyElems = new ArrayList( );
+ for ( int i = 0; i < allBodyElems.length; i++ )
+ {
+ if ( qName.equals( allBodyElems[i].schemaType( ).getName( ) ) )
+ {
+ bodyElems.add( allBodyElems[i] );
+ }
+ }
+
+ return (XmlObject[]) bodyElems.toArray( new XmlObject[0] );
+ }
+
+}
\ No newline at end of file
Added: webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/DynamicSchemaClassBuilder.java
URL: http://svn.apache.org/viewcvs/webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/DynamicSchemaClassBuilder.java?rev=320783&view=auto
==============================================================================
--- webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/DynamicSchemaClassBuilder.java (added)
+++ webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/DynamicSchemaClassBuilder.java Thu Oct 13 08:19:35 2005
@@ -0,0 +1,583 @@
+/*=============================================================================*
+ * Confidential Copyright (c) 2004 Hewlett-Packard Development Company, L.P. *
+ *=============================================================================*/
+package org.apache.ws.client.muse.client.impl.dynamic;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import javax.wsdl.Definition;
+import javax.wsdl.WSDLException;
+import javax.xml.namespace.QName;
+import javax.xml.soap.SOAPElement;
+
+import org.apache.ws.resource.tool.Wsdl2Java;
+import org.apache.ws.util.XmlBeanNameUtils;
+import org.apache.xmlbeans.XmlObject;
+import org.apache.xmlbeans.impl.common.XmlErrorPrinter;
+import org.apache.xmlbeans.impl.tool.SchemaCompiler;
+
+/**
+ * This class takes a WSDL's schema and converts it into a set of XMLBeans.
+ * These XMLBeans can then be used to create requests and deliver responses to
+ * SOAP requests. The java classes generated must be loaded through this classes
+ * private class loader which is populated by XMLBean's schema compiler.
+ *
+ * @author wire
+ */
+public class DynamicSchemaClassBuilder
+{
+ /**
+ * The temp directory that will hold the classes generated by the builder.
+ */
+ static File m_tempDir;
+ static {
+ try {
+ buildTempDirs( );
+ } catch (IOException e) {
+ }
+ }
+
+ /**
+ * The directory that is the root for all generated classes.
+ */
+ static File m_classes;
+
+ /** DOCUMENT_ME */
+ static String[] m_reservedPropNames =
+ new String[]
+ {
+ "get_elementflags",
+ "get_default_attribute_text",
+ "get_default_element_text",
+ "getObjectValue",
+ "getStringValue",
+ "get_schema_type",
+ "get_attribute_type",
+ "get_element_type",
+ "get_element_ending_delimiters",
+ "get_attributeflags",
+ "get_attribute_field",
+ "get_store",
+ "getIntValue",
+ "getByteArrayValue",
+ "getQNameValue",
+ "getFloatValue",
+ "getDoubleValue",
+ "get_wscanon_text",
+ "getBooleanValue",
+ "getByteValue",
+ "getShortValue",
+ "getLongValue",
+ "getBigIntegerValue",
+ "getBigDecimalValue",
+ "getEnumValue",
+ "getCalendarValue",
+ "getDateValue",
+ "getGDateValue",
+ "getGDurationValue",
+ "getListValue",
+ "getClass"
+ };
+
+ /** DOCUMENT_ME */
+ static ArrayList m_reservedList;
+
+ /**
+ * The URL of the WSDL document who's schema we are building classes for.
+ */
+ URL m_wsdlURL;
+
+ /**
+ * The path to a local temp copy of the WSDL document in m_wsdl.
+ */
+ //File m_localWsdl;
+
+ /**
+ * The directory that contains generated source file for the schema
+ * compiler.
+ */
+ File m_src;
+
+ /**
+ * The classpath that the schema compiler should when it invokes javac.
+ */
+ String m_SchemaCompileClassPath;
+
+ /**
+ * Indicates if this class has already generated classes for this wsdl file.
+ */
+ boolean m_compiled = false;
+
+ /**
+ * The WSDL definition created by WSDL4J.
+ */
+ protected Definition m_definition;
+
+ /**
+ * The classloader to use to access classes created by the schema compiler.
+ */
+ ClassLoader m_xmlBeansClassLoader;
+
+ {
+ m_reservedList = new ArrayList( );
+ for ( int index = 0; index < m_reservedPropNames.length; index++ )
+ {
+ String string = m_reservedPropNames[index];
+ m_reservedList.add( string );
+ }
+ }
+
+ public DynamicSchemaClassBuilder(URL wsdlURL )
+ throws WSDLException,
+ IOException
+ {
+ this(null,wsdlURL);
+ }
+
+ /**
+ * Creates a new {@link DynamicSchemaClassBuilder} object.
+ *
+ * @param wsdlURL DOCUMENT_ME
+ *
+ * @throws WSDLException DOCUMENT_ME
+ * @throws IOException DOCUMENT_ME
+ */
+ public DynamicSchemaClassBuilder(String contextUrl, URL wsdlURL )
+ throws WSDLException,
+ IOException
+ {
+ m_wsdlURL = wsdlURL;
+
+ // Download a local copy for use by the schema compiler
+ //String wsdlUrlString = wsdlURL.toString( );
+
+ // Build a definition
+ //System.err.println("Attemted to load def for "+m_wsdlURL);
+ // This must be repaired m_definition = WsdlUtils.loadWsdlDefinition(m_wsdlURL );
+
+
+// m_localWsdl =
+// WsdlUtils.writeWsdlToTempDir( wsdlUrlString.substring( wsdlUrlString.lastIndexOf( "/" ) + 1 ),
+// m_definition,
+// m_tempDir );
+// HashMap map1 = new HashMap();
+// HashMap map2=new HashMap();
+// WsdlUtils.iterateWsdlDefinitionImports(m_definition,m_tempDir,map1,map2);
+// System.err.println("Temp for Wsdl is "+m_localWsdl.getPath());
+// if ( !m_localWsdl.exists( ) )
+// {
+// throw new IOException( "Failed to wsdl in temp directory " + m_localWsdl.getPath( ) );
+// }
+
+ // Establish a src directory
+ m_src = new File( m_tempDir.getPath( ) + File.separator + "src" );
+ m_src.mkdir( );
+ if ( !m_src.exists( ) )
+ {
+ throw new IOException( "Failed to create the temp directory " + m_src.getPath( ) );
+ }
+
+ // Establish an XMLBeans classpath based on this VM's cp
+ m_SchemaCompileClassPath = getXMLBeansClasspathFromSystemPath( );
+
+ //set up the classloader for the resulting classes
+ m_xmlBeansClassLoader = getXmlBeanClassLoader( m_classes.getPath( ) );
+ }
+
+ /**
+ * Causes the class to invoke the schema compiler and create
+ * the classes which represent the schema objects.
+ * @throws FileNotFoundException
+ * @throws WSDLException
+ */
+ public void compile( )
+ throws IOException,
+ WSDLException
+ {
+ if ( m_compiled )
+ {
+ return;
+ }
+
+ // This must be fixed compileWsdlSchema( WsdlUtils.getAllWsdlFiles( m_wsdlURL, m_tempDir, MuseConstants.WS_SPEC_NSURIS ) );
+ m_compiled = true;
+ }
+
+ /**
+ * Deletes all temp file resources associated with this WSDL. Will prevent
+ * this class from providing any new xmlbeans what have not already been loaded.
+ *
+ */
+ public static void dispose( )
+ {
+ //IoUtils.deleteDir( m_tempDir ); This must be restored
+ try {
+ buildTempDirs();
+ } catch (IOException e) {
+ }
+ }
+
+ /**
+ * Builds the class name of the generated XmlBean off of the element's
+ * QName.
+ *
+ * @param resoucePropsDocElemQName
+ * @return
+ */
+ protected static String getElementXmlBeanClassName( QName resoucePropsDocElemQName )
+ throws NoClassDefFoundError
+ {
+ if ( resoucePropsDocElemQName == null )
+ {
+ throw new NoClassDefFoundError( "Could not figure out the name of the Resource Properties Document XML Bean class for document element "
+ + resoucePropsDocElemQName + "." );
+ }
+
+ String resourcePropertiesClassName = XmlBeanNameUtils.getElementXmlBeanClassName( resoucePropsDocElemQName );
+
+ if ( resourcePropertiesClassName == null )
+ {
+ throw new NoClassDefFoundError( "Could not figure out the name of the Resource Properties Document XML Bean class for document element "
+ + resoucePropsDocElemQName + "." );
+ }
+
+ return resourcePropertiesClassName;
+ }
+
+ /**
+ * Manufactures an instance of an XMLBean that is backed by an empty XML document.
+ * @param schemaElement
+ * @return an XMLObject that is a schema generated class for element.
+ * @throws ClassNotFoundException
+ * @throws SecurityException
+ * @throws NoSuchMethodException
+ * @throws IllegalArgumentException
+ * @throws IllegalAccessException
+ * @throws InvocationTargetException
+ */
+ public XmlObject getEmptyInstanceOfXMLBean( QName schemaElement )
+ throws ClassNotFoundException,
+ SecurityException,
+ NoSuchMethodException,
+ IllegalArgumentException,
+ IllegalAccessException,
+ InvocationTargetException
+ {
+ String className = getElementXmlBeanClassName( schemaElement );
+ if ( className != null )
+ {
+ String factoryName = className.substring( 0,
+ className.lastIndexOf( "." ) ) + "$Factory";
+ Class xmlBeanClass = m_xmlBeansClassLoader.loadClass( factoryName );
+ Method method = xmlBeanClass.getMethod( "newInstance", null );
+ XmlObject requestXmlObject = (XmlObject) method.invoke( xmlBeanClass, null );
+ return requestXmlObject;
+ }
+ else
+ {
+ throw new ClassNotFoundException( schemaElement.toString( ) + " does not have an equivalent class." );
+ }
+ }
+
+ /**
+ * Returns and XmlObject that is an XMLBeans schema based object that is populated
+ * by the soap element passed if they are compatible.
+ * @param schemaElement
+ * @param element
+ * @return an XMLObject that is a schema generated class for element.
+ * @throws ClassNotFoundException
+ * @throws SecurityException
+ * @throws NoSuchMethodException
+ * @throws IllegalArgumentException
+ * @throws IllegalAccessException
+ * @throws InvocationTargetException
+ */
+ protected XmlObject getInstanceOfXMLBean( QName schemaElement,
+ SOAPElement element )
+ throws ClassNotFoundException,
+ SecurityException,
+ NoSuchMethodException,
+ IllegalArgumentException,
+ IllegalAccessException,
+ InvocationTargetException
+ {
+ String className = getElementXmlBeanClassName( schemaElement );
+ if ( className != null )
+ {
+ String factoryName = className.substring( 0,
+ className.lastIndexOf( "." ) ) + "$Factory";
+ Class xmlBeanClass = m_xmlBeansClassLoader.loadClass( factoryName );
+ Method[] methods = xmlBeanClass.getMethods( );
+ Method methodNewInstance = xmlBeanClass.getMethod( "newInstance", null );
+
+ Method methodParse = xmlBeanClass.getMethod( "parse",
+ new Class[]
+ {
+ String.class
+ } );
+
+ XmlObject requestXmlObject =
+ (XmlObject) methodParse.invoke( xmlBeanClass,
+ new Object[]
+ {
+ element.toString( )
+ } );
+
+ // Convert the document to a bean by calling get className /wDocumentImpl
+ return requestXmlObject;
+ }
+ else
+ {
+ throw new ClassNotFoundException( schemaElement.toString( ) + " does not have an equivalent class." );
+ }
+ }
+
+ /**
+ * Given a class returns only the name without its containing packages.
+ * Good for buildiing method names from class names.
+ * @param aClass
+ * @return A string containing just the name of the class.
+ */
+ protected static String getNameFromClass( Class aClass )
+ {
+ String className = aClass.getName( );
+ String[] classparts = className.split( "\\." );
+ return classparts[classparts.length - 1];
+ }
+
+ /**
+ * Applies a simple set of rules to produce a list of properties to set on
+ * and XMLBeans based object.
+ * @param object
+ * @return a list of getters with the word get removed from them that are the "proeprties" of this object.
+ */
+ public static String[] getProperties( XmlObject object )
+ {
+ ArrayList ret = new ArrayList( );
+ Method[] methods = object.getClass( ).getMethods( );
+ for ( int index = 0; index < methods.length; index++ )
+ {
+ Method method = methods[index];
+ if ( method.getName( ).matches( "^get.+" ) )
+ {
+ if ( !( Modifier.isPrivate( method.getModifiers( ) )
+ || Modifier.isProtected( method.getModifiers( ) ) ) )
+ {
+ if ( !isReserved( method.getName( ) ) )
+ {
+ ret.add( method.getName( ).substring( 3 ) );
+ }
+ }
+ }
+ }
+
+ return (String[]) ret.toArray( new String[0] );
+ }
+
+// /**
+// */
+// public static String[] getOperations( XmlObject object )
+// {
+// ArrayList ret = new ArrayList( );
+// Method[] methods = object.getClass( ).getMethods( );
+// for ( int index = 0; index < methods.length; index++ )
+// {
+// Method method = methods[index];
+// if ( !(method.getName( ).matches( "^get.+" )||method.getName( ).matches( "^set.+" )) )
+// {
+// if ( !( Modifier.isPrivate( method.getModifiers( ) )
+// || Modifier.isProtected( method.getModifiers( ) ) ) )
+// {
+// if ( !isReserved( method.getName( ) ) )
+// {
+// ret.add( method.getName( ).substring( 3 ) );
+// }
+// }
+// }
+// }
+//
+// return (String[]) ret.toArray( new String[0] );
+// }
+
+ /**
+ * A utility to do preoprty setting via introspection.
+ * @param object
+ * @param propertyName
+ * @param value
+ * @throws SecurityException
+ * @throws NoSuchMethodException
+ * @throws IllegalArgumentException
+ * @throws IllegalAccessException
+ * @throws InvocationTargetException
+ */
+ public static void setProperty( XmlObject object,
+ String propertyName,
+ Object value )
+ throws SecurityException,
+ NoSuchMethodException,
+ IllegalArgumentException,
+ IllegalAccessException,
+ InvocationTargetException
+ {
+ Method methodGetter =
+ object.getClass( ).getMethod( "set" + propertyName,
+ new Class[]
+ {
+ value.getClass( )
+ } );
+ Object ret = methodGetter.invoke( object, null );
+ }
+
+ /**
+ * A utility used to call get<YourPropName> when you have an XML Object.
+ * Saves on repetitive introspection code.
+ * @param object
+ * @param propertyName
+ * @return
+ * @throws NoSuchMethodException
+ * @throws SecurityException
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ * @throws IllegalArgumentException
+ */
+ public static Object getProperty( XmlObject object,
+ String propertyName )
+ throws SecurityException,
+ NoSuchMethodException,
+ IllegalArgumentException,
+ IllegalAccessException,
+ InvocationTargetException
+ {
+ Method[] methods = object.getClass( ).getMethods( );
+ Method methodGetter = object.getClass( ).getMethod( "get" + propertyName,
+ new Class[] { } );
+ Object ret = methodGetter.invoke( object,
+ new Object[] { } );
+ return ret;
+ }
+
+ /**
+ * Uses the system classpath as the schema compiler classpath.
+ * Can be overridden to provide a different classpath source.
+ * @return
+ */
+ protected String getXMLBeansClasspathFromSystemPath( )
+ {
+ return m_classes+File.pathSeparator+System.getProperty( "java.class.path" );
+ }
+
+ private static boolean isReserved( String propName )
+ {
+ return m_reservedList.contains( propName );
+ }
+
+ /**
+ * Builds a classloader based on the classes output dir used by the XmlBeans
+ * SchemaCompiler. This ensures the classes written by the compiler will be
+ * loaded.
+ *
+ * @param classesPath
+ * @return @throws
+ * MalformedURLException
+ */
+ private static ClassLoader getXmlBeanClassLoader( String classesPath )
+ throws MalformedURLException
+ {
+ final URL classesURL = new File( classesPath ).toURL( );
+
+ return new URLClassLoader( new URL[]
+ {
+ classesURL
+ },
+ Wsdl2Java.class.getClassLoader( ) );
+ }
+
+ /**
+ * Builds the temp dirs for writing files to the filesystem.
+ *
+ * @throws IOException
+ */
+ private static void buildTempDirs( )
+ throws IOException
+ {
+ String hashAsString =
+ DynamicSchemaClassBuilder.class.getName( ) + "@" + DynamicSchemaClassBuilder.class.hashCode( );
+
+ // Build the base temp dir
+ //m_tempDir = new File( System.getProperty( "java.io.tmpdir" ) + File.separator + hashAsString );
+ m_tempDir = new File( System.getProperty( "user.home" ) + File.separator + ".wsdmcache" );
+ //user.home
+ m_tempDir.mkdir( );
+ if ( !m_tempDir.exists( ) )
+ {
+ throw new IOException( "Failed to create the temp directory " + m_tempDir.getPath( ) );
+ }
+
+ m_classes = new File( m_tempDir.getPath( ) + File.separator + "classes" );
+ m_classes.mkdir( );
+ if ( !m_classes.exists( ) )
+ {
+ throw new IOException( "Failed to create the temp directory " + m_classes.getPath( ) );
+ }
+ }
+
+ /**
+ * Builds and compiles the Schema from the WSDL using XmlBeans
+ * SchemaCompiler
+ *
+ * @param wsdlFiles
+ */
+ private void compileWsdlSchema( File[] wsdlFiles )
+ {
+ System.out.println("Schema Compile Request:");
+ for (int index = 0; index < wsdlFiles.length; index++) {
+ File file = wsdlFiles[index];
+ System.out.println(file.getPath());
+ }
+ SchemaCompiler.Parameters sCompParams = new SchemaCompiler.Parameters( );
+ sCompParams.setSrcDir( m_src );
+ sCompParams.setClassesDir( m_classes );
+ sCompParams.setQuiet(true);
+ if ( m_SchemaCompileClassPath != null )
+ {
+ String[] cpparts = m_SchemaCompileClassPath.split( File.pathSeparator );
+ List cpList = new ArrayList( );
+
+ for ( int i = 0; i < cpparts.length; i++ )
+ {
+ cpList.add( new File( cpparts[i] ) );
+ }
+
+ File[] classpath = (File[]) cpList.toArray( new File[cpList.size( )] );
+
+ sCompParams.setClasspath( classpath );
+ }
+
+ sCompParams.setDownload( true );
+ sCompParams.setWsdlFiles( wsdlFiles );
+ sCompParams.setErrorListener( new XmlErrorPrinter( false, null ) );
+ Properties props = System.getProperties();
+ //sCompParams.setCompiler("C:\\java\\j2sdk1.4.2_05\\bin\\javac");
+ SchemaCompiler.compile( sCompParams );
+ }
+
+ /**
+ * Clears the cache of generated classes in the users home directory;
+ * Should be used in unit tests and to flush generated classes if a wsdl on the
+ * server has changed and the client classes should be re-generated.
+ */
+ public static void clearGeneratedClassCache(){
+ dispose();
+ }
+}
\ No newline at end of file
Added: webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/DynamicSoapClient.java
URL: http://svn.apache.org/viewcvs/webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/DynamicSoapClient.java?rev=320783&view=auto
==============================================================================
--- webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/DynamicSoapClient.java (added)
+++ webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/DynamicSoapClient.java Thu Oct 13 08:19:35 2005
@@ -0,0 +1,474 @@
+/*=============================================================================*
+ * Confidential Copyright (c) 2004 Hewlett-Packard Development Company, L.P. *
+ *=============================================================================*/
+package org.apache.ws.client.muse.client.impl.dynamic;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.wsdl.Binding;
+import javax.wsdl.Input;
+import javax.wsdl.Message;
+import javax.wsdl.Operation;
+import javax.wsdl.Part;
+import javax.wsdl.PortType;
+import javax.wsdl.WSDLException;
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.soap.MessageFactory;
+import javax.xml.soap.SOAPBody;
+import javax.xml.soap.SOAPConnection;
+import javax.xml.soap.SOAPConnectionFactory;
+import javax.xml.soap.SOAPEnvelope;
+import javax.xml.soap.SOAPMessage;
+
+import org.apache.axis.message.addressing.AddressingHeaders;
+import org.apache.axis.message.addressing.ReferencePropertiesType;
+import org.apache.xmlbeans.XmlCursor;
+import org.apache.xmlbeans.XmlObject;
+import org.apache.xmlbeans.XmlOptions;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import com.ibm.wsdl.MessageImpl;
+
+/**
+ * A SOAP client that can make calls by generating complex types dynamically at
+ * run time using xmlbeans and WSDL schema.
+ *
+ * @author wire
+ */
+public class DynamicSoapClient extends DynamicSchemaClassBuilder {
+
+ protected URL m_targetURL;
+
+ /**
+ * @param wsdlURL
+ * @throws WSDLException
+ * @throws IOException
+ */
+ public DynamicSoapClient(URL wsdlURL, URL targetURL) throws WSDLException,
+ IOException {
+ super(wsdlURL);
+ m_targetURL = targetURL;
+ compile();
+ }
+
+ /**
+ * Returns a list of operations that can be called on this WSDL.
+ *
+ * @return A list off import javax.wsdl.Operation objects
+ */
+ public Operation[] getWsdlOperations() {
+ Map bindings = m_definition.getBindings();
+ Iterator iterator = bindings.values().iterator();
+ List ops = new ArrayList();
+
+ // Iterate though all bindings
+ while (iterator.hasNext()) {
+ Binding binding = (Binding) iterator.next();
+ PortType portType = binding.getPortType();
+ List operations = portType.getOperations();
+
+ // interate all operations in each binding
+ for (int i = 0; i < operations.size(); i++) {
+ Operation operation = (Operation) operations.get(i);
+ ops.add(operation);
+ }
+ }
+
+ return (Operation[])ops.toArray(new Operation[0]);
+
+ }
+
+
+ /**
+ * Searches operations for all the ops with this name.
+ * Returns an array because params of those ops may vary.
+ * @param name
+ * @return
+ */
+ public Operation[] findOperation(String name){
+
+ Operation[] ops=getWsdlOperations();
+ ArrayList ret=new ArrayList();
+ for (int index = 0; index < ops.length; index++) {
+ Operation operation = ops[index];
+ if(operation.getName().equals(name))
+ ret.add(operation);
+ }
+ return (Operation[])ret.toArray(new Operation[0]);
+ }
+
+ /**
+ * Given an operation, returns an array of Parameter names.
+ *
+ * @param op
+ * @return @throws
+ * ClassNotFoundException
+ * @throws InvocationTargetException
+ * @throws IllegalAccessException
+ * @throws NoSuchMethodException
+ * @throws IllegalArgumentException
+ * @throws SecurityException
+ */
+ public String[] getParameters(Operation op) throws SecurityException,
+ IllegalArgumentException, ClassNotFoundException,
+ NoSuchMethodException, IllegalAccessException,
+ InvocationTargetException {
+ Map bindings = m_definition.getBindings();
+ Iterator iterator = bindings.values().iterator();
+ ArrayList parameters = new ArrayList();
+
+ // Iterate though all bindings
+ while (iterator.hasNext()) {
+ Binding binding = (Binding) iterator.next();
+ PortType portType = binding.getPortType();
+ List operations = portType.getOperations();
+
+ // iterate all operations in each binding
+ for (int i = 0; i < operations.size(); i++) {
+ Operation operation = (Operation) operations.get(i);
+ if (op == operation) {
+ Input in = operation.getInput();
+ Message message = in.getMessage();
+ Map parts = message.getParts();
+ for (Iterator iter = parts.keySet().iterator(); iter
+ .hasNext();) {
+ Part part = (Part) parts.get(iter.next());
+ QName ElementName = part.getElementName();
+ getParamInfoFromBeanClassName(parameters, ElementName);
+ }
+ }
+ }
+ return (String[]) parameters.toArray(new String[0]);
+ }
+ return null;
+ }
+
+ /**
+ * @param parameters
+ * @param xmlBeanClassName
+ * @throws ClassNotFoundException
+ * @throws NoSuchMethodException
+ * @throws IllegalAccessException
+ * @throws InvocationTargetException
+ */
+ private void getParamInfoFromBeanClassName(ArrayList parameters,
+ QName schemaType) throws ClassNotFoundException,
+ NoSuchMethodException, IllegalAccessException,
+ InvocationTargetException {
+ XmlObject instance = getEmptyInstanceOfXMLBean(schemaType);
+ Class xmlBeanClass = instance.getClass();
+ String docObjMethodName = getMethodNameForDocumentImpl(xmlBeanClass);
+ Method docObjMethod = xmlBeanClass.getMethod(docObjMethodName, null);
+ Class returnType = docObjMethod.getReturnType();
+
+ Method[] methods = returnType.getDeclaredMethods();
+ for (int j = 0; j < methods.length; j++) {
+ Method method = methods[j];
+ String methType = method.getReturnType().getName();
+ if (method.getName().matches("^get.+")) {
+ String paramName = method.getName().replaceFirst("get", "");
+ parameters.add(paramName + "[" + methType + "]");
+
+ }
+ }
+ }
+
+ private String getMethodNameForDocumentImpl(Class ImplClass) {
+ String name = ImplClass.getName();
+ String[] nameParts = name.split("\\.");
+ String rootClassName = nameParts[nameParts.length - 1];
+ String rootNoImpl = rootClassName.replaceFirst("DocumentImpl", "");
+ return "get" + rootNoImpl;
+
+ }
+
+ public XmlObject[] execute(Operation operation, Map parameters)
+ throws Exception {
+ return execute(operation,parameters,null);
+ }
+
+ public XmlObject[] execute(Operation operation, Map parameters,String resourceID)
+ throws Exception {
+
+ // Use the operation to get the first part element name
+ String textRequest="";
+
+ if(operation.getInput().getMessage().getParts().size()>0){
+ QName element = getFirstPartElementQName(operation.getInput());
+ textRequest = createRequestHavingComplexTypeArgs(operation, parameters,element);
+ } else {
+ textRequest = createRequestHavingNativeOrNoArgs(operation, parameters);
+ }
+
+ EnvelopeWrapper returnedSoapElements = sendSoapRequest(m_targetURL, textRequest, resourceID);
+ BodyWrapper body = returnedSoapElements.getBodyWrapper();
+ return body.getBodyElements();
+ }
+
+ /**
+ * @param operation
+ * @param parameters
+ * @param element
+ * @return
+ * @throws SecurityException
+ * @throws IllegalArgumentException
+ * @throws NoSuchMethodException
+ * @throws IllegalAccessException
+ * @throws InvocationTargetException
+ * @throws ClassNotFoundException
+ */
+ private String createRequestHavingNativeOrNoArgs(Operation operation, Map parameters) throws SecurityException, IllegalArgumentException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+
+ // It is quite likely that this type of request will show no parts
+ // Forced to use MessageImpl to get QName to create XML Bean
+ MessageImpl message = (MessageImpl)operation.getInput().getMessage();
+ QName elementName=message.getQName();
+ XmlObject requestDocument = null;
+ try {
+ requestDocument = getEmptyInstanceOfXMLBean(elementName);
+ } catch (ClassNotFoundException e){
+ // Build a no args request
+ return "<reqns:"+operation.getName()+" xmlns:reqns=\""+elementName.getNamespaceURI()+"\"/>";
+ }
+ if(parameters!=null){
+ // Using only the first and only parameter
+ // This may not be a valid assumtion
+ // Calling set(InsertRequestElementName) with the first passed parameter.
+ Iterator iter1 = parameters.keySet().iterator();
+ Object paramValue = parameters.get(iter1.next());
+ String requestBaseName=elementName.getLocalPart();
+ String nameOfAddNewOperation = "set" + requestBaseName;
+
+ // Debug
+ Method setterForComplexType=null;
+ try {
+ setterForComplexType = requestDocument.getClass().getMethod(
+ nameOfAddNewOperation, new Class[]{paramValue.getClass()});
+ } catch(NoSuchMethodException e){
+
+ return createRequestHavingComplexTypeArgs(operation, parameters,elementName);
+ }
+ setterForComplexType.invoke(
+ requestDocument, new Object[]{paramValue});
+ }
+
+ XmlOptions opts = new XmlOptions();
+ opts.setSaveOuter();
+ String textRequest = ((XmlObject) requestDocument).xmlText(opts);
+ return textRequest;
+ }
+
+ /**
+ * @param operation
+ * @param parameters
+ * @param element
+ * @return
+ * @throws ClassNotFoundException
+ * @throws NoSuchMethodException
+ * @throws IllegalAccessException
+ * @throws InvocationTargetException
+ * @throws NoClassDefFoundError
+ */
+ private String createRequestHavingComplexTypeArgs(Operation operation, Map parameters,QName element) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, NoClassDefFoundError {
+ String textRequestParams;
+ String textRequest;
+
+
+ // Use the element to manufacture an request instance
+
+ XmlObject requestDocument = getEmptyInstanceOfXMLBean(element);
+
+ // extract the baseClassName for the XMLBean
+ String className = getElementXmlBeanClassName(element);
+ String[] classParts = className.split("\\.");
+ String requestBaseName = classParts[classParts.length - 1];
+
+ // Determine then AddNew+BaseClassName operation name the request object
+ String nameOfAddNewOperation = "addNew" + requestBaseName;
+
+ // Determine if addnew+BaseClassName method exists
+ Method[] methodsOfDocument = requestDocument.getClass().getMethods();
+ boolean addNewExists=false;
+ for (int i = 0; i < methodsOfDocument.length; i++) {
+ Method method = methodsOfDocument[i];
+ if(method.getName().equals(nameOfAddNewOperation)){
+ addNewExists=true;
+ break;
+ }
+ }
+
+ // If it does exist then this request has a body
+ // the return value of addnew is the request document
+ Object requestObject;
+ if(addNewExists) {
+ Method methodForAddNewOperation = requestDocument.getClass().getMethod(
+ nameOfAddNewOperation, null);
+ requestObject = methodForAddNewOperation.invoke(
+ requestDocument, null);
+
+
+ // Fill in the complex type with the parameters passed in
+ for (Iterator iterator = parameters.keySet().iterator(); iterator
+ .hasNext();) {
+ String paramName = (String) iterator.next();
+ String methodName = "set" + capitalize(paramName);
+ Object paramValue = parameters.get(paramName);
+
+ Class requestClass = requestObject.getClass();
+ Method setterMethod = null;
+
+ try{
+ setterMethod = requestClass.getMethod(methodName,
+ new Class[] { paramValue.getClass() });
+ } catch (Throwable e){
+ }
+
+ if(setterMethod==null){
+ Class[] interfaces = paramValue.getClass().getInterfaces();
+ for (int index = 0; index < interfaces.length; index++) {
+ Class interface1 = interfaces[index];
+ try{
+ setterMethod = requestClass.getMethod(methodName,
+ new Class[] { interface1 });
+ break;
+ } catch (Throwable e){
+ }
+
+ }
+ }
+ setterMethod.invoke(requestObject,
+ new Object[] { paramValue });
+ }
+
+ // Save request using forced Requestname to match operation (Sal wants this fixed)
+ XmlOptions opts = new XmlOptions();
+ opts.setSaveOuter();
+ XmlCursor cursor = requestDocument.newCursor();
+ StringBuffer buff= new StringBuffer();
+ cursor.toFirstChild();
+ cursor.toFirstChild();
+ buff.append(cursor.toString());
+ while(cursor.toNextSibling()){
+ buff.append(cursor.toString());
+ }
+ cursor.dispose();
+ textRequestParams=buff.toString();
+
+ // Build the enclosing node containing the operation
+ String opName=operation.getName();
+ String opNamespace=m_definition.getTargetNamespace();
+ textRequest="<oper:"+opName+" xmlns:oper=\""+opNamespace+"\" >"+textRequestParams+"</oper:"+opName+">";
+
+
+ } else {
+ // This will occur when the request is not a complex type
+ // an example of this is when the request is a QName such as GetResourcePropertiesReq
+
+ Iterator iter = parameters.keySet().iterator();
+ Object paramValue = parameters.get(iter.next());
+
+ nameOfAddNewOperation = "set" + requestBaseName;
+
+ Method setterForComplexType = requestDocument.getClass().getMethod(
+ nameOfAddNewOperation, new Class[]{paramValue.getClass()});
+ setterForComplexType.invoke(
+ requestDocument, new Object[]{paramValue});
+ requestObject = requestDocument;
+
+ XmlOptions opts = new XmlOptions();
+ opts.setSaveOuter();
+ //opts.setSaveInner();
+ textRequest = ((XmlObject) requestDocument).xmlText(opts);
+
+ }
+ return textRequest;
+ }
+
+ /**
+ * @param input
+ */
+ private QName getFirstPartElementQName(Input input) {
+ if (input.getMessage() == null) {
+ return null;
+ }
+ Map parts = input.getMessage().getParts();
+ if (parts == null)
+ return null;
+ Iterator iter = parts.keySet().iterator();
+ if (!iter.hasNext())
+ {
+ // Might have native parts
+ return null;
+ }
+ Object partName = iter.next();
+ Part part = (Part) parts.get(partName);
+ return part.getElementName();
+ }
+
+ protected static EnvelopeWrapper sendSoapRequest(URL endpointURL, String xmlText)
+ throws Exception {
+ return sendSoapRequest(endpointURL, xmlText,null);
+ }
+
+ protected static EnvelopeWrapper sendSoapRequest(URL endpointURL, String xmlText,String resourceID)
+ throws Exception {
+ SOAPMessage soapRequestMsg = MessageFactory.newInstance()
+ .createMessage();
+ SOAPEnvelope envelope = soapRequestMsg.getSOAPPart().getEnvelope();
+
+ // Add addressing headers
+ AddressingHeaders addHeader=new AddressingHeaders(envelope);
+ addHeader.setSetMustUnderstand(false);
+ addHeader.setAction(endpointURL.toString()+"/action");
+ // wire TODO Broken to build
+ //addHeader.setTo(new To(endpointURL.toString()));
+ if(!(resourceID==null||resourceID.equals("Singleton"))){
+ ReferencePropertiesType refProperty = new ReferencePropertiesType();
+// refProperty.append(makeResourceIdElement(resourceID),null);
+ refProperty.add(makeResourceIdElement(resourceID));
+ addHeader.setReferenceProperties(refProperty);
+ }
+ addHeader.toEnvelope(envelope,"http://schemas.xmlsoap.org/soap/actor/next");
+ // THis must be restored body.addDocument(JaxpUtils.toDocument(xmlText));
+ SOAPConnection soapConn = SOAPConnectionFactory.newInstance()
+ .createConnection();
+
+ SOAPMessage soapResponseMsg = soapConn.call(soapRequestMsg, endpointURL
+ .toString());
+ soapConn.close();
+ EnvelopeWrapper wrapper = new EnvelopeWrapper(soapResponseMsg);
+ return wrapper;
+
+
+ }
+
+ private static String capitalize(String input){
+ String firstLetter=input.substring(0,1);
+ return firstLetter.toUpperCase()+input.substring(1);
+ }
+
+ private static Element makeResourceIdElement(String resourceId)
+ throws Exception {
+ String xmlText="<muse-wsa:ResourceID xmlns:muse-wsa=\"urn:proposedstandard.org/muse/addressing\">"+resourceId+"</muse-wsa:ResourceID>";
+ //<ns3:ResourceID SOAP-ENV:actor="http://schemas.xmlsoap.org/soap/actor/next" SOAP-ENV:mustUnderstand="0" xmlns:ns3="http://www.apache.org/props">1234</ns3:ResourceID>
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ DocumentBuilder builder = dbf.newDocumentBuilder();
+ ByteArrayInputStream bais = new ByteArrayInputStream(xmlText.getBytes());
+ Document d = builder.parse(bais);
+ Element xmlRoot = d.getDocumentElement();
+ return xmlRoot;
+}
+
+}
\ No newline at end of file
Added: webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/EnvelopeWrapper.java
URL: http://svn.apache.org/viewcvs/webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/EnvelopeWrapper.java?rev=320783&view=auto
==============================================================================
--- webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/EnvelopeWrapper.java (added)
+++ webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/EnvelopeWrapper.java Thu Oct 13 08:19:35 2005
@@ -0,0 +1,80 @@
+/*=============================================================================*
+ * Confidential Copyright (c) 2004 Hewlett-Packard Development Company, L.P. *
+ *=============================================================================*/
+package org.apache.ws.client.muse.client.impl.dynamic;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import javax.xml.soap.SOAPException;
+import javax.xml.soap.SOAPMessage;
+
+import org.apache.ws.util.IoUtils;
+import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlObject;
+import org.xmlsoap.schemas.soap.envelope.Envelope;
+import org.xmlsoap.schemas.soap.envelope.EnvelopeDocument;
+
+/**
+ * Wraps an XmlBean Envelope (or a javax.xml.soap.SOAPMessage class) to provide
+ * utility methods for getting at the XmlBean objects.
+ *
+ * @author Ian Springer, Sal Campana
+ */
+public class EnvelopeWrapper
+{
+ private Envelope m_envelope;
+
+ /**
+ * Constructor. Takes an XmlBean Envelope type.
+ *
+ * @param envelope
+ */
+ public EnvelopeWrapper( Envelope envelope )
+ {
+ m_envelope = envelope;
+ }
+
+ /**
+ * Constructor. Takes a java.xml.soap.SOAPMessage type and converts
+ * it to an XmlObject Envelope type inside the wrapper.
+ *
+ * @param message
+ * @throws IOException
+ * @throws SOAPException
+ * @throws XmlException
+ */
+ public EnvelopeWrapper( SOAPMessage message )
+ throws IOException,
+ SOAPException,
+ XmlException
+ {
+ ByteArrayOutputStream byteout = new ByteArrayOutputStream( );
+ message.writeTo( byteout );
+ ByteArrayInputStream byteinput = IoUtils.toByteArrayInputStream( byteout );
+ m_envelope = ((EnvelopeDocument) XmlObject.Factory.parse( byteinput )).getEnvelope();
+ byteout.close( );
+ byteinput.close( );
+ }
+
+ /**
+ * Returns the BodyWrapper class for accessing the body XmlObjects
+ *
+ * @return BodyWrapper
+ */
+ public BodyWrapper getBodyWrapper( )
+ {
+ return new BodyWrapper( m_envelope.getBody( ) );
+ }
+
+ /**
+ * Returns the HeaderWrapper class for accessing the header XmlObjects
+ *
+ * @return HeaderWrapper
+ */
+ public HeaderWrapper getHeaderWrapper( )
+ {
+ return new HeaderWrapper( m_envelope.getHeader( ) );
+ }
+}
\ No newline at end of file
Added: webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/HeaderWrapper.java
URL: http://svn.apache.org/viewcvs/webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/HeaderWrapper.java?rev=320783&view=auto
==============================================================================
--- webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/HeaderWrapper.java (added)
+++ webservices/muse/trunk/client/src/java/org/apache/ws/client/muse/client/impl/dynamic/HeaderWrapper.java Thu Oct 13 08:19:35 2005
@@ -0,0 +1,86 @@
+/*=============================================================================*
+ * Confidential Copyright (c) 2004 Hewlett-Packard Development Company, L.P. *
+ *=============================================================================*/
+package org.apache.ws.client.muse.client.impl.dynamic;
+
+import org.apache.xmlbeans.XmlCursor;
+import org.apache.xmlbeans.XmlObject;
+import org.xmlsoap.schemas.soap.envelope.Header;
+import javax.xml.namespace.QName;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Wraps an XmlBean generated Header to provide
+ * utility methods for getting at the XmlBean objects.
+ *
+ * @author Ian Springer, Sal Campana
+ */
+public class HeaderWrapper
+{
+ private Header m_header;
+
+ /**
+ * Creates a new {@link HeaderWrapper} object.
+ *
+ * @param header
+ */
+ public HeaderWrapper( Header header )
+ {
+ m_header = header;
+ }
+
+ /**
+ * Returns the top-level elements from the header as an XmlBean Object[].
+ *
+ * @return XmlObject[] of header elements
+ */
+ public XmlObject[] getHeaderElements( )
+ {
+ if ( m_header == null )
+ {
+ return new XmlObject[0];
+ }
+
+ XmlCursor xmlCursor = m_header.newCursor( );
+ xmlCursor.toNextToken( );
+
+ //get the first child of the body i.e. the response message, or fault
+ XmlObject xmlBeanResponseMessage = xmlCursor.getObject( );
+ List xmlObjects = new ArrayList( );
+ xmlObjects.add( xmlBeanResponseMessage );
+
+ //add the rest of the top-level-elements to the list
+ while ( xmlCursor.toNextSibling( ) )
+ {
+ xmlObjects.add( xmlCursor.getObject( ) );
+ }
+
+ return (XmlObject[]) xmlObjects.toArray( new XmlObject[0] );
+ }
+
+ /**
+ * Returns the top-level header elements with the specified name.
+ *
+ * @return the top-level header elements with the specified name
+ */
+ public XmlObject[] getHeaderElements( QName qName )
+ {
+ if ( qName == null )
+ {
+ throw new IllegalArgumentException( "Null name is not allowed." );
+ }
+
+ XmlObject[] allHeaderElems = getHeaderElements( );
+ List headerElems = new ArrayList( );
+ for ( int i = 0; i < allHeaderElems.length; i++ )
+ {
+ if ( qName.equals( allHeaderElems[i].schemaType( ).getName( ) ) )
+ {
+ headerElems.add( allHeaderElems[i] );
+ }
+ }
+
+ return (XmlObject[]) headerElems.toArray( new XmlObject[0] );
+ }
+}
\ No newline at end of file