blob: 19e9f16ee54a0409c6baf8c1e70f0bae606ec330 [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) 2000-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.marshal;
import org.apache.xmlbeans.XmlRuntimeException;
import org.apache.xmlbeans.impl.binding.bts.BindingLoader;
import org.apache.xmlbeans.impl.binding.bts.BindingProperty;
import org.apache.xmlbeans.impl.binding.bts.BindingType;
import org.apache.xmlbeans.impl.binding.bts.ByNameBean;
import org.apache.xmlbeans.impl.binding.bts.JavaName;
import org.apache.xmlbeans.impl.binding.bts.QNameProperty;
import javax.xml.namespace.QName;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;
final class ByNameRuntimeBindingType
implements RuntimeBindingType
{
private final ByNameBean byNameBean;
private final Property[] properties;
private final Class javaClass;
ByNameRuntimeBindingType(ByNameBean btype)
{
byNameBean = btype;
try {
javaClass = getJavaClass(btype, getClass().getClassLoader());
}
catch (ClassNotFoundException e) {
final String msg = "failed to load " + btype.getName().getJavaName();
throw (RuntimeException)(new RuntimeException(msg).initCause(e));
}
properties = new Property[btype.getProperties().size()];
}
//prepare internal data structures for use
public void initialize(RuntimeBindingTypeTable typeTable,
BindingLoader loader)
{
int idx = 0;
for (Iterator itr = byNameBean.getProperties().iterator(); itr.hasNext();) {
QNameProperty bprop = (QNameProperty)itr.next();
Property prop = new Property(javaClass, bprop, typeTable, loader);
properties[idx++] = prop;
}
}
public Object createIntermediary(UnmarshalContext context)
{
return ClassLoadingUtils.newInstance(javaClass);
}
private static Class getJavaClass(BindingType btype, ClassLoader backup)
throws ClassNotFoundException
{
final JavaName javaName = btype.getName().getJavaName();
String jclass = javaName.toString();
return ClassLoadingUtils.loadClass(jclass, backup);
}
public Object getFinalObjectFromIntermediary(Object retval,
UnmarshalContext context)
{
return retval;
}
//TODO: optimize this linear scan
RuntimeBindingProperty getMatchingElementProperty(String uri,
String localname)
{
for (int i = 0, len = properties.length; i < len; i++) {
final Property prop = properties[i];
if (prop.isAttribute()) continue;
QName qn = prop.getQName();
if (qn.getLocalPart().equals(localname) &&
qn.getNamespaceURI().equals(uri)) {
return prop;
}
}
return null;
}
//TODO: optimize this linear scan
RuntimeBindingProperty getMatchingAttributeProperty(String uri,
String localname)
{
for (int i = 0, len = properties.length; i < len; i++) {
final Property prop = properties[i];
if (!prop.isAttribute()) continue;
QName qn = prop.getQName();
if (qn.getLocalPart().equals(localname) &&
qn.getNamespaceURI().equals(uri)) {
return prop;
}
}
return null;
}
private static final class Property implements RuntimeBindingProperty
{
private final QNameProperty bindingProperty;
private final TypeUnmarshaller unmarshaller;
private final Class propertyClass;
private final Method setMethod;
private final boolean javaPrimitive;
Property(Class beanClass,
QNameProperty prop,
RuntimeBindingTypeTable typeTable,
BindingLoader loader)
{
this.bindingProperty = prop;
this.unmarshaller = lookupUnmarshaller(prop, typeTable, loader);
final BindingType bindingType = loader.getBindingType(prop.getTypeName());
try {
this.propertyClass = getJavaClass(bindingType, getClass().getClassLoader());
}
catch (ClassNotFoundException e) {
final String msg = "error loading " + bindingType.getName().getJavaName();
throw (RuntimeException)(new RuntimeException(msg).initCause(e));
}
setMethod = getSetterMethod(prop, beanClass, propertyClass);
javaPrimitive = propertyClass.isPrimitive();
}
private TypeUnmarshaller lookupUnmarshaller(BindingProperty prop,
RuntimeBindingTypeTable typeTable,
BindingLoader bindingLoader)
{
final BindingType bindingType =
bindingLoader.getBindingType(prop.getTypeName());
TypeUnmarshaller um = typeTable.getTypeUnmarshaller(bindingType);
if (um == null) {
throw new AssertionError("failed to get unmarshaller for " + prop);
}
return um;
}
public TypeUnmarshaller getTypeUnmarshaller(UnmarshalContext context)
{
final QName xsi_type = context.getXsiType();
if (xsi_type == null)
return unmarshaller;
else
if (xsi_type == UnmarshalContext.XSI_NIL_MARKER)
return NullUnmarshaller.getInstance();
return context.getTypeUnmarshaller(xsi_type);
}
public void fill(Object inter, Object prop_obj)
{
//means xsi:nil was true but we're a primtive.
//schema should have nillable="false" so this
//is a validation problems
if (prop_obj == null && javaPrimitive)
return;
try {
setMethod.invoke(inter, new Object[]{prop_obj});
}
catch (SecurityException e) {
throw new XmlRuntimeException(e);
}
catch (IllegalAccessException e) {
throw new XmlRuntimeException(e);
}
catch (InvocationTargetException e) {
throw new XmlRuntimeException(e);
}
}
private static Method getSetterMethod(QNameProperty bindingProperty1,
Class beanClass,
Class propClass)
{
String setter = bindingProperty1.getSetterName();
try {
final Method set_method =
beanClass.getMethod(setter, new Class[]{propClass});
return set_method;
}
catch (NoSuchMethodException e) {
throw new XmlRuntimeException(e);
}
catch (SecurityException e) {
throw new XmlRuntimeException(e);
}
}
boolean isAttribute()
{
return bindingProperty.isAttribute();
}
QName getQName()
{
return bindingProperty.getQName();
}
}
}