blob: 568d0530debe94f1f35a206138fa0b93ab0c55e6 [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache
* XMLBeans", nor may "Apache" appear in their name, without prior
* written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 2003 BEA Systems
* Inc., <http://www.bea.com/>. For more information on the Apache Software
* Foundation, please see <http://www.apache.org/>.
*/
package org.apache.xmlbeans.impl.binding.compile;
import org.apache.xmlbeans.impl.binding.bts.*;
import org.apache.xmlbeans.impl.jam.JAnnotation;
import org.apache.xmlbeans.impl.jam.JClass;
import org.apache.xmlbeans.impl.jam.JProperty;
import org.apache.xmlbeans.impl.jam.JElement;
import org.w3.x2001.xmlSchema.*;
import javax.xml.namespace.QName;
/**
* Transforms a set of JClasses into a BTS and a schema. This is really just
* a sketch at this point.
*/
public class Java2Schema {
// =========================================================================
// Constants
private static final String JAVA_URI_SCHEME = "java:";
private static final String JAVA_NAMESPACE_URI = "language_builtins";
private static final String JAVA_PACKAGE_PREFIX = "java.";
private static final String TAG_CT = "xsdgen:complexType";
private static final String TAG_CT_TYPENAME = TAG_CT+".typeName";
private static final String TAG_CT_TARGETNS = TAG_CT+".targetNamespace";
private static final String TAG_CT_ROOT = TAG_CT+".rootElement";
private static final String TAG_EL = "xsdgen:element";
private static final String TAG_EL_NAME = TAG_EL+".name";
private static final String TAG_AT = "xsdgen:attribute";
private static final String TAG_AT_NAME = TAG_AT+".name";
// =========================================================================
// Variables
private BindingFile mBindingFile;
private BindingLoader mLoader;
private SchemaDocument mSchemaDocument;
private SchemaDocument.Schema mSchema;
// =========================================================================
// Constructors
public Java2Schema() {}
// =========================================================================
// Public methods
public void bind(JClass[] classes, TylarBuilder tb) {
tb.addBindingFile(mBindingFile = new BindingFile());
mLoader = PathBindingLoader.forPath
(new BindingLoader[] {mBindingFile,
BuiltinBindingLoader.getInstance()});
tb.addSchema(mSchemaDocument = SchemaDocument.Factory.newInstance());
mSchema = mSchemaDocument.addNewSchema();
for(int i=0; i<classes.length; i++) {
getBindingTypeFor(classes[i]);
}
}
// =========================================================================
// Private methods
private static JavaName getJavaName(JClass jc) {
return JavaName.forString(jc.getQualifiedName());
}
private BindingType getBindingTypeFor(JClass clazz) {
BindingType out = mLoader.getBindingType(mLoader.lookupTypeFor(getJavaName(clazz)));
if (out == null) {
out = createBindingTypeFor(clazz);
}
return out;
}
private BindingType createBindingTypeFor(JClass clazz) {
if (clazz.isPrimitive()) {
throw new IllegalStateException(clazz.getSimpleName());
}
// create the schema type
TopLevelComplexType xsdType = mSchema.addNewComplexType();
String tns = getTargetNamespace(clazz);
String xsdName = getAnnotation(clazz,TAG_CT_TYPENAME,clazz.getSimpleName());
QName qname = new QName(tns,xsdName);
xsdType.setName(xsdName);
// create a binding type
BindingTypeName btname = BindingTypeName.forPair(getJavaName(clazz),
XmlName.forTypeNamed(qname));
ByNameBean bindType = new ByNameBean(btname);
mBindingFile.addBindingType(bindType,true,true);
String rootName = getAnnotation(clazz,TAG_CT_ROOT,null);
if (rootName != null) {
SimpleDocumentBinding sdb = new SimpleDocumentBinding(btname,rootName);
mBindingFile.addBindingType(sdb,true,true);
}
// run through the class' properties to populate the binding and xsdtypes
//FIXME this is going to have to change to take inheritance into account
JProperty props[] = clazz.getProperties();
Group xsdSequence = null;
for(int i=0; i<props.length; i++) {
if (props[i].getGetter() == null || props[i].getSetter() == null) {
continue; // we can only deal with read-write props
}
boolean isAttribute = false;
String propName = getAnnotation(props[i],TAG_AT_NAME,null);
if (propName != null) {
isAttribute = true;
} else {
propName = getAnnotation(props[i],TAG_EL_NAME,props[i].getSimpleName());
}
BindingType propType = getBindingTypeFor(props[i].getType());
QNameProperty qprop = new QNameProperty();
qprop.setBindingType(propType);
qprop.setQName(new QName(tns,propName));
qprop.setGetterName(props[i].getGetter().getSimpleName());
qprop.setSetterName(props[i].getSetter().getSimpleName());
bindType.addProperty(qprop);
// also populate the schema type
if (!isAttribute) {
if (xsdSequence == null) xsdSequence = xsdType.addNewSequence();
LocalElement xsdElement = xsdSequence.addNewElement();
xsdElement.setName(propName);
xsdElement.setType(getBuiltinTypeNameFor(props[i].getType()));
} else {
Attribute xsdAtt = xsdType.addNewAttribute();
qprop.setAttribute(true);
xsdAtt.setName(propName);
xsdAtt.setType(getBuiltinTypeNameFor(props[i].getType()));
}
}
// check to see if they want to create a root elements from this type
JAnnotation[] anns = clazz.getAnnotations(TAG_CT_ROOT);
for(int i=0; i<anns.length; i++) {
TopLevelElement root = mSchema.addNewElement();
root.setName(anns[i].getStringValue());
root.setType(qname);
// FIXME still not entirely clear to me what we should do about
// the binding file here
}
return bindType;
}
//REVIEW seems like having this functionality in jam (getters w/defaults)
//would be a good thing to add to JAM
private static String getAnnotation(JElement elem, String annName, String dflt) {
JAnnotation ann = elem.getAnnotation(annName);
return (ann == null) ? dflt : ann.getStringValue();
}
private QName getBuiltinTypeNameFor(JClass clazz) {
BindingType bt =
mLoader.getBindingType(mLoader.lookupTypeFor(JavaName.forString(clazz.getQualifiedName())));
if (bt != null) return bt.getName().getXmlName().getQName();
System.out.println("no type found for "+clazz.getQualifiedName());
return null; //FIXME
}
private String getTargetNamespace(JClass clazz) {
JAnnotation ann = clazz.getAnnotation(TAG_CT_TARGETNS);
if (ann != null) return ann.getStringValue();
// Ok, they didn't specify it in the markup, so we have to
// synthesize it from the classname.
String pkg_name;
if (clazz.isPrimitive()) {
pkg_name = JAVA_NAMESPACE_URI;
} else {
pkg_name = clazz.getContainingPackage().getQualifiedName();
if (pkg_name.startsWith(JAVA_PACKAGE_PREFIX)) {
pkg_name = JAVA_NAMESPACE_URI+"."+
pkg_name.substring(JAVA_PACKAGE_PREFIX.length());
}
}
return JAVA_URI_SCHEME + pkg_name;
}
private static boolean isXmlObj(JClass clazz) {
try {
JClass xmlObj = clazz.forName("org.apache.xmlbeans.XmlObject");
return xmlObj.isAssignableFrom(clazz);
} catch(Exception e) {
e.printStackTrace(); //FIXME
return false;
}
}
}