|
What this is
This file is included in the DevDaily.com
"Java Source Code
Warehouse" project. The intent of this project is to help you "Learn
Java by Example" TM.
Other links
The source code
/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is NetBeans. The Initial Developer of the Original
* Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
* Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.modules.schema2beans;
import java.util.*;
import java.io.*;
import java.beans.*;
import org.w3c.dom.*;
import java.lang.reflect.Constructor;
/**
* This class is the base class for any generated bean. This class provides
* the property book-keeping and access as a set of dynamic creation/accessor
* property methods.
*
* BaseBean is the class that any generated schema2beans class extends. The
* generated code implements the specific accessors methods while the BaseBean
* class provides the generic ones. For example, a generated bean would have
*
* public String getDescription() {
* return (String)this.getValue(DESCRIPTION);
* }
*
* BaseBean handles any value as an Object, where the generated schema2beans
* class handles a specific class/scalar type depending on its corresponding
* DTD element (and optional mdd values. See user document for mdd info).
*
* The idea of BaseBean is to provide the unique schema2beans java bean on
* which all generated schema2beans class rely. This is the user entry point
* of the schema2beans runtime. This is where you find all the generic methods
* that apply to all schema2beans classes: merge, find, clone, get/set attributes,
* etc.
*
* If we had to draw a gereric overview of the schema2beans architecture, we would
* draw three parts: BaseBean, BeanProp and DOMBinding. This is where most
* of the schema2beans runtime is implemented.
*
* There is one BaseBean instance per schema2beans node (one non final element
* of the DTD has one generated class that extends BaseBean).
* Each BaseBean holds its properties as BeanProp objects. For each property,
* BaseBean has one instance of BeanProp. For example, if we have as a DTD:
*
*
*
*
*
* The we would have two classes that would extend BaseBean: Book and Chapter.
* The book BaseBean would handle two instance of BeanProp, one for the
* property chapter and one of summary.
* The BeanProp for summary would handle a single String property, and the
* BeanProp for chapter would handle an indexed property of Chapter classes.
* Also, the chapter BaseBean (one instance for each element of the indexed
* property), would have one instance of BeanProp, that would handle the
* String indexed property line.
*
* The internal graph representation of the XML document is handled using
* a DOM tree. DOMBinding is the class that takes care of linking the
* BeanProp instances to the DOM nodes.
*
*/
public abstract class BaseBean implements Cloneable, Bean {
/*
* Because schema2beans doesn't generate user information about the
* relationship between the properties, BaseBean provides some
* method to give the user this information.
*/
public class IterateChoiceProperties implements java.util.Iterator {
private ArrayList groups;
private int index;
public IterateChoiceProperties() {
this.groups = new ArrayList();
this.index = 0;
}
void add(BeanProp prop) {
if (prop.group != null && !this.groups.contains(prop.group))
this.groups.add(prop.group);
}
public boolean hasNext() {
return (this.index < this.groups.size());
}
public Object next() throws NoSuchElementException {
if (hasNext()) {
BeanProp.GroupProp gp =
(BeanProp.GroupProp)this.groups.get(this.index++);
return (BaseProperty[])gp.list();
}
else
throw new NoSuchElementException();
}
public void remove()
throws UnsupportedOperationException, IllegalStateException {
throw new UnsupportedOperationException();
}
}
// The binding object that links us to the DOM node. This might be null
// if there is no DOM Node yet (brand new object not attached to a graph)
protected DOMBinding binding;
// A unique instance for all the nodes of the schema2beans tree
protected GraphManager graphManager;
//
// HashMaps of the properties - those are the same properties but are
// sorted by Bean name (propByName) and by dtd name (propByDtdName).
//
private Map propByName;
private Map propByOrder;
//
// If we use this hashMap, we have better performances whenever we
// access the element using the dtd name. Since schema2beans generate classes
// using Bean names, we can assume that very few accesses are performed
// using the dtd name and we can then save memory commenting out this
// hashMap. If performance is an issue while accessing the element using
// dtd names, we should consider using this hashmap again.
//
//private HashMap propByDtdName;
// When an attribute is added, we might not be part of a graph yet.
// In this case, we want to cache the attribute information and defer
// its processing. Whenever the node is added to a schema2beans tree,
// the values of the cache are automatically check to populate
// the attribute values.
private HashMap attrCache;
// We can define an array of comparator, even though most of the usage
// is to have one comparator.
private ArrayList comparators;
// This is a provision to mark at runtime the version of each node
// of the schema2beans tree. As this is not of much use for now, we simply
// save the memory space.
//private Version version;
// True if this node is the root of the schema2beans graph.
private boolean isRoot;
// When the properties are created (calls from the generated class
// constructor), we give a number to each property so we know what
// their order is. This is how we know, when we add a new property
// where it should be added (it has to match the DTD order declaration)
private int propertyOrder;
private String defaultNamespace;
/*
public BaseBean() {
this(null, new Version(Version.MAJVER, Version.MINVER,
Version.PTCVER));
System.out.println("warning: schema2beans.BaseBean: unknown version of generated beans being used.");
}
*/
/**
* @param comps the comparators to use. Can be null
* @param version which runtime version to be compatible with. This should be the version of the generated beans.
*/
public BaseBean(Vector comps, Version version) {
init(comps, version);
}
protected void init(Vector comps, Version version) {
if (version.getMajor() < 3) {
initPropertyTables(13);
}
this.comparators = new ArrayList(2);
//this.version = version;
this.isRoot = false;
this.propertyOrder = 0;
this.attrCache = null;
if ((comps == null) || (comps.size()==0)) {
// Use the default comparator
this.comparators.add(new BeanComparator());
}
else {
int size = comps.size();
for (int i=0; i the number of expected elements / load factor.
// If we make the load factor=1, then the initial capacity could be
// just the expected elements + 1. However, if 2 elements map to
// the same bucket, then they start getting strung together in
// a list, and that slows things down (you lose the O(1) performance).
// So, double the expected size to make it less likely that 2
// elements will map to the same bucket.
//
int hashTableSize = propertyCount * 2;
this.propByName = new HashMap(hashTableSize, 1.0f);
this.propByOrder = new HashMap(hashTableSize, 1.0f);
//this.propByDtdName = new HashMap(hashTableSize, 1.0f);
}
//
// Dynamically add/remove a comparator. Comparator are used to compare
// and merge graphs. There are usually populated in the constructor
//
public synchronized void addBeanComparator(BeanComparator cmp) {
if (cmp != null)
this.comparators.add(cmp);
}
public synchronized void removeBeanComparator(BeanComparator cmp) {
int i = this.comparators.indexOf(cmp);
if (i != -1)
this.comparators.remove(i);
}
/**
* Create a new property for the current bean, selecting default option
* values.
*/
public void createProperty(String dtdName, String beanName, Class type) {
int o = Common.TYPE_0_1;
if (type.isInstance(java.lang.String.class))
o |= Common.TYPE_STRING;
else
o |= Common.TYPE_BEAN;
this.createProperty(dtdName, beanName, o, type);
}
/**
* Create the root element of the graph
*/
public void createRoot(String dtdName, String beanName,
int option, Class type) throws Schema2BeansRuntimeException {
BeanProp prop = new BeanProp(this, dtdName, beanName,
option, type, true);
try {
this.graphManager.createRootBinding(this, prop, null);
} catch (Schema2BeansException e) {
throw new Schema2BeansRuntimeException(e);
}
this.isRoot = true;
}
/**
* Create a new property for the current bean. This creates a BeanProp
* object (which is the internal representation of a single/indexed
* property) and adds it to the bean property hash table.
*
* This property is later accessed by its bean name.
*/
public void createProperty(String dtdName, String beanName,
int option, Class type) throws
Schema2BeansRuntimeException {
// This number represents the order of this property amoung
// its siblings. The beans generator generates the createProperty()
// method calls in the order of the DTD declaration. Therefore, we
// can simply relies on the order of the createProperty method calls
// to affect the order value for the property.
this.propertyOrder++;
BeanProp prop = new BeanProp(this, dtdName, beanName, option, type);
prop.setOrder(this.propertyOrder);
Object obj1 = this.propByName.put(beanName, prop);
//Object obj2 = this.propByDtdName.put(dtdName, prop);
this.propByOrder.put(String.valueOf(this.propertyOrder), prop);
if (obj1 != null) // || obj2 != null)
throw new Schema2BeansRuntimeException(Common.
getMessage("DuplicateProperties_msg"));
prop.initialize();
}
public void setDefaultNamespace(String namespace) {
defaultNamespace = namespace;
createAttribute("xmlns", "xmlns", AttrProp.CDATA | AttrProp.IMPLIED,
null, namespace);
setAttributeValue("xmlns", namespace);
}
public String getDefaultNamespace() {
return defaultNamespace;
}
/**
* Returns the list of properties of this bean as an array.
*/
public BeanProp[] beanProps() {
int size = this.propByOrder.size();
BeanProp[] ret = new BeanProp[size];
for (int i=1; i<=size; i++)
ret[i-1] = (BeanProp)this.propByOrder.get(String.valueOf(i));
return ret;
}
/**
* Returns the list of properties of this bean as an array.
*/
protected Iterator beanPropsIterator() {
return propByName.values().iterator();
}
/**
* Return the internal object representation of the property. This method
* cannot return null. If there is no object available for the specified
* property name, an exception is thrown.
*/
public BeanProp beanProp(String name) {
BeanProp prop = (BeanProp)this.propByName.get(name);
if (prop == null) {
// Search using the dtd name
String beanName = Common.convertName(name);
prop = (BeanProp)this.propByName.get(beanName);
if (prop == null)
throw new IllegalArgumentException(Common.
getMessage("BeanPropertyDoesntExist_msg",
this.getClass().getName(), name));
}
return prop;
}
/**
* Return the internal object representation of the property. This method
* cannot return null. If there is no object available for the specified
* property name, an exception is thrown.
*/
public BeanProp beanProp(int order) {
return (BeanProp)this.propByOrder.get(String.valueOf(order));
}
/**
* Return the value of the single property named name.
*/
public Object getValue(String name) {
return this.beanProp(name).getValue(0);
}
/**
* Return one element of the indexed property named name.
*/
public Object getValue(String name, int index) {
return this.beanProp(name).getValue(index);
}
/**
* Return one element of the index property using the internal
* id index value. This index is unique and doesn't change over
* the time of the graph life. This method allows to get an element
* of an indexed property without keeping track of index shifting,
* and other elements removal.
*/
public Object getValueById(String name, int id) {
return this.beanProp(name).getValueById(id);
}
/**
* Convert an unique internal index value into the user visible
* index value. The property name specified must be an indexed
* property.
* This method may return -1 if we cannot figure out the index.
*/
public int idToIndex(String name, int id) {
return this.beanProp(name).idToIndex(id);
}
/**
* Convert the user index value into the internal unique index value.
* The property name specified must be an indexed property.
*/
public int indexToId(String name, int index) {
return this.beanProp(name).indexToId(index);
}
/**
* Return true if this property is null
*/
public boolean isNull(String name) {
return (this.getValue(name) == null);
}
/**
* Return true if this property is null
*/
public boolean isNull(String name, int index) {
return (this.getValue(name, index) == null);
}
/**
* Return the values of the indexed property named name. The result
* can be cast as an array of the property type.
*/
public Object[] getValues(String name) {
return this.beanProp(name).getValues();
}
/**
* Set the value for the single property named name.
*/
public void setValue(String name, Object value) {
setValue(beanProp(name), 0, value);
}
/**
* Set the value of an element for the indexed property named name.
*/
public void setValue(String name, int index, Object value) {
setValue(beanProp(name), index, value);
}
protected void setValue(BeanProp prop, int index, Object value) {
prop.setValue(index, value);
}
protected int addValue(BeanProp prop, Object value) {
return prop.addValue(value);
}
protected int removeValue(BeanProp prop, Object value) {
return prop.removeValue(value);
}
protected void removeValue(BeanProp prop, int index) {
prop.removeValue(index);
}
/**
* Set the value of an element for the indexed property named name,
* using the unique internal index.
*/
public void setValueById(String name, int id, Object value) {
BeanProp bp = this.beanProp(name);
int index = bp.idToIndex(id);
bp.setValue(index, value);
}
/**
* Set the values for the indexed property named name.
*/
public void setValue(String name, Object[] value) {
this.beanProp(name).setValue(value);
}
/**
* Add a value to the indexed property named name.
*/
public int addValue(String name, Object value) {
return addValue(beanProp(name), value);
}
/**
* Remove a value from the indexed property named name.
*/
public int removeValue(String name, Object value) {
return removeValue(beanProp(name), value);
}
/**
* Remove a value from the indexed property named name.
*/
public void removeValue(String name, int index) {
removeValue(beanProp(name), index);
}
/**
* Returns the position of the indexed property element.
* If the type of the property is a bean, use the == comparison,
* else use the equals() method.
* If the element is not found, return -1.
*/
public int indexOf(String name, Object value) throws
Schema2BeansRuntimeException {
BeanProp bp = this.beanProp(name);
if (bp == null)
throw new Schema2BeansRuntimeException(Common.
getMessage("UnknownPropertyName_msg", name));
if (Common.isArray(bp.type)) {
boolean isBean = Common.isBean(bp.type);
int size = bp.size();
for (int i=0; i0) {
Iterator it = this.attrCache.keySet().iterator();
int i = 0;
while (it.hasNext())
ret[i++] = it.next().toString();
}
return ret;
}
/**
* Return the value cached for the attribute named name.
*/
String cachedAttributeValue(String name) {
if (this.attrCache != null)
return (String)this.attrCache.get(name);
else
return null;
}
/**
* Return the value cached for the attribute named name.
*/
void cachedAttributeClear() {
this.attrCache = null;
}
/**
* Get the attribute value on the current property bean.
* If there is no current attribute (or element for that matter),
* then null is returned.
*/
public String getAttributeValue(String name) {
BeanProp bp = this.beanProp();
if (bp != null) {
// Find out what our index is within the BeanProp object
int i = bp.idToIndex(this.binding.getId());
if (i < 0) // I guess we're not part of the BeanProp yet.
return null;
return bp.getAttributeValue(i, name);
}
else {
//
// That's a brand new bean not attached yet to a graph. Try
// to get the value from the cache.
//
if (this.attrCache != null)
return (String)this.attrCache.get(name);
else
return null;
}
}
/**
* Get the attribute value (see BeanProp class)
*/
public String getAttributeValue(String propName, String name) {
return this.beanProp(propName).getAttributeValue(0, name);
}
/**
* Set the value of the attribute (see the BeanClass class)
*/
public void setAttributeValue(String propName, int index, String name,
String value) {
this.beanProp(propName).setAttributeValue(index, name, value);
}
/**
* Get the attribute value (see BeanProp class)
*/
public String getAttributeValue(String propName, int index, String name) {
return this.beanProp(propName).getAttributeValue(index, name);
}
/**
* Return the list of all known attribute names for this property
* (even if they are not set).
*/
public String[] getAttributeNames(String propName) {
return this.beanProp(propName).getAttributeNames();
}
/**
* Return the list of all known attribute names for the current bean
*/
public String[] getAttributeNames() {
BeanProp bp = this.beanProp();
if (bp != null)
return bp.getAttributeNames();
else
return null;
}
/**
* Return the list of all known attribute names for this property
* (even if they are not set).
*/
public BaseAttribute[] listAttributes(String propName) {
return this.beanProp(propName).getAttributes();
}
/**
* Return the list of all known attribute names for the current bean
*/
public BaseAttribute[] listAttributes() {
BeanProp bp = this.beanProp();
if (bp != null)
return bp.getAttributes();
else
return null;
}
// Called by find() method. Where the attributes are searched for.
private void lookForAttribute(ArrayList found, BeanProp bp, BaseBean bean,
BaseAttribute[] attrs, String attrName,
Object value) {
for (int j=0; j":bean.getClass().getName()) +
" - " + propName + "/" + attrName + " for value " +
((value == null)?"":value.toString()));
}
if (bean == null || value == null)
return;
BaseProperty[] props = bean.listProperties();
//
// Search our own attributes first (as any node might be the
// root of the search, we have to start by ourself first)
//
BaseAttribute[] attrs = bean.listAttributes();
if (propName == null && attrs != null && attrs.length > 0) {
BeanProp bp = bean.beanProp();
this.lookForAttribute(found, bp, bean, attrs, attrName, value);
}
//
// Look for the properties and the attributes of the non-bean
// properties (bean property attributes are searched as the root
// case explained above)
//
for (int i=0; i 0)
this.lookForAttribute(found, bp, null, attrs,
attrName, value);
}
// recurse
if (p.isBean() && p.isIndexed()) {
BaseBean[] ba = (BaseBean[])bean.getValues(name);
for (int k=0; k G1 + E2
* INTERSECT is G1 n G2 <=> (G1 U G2) - E1 - E2
*/
public static final int MERGE_NONE = 0x00;
public static final int MERGE_INTERSECT = 0x01;
public static final int MERGE_UNION = 0x02;
public static final int MERGE_UPDATE = (MERGE_UNION|MERGE_INTERSECT);
public static final int MERGE_COMPARE = 0x04;
static String mergeModeToString(int mode) {
switch(mode) {
case MERGE_NONE: return "MERGE_NONE"; // NOI18N
case MERGE_INTERSECT: return "MERGE_INTERSECT"; // NOI18N
case MERGE_UNION: return "MERGE_UNION"; // NOI18N
case MERGE_UPDATE: return "MERGE_UPDATE"; // NOI18N
case MERGE_COMPARE: return "MERGE_COMPARE"; // NOI18N
default: return "Unknown merge mode: " + mode; // NOI18N
}
}
/**
* Merge the specified bean schema2beans graph into the current graph using
* the specified mode.
*/
public void merge(BaseBean bean, int mode) {
if (mode == MERGE_UPDATE)
mergeUpdate(bean);
else
mergeTreeRoot(bean, mode);
}
/**
* Merge the bean tree with the current graph using the default
* merging option.
*/
public void merge(BaseBean bean) {
mergeUpdate(bean);
}
/**
* Same as merge(BaseBean bean).
* It's possible to override this method and make it more efficient,
* than the generic one.
*/
public void mergeUpdate(BaseBean sourceBean) {
mergeTreeRoot(sourceBean, MERGE_UPDATE);
}
// Called by mergeTree to set the default hasKey value
private boolean setHasKeyDefaultValue(BeanProp prop) {
BeanComparator cmp = (BeanComparator)this.comparators.get(0);
return cmp.hasKeyDefined(prop);
}
/*
* Copy a property from the graph 'bean' to the graph 'prop', making
* sure that both property and attributes are copied.
* This method is used to copy non BaseBean properties
* (a clone on a BaseBean automatically copies the attributes).
*/
protected void copyProperty(BeanProp prop, BaseBean bean,
int index, Object value) {
boolean isArray = Common.isArray(prop.type);
String name = prop.getName();
// Copy the property value
if (value == null) {
if (isArray)
value = bean.getValue(name, index);
else
value = bean.getValue(name, 0);
}
int newIndex = 0;
if (isArray) {
newIndex = addValue(prop, value);
} else {
setValue(prop, 0, value);
index = 0;
}
this.copyAttributes(prop, newIndex, bean, index);
}
/*
* This copies the attributes of a property from 'bean' (whole BaseBean)
* to a property BeanProp (the specific BeanProp of the other BaseBean
* where the copy as to occur).
*/
private void copyAttributes(BeanProp prop, int propIndex,
BaseBean bean, int beanIndex) {
// Copy the attributes
String name = prop.getName();
BaseAttribute[] ba = bean.listAttributes(name);
if (ba != null) {
for(int j=0; j":bean.getClass().getName()) +
" - " + mergeModeToString(mode));
}
//
// The merge method is called only when two beans are logically
// identical. Therefore, this method doesn't try to check if it
// is equal to the other beans, but find out which properties
// have to be updated.
//
if (this.getClass().isInstance(bean)) {
// We got the same as ourself in another graph
Iterator it = beanPropsIterator();
//
// Parse our attributes
//
// To have the following code easier to read, we could
// call the setter/getter method of the BaseBean object for
// both our attributes and the bean-to-merge attributes.
// However, since we get the BeanProp objects from our
// properties hashtable, we can call directly the BeanProp
// getter/setter methods for our properties and the
// BaseBean getter/setter for the bean we have to merge.
//
while (it.hasNext()) {
// Get our next property (as a BeanProp)
BeanProp prop = (BeanProp)it.next();
if (prop == null)
continue;
String name = prop.getBeanName();
boolean isArray = Common.isArray(prop.type);
boolean isBean = Common.isBean(prop.type);
Object o1, o2, o3;
boolean hasKey = false;
boolean hasKeyDefined = false;
if (isArray) {
//
// For each element of the index property, we have to
// find if there is a matching element in the other
// indexed property. If there is, merge the two
// elements if this is a bean. If there are no
// matching elements, remove it. At the end,
// add any new elements of the other indexed property.
//
int i, j = 0;
int size1 = prop.size();
int size2 = bean.size(name);
boolean toRemove[] = new boolean[size1];
boolean toAdd[] = new boolean[size2];
boolean compared[] = new boolean[size2];
// To keep track of that need to be removed
Arrays.fill(toRemove, false);
// To keep track of what we'll need to add after the loop
Arrays.fill(toAdd, true);
// To make sure that we do not match twice the same elt
Arrays.fill(compared, false);
if (DDLogFlags.debug) {
TraceLogger.put(TraceLogger.DEBUG, TraceLogger.SVC_DD,
DDLogFlags.DBG_UBN, 5,
DDLogFlags.MERGEPROP,
this.getClass().getName() + "." +
name + "[" + size1 + "] / " +
bean.getClass().getName() + "." +
name + "[" + size2 + "]");
}
// For each of our current property elts ...
for (i=0; i " +
name + "[" + j + "]");
}
} else {
toRemove[i] = true; // no more exists
if (DDLogFlags.debug) {
TraceLogger.put(TraceLogger.DEBUG,
TraceLogger.SVC_DD,
DDLogFlags.DBG_UBN, 5,
DDLogFlags.MERGENTFND,
name + "[" + i +
"] to be removed");
}
}
}
//
// We want to make sure that we set a proper value
// to hasKey when one of the two array is empty
// (either null or containing null elements)
//
if (!hasKeyDefined)
hasKey = this.setHasKeyDefaultValue(prop);
if ((mode & MERGE_COMPARE) == MERGE_COMPARE) {
// Any diff returns false
for (i=0; i Same");
continue;
}
//System.out.println("--> Different");
if (pos1 >= size1) {
//System.out.println("New stuff added to end.");
for (; pos2 < size2; ++pos2) {
n2 = nodes2.item(pos2);
if (n2 instanceof CharacterData) {
Node newNode = doc1.importNode(n2, true);
startingNode1.appendChild(newNode);
}
}
break;
}
if (pos2 >= size2) {
//System.out.println("Stuff deleted from end.");
for (int i = size1 - 1; i >= pos1; --i) {
n1 = nodes1.item(i);
if (n1 instanceof CharacterData) {
startingNode1.removeChild(n1);
}
}
break;
}
if (n1 instanceof CharacterData &&
n2 != null && n2.getNodeType() == n1.getNodeType()) {
String value1 = n1.getNodeValue();
String value2 = n2.getNodeValue();
// Are they both just whitespace?
if ((value1 == null || "".equals(value1.trim())) &&
(value2 == null || "".equals(value2.trim())) ) {
//System.out.println("whitespace was changed in graph 2");
((CharacterData)n1).setData(value2);
++pos1;
++pos2;
continue;
}
}
int j2 = pos2;
int j1 = -1;
for (; j2 < size2; ++j2) {
Node j2node = nodes2.item(j2);
// Skip whitespace here
if (j2node instanceof CharacterData) {
String j2value = j2node.getNodeValue();
if (j2value == null || "".equals(j2value.trim()))
continue;
}
j1 = findInNodeList(nodes1, j2node, pos1);
if (j1 >= 0)
break;
}
//System.out.println("j1="+j1+" j2="+j2);
if (j1 == pos1 && j2 > pos2) {
//System.out.println("stuff was added in graph 2");
// pos2 thru j2 were added (including pos2 and not j2)
Node nodeToInsertBefore = nodes1.item(j1);
for (; pos2 < j2; ++pos2) {
n2 = nodes2.item(pos2);
if (n2 instanceof CharacterData) {
Node newNode = doc1.importNode(n2, true);
//System.out.println("newNode="+newNode);
++pos1;
startingNode1.insertBefore(newNode, nodeToInsertBefore);
}
}
// reestablish nodes1 and size1 data
nodes1 = startingNode1.getChildNodes();
size1 = nodes1.getLength();
} else if (j1 - 1 < pos1) {
//System.out.println("Simply replace n1 with n2");
if (n2 instanceof CharacterData) {
startingNode1.replaceChild(doc1.importNode(n2, true), n1);
}
++pos1;
++pos2;
} else {
//System.out.println("stuff was deleted in graph 2");
for (int i = j1 - 1; i >= pos1; --i) {
n1 = nodes1.item(i);
if (n1 instanceof CharacterData) {
//System.out.println("Deleting: "+n1);
startingNode1.removeChild(n1);
} else {
++pos1;
}
}
// reestablish nodes1 and size1 data
nodes1 = startingNode1.getChildNodes();
size1 = nodes1.getLength();
}
}
}
}
//
// For the MERGE_COMPARE option: if we reach this point, that
// means we didn't find any diff. We can therefore return true.
// Any other option returns always true.
//
return true;
}
else
throw new IllegalArgumentException(Common.getMessage(
"MergeWrongClassType_msg", this.getClass().getName(),
(bean==null ? "" : bean.getClass().getName())));
}
/**
* Compare 2 Node's and tell me if they're roughly equivalent.
* By roughly equivalent, attributes and children are ignored.
*/
private boolean areNodesEqual(Node node1, Node node2) {
if (node1 == null && node2 == null)
return true;
if (node1 == null || node2 == null)
return false;
if (node1.getNodeType() != node2.getNodeType())
return false;
if (!node1.getNodeName().equals(node2.getNodeName()))
return false;
String value1 = node1.getNodeValue();
String value2 = node2.getNodeValue();
if (value1 == null) {
if (value2 != null)
return false;
} else if (!value1.equals(value2))
return false;
return true;
}
/**
* Search in @param nodes for an equivalent node to @param node
* (equivalent as defined by areNodesEqual) starting the search
* at position @param start.
*/
private int findInNodeList(NodeList nodes, Node node, int start) {
return findInNodeList(nodes, node, start, nodes.getLength());
}
/**
* Search in @param nodes for an equivalent node to @param node
* (equivalent as defined by areNodesEqual) starting the search
* at position @param start, giving up the search at position
* @param maxPosition.
*/
private int findInNodeList(NodeList nodes, Node node,
int start, int maxPosition) {
for (; start < maxPosition; ++start) {
if (areNodesEqual(nodes.item(start), node))
return start;
}
return -1;
}
/**
* Perform a deep recursive comparison. Return true if the two graphs
* are equals, false otherwise.
*
* The comparison is using the comparators and therfore returns a
* result wrt to the comparators. That means a true return value
* only means that the graphs are logically equals depending on the
* comparator implementation.
*
* Note that the default comparator compares every property value.
*
*/
public boolean equals(Object obj) {
boolean ret = false;
try {
if (this == obj)
return true;
else
if (obj instanceof BaseBean)
ret = this.mergeTreeRoot((BaseBean)obj, MERGE_COMPARE);
}
catch(Exception e) {
// Equals method only returns either true or false
if (DDLogFlags.debug) {
TraceLogger.put(TraceLogger.DEBUG, TraceLogger.SVC_DD,
DDLogFlags.DBG_UBN, 1, DDLogFlags.EQUALS,
"got exception while comparing: " +
e + "\n");
e.printStackTrace();
}
ret = false;
}
if (DDLogFlags.debug) {
TraceLogger.put(TraceLogger.DEBUG, TraceLogger.SVC_DD,
DDLogFlags.DBG_UBN, 1, DDLogFlags.EQUALS,
(ret?"true":"false"));
}
return ret;
}
public int hashCode() {
int result = 17;
for (Iterator it = beanPropsIterator(); it.hasNext(); ) {
BeanProp prop = (BeanProp) it.next();
boolean isArray = Common.isArray(prop.type);
int size;
if (isArray) {
size = prop.size();
} else {
size = 1;
}
for (int propNum = 0; propNum < size; ++propNum) {
Object obj = prop.getValue(propNum);
result = 37*result + (obj == null ? 0 : obj.hashCode());
}
}
// And attributes
if (beanProp() != null) {
String[] attributeNames = beanProp().getAttributeNames();
for (int attrNum = 0; attrNum < attributeNames.length; ++attrNum) {
String attrName = attributeNames[attrNum];
String attrValue = getAttributeValue(attrName);
result = 37*result + (attrValue == null ? 0 : attrValue.hashCode());
}
}
return result;
}
/**
* Get the bean using its unique identifier. This identifier is not
* the indexed position of the element in the array but a unique id
* associated to the DOMBinding object (see the BeanProp and DOMBinding
* classes)
*/
public Bean propertyById(String name, int id) {
BeanProp bp = this.beanProp(name);
if (Common.isBean(bp.type)) {
if (Common.isArray(bp.type))
return (BaseBean)bp.getValueById(id);
else
return (BaseBean)bp.getValue(0);
}
else
throw new IllegalStateException(Common.
getMessage("PropertyIsNotABean_msg", name));
}
/**
* Return the BeanProp object where this bean belongs.
*/
public BeanProp beanProp() {
if (this.binding != null)
return this.binding.getBeanProp(this);
else
return null;
}
/**
* Return the BaseBean parent of the current bean. This might return null
* either because this is the root of the graph or because this node is not
* part of a schema2beans graph yet.
*/
public BaseBean parent() {
BeanProp bp = this.beanProp();
if (bp != null)
return this.beanProp().getBean();
else
return null;
}
public Bean _getParent() {
return parent();
}
/**
* Return the root of the graph. If the graph is not connected to a
* generated root, then the topmost bean is returned.
*/
public Bean _getRoot() {
Bean b = this;
Bean bParent;
while (!b.isRoot()) {
bParent = b._getParent();
if (bParent == null)
break;
b = bParent;
}
return b;
}
/**
* Return the path name of this element in the graph.
*/
public String fullName() {
StringBuffer str = new StringBuffer();
this.buildPathName(str);
return str.toString();
}
public boolean hasName(String name) {
if (name != null)
return (name.equals(this.name()) || name.equals(this.dtdName()));
else
return false;
}
/**
* Return true if this element is the root of the schema2beans tree.
*/
public boolean isRoot() {
return this.isRoot;
}
/**
* Return the bean name of this schema2beans graph node.
*/
public String name() {
BeanProp bp = this.beanProp();
if (bp != null)
return this.beanProp().getBeanName();
else
return ""; // NOI18N
}
/**
* Return the DTD name of this schema2beans graph node.
*/
public String dtdName() {
return this.beanProp().getDtdName();
}
public void createBean(Node node, GraphManager mgr) throws Schema2BeansRuntimeException {
if (this.isRoot) {
mgr.completeRootBinding(this, node);
}
this.graphManager = mgr;
try {
mgr.fillProperties(this.beanProps(), node);
} catch (Schema2BeansException e) {
throw new Schema2BeansRuntimeException(e);
}
}
/**
* Return a new instance of the specified bean property
*/
public BaseBean newInstance(String name) {
return this.beanProp(name).newBeanInstance();
}
public abstract void dump(StringBuffer str, String indent);
// The old abstract verify method never did anything.
// a validate method will get generated if the -validate option is on.
//public abstract void validate() throws org.netbeans.modules.schema2beans.ValidateException;
/**
* Dump the DOM content of this bean. If nodeName is specified,
* dump only from the subname named nodeName.
*/
public String dumpDomNode(String nodeName, int depth) {
Node n = null;
if (this.binding == null)
return ""; // NOI18N
else {
n = this.binding.node;
if (n == null)
return ""; // NOI18N
}
return DDFactory.XmlToString(n, depth, nodeName);
}
public String dumpDomNode(int depth) {
return this.dumpDomNode(null, depth);
}
public String dumpDomNode() {
return this.dumpDomNode(null, 99999);
}
public String dumpBeanNode() {
return null;
}
public void dumpAttributes(String name, int index, StringBuffer str,
String indent) {
String[] names = this.getAttributeNames(name);
for (int i=0; i
|