com.tangosol.run.xml.CollectionAdapter Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of coherence Show documentation
Show all versions of coherence Show documentation
Oracle Coherence Community Edition
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
package com.tangosol.run.xml;
import com.tangosol.util.ClassHelper;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
/**
* A CollectionAdapter supports properties whose types implement the
* java.util.Collection interface.
*
* <property>
* <name>People</name>
* <xml-name>people</xml-name> <!-- defaults to <name> -->
* <type>java.util.Collection</type> <!-- defaults via reflection -->
* <class>java.util.LinkedList</class> <!-- defaults to <type> -->
* <empty-is-null>true</empty-is-null> <!-- defaults to false -->
* <element>
* <xml-name>person</xml-name> <!-- optional, nests the elements -->
* <type>com...PersonBean</type> <!-- required -->
* <adapter>...</adapter> <!-- optional -->
* <...> <!-- for the type-specific adapter -->
* </element>
* </property>
*
*
* Example of collection nested within collection tags:
*
* <doc>
* <people>
* <person>
* <...>
* </person>
* <person>
* <...>
* </person>
* ...
* </people>
* </doc>
*
*
* @version 1.00 2001.03.18
* @author cp
*/
public class CollectionAdapter
extends IterableAdapter
{
// ----- constructors ---------------------------------------------------
/**
* Construct a CollectionAdapter.
*
* @param infoBean BeanInfo for a bean containing this property
* @param clzType the type of the property
* @param sName the property name
* @param sXml the XML tag name
* @param xml additional XML information
*/
public CollectionAdapter(XmlBean.BeanInfo infoBean, Class clzType, String sName, String sXml, XmlElement xml)
{
super(infoBean, clzType, sName, sXml, xml);
azzert(Collection.class.isAssignableFrom(clzType));
// determine the collection class used
Class clzCollection = getType();
XmlValue xmlClz = xml.getElement("class");
if (xmlClz != null)
{
clzCollection = infoBean.resolveClass(xmlClz.getString());
}
m_clzCollection = clzCollection;
XmlElement xmlElement = xml.getElement("element");
if (xmlElement == null)
{
throw new IllegalStateException(
"Missing the \"\" information for the \"" +
sName + "\" property of the \"" +
ClassHelper.getSimpleName(infoBean.getType()) +
"\" XmlBean.");
}
m_adapterElement = findAdapter(infoBean, xmlElement);
}
// ----- Object method helpers ------------------------------------------
/**
* Make a clone of the passed object.
*
* @param o the object to clone
*
* @return a clone of the passed object
*/
public Object clone(Object o)
{
if (o == null)
{
return null;
}
PropertyAdapter adapterElement = m_adapterElement;
Collection colOld = (Collection) o;
Collection colNew = instantiateCollection();
for (Iterator iter = colOld.iterator(); iter.hasNext(); )
{
Object oElement = iter.next();
if (oElement != null)
{
oElement = adapterElement.clone(oElement);
}
colNew.add(oElement);
}
return colNew;
}
// ----- XmlSerializable helpers ----------------------------------------
/**
* @param xml the XML element containing the XML elements to deserialize
* from
*
* @return the object deserialized from the XML (not null)
*/
protected Object readElements(XmlElement xml)
{
Collection collection = instantiateCollection();
PropertyAdapter adapterElement = m_adapterElement;
boolean fAnonymous = adapterElement.isAnonymous();
Iterator iter = fAnonymous ?
xml.getElementList().iterator() :
XmlHelper.getElements(
xml, getElementName(), adapterElement.getNamespaceUri());
while (iter.hasNext())
{
XmlElement xmlElement = (XmlElement) iter.next();
Object oElement = adapterElement.fromXml(xmlElement);
// anonymous collections do not allow null elements
if (!fAnonymous || oElement != null)
{
collection.add(oElement);
}
}
return collection;
}
/**
* @param xml the XML element to which the iterable elements are written
* @param o the object to serialize (not null)
*/
protected void writeElements(XmlElement xml, Object o)
{
Collection collection = (Collection) o;
if (collection.isEmpty())
{
return;
}
PropertyAdapter adapterElement = m_adapterElement;
boolean fAnonymous = adapterElement.isAnonymous();
String sNmsPrefix = null;
String sElement = null;
if (!fAnonymous)
{
sNmsPrefix = adapterElement.getNamespacePrefix();
sElement = XmlHelper.getUniversalName(getElementName(), sNmsPrefix);
}
List list = xml.getElementList();
for (Iterator iter = ((Collection) o).iterator(); iter.hasNext();)
{
Object oElement = iter.next();
// the following is almost identical to a call
// adapterElement.writeXml(xml, oElement);
// except that the element name could be different
XmlElement xmlElement = adapterElement.toXml(oElement);
if (xmlElement != null)
{
if (fAnonymous)
{
List listElement = xmlElement.getElementList();
int cElements = listElement.size();
if (cElements == 1)
{
list.add(listElement.get(0));
}
else if (cElements > 1)
{
throw new IllegalStateException("Too many elements: " + xmlElement +
"\nadapter=" + adapterElement);
}
}
else
{
xmlElement.setName(sElement);
list.add(xmlElement);
}
}
}
/*
if (sNmsPrefix != null)
{
XmlHelper.ensureNamespace(xml, sNmsPrefix, adapterElement.getNamespaceUri());
XmlHelper.purgeChildrenNamespace(xml);
}
*/
}
// ----- ExternalizableLite helpers -------------------------------------
/**
* Read a value from the passed DataInput object.
*
* @param in the DataInput stream to read property data from
*
* @return the data read from the DataInput; never null
*
* @exception IOException if an I/O exception occurs
*/
public Object readExternal(DataInput in)
throws IOException
{
Collection collection = instantiateCollection();
PropertyAdapter adapter = getElementAdapter();
// "in" contains a collection size and, for each element, a non-null
// indicator and (if non-null) the object
for (int i = 0, c = readInt(in); i < c; ++i)
{
collection.add(in.readBoolean() ? adapter.readExternal(in) : null);
}
return collection;
}
/**
* Write the specified data to the passed DataOutput object.
*
* @param out the DataOutput stream to write to
* @param o the data to write to the DataOutput; never null
*
* @exception IOException if an I/O exception occurs
*/
public void writeExternal(DataOutput out, Object o)
throws IOException
{
Collection collection = (Collection) o;
PropertyAdapter adapter = getElementAdapter();
int c = collection.size();
writeInt(out, c);
int cActual = 0;
for (Iterator iter = collection.iterator(); iter.hasNext(); )
{
Object oElement = iter.next();
boolean fExists = (oElement != null);
out.writeBoolean(fExists);
if (fExists)
{
adapter.writeExternal(out, oElement);
}
++cActual;
}
if (c != cActual)
{
throw new IOException("expected " + c + " elements, but wrote " + cActual);
}
}
// ----- PropertyAdapter methods ----------------------------------------
/**
* Determine if the specified value is empty.
*
* @param o the value
*
* @return true if the object is considered to be empty for persistence
* and XML-generation purposes
*/
public boolean isEmpty(Object o)
{
return o == null || isEmptyIsNull() && ((Collection) o).isEmpty();
}
// ----- internal helpers -----------------------------------------------
/**
* @return a PropertyAdapter for collection elements
*/
public PropertyAdapter getElementAdapter()
{
return m_adapterElement;
}
/**
* @return a new Collection instance
*/
protected Collection instantiateCollection()
{
try
{
return (Collection) m_clzCollection.newInstance();
}
catch (Throwable e)
{
throw ensureRuntimeException(e);
}
}
// ----- data members ---------------------------------------------------
private Class m_clzCollection;
private PropertyAdapter m_adapterElement;
}