blob: ec94881cc6f348e0f862132f8e8f30af4968d7e1 [file] [log] [blame]
/* 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.xmlbeans.impl.marshal;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.impl.binding.bts.BindingLoader;
import org.apache.xmlbeans.impl.binding.bts.ByNameBean;
import org.apache.xmlbeans.impl.binding.bts.QNameProperty;
import org.apache.xmlbeans.impl.marshal.util.collections.Accumulator;
import org.apache.xmlbeans.impl.marshal.util.collections.AccumulatorFactory;
import javax.xml.namespace.QName;
import java.util.Collection;
import java.util.Iterator;
final class ByNameRuntimeBindingType
extends AttributeRuntimeBindingType
{
private final ElementQNameProperty[] elementProperties;
private final boolean hasMulti; //has any multi properties
//DO NOT CALL THIS CONSTRUCTOR, use the RuntimeTypeFactory
ByNameRuntimeBindingType(ByNameBean btype)
throws XmlException
{
super(btype);
final Class java_type = getJavaType();
if (java_type.isPrimitive() || java_type.isArray()) {
final String msg = "invalid ByNameBean java type: " + java_type +
" found in " + btype;
throw new XmlException(msg);
}
int elem_prop_cnt = 0;
boolean has_multi = false;
final Collection type_props = getQNameProperties();
for (Iterator itr = type_props.iterator(); itr.hasNext();) {
QNameProperty p =
(QNameProperty)itr.next();
if (p.isAttribute()) continue;
if (p.isMultiple()) has_multi = true;
elem_prop_cnt++;
}
elementProperties = new ElementQNameProperty[elem_prop_cnt];
hasMulti = has_multi;
}
void accept(RuntimeTypeVisitor visitor)
throws XmlException
{
visitor.visit(this);
}
Object getObjectFromIntermediate(Object inter)
{
if (hasMulti()) {
UResultHolder res = (UResultHolder)inter;
return res.getValue();
} else {
return inter;
}
}
boolean hasElementChildren()
{
return true;
}
protected Collection getQNameProperties()
{
ByNameBean narrowed_type = (ByNameBean)getBindingType();
return narrowed_type.getProperties();
}
protected void initElementProperty(QNameProperty prop,
int elem_idx,
RuntimeBindingTypeTable typeTable,
BindingLoader loader
)
throws XmlException
{
elementProperties[elem_idx] =
new ElementQNameProperty(elem_idx, getJavaType(), hasMulti(), prop,
this, typeTable, loader);
}
protected Object createIntermediary(UnmarshalResult context)
{
if (hasMulti) {
return new UResultHolder(this);
} else {
return ClassLoadingUtils.newInstance(getJavaType());
}
}
protected Object createIntermediary(UnmarshalResult context,
Object actual_object)
{
if (hasMulti) {
return new UResultHolder(this, actual_object);
} else {
return actual_object;
}
}
protected Object getFinalObjectFromIntermediary(Object retval,
UnmarshalResult context)
throws XmlException
{
if (hasMulti) {
UResultHolder rh = (UResultHolder)retval;
return rh.getFinalValue();
} else {
return retval;
}
}
RuntimeBindingProperty getElementProperty(int index)
{
return elementProperties[index];
}
//TODO: optimize this linear scan
RuntimeBindingProperty getMatchingElementProperty(String uri,
String localname)
{
for (int i = 0, len = elementProperties.length; i < len; i++) {
final ElementQNameProperty prop = elementProperties[i];
if (doesPropMatch(uri, localname, prop))
return prop;
}
return null;
}
private static boolean doesPropMatch(String uri,
String localname,
QNameRuntimeProperty prop)
{
assert localname != null;
final QName qn = prop.getQName();
return UnmarshalResult.doesElementMatch(qn, localname, uri);
}
public int getElementPropertyCount()
{
return elementProperties.length;
}
protected boolean hasMulti()
{
return hasMulti;
}
protected static final class ElementQNameProperty
extends QNameRuntimeProperty
{
protected final int propertyIndex;
ElementQNameProperty(int property_index,
Class beanClass,
boolean bean_has_multis,
QNameProperty prop,
RuntimeBindingType containing_type,
RuntimeBindingTypeTable typeTable,
BindingLoader loader)
throws XmlException
{
super(beanClass, bean_has_multis,
prop, containing_type, typeTable, loader);
propertyIndex = property_index;
assert !prop.isAttribute();
}
public void fill(final Object inter, final Object prop_obj)
throws XmlException
{
//means xsi:nil was true but we're a primtive.
//schema should have nillable="false" so this
//is a validation problem
if (prop_obj == null && runtimeBindingType.isJavaPrimitive())
return;
if (beanHasMulti) {
final UResultHolder rh = (UResultHolder)inter;
if (isMultiple()) {
rh.addItem(propertyIndex, prop_obj);
} else {
setValue(rh.getValue(), prop_obj);
}
} else {
setValue(inter, prop_obj);
}
}
}
protected static final class UResultHolder
{
private final ByNameRuntimeBindingType runtimeBindingType;
private final Object value;
private Accumulator[] accumulators;
UResultHolder(ByNameRuntimeBindingType type)
{
this(type, ClassLoadingUtils.newInstance(type.getJavaType()));
}
UResultHolder(ByNameRuntimeBindingType type, Object actual_obj)
{
runtimeBindingType = type;
value = actual_obj;
}
Object getFinalValue() throws XmlException
{
if (accumulators != null) {
final QNameRuntimeProperty[] props =
runtimeBindingType.elementProperties;
for (int i = 0, len = accumulators.length; i < len; i++) {
final Accumulator accum = accumulators[i];
if (accum != null) {
final QNameRuntimeProperty prop = props[i];
prop.fillCollection(value, accum.getFinalArray());
}
}
}
return value;
}
void addItem(int elem_idx, Object value)
{
initAccumulator(elem_idx);
accumulators[elem_idx].append(value);
}
private void initAccumulator(int elem_idx)
{
Accumulator[] accs = accumulators;
if (accs == null) {
accs = new Accumulator[runtimeBindingType.getElementPropertyCount()];
accumulators = accs;
}
if (accs[elem_idx] == null) {
final QNameRuntimeProperty p =
runtimeBindingType.elementProperties[elem_idx];
accs[elem_idx] =
AccumulatorFactory.createAccumulator(p.propertyClass,
p.collectionElementClass);
}
}
Object getValue()
{
return value;
}
public Object getActualObject()
{
return null;
}
}
}