/*=============================================================================*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*=============================================================================*/
package org.apache.ws.resource.tool;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.ws.resource.ResourceDefinition;
import org.apache.ws.resource.i18n.Keys;
import org.apache.ws.resource.i18n.MessagesImpl;
import org.apache.ws.resource.impl.ResourceDefinitionImpl;
import org.apache.ws.resource.tool.velocity.ImplementsListBuilder;
import org.apache.ws.resource.tool.velocity.ServiceProperties;
import org.apache.ws.util.XmlBeanNameUtils;
import org.apache.ws.util.OperationInfo;
import org.apache.ws.util.i18n.Messages;
import org.apache.ws.util.velocity.CommonsLogLogSystem;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.impl.common.XmlErrorPrinter;
import org.apache.xmlbeans.impl.common.NameUtil;
import org.apache.xmlbeans.impl.tool.SchemaCompiler;
import javax.wsdl.Definition;
import javax.wsdl.Port;
import javax.wsdl.Service;
import javax.wsdl.Fault;
import javax.wsdl.Message;
import javax.wsdl.Part;
import javax.wsdl.factory.WSDLFactory;
import javax.wsdl.xml.WSDLReader;
import javax.xml.namespace.QName;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.FilenameFilter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
/**
* Generates Java Web service types and skeletons from a WSRF WSDL.
*
* @author Ian Springer (ian DOT springer AT hp DOT com)
*/
public class Wsdl2Java
{
private static final Messages MSG = MessagesImpl.getInstance();
/**
* DOCUMENT_ME
*/
protected static final Options CMD_LINE_OPTIONS = new Options();
static
{
initCmdLineOptions();
}
private File[] m_wsdlFiles;
private Wsdl2JavaOptions m_options;
private Map m_portTypeInfoMap = new HashMap();
private WSDLReader m_wsdlReader;
private File m_outputDir;
private File[] m_classpath;
private File m_xmlbeansDir;
protected String WEBAPP_NAME = "wsrf";
/**
* Creates a new {@link Wsdl2Java} object.
*
* @param wsdlFiles DOCUMENT_ME
* @param outputDir DOCUMENT_ME
* @param classpathFiles
* @param options DOCUMENT_ME
*/
public Wsdl2Java( File[] wsdlFiles,
File outputDir,
File[] classpathFiles,
Wsdl2JavaOptions options ) throws Exception
{
m_wsdlFiles = wsdlFiles;
if ( m_wsdlFiles.length == 0 )
{
System.out.println( MSG.getMessage( Keys.WARN_EMPTY_WSDLS ) );
}
for (int i = 0; i < wsdlFiles.length; i++)
{
File wsdlFile = wsdlFiles[i];
if(!wsdlFile.getName().endsWith(".wsdl"))
{
System.out.println(MSG.getMessage( Keys.ERROR_ONLY_WSDLS , wsdlFile.getName()));
System.exit(0);
}
}
m_outputDir = outputDir;
m_xmlbeansDir = new File( m_outputDir, ".xmlbeans" );
m_classpath = classpathFiles;
validateClasspath();
m_options = ( options != null ) ? options : new Wsdl2JavaOptions();
m_wsdlReader = WSDLFactory.newInstance().newWSDLReader();
initVelocity();
initPortTypeInfoMap();
}
private void validateClasspath()
throws MalformedURLException
{
URLClassLoader cpClassLoader = new URLClassLoader( toURLs( m_classpath ), null );
try
{
cpClassLoader.loadClass( XmlObject.class.getName() );
}
catch ( ClassNotFoundException cnfe )
{
throw new IllegalStateException( "Specified classpath must contain the XMLBeans runtime jar (e.g. xbean-v1HEAD-SNAPSHOT-20041129.jar)" );
}
try
{
cpClassLoader.loadClass( org.oasisOpen.docs.wsrf.x2004.x06.wsrfWSResourceProperties12Draft01.GetResourcePropertyDocument.class.getName() );
}
catch ( ClassNotFoundException cnfe )
{
throw new IllegalStateException( "Specified classpath must contain the WSRF generated XMLBeans jar (e.g. wsrf-xbeans-SNAPSHOT.jar)" );
}
}
private URL[] toURLs( File[] files ) throws MalformedURLException
{
URL[] urls = new URL[files.length];
for ( int i = 0; i < files.length; i++ )
{
urls[i] = files[i].toURL();
}
return urls;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public Wsdl2JavaOptions getOptions()
{
return m_options;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public File getOutputDir()
{
return m_outputDir;
}
/**
* DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
public File[] getWsdlFiles()
{
return m_wsdlFiles;
}
/**
* DOCUMENT_ME
*
* @throws Exception DOCUMENT_ME
*/
public void generate()
throws Exception
{
for ( int i = 0; i < m_wsdlFiles.length; i++ )
{
processWsdlFile( m_wsdlFiles[i] );
}
}
private void processWsdlFile( File wsdlFile )
throws Exception
{
System.out.println( "Processing WSDL file \"" + wsdlFile + "\"..." );
Definition def = m_wsdlReader.readWSDL( wsdlFile.getPath() );
generateXmlBeans( wsdlFile );
Iterator serviceIter = def.getServices().values().iterator();
while ( serviceIter.hasNext() )
{
Service service = (Service) serviceIter.next();
Iterator iterator = service.getPorts().values().iterator();
while (iterator.hasNext())
{
Port port = (Port) iterator.next();
ResourceDefinition resourceDef = new ResourceDefinitionImpl( def, port, wsdlFile.toURL());
File serviceDir = new File( m_outputDir, resourceDef.getName() );
System.out.println( "Processing WSRF WSDL port \"" + resourceDef.getName() + "\"..." );
processTemplates( resourceDef, wsdlFile, serviceDir );
copyWsdlFile( wsdlFile, serviceDir );
}
}
}
/**
* DOCUMENT_ME
*
* @param args DOCUMENT_ME
*
* @throws ParseException DOCUMENT_ME
*/
public static void main( String[] args )
throws ParseException
{
CommandLine cmdLine = new PosixParser().parse( CMD_LINE_OPTIONS, args, true );
checkForRequiredOption( cmdLine, Opts.OUTPUT_DIR );
checkForRequiredOption( cmdLine, Opts.CLASSPATH );
File outputDir = new File( cmdLine.getOptionValue( Opts.OUTPUT_DIR ) );
File[] classpathFiles = toFileArray( cmdLine.getOptionValue( Opts.CLASSPATH ) );
Wsdl2JavaOptions options = new Wsdl2Java.Wsdl2JavaOptions();
if ( cmdLine.hasOption( Opts.VERBOSE ) )
{
options.setVerbose( Boolean.valueOf( cmdLine.getOptionValue( Opts.VERBOSE ) ).booleanValue() );
}
File[] wsdlFiles = new File[cmdLine.getArgs().length];
for ( int i = 0; i < cmdLine.getArgs().length; i++ )
{
wsdlFiles[i] = new File( cmdLine.getArgs()[i] );
}
try
{
System.out.println( MSG.getMessage( Keys.WSDL4J_PASSED_ARGUMENTS,
Integer.toString( wsdlFiles.length ),
outputDir ) );
new Wsdl2Java( wsdlFiles, outputDir, classpathFiles, options ).generate();
}
catch ( Exception e )
{
e.printStackTrace();
System.exit( 1 );
}
}
/**
* DOCUMENT_ME
*
* @param ptName DOCUMENT_ME
*
* @return DOCUMENT_ME
*/
protected PortType2JavaInfo getPortType2JavaInfo( QName ptName )
{
return (PortType2JavaInfo) m_portTypeInfoMap.get( ptName );
}
/**
* DOCUMENT_ME
*
* @param ptInfo DOCUMENT_ME
*/
protected void addPortType2JavaInfo( PortType2JavaInfo ptInfo )
{
m_portTypeInfoMap.put( ptInfo.getName(), ptInfo );
}
private static void checkForRequiredOption( CommandLine cmdLine,
String opt )
{
if ( !cmdLine.hasOption( opt ) )
{
System.err.println( MSG.getMessage( Keys.OPT_REQUIRED, opt ) );
System.exit( 1 );
}
}
private static void initCmdLineOptions()
{
CMD_LINE_OPTIONS.addOption( Opts.OUTPUT_DIR,
LongOpts.OUTPUT_DIR,
true,
MSG.getMessage( Keys.OPT_OUTPUT_DIR_FOR_GEN_SRC ) );
CMD_LINE_OPTIONS.addOption( Opts.CLASSPATH,
LongOpts.CLASSPATH,
true,
MSG.getMessage( Keys.OPT_CLASSPATH_SENT_TO_XMLBEANS ) );
CMD_LINE_OPTIONS.addOption( Opts.VERBOSE,
LongOpts.VERBOSE,
false,
MSG.getMessage( Keys.OPT_ENABLE_VERBOSE ) );
}
private String getJarFileName( File wsdlFile )
{
String wsdlFileName = wsdlFile.getName();
String baseName = wsdlFileName.substring( 0, wsdlFileName.lastIndexOf( "." ) );
return baseName + "-xbeans.jar";
}
private File getPackageDir( String targetNamespace, File serviceDir )
{
String javaPackageName = GenerationUtils.getJavaPackageName( targetNamespace );
File javaDir = new File( serviceDir, "src/java" );
return new File( javaDir,
javaPackageName.replace( '.', '/' ) );
}
private File getTempDir()
{
String userTempDir = System.getProperty( "java.io.tmpdir" );
File userDir = new File( userTempDir );
userDir.mkdirs();
File tempClassesDir = new File( userDir, "tmp" + new Date().getTime() );
tempClassesDir.mkdir();
return tempClassesDir;
}
protected ServiceProperties buildServiceProperties( ResourceDefinition resourceDef,
File wsdlFile,
File serviceDir )
{
ServiceProperties props = new ServiceProperties(resourceDef);
String targetNamespace = resourceDef.getDefinition().getTargetNamespace();
props.setPackageName( GenerationUtils.getJavaPackageName( targetNamespace ) );
String serviceName = resourceDef.getName();
String capitalizedServiceName = StringUtils.capitalize( serviceName );
props.setServiceName( capitalizedServiceName );
props.setSrcDir( new File( serviceDir, "src/java" ).getAbsolutePath() );
props.setJarDir( new File(m_xmlbeansDir,"lib").getAbsolutePath() );
props.setJarFileName( getJarFileName( wsdlFile ) );
props.setClassesDir( new File( serviceDir, "classes" ).getAbsolutePath() );
props.setEndpointURL( resourceDef.getEndpointURL() );
props.setEndpointServiceName( serviceName );
props.setServiceImplements( ImplementsListBuilder.getServiceImplementsList( resourceDef, m_portTypeInfoMap ) );
props.setNamespace( targetNamespace );
props.setPrefix( GenerationUtils.getPrefix( targetNamespace ) );
props.setCustomMappings( GenerationUtils.getOperationInfoMap( resourceDef ) );
props.setHasProperties( resourceDef.hasProperties() );
props.setWebappName(getWebbappName());
if (resourceDef.hasProperties())
{
QName[] propertyNames = resourceDef.getPropertyNames();
Map propMap = new HashMap();
for ( int i = 0; i < propertyNames.length; i++ )
{
QName propertyName = propertyNames[i];
String propName = getJavaConstantName( propertyName, propMap );
propMap.put( propName, propertyName );
}
props.setPropertyMap( propMap );
}
// define the names of the resource props that we initialize for the user...
props.addImplementedProperty(org.apache.ws.resource.lifetime.v2004_06.porttype.ScheduledResourceTerminationPortType.PROP_QNAME_TERMINATION_TIME);
props.addImplementedProperty(org.apache.ws.resource.lifetime.v2004_06.porttype.ScheduledResourceTerminationPortType.PROP_QNAME_CURRENT_TIME);
props.addImplementedProperty(org.apache.ws.resource.lifetime.v2004_11.porttype.ScheduledResourceTerminationPortType.PROP_QNAME_TERMINATION_TIME);
props.addImplementedProperty(org.apache.ws.resource.lifetime.v2004_11.porttype.ScheduledResourceTerminationPortType.PROP_QNAME_CURRENT_TIME);
props.setResourceImplements( ImplementsListBuilder.getResourceImplementsList( resourceDef, m_portTypeInfoMap ) );
QName propertiesDocumentName = resourceDef.getPropertiesDocumentName();
if( propertiesDocumentName != null)
{
props.setPropertyDocumentName(
XmlBeanNameUtils.getDocumentElementXmlBeanClassName(
propertiesDocumentName ) );
}
props.setWsdlName( wsdlFile.getName() );
props.setResourcekey( new QName( targetNamespace, "ResourceIdentifier" ) );
Iterator ptNameIter = resourceDef.getImplementedResourceCapabilities().keySet().iterator();
while ( ptNameIter.hasNext() )
{
QName ptName = (QName) ptNameIter.next();
PortType2JavaInfo ptInfo = (PortType2JavaInfo) m_portTypeInfoMap.get( ptName );
if ( ptInfo != null )
{
if ( ptInfo.getResourceTemplateFileName() != null )
{
props.addResourceIncludeFile( ptInfo.getResourceTemplateFileName() );
}
if ( ptInfo.getResourceInitMethodIncludeLocation() != null )
{
props.addResourceInitIncludeLocation( ptInfo.getResourceInitMethodIncludeLocation() );
}
if ( ptInfo.getAbstractResourceInitMethodIncludeLocation() != null )
{
props.addAbstractResourceInitIncludeLocation( ptInfo.getAbstractResourceInitMethodIncludeLocation() );
}
if ( ptInfo.getServiceTemplateFileName() != null )
{
props.addServiceIncludeFile( ptInfo.getServiceTemplateFileName() );
}
}
else
{
System.err.println("\n\nUnable to find a port type info for the implemented capability: " + ptName.toString() + "!!!!!!\n\n");
}
}
if(isDraft01Specific(resourceDef))
{
props.setNamespaceVersionHolder(org.apache.ws.resource.properties.v2004_06.impl.NamespaceVersionHolderImpl.class);
}
else if(isDraft05Specific(resourceDef))
{
props.setNamespaceVersionHolder(org.apache.ws.resource.properties.v2004_11.impl.NamespaceVersionHolderImpl.class);
}
/*
* These props are for JIRA APOLLO-4 and could be added to context obj
* The question is whether the service name here should be the real wsdl
* service name or the service name as we use it...
*/
String portName = resourceDef.getPort().getName();
props.setPortName(portName);
QName portTypeQName = resourceDef.getPortType().getQName();
props.setPortTypeQName(portTypeQName);
QName serviceQname = new QName(targetNamespace,serviceName);
props.setServiceQName(serviceQname);
return props;
}
private String getJavaConstantName( QName propertyName, Map propMap )
{
String constName = propertyName.getLocalPart().toUpperCase();
for ( int count = 2; propMap.containsKey( constName ); count++ )
{
constName += count;
}
return constName;
}
protected String getWebbappName()
{
return WEBAPP_NAME;
}
private boolean isDraft05Specific(ResourceDefinition resourceDef)
{
return resourceDef.implementsResourceCapability(org.apache.ws.resource.properties.v2004_11.porttype.GetMultipleResourcePropertiesPortType.NAME)
|| resourceDef.implementsResourceCapability(org.apache.ws.resource.properties.v2004_11.porttype.GetResourcePropertyDocumentPortType.NAME)
|| resourceDef.implementsResourceCapability(org.apache.ws.resource.properties.v2004_11.porttype.DeleteResourcePropertiesPortType.NAME)
|| resourceDef.implementsResourceCapability(org.apache.ws.resource.properties.v2004_11.porttype.GetResourcePropertyPortType.NAME)
|| resourceDef.implementsResourceCapability(org.apache.ws.resource.properties.v2004_11.porttype.InsertResourcePropertiesPortType.NAME)
|| resourceDef.implementsResourceCapability(org.apache.ws.resource.properties.v2004_11.porttype.QueryResourcePropertiesPortType.NAME)
|| resourceDef.implementsResourceCapability(org.apache.ws.resource.properties.v2004_11.porttype.SetResourcePropertiesPortType.NAME)
|| resourceDef.implementsResourceCapability(org.apache.ws.resource.properties.v2004_11.porttype.UpdateResourcePropertiesPortType.NAME);
}
private boolean isDraft01Specific(ResourceDefinition resourceDef)
{
return resourceDef.implementsResourceCapability(org.apache.ws.resource.properties.v2004_06.porttype.GetMultipleResourcePropertiesPortType.NAME)
|| resourceDef.implementsResourceCapability(org.apache.ws.resource.properties.v2004_06.porttype.GetResourcePropertyPortType.NAME)
|| resourceDef.implementsResourceCapability(org.apache.ws.resource.properties.v2004_06.porttype.QueryResourcePropertiesPortType.NAME)
|| resourceDef.implementsResourceCapability(org.apache.ws.resource.properties.v2004_06.porttype.SetResourcePropertiesPortType.NAME);
}
private void generateXmlBeans( File wsdlFile )
throws Exception
{
System.out.println( "Generating XMLBeans for WSDL file \"" + wsdlFile + "\"..." );
SchemaCompiler.Parameters scompParams = new SchemaCompiler.Parameters();
scompParams.setSrcDir( new File( m_xmlbeansDir, "src" ) );
File tempClassesDir = getTempDir();
scompParams.setClassesDir( tempClassesDir );
scompParams.setWsdlFiles( new File[]
{
wsdlFile
} );
String xmlbeansJarFileName = getJarFileName( wsdlFile );
File[] classpath = removeJarFromClasspathArray(xmlbeansJarFileName, m_classpath);
scompParams.setClasspath( classpath );
scompParams.setDownload( true ); // download remote xsd inputs/imports
scompParams.setDebug( true ); // compile w/ debug symbols
scompParams.setVerbose( m_options.isVerbose() );
scompParams.setQuiet( ! m_options.isVerbose() );
final boolean beNoisy = true;
XmlErrorPrinter xErrorListener = new XmlErrorPrinter( beNoisy, null );
scompParams.setErrorListener( xErrorListener );
File jarDir = new File( m_xmlbeansDir, "lib" );
jarDir.mkdirs();
scompParams.setOutputJar( new File( jarDir, xmlbeansJarFileName ) );
try
{
if ( !SchemaCompiler.compile( scompParams ) )
{
throw new Exception( xErrorListener.toString() );
}
}
finally
{
//delete the temp directory
FileUtils.deleteDirectory( tempClassesDir );
}
}
/**
* This method is used to remove an existing xmlbeans jar of the same name from the
* array of files passed to scomp. This will avoid the potential deletion of the
* previously generated jar file and scomps lack of regenerating classes for existing jars.
*
* This will ensure scomp generates the jar for the given xbeans jar name.
*
* @param xmlbeansJarFileName
* @param classpath
*/
private File[] removeJarFromClasspathArray(String xmlbeansJarFileName, File[] classpath)
{
List fileList = new ArrayList();
for (int i = 0; i < classpath.length; i++)
{
File file = classpath[i];
if( ! xmlbeansJarFileName.equals(file.getName()))
{
fileList.add(file);
}
else
{
System.out.println("Found existing generated xmlbean jar in the classpath at location: " + file.toString() +
" ...This will be removed from the classpath sent to Scomp in order " +
"to regenerate all imports.");
}
}
return (File[])fileList.toArray(new File[0]);
}
private void copyWsdlFile( File wsdlFile, File serviceDir )
throws IOException
{
File javaDir = new File( serviceDir, "src" );
File wsdlDir = new File( javaDir, "wsdl" );
wsdlDir.mkdirs();
FileUtils.copyFile( wsdlFile, new File( wsdlDir, wsdlFile.getName() ) );
}
private void initPortTypeInfoMap()
{
//draft 01
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_06.GetResourcePropertyPortType2JavaInfo() );
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_06.GetMultipleResourcePropertiesPortType2JavaInfo() );
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_06.SetResourcePropertiesPortType2JavaInfo() );
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_06.QueryResourcePropertiesPortType2JavaInfo() );
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_06.ImmediateResourceTerminationPortType2JavaInfo() );
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_06.ScheduledResourceTerminationPortType2JavaInfo() );
//draft 05
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_11.GetResourcePropertyPortType2JavaInfo() );
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_11.GetMultipleResourcePropertiesPortType2JavaInfo() );
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_11.SetResourcePropertiesPortType2JavaInfo() );
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_11.QueryResourcePropertiesPortType2JavaInfo() );
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_11.ImmediateResourceTerminationPortType2JavaInfo() );
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_11.ScheduledResourceTerminationPortType2JavaInfo() );
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_11.InsertResourcePropertiesPortType2JavaInfo() );
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_11.UpdateResourcePropertiesPortType2JavaInfo() );
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_11.DeleteResourcePropertiesPortType2JavaInfo() );
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_11.GetResourcePropertyDocumentPortType2JavaInfo() );
//metadataexchange 2004/09
addPortType2JavaInfo( new org.apache.ws.resource.tool.porttype.v2004_09.MetadataExchangePortType2JavaInfo() );
}
private void initVelocity()
throws Exception
{
// configure to use Commons Logging for logging
Velocity.setProperty( RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS, CommonsLogLogSystem.class.getName() );
// don't log warnings for invalid variable references
Velocity.setProperty( RuntimeConstants.RUNTIME_LOG_REFERENCE_LOG_INVALID, "false" );
// don't load any global macro libraries (override default of "VM_global_library.vm")
Velocity.setProperty( RuntimeConstants.VM_LIBRARY, "" );
// configure to use classpath-based resource loader
Velocity.addProperty( RuntimeConstants.RESOURCE_LOADER, "classpath" );
String resourceLoaderBaseKey = "classpath." + RuntimeConstants.RESOURCE_LOADER + ".";
Velocity.setProperty( resourceLoaderBaseKey + "class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader" );
Velocity.setProperty( resourceLoaderBaseKey + "cache", "false" );
Velocity.setProperty( resourceLoaderBaseKey + "modificationCheckInterval", "2" );
Velocity.init();
}
private void processTemplate( VelocityContext context,
String templateLocation,
File outputFile )
throws Exception
{
/*
* get the Template object. This is the parsed version of your
* template input file. Note that getTemplate() can throw
* ResourceNotFoundException : if it doesn't find the template
* ParseErrorException : if there is something wrong with the VTL
* Exception : if something else goes wrong (this is generally
* indicative of a serious problem...)
*/
try
{
Template template = Velocity.getTemplate( templateLocation );
/*
* Now have the template engine process your template using the
* data placed into the context. Think of it as a 'merge'
* of the template and the data to produce the output stream.
*/
FileWriter writer = new FileWriter( outputFile );
if ( template != null )
{
template.merge( context, writer );
}
writer.close();
}
catch ( Exception e )
{
System.err.println( "Error processing template " + templateLocation );
e.printStackTrace();
}
}
/**
* Provides a hook for adding to the Velocity Context.
*
* @param context
* @return VelocityContext
*/
protected VelocityContext updateVelocityContext(VelocityContext context,ResourceDefinition resourceDef)
{
return context;
}
private void processTemplates( ResourceDefinition resourceDef,
File wsdlFile, File serviceDir )
throws Exception
{
String capitalizedServiceName = StringUtils.capitalize( resourceDef.getName() );
try
{
VelocityContext context = new VelocityContext();
ServiceProperties props = buildServiceProperties( resourceDef, wsdlFile, serviceDir );
context.put( "generated", props );
updateVelocityContext(context,resourceDef);
//generate files
File packageDir = getPackageDir( resourceDef.getDefinition().getTargetNamespace(), serviceDir );
packageDir.mkdirs();
File outputFile = new File( packageDir, "Abstract" + capitalizedServiceName + "Service.java" );
processTemplate( context, "templates/AbstractService.vm", outputFile );
outputFile = new File( packageDir, capitalizedServiceName + "Service.java" );
if ( !outputFile.exists() )
{
processTemplate( context, "templates/Service.vm", outputFile );
}
generateFaultClasses( context, props, packageDir );
outputFile = new File( packageDir, "Abstract" + capitalizedServiceName + "Resource.java" );
processTemplate( context, "templates/AbstractResource.vm", outputFile );
outputFile = new File( packageDir, capitalizedServiceName + "Resource.java" );
if ( !outputFile.exists() )
{
processTemplate( context, "templates/Resource.vm", outputFile );
}
outputFile = new File( packageDir, capitalizedServiceName + "Home.java" );
if ( !outputFile.exists() )
{
processTemplate( context, "templates/Home.vm", outputFile );
}
if ( resourceDef.hasProperties() )
{
outputFile = new File( packageDir, capitalizedServiceName + "PropertyQNames.java" );
processTemplate( context, "templates/PropertyQNames.vm", outputFile );
}
outputFile = new File( packageDir, capitalizedServiceName + "_deploy.wsdd" );
processTemplate( context, "templates/deploy.vm", outputFile );
outputFile = new File( packageDir, capitalizedServiceName + "_jndi-config.xml" );
processTemplate( context, "templates/jndi.vm", outputFile );
outputFile = new File( packageDir, capitalizedServiceName + "CustomOperationsPortType.java" );
processTemplate( context, "templates/CustomOperationsPortType.vm", outputFile );
outputFile = new File( serviceDir, "build.xml" );
processTemplate( context, "templates/build.xml.vm", outputFile );
outputFile = new File( serviceDir, "build.properties" );
if ( !outputFile.exists() )
{
processTemplate( context, "templates/build.properties.vm", outputFile );
}
}
catch ( Exception e )
{
e.printStackTrace();
}
}
private void generateFaultClasses( VelocityContext context, ServiceProperties props, File packageDir )
throws Exception
{
File outputFile;
Iterator customOperations = props.getCustomMappings().values().iterator();
while (customOperations.hasNext())
{
OperationInfo oparationInfo = (OperationInfo) customOperations.next();
//need to determine if fault is instanceof BaseFault
Iterator faultIterator = oparationInfo.getFaults().values().iterator();
while (faultIterator.hasNext())
{
Fault fault = (Fault) faultIterator.next();
Message message = fault.getMessage();
Map parts = message.getParts();
if (parts.size() != 1)
{
throw new Exception( "WSDL fault message should have exactly one part." );
}
Part part = (Part) parts.values().iterator().next();
QName faultName = part.getTypeName();
boolean isType=true;
if (faultName == null)
{
faultName = part.getElementName();
isType = false;
}
if (faultName == null)
{
throw new Exception( "WSDL fault message part should have either an element or a type." );
}
String exceptionFaultName = StringUtils.capitalize(faultName.getLocalPart()) + "Exception";
//ok here's the file we'll generate
outputFile = new File(packageDir, exceptionFaultName + ".java");
context.put("faultName", exceptionFaultName);
if (!outputFile.exists())
{
try
{
if (isBaseFaultExtension(faultName, isType))
{
processTemplate(context, "templates/BaseFaultExtension.vm", outputFile);
}
else
{
processTemplate(context, "templates/CustomFault.vm", outputFile);
}
}
catch (Exception e)
{
throw new Exception( "Unable to generate WSDL fault. Cause: " + e, e );
}
}
}
}
}
/**
* Determines if the passed in QName is for a type which extends
* BaseFault.
*
* @param faultName
* @param type
* @return true if the "type" extends BaseFault.
*/
private boolean isBaseFaultExtension(QName faultName, boolean type) throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, NoSuchMethodException
{
String xmlbeanFaultClassName = null;
Class faultClass = null;
URLClassLoader generatedXmlBeanClassloader = getGeneratedXmlBeanClassloader();
if(type)
{
xmlbeanFaultClassName = NameUtil.getClassNameFromQName(faultName);
//type to get an instance of the class
faultClass = generatedXmlBeanClassloader.loadClass(xmlbeanFaultClassName);
}
else
{
//attempt to get the generated "Document" class name
xmlbeanFaultClassName = XmlBeanNameUtils.getDocumentElementXmlBeanFactoryClassName(new QName(faultName.getNamespaceURI(), faultName.getLocalPart()));
//try to load the document class
Class xmlbeanGeneratedClass = generatedXmlBeanClassloader.loadClass(xmlbeanFaultClassName);
//invoke newInstance in the Xmlbean's Factory class
Method method = xmlbeanGeneratedClass.getMethod("newInstance", null);
Object o = method.invoke(xmlbeanGeneratedClass,null);
//invoke the addNew... method on the object to get its type
xmlbeanGeneratedClass = o.getClass();
method = xmlbeanGeneratedClass.getMethod("addNew" + faultName.getLocalPart(), null);
//get the types's Class
faultClass = method.invoke(o,null).getClass();
}
//determine if the class is assignable from any known versions of BaseType
return (org.oasisOpen.docs.wsrf.x2004.x06.wsrfWSBaseFaults12Draft01.BaseFaultType.class.isAssignableFrom(faultClass) ||
org.oasisOpen.docs.wsrf.x2004.x11.wsrfWSBaseFaults12Draft03.BaseFaultType.class.isAssignableFrom(faultClass));
}
/**
* DOCUMENT_ME
*
* @author $author$
* @version $Revision: 1.8 $
*/
static interface LongOpts
{
/**
* DOCUMENT_ME
*/
String OUTPUT_DIR = "outputDir";
/**
* DOCUMENT_ME
*/
String VERBOSE = "verbose";
/**
* DOCUMENT_ME
*/
String CLASSPATH = "classpath";
}
/**
* DOCUMENT_ME
*
* @author $author$
* @version $Revision: 1.8 $
*/
static interface Opts
{
/**
* DOCUMENT_ME
*/
String OUTPUT_DIR = "o";
/**
* DOCUMENT_ME
*/
String VERBOSE = "v";
/**
* DOCUMENT_ME
*/
String CLASSPATH = "C";
}
/**
* DOCUMENT_ME
*
* @author $author$
* @version $Revision: 1.8 $
*/
public static class Wsdl2JavaOptions
{
private boolean m_verbose;
/**
* Enable/disable verbose output.
*
* @param verbose option indicating whether or not to enable verbose output
*/
public void setVerbose( boolean verbose )
{
m_verbose = verbose;
}
/**
* Returns true if verbose output is enabled, or false otherwise.
*
* @return true if verbose output is enabled, or false otherwise
*/
public boolean isVerbose()
{
return m_verbose;
}
}
static File[] toFileArray( String classpath )
{
List classpathItems = new ArrayList();
for ( StringTokenizer tokenizer = new StringTokenizer( classpath, File.pathSeparator );
tokenizer.hasMoreTokens(); )
{
classpathItems.add( new File( tokenizer.nextToken() ) );
}
return (File[]) classpathItems.toArray( new File[0] );
}
private URLClassLoader getGeneratedXmlBeanClassloader()
{
File libDir = new File(m_xmlbeansDir, "lib");
File[] jarFiles = libDir.listFiles(new FilenameFilter(){
public boolean accept(File dir, String name)
{
return name.endsWith(".jar");
}
});
URL[] urls = new URL[jarFiles.length];
for (int i = 0; i < jarFiles.length; i++)
{
try
{
urls[i] = jarFiles[i].toURL();
}
catch (MalformedURLException murle)
{
throw new RuntimeException( "Unable to load XMLBeans-generated jars and convert to URLs. Cause: " + murle, murle );
}
}
return new URLClassLoader(urls, this.getClass().getClassLoader());
}
}