blob: 132c37a1f41eb85bfdd36ee246dafee1ce246d8a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.axis2.jaxbri;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.writer.FileCodeWriter;
import com.sun.tools.xjc.api.ErrorListener;
import com.sun.tools.xjc.api.Mapping;
import com.sun.tools.xjc.api.Property;
import com.sun.tools.xjc.api.S2JJAXBModel;
import com.sun.tools.xjc.api.SchemaCompiler;
import com.sun.tools.xjc.api.XJC;
import com.sun.tools.xjc.BadCommandLineException;
import org.apache.axis2.description.AxisMessage;
import org.apache.axis2.description.AxisOperation;
import org.apache.axis2.description.AxisService;
import org.apache.axis2.util.SchemaUtil;
import org.apache.axis2.util.URLProcessor;
import org.apache.axis2.util.XMLUtils;
import org.apache.axis2.wsdl.WSDLConstants;
import org.apache.axis2.wsdl.WSDLUtil;
import org.apache.axis2.wsdl.codegen.CodeGenConfiguration;
import org.apache.axis2.wsdl.databinding.DefaultTypeMapper;
import org.apache.axis2.wsdl.databinding.JavaTypeMapper;
import org.apache.axis2.wsdl.databinding.TypeMapper;
import org.apache.axis2.wsdl.util.Constants;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.commons.schema.XmlSchema;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import javax.xml.namespace.QName;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.util.*;
import java.net.URLClassLoader;
import java.net.URL;
public class CodeGenerationUtility {
private static final Log log = LogFactory.getLog(CodeGenerationUtility.class);
public static final String BINDING_FILE_NAME = "bindingFileName";
/**
* @param additionalSchemas
* @throws RuntimeException
*/
public static TypeMapper processSchemas(final List schemas,
Element[] additionalSchemas,
CodeGenConfiguration cgconfig)
throws RuntimeException {
try {
//check for the imported types. Any imported types are supposed to be here also
if (schemas == null || schemas.isEmpty()) {
//there are no types to be code generated
//However if the type mapper is left empty it will be a problem for the other
//processes. Hence the default type mapper is set to the configuration
return new DefaultTypeMapper();
}
final Map schemaToInputSourceMap = new HashMap();
//create the type mapper
JavaTypeMapper mapper = new JavaTypeMapper();
String baseURI = cgconfig.getBaseURI();
if (!baseURI.endsWith("/")){
baseURI = baseURI + "/";
}
for (int i = 0; i < schemas.size(); i++) {
XmlSchema schema = (XmlSchema)schemas.get(i);
InputSource inputSource =
new InputSource(new StringReader(getSchemaAsString(schema)));
//here we have to set a proper system ID. otherwise when processing the
// included schaemas for this schema we have a problem
// it creates the system ID using this target namespace value
inputSource.setSystemId(baseURI + "xsd" + i + ".xsd");
inputSource.setPublicId(schema.getTargetNamespace());
schemaToInputSourceMap.put(schema,inputSource);
}
File outputDir = new File(cgconfig.getOutputLocation(), "src");
outputDir.mkdir();
Map nsMap = cgconfig.getUri2PackageNameMap();
EntityResolver resolver = new EntityResolver() {
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
InputSource returnInputSource = null;
XmlSchema key = null;
for (Iterator iter = schemaToInputSourceMap.keySet().iterator();iter.hasNext();) {
key = (XmlSchema) iter.next();
String nsp = key.getTargetNamespace();
if (nsp != null && nsp.equals(publicId)) {
// when returning the input stream we have to always return a new
// input stream.
// sinc jaxbri internally consumes the input stream it gives an
// exception.
returnInputSource = new InputSource(new StringReader(getSchemaAsString(key)));
InputSource existingInputSource = (InputSource) schemaToInputSourceMap.get(key);
returnInputSource.setSystemId(existingInputSource.getSystemId());
returnInputSource.setPublicId(existingInputSource.getPublicId());
break;
}
}
if (returnInputSource == null){
// then we have to find this using the file system
if (systemId != null){
returnInputSource = new InputSource(systemId);
returnInputSource.setSystemId(systemId);
}
}
return returnInputSource;
}
};
Map properties = cgconfig.getProperties();
String bindingFileName = (String) properties.get(BINDING_FILE_NAME);
XmlSchema key = null;
for (Iterator schemaIter = schemaToInputSourceMap.keySet().iterator();
schemaIter.hasNext();) {
SchemaCompiler sc = XJC.createSchemaCompiler();
if (bindingFileName != null){
if (bindingFileName.endsWith(".jar")) {
scanEpisodeFile(new File(bindingFileName), sc);
} else {
InputSource inputSoruce = new InputSource(new FileInputStream(bindingFileName));
inputSoruce.setSystemId(new File(bindingFileName).toURI().toString());
sc.getOptions().addBindFile(inputSoruce);
}
}
key = (XmlSchema) schemaIter.next();
if (nsMap != null) {
Iterator iterator = nsMap.entrySet().iterator();
while(iterator.hasNext()){
Map.Entry entry = (Map.Entry) iterator.next();
String namespace = (String) entry.getKey();
String pkg = (String)nsMap.get(namespace);
registerNamespace(sc, namespace, pkg);
}
}
sc.setEntityResolver(resolver);
sc.setErrorListener(new ErrorListener(){
public void error(SAXParseException saxParseException) {
log.error(saxParseException.getMessage());
log.debug(saxParseException.getMessage(), saxParseException);
}
public void fatalError(SAXParseException saxParseException) {
log.error(saxParseException.getMessage());
log.debug(saxParseException.getMessage(), saxParseException);
}
public void warning(SAXParseException saxParseException) {
log.warn(saxParseException.getMessage());
log.debug(saxParseException.getMessage(), saxParseException);
}
public void info(SAXParseException saxParseException) {
log.info(saxParseException.getMessage());
log.debug(saxParseException.getMessage(), saxParseException);
}
});
sc.parseSchema((InputSource) schemaToInputSourceMap.get(key));
// Bind the XML
S2JJAXBModel jaxbModel = sc.bind();
if(jaxbModel == null){
throw new RuntimeException("Unable to generate code using jaxbri");
}
// Emit the code artifacts
JCodeModel codeModel = jaxbModel.generateCode(null, null);
FileCodeWriter writer = new FileCodeWriter(outputDir);
codeModel.build(writer);
Collection mappings = jaxbModel.getMappings();
Iterator iter = mappings.iterator();
while (iter.hasNext()) {
Mapping mapping = (Mapping)iter.next();
QName qn = mapping.getElement();
String typeName = mapping.getType().getTypeClass().fullName();
mapper.addTypeMappingName(qn, typeName);
}
//process the unwrapped parameters
if (!cgconfig.isParametersWrapped()) {
//figure out the unwrapped operations
List axisServices = cgconfig.getAxisServices();
for (Iterator servicesIter = axisServices.iterator(); servicesIter.hasNext();) {
AxisService axisService = (AxisService)servicesIter.next();
for (Iterator operations = axisService.getOperations();
operations.hasNext();) {
AxisOperation op = (AxisOperation)operations.next();
if (WSDLUtil.isInputPresentForMEP(op.getMessageExchangePattern())) {
AxisMessage message = op.getMessage(
WSDLConstants.MESSAGE_LABEL_IN_VALUE);
if (message != null &&
message.getParameter(Constants.UNWRAPPED_KEY) != null) {
Mapping mapping = jaxbModel.get(message.getElementQName());
List elementProperties = mapping.getWrapperStyleDrilldown();
for(int j = 0; j < elementProperties.size(); j++){
Property elementProperty = (Property) elementProperties.get(j);
QName partQName =
WSDLUtil.getPartQName(op.getName().getLocalPart(),
WSDLConstants.INPUT_PART_QNAME_SUFFIX,
elementProperty.elementName().getLocalPart());
//this type is based on a primitive type- use the
//primitive type name in this case
String fullJaveName =
elementProperty.type().fullName();
if (elementProperty.type().isArray()) {
fullJaveName = fullJaveName.concat("[]");
}
mapper.addTypeMappingName(partQName, fullJaveName);
if (elementProperty.type().isPrimitive()) {
mapper.addTypeMappingStatus(partQName, Boolean.TRUE);
}
if (elementProperty.type().isArray()) {
mapper.addTypeMappingStatus(partQName,
Constants.ARRAY_TYPE);
}
}
}
}
if (WSDLUtil.isOutputPresentForMEP(op.getMessageExchangePattern())) {
AxisMessage message = op.getMessage(
WSDLConstants.MESSAGE_LABEL_OUT_VALUE);
if (message != null &&
message.getParameter(Constants.UNWRAPPED_KEY) != null) {
Mapping mapping = jaxbModel.get(message.getElementQName());
List elementProperties = mapping.getWrapperStyleDrilldown();
for(int j = 0; j < elementProperties.size(); j++){
Property elementProperty = (Property) elementProperties.get(j);
QName partQName =
WSDLUtil.getPartQName(op.getName().getLocalPart(),
WSDLConstants.OUTPUT_PART_QNAME_SUFFIX,
elementProperty.elementName().getLocalPart());
//this type is based on a primitive type- use the
//primitive type name in this case
String fullJaveName =
elementProperty.type().fullName();
if (elementProperty.type().isArray()) {
fullJaveName = fullJaveName.concat("[]");
}
mapper.addTypeMappingName(partQName, fullJaveName);
if (elementProperty.type().isPrimitive()) {
mapper.addTypeMappingStatus(partQName, Boolean.TRUE);
}
if (elementProperty.type().isArray()) {
mapper.addTypeMappingStatus(partQName,
Constants.ARRAY_TYPE);
}
}
}
}
}
}
}
}
// Return the type mapper
return mapper;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static void scanEpisodeFile(File jar, SchemaCompiler sc)
throws BadCommandLineException, IOException {
URLClassLoader ucl = new URLClassLoader(new URL[]{jar.toURL()});
Enumeration<URL> resources = ucl.findResources("META-INF/sun-jaxb.episode");
while (resources.hasMoreElements()) {
URL url = resources.nextElement();
sc.getOptions().addBindFile(new InputSource(url.toExternalForm()));
}
}
private static void registerNamespace(SchemaCompiler sc, String namespace, String pkgName) throws Exception {
Document doc = XMLUtils.newDocument();
Element rootElement = doc.createElement("schema");
rootElement.setAttribute("xmlns", "http://www.w3.org/2001/XMLSchema");
rootElement.setAttribute("xmlns:jaxb", "http://java.sun.com/xml/ns/jaxb");
rootElement.setAttribute("jaxb:version", "2.0");
rootElement.setAttribute("targetNamespace", namespace);
Element annoElement = doc.createElement("annotation");
Element appInfo = doc.createElement("appinfo");
Element schemaBindings = doc.createElement("jaxb:schemaBindings");
Element pkgElement = doc.createElement("jaxb:package");
pkgElement.setAttribute("name", pkgName);
annoElement.appendChild(appInfo);
appInfo.appendChild(schemaBindings);
schemaBindings.appendChild(pkgElement);
rootElement.appendChild(annoElement);
File file = File.createTempFile("customized",".xsd");
FileOutputStream stream = new FileOutputStream(file);
try {
Result result = new StreamResult(stream);
Transformer xformer = TransformerFactory.newInstance().newTransformer();
xformer.transform(new DOMSource(rootElement), result);
stream.flush();
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
InputSource ins = new InputSource(file.toURI().toString());
sc.parseSchema(ins);
file.delete();
}
private static String extractNamespace(XmlSchema schema) {
String pkg;
pkg = schema.getTargetNamespace();
if (pkg == null) {
XmlSchema[] schemas2 = SchemaUtil.getAllSchemas(schema);
for (int j = 0; schemas2 != null && j < schemas2.length; j++) {
pkg = schemas2[j].getTargetNamespace();
if (pkg != null)
break;
}
}
if (pkg == null) {
pkg = URLProcessor.DEFAULT_PACKAGE;
}
pkg = URLProcessor.makePackageName(pkg);
return pkg;
}
private static String getSchemaAsString(XmlSchema schema) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
schema.write(baos);
return baos.toString();
}
}