Index: NodeTypeRegistry.java
===================================================================
--- NodeTypeRegistry.java (revision 368126)
+++ NodeTypeRegistry.java (working copy)
@@ -222,56 +222,8 @@
return def;
}
- /**
- * Validates and registers the specified collection of NodeTypeDef
- * objects. An InvalidNodeTypeDefException is thrown if the
- * validation of any of the contained NodeTypeDef objects fails.
- *
NodeTypeDef objects
- * @throws InvalidNodeTypeDefException
- * @throws RepositoryException
- * @see #registerNodeType
- */
- private synchronized void internalRegister(Collection ntDefs)
- throws InvalidNodeTypeDefException, RepositoryException {
- ArrayList list = new ArrayList(ntDefs);
- // iterate over definitions until there are no more definitions with
- // unresolved (i.e. unregistered) dependencies or an error occurs;
- int count = -1; // number of registered nt's per iteration
- while (list.size() > 0 && count != 0) {
- count = 0;
- Iterator iterator = list.iterator();
- while (iterator.hasNext()) {
- NodeTypeDef ntd = (NodeTypeDef) iterator.next();
- // check if definition has unresolved dependencies
- if (registeredNTDefs.keySet().containsAll(ntd.getDependencies())) {
- // try to register it
- internalRegister(ntd);
- // remove it from list
- iterator.remove();
- // increase count
- count++;
- }
- }
- }
- if (list.size() > 0) {
- StringBuffer msg = new StringBuffer();
- msg.append("the following node types could not be registered because of unresolvable dependencies: ");
- Iterator iterator = list.iterator();
- while (iterator.hasNext()) {
- msg.append(((NodeTypeDef) iterator.next()).getName());
- msg.append(" ");
- }
- log.error(msg.toString());
- throw new InvalidNodeTypeDefException(msg.toString());
- }
- }
-
private EffectiveNodeType internalRegister(NodeTypeDef ntd)
throws InvalidNodeTypeDefException, RepositoryException {
QName name = ntd.getName();
@@ -281,7 +233,7 @@
throw new InvalidNodeTypeDefException(msg);
}
- EffectiveNodeType ent = validateNodeTypeDef(ntd);
+ EffectiveNodeType ent = validateNodeTypeDef(ntd, this.entCache, this.registeredNTDefs);
// store new effective node type instance
entCache.put(ent);
@@ -428,7 +380,17 @@
}
}
- private EffectiveNodeType validateNodeTypeDef(NodeTypeDef ntd)
+ /**
+ * Validates the specified NodeTypeDef within the context of the two other parameter and
+ * returns an EffectiveNodeType.
+ * @param ntd
+ * @param anEntCache
+ * @param aRegisteredNTDefCache
+ * @return The EffectiveNodeType
+ * @throws InvalidNodeTypeDefException
+ * @throws RepositoryException
+ */
+ private EffectiveNodeType validateNodeTypeDef(NodeTypeDef ntd, EffectiveNodeTypeCache anEntCache, Map aRegisteredNTDefCache)
throws InvalidNodeTypeDefException, RepositoryException {
/**
@@ -462,7 +424,7 @@
log.debug(msg);
throw new InvalidNodeTypeDefException(msg);
}
- if (!registeredNTDefs.containsKey(supertypes[i])) {
+ if (!aRegisteredNTDefCache.containsKey(supertypes[i])) {
String msg = "[" + name + "] invalid supertype: "
+ supertypes[i];
log.debug(msg);
@@ -476,7 +438,7 @@
*/
Stack inheritanceChain = new Stack();
inheritanceChain.push(name);
- checkForCircularInheritance(supertypes, inheritanceChain);
+ checkForCircularInheritance(supertypes, inheritanceChain, aRegisteredNTDefCache);
}
/**
@@ -492,7 +454,7 @@
*/
if (supertypes != null && supertypes.length > 0) {
try {
- EffectiveNodeType est = getEffectiveNodeType(supertypes);
+ EffectiveNodeType est = getEffectiveNodeType(supertypes, anEntCache, aRegisteredNTDefCache);
// make sure that all primary types except nt:base extend from nt:base
if (!ntd.isMixin() && !QName.NT_BASE.equals(ntd.getName())
&& !est.includesNodeType(QName.NT_BASE)) {
@@ -620,7 +582,7 @@
for (int j = 0; j < constraints.length; j++) {
ReferenceConstraint rc = (ReferenceConstraint) constraints[j];
QName ntName = rc.getNodeTypeName();
- if (!name.equals(ntName) && !registeredNTDefs.containsKey(ntName)) {
+ if (!name.equals(ntName) && !aRegisteredNTDefCache.containsKey(ntName)) {
String msg = "[" + name + "#" + pd.getName()
+ "] invalid REFERENCE value constraint '"
+ ntName + "' (unknown node type)";
@@ -674,7 +636,7 @@
* the default primary type must be registered, with one notable
* exception: the node type just being registered
*/
- if (!name.equals(dpt) && !registeredNTDefs.containsKey(dpt)) {
+ if (!name.equals(dpt) && !aRegisteredNTDefCache.containsKey(dpt)) {
String msg = "[" + name + "#" + cnd.getName()
+ "] invalid default primary type '" + dpt + "'";
log.debug(msg);
@@ -686,14 +648,14 @@
*/
try {
if (!referenceToSelf) {
- defaultENT = getEffectiveNodeType(dpt);
+ defaultENT = getEffectiveNodeType(dpt, anEntCache, aRegisteredNTDefCache);
} else {
/**
* the default primary type is identical with the node
* type just being registered; we have to instantiate it
* 'manually'
*/
- ent = EffectiveNodeType.create(this, ntd);
+ ent = EffectiveNodeType.create(this, ntd, anEntCache, aRegisteredNTDefCache);
defaultENT = ent;
}
if (cnd.isAutoCreated()) {
@@ -704,7 +666,7 @@
*/
Stack definingNTs = new Stack();
definingNTs.push(name);
- checkForCircularNodeAutoCreation(defaultENT, definingNTs);
+ checkForCircularNodeAutoCreation(defaultENT, definingNTs, anEntCache, aRegisteredNTDefCache);
}
} catch (NodeTypeConflictException ntce) {
String msg = "[" + name + "#" + cnd.getName()
@@ -736,7 +698,7 @@
* the required primary type must be registered, with one
* notable exception: the node type just being registered
*/
- if (!name.equals(rpt) && !registeredNTDefs.containsKey(rpt)) {
+ if (!name.equals(rpt) && !aRegisteredNTDefCache.containsKey(rpt)) {
String msg = "[" + name + "#" + cnd.getName()
+ "] invalid required primary type: " + rpt;
log.debug(msg);
@@ -759,7 +721,7 @@
*/
try {
if (!referenceToSelf) {
- getEffectiveNodeType(rpt);
+ getEffectiveNodeType(rpt,anEntCache, aRegisteredNTDefCache);
} else {
/**
* the required primary type is identical with the
@@ -767,7 +729,7 @@
* instantiate it 'manually'
*/
if (ent == null) {
- ent = EffectiveNodeType.create(this, ntd);
+ ent = EffectiveNodeType.create(this, ntd, anEntCache, aRegisteredNTDefCache);
}
}
} catch (NodeTypeConflictException ntce) {
@@ -792,7 +754,7 @@
*/
if (ent == null) {
try {
- ent = EffectiveNodeType.create(this, ntd);
+ ent = EffectiveNodeType.create(this, ntd, anEntCache, aRegisteredNTDefCache);
} catch (NodeTypeConflictException ntce) {
String msg = "[" + name + "] failed to resolve node type definition";
log.debug(msg);
@@ -823,29 +785,50 @@
return rootNodeDef;
}
+
/**
+ *
* @param ntName
* @return
* @throws NoSuchNodeTypeException
*/
- public synchronized EffectiveNodeType getEffectiveNodeType(QName ntName)
+ public EffectiveNodeType getEffectiveNodeType(QName ntName) throws NoSuchNodeTypeException {
+ return this.getEffectiveNodeType(ntName, this.entCache, this.registeredNTDefs);
+ }
+
+ /**
+ * @param ntName
+ * @return
+ * @throws NoSuchNodeTypeException
+ */
+ public synchronized EffectiveNodeType getEffectiveNodeType(QName ntName, EffectiveNodeTypeCache anEntCache, Map aRegisteredNTDefCache)
throws NoSuchNodeTypeException {
- // 1. make sure that the specified node type is registered
- if (!registeredNTDefs.containsKey(ntName)) {
+ // 1. make sure that the specified node type exists
+ if (!aRegisteredNTDefCache.containsKey(ntName)) {
throw new NoSuchNodeTypeException(ntName.toString());
}
// 2. check if effective node type has already been built
WeightedKey key = new WeightedKey(new QName[]{ntName});
- if (entCache.contains(key)) {
- return entCache.get(key);
+ if (anEntCache.contains(key)) {
+ return anEntCache.get(key);
}
// 3. build effective node type
try {
- EffectiveNodeType ent = EffectiveNodeType.create(this, ntName);
+ NodeTypeDef def = (NodeTypeDef) aRegisteredNTDefCache.get(ntName);
+ NodeTypeDef ntDef4ENT = null;
+ // return clone to make sure nobody messes around with the 'live' definition
+ try {
+ ntDef4ENT = (NodeTypeDef) def.clone();
+ } catch (CloneNotSupportedException e) {
+ // should never get here
+ log.fatal("internal error", e);
+ throw new InternalError(e.getMessage());
+ }
+ EffectiveNodeType ent = EffectiveNodeType.create(this, ntDef4ENT, anEntCache, aRegisteredNTDefCache);
// store new effective node type
- entCache.put(ent);
+ anEntCache.put(ent);
return ent;
} catch (NodeTypeConflictException ntce) {
// should never get here as all registered node types have to be valid!
@@ -855,17 +838,21 @@
}
}
+
+ public EffectiveNodeType getEffectiveNodeType(QName[] ntNames) throws NodeTypeConflictException, NoSuchNodeTypeException {
+ return this.getEffectiveNodeType(ntNames, this.entCache, this.registeredNTDefs);
+ }
/**
* @param ntNames
* @return
* @throws NodeTypeConflictException
* @throws NoSuchNodeTypeException
*/
- public synchronized EffectiveNodeType getEffectiveNodeType(QName[] ntNames)
+ public synchronized EffectiveNodeType getEffectiveNodeType(QName[] ntNames, EffectiveNodeTypeCache anEntCache, Map aRegisteredNTDefCache)
throws NodeTypeConflictException, NoSuchNodeTypeException {
- // 1. make sure every single node type is registered
+ // 1. make sure every single node type exists
for (int i = 0; i < ntNames.length; i++) {
- if (!registeredNTDefs.containsKey(ntNames[i])) {
+ if (!aRegisteredNTDefCache.containsKey(ntNames[i])) {
throw new NoSuchNodeTypeException(ntNames[i].toString());
}
}
@@ -873,8 +860,8 @@
WeightedKey key = new WeightedKey(ntNames);
// 2. check if aggregate has already been built
- if (entCache.contains(key)) {
- return entCache.get(key);
+ if (anEntCache.contains(key)) {
+ return anEntCache.get(key);
}
// 3. build aggregate
@@ -884,8 +871,8 @@
ArrayList tmpResults = new ArrayList();
while (key.size() > 0) {
// check if we've already built this aggregate
- if (entCache.contains(key)) {
- tmpResults.add(entCache.get(key));
+ if (anEntCache.contains(key)) {
+ tmpResults.add(anEntCache.get(key));
// subtract the result from the temporary key
// (which is 'empty' now)
key = key.subtract(key);
@@ -896,7 +883,7 @@
* aggregate (i.e. the cost of building it)
*/
boolean foundSubResult = false;
- Iterator iter = entCache.keys();
+ Iterator iter = anEntCache.keys();
while (iter.hasNext()) {
WeightedKey k = (WeightedKey) iter.next();
/**
@@ -904,7 +891,7 @@
* we're looking for
*/
if (key.contains(k)) {
- tmpResults.add(entCache.get(k));
+ tmpResults.add(anEntCache.get(k));
// subtract the result from the temporary key
key = key.subtract(k);
foundSubResult = true;
@@ -918,16 +905,27 @@
*/
QName[] remainder = key.toArray();
for (int i = 0; i < remainder.length; i++) {
+ NodeTypeDef def = (NodeTypeDef) aRegisteredNTDefCache.get(remainder[i]);
+ NodeTypeDef clonedDef = null;
+ // return clone to make sure nobody messes around with the 'live' definition
+ try {
+ clonedDef = (NodeTypeDef) def.clone();
+ } catch (CloneNotSupportedException e) {
+ // should never get here
+ log.fatal("internal error", e);
+ throw new InternalError(e.getMessage());
+ }
+
EffectiveNodeType ent =
- EffectiveNodeType.create(this, remainder[i]);
+ EffectiveNodeType.create(this, clonedDef, anEntCache, aRegisteredNTDefCache);
// store new effective node type
- entCache.put(ent);
+ anEntCache.put(ent);
if (result == null) {
result = ent;
} else {
result = result.merge(ent);
// store intermediate result (sub-aggregate)
- entCache.put(result);
+ anEntCache.put(result);
}
}
// add aggregate of remaining node types to result list
@@ -942,14 +940,14 @@
} else {
result = result.merge((EffectiveNodeType) tmpResults.get(i));
// store intermediate result
- entCache.put(result);
+ anEntCache.put(result);
}
}
// we're done
return result;
}
- void checkForCircularInheritance(QName[] supertypes, Stack inheritanceChain)
+ void checkForCircularInheritance(QName[] supertypes, Stack inheritanceChain, Map aRegisteredNTDefCache)
throws InvalidNodeTypeDefException, RepositoryException {
for (int i = 0; i < supertypes.length; i++) {
QName nt = supertypes[i];
@@ -969,11 +967,13 @@
}
try {
- QName[] sta = getNodeTypeDef(nt).getSupertypes();
+
+ NodeTypeDef ntd = (NodeTypeDef) aRegisteredNTDefCache.get(nt);
+ QName[] sta = ntd.getSupertypes();
if (sta != null && sta.length > 0) {
// check recursively
inheritanceChain.push(nt);
- checkForCircularInheritance(sta, inheritanceChain);
+ checkForCircularInheritance(sta, inheritanceChain, aRegisteredNTDefCache);
inheritanceChain.pop();
}
} catch (NoSuchNodeTypeException nsnte) {
@@ -985,7 +985,7 @@
}
void checkForCircularNodeAutoCreation(EffectiveNodeType childNodeENT,
- Stack definingParentNTs)
+ Stack definingParentNTs, EffectiveNodeTypeCache anEntCache, Map aRegisteredNTDefCache)
throws InvalidNodeTypeDefException {
// check for circularity through default node types of auto-created child nodes
// (node type 'a' defines auto-created child node with default node type 'a')
@@ -1019,8 +1019,8 @@
if (dnt != null) {
// check recursively
definingParentNTs.push(definingNT);
- checkForCircularNodeAutoCreation(getEffectiveNodeType(dnt),
- definingParentNTs);
+ checkForCircularNodeAutoCreation(getEffectiveNodeType(dnt,anEntCache, aRegisteredNTDefCache),
+ definingParentNTs,anEntCache, aRegisteredNTDefCache);
definingParentNTs.pop();
}
} catch (NoSuchNodeTypeException nsnte) {
@@ -1098,18 +1098,15 @@
* @throws InvalidNodeTypeDefException
* @throws RepositoryException
*/
- public synchronized void registerNodeTypes(Collection ntDefs)
+ public synchronized void registerNodeTypes(Collection newNTDefs)
throws InvalidNodeTypeDefException, RepositoryException {
// exceptions that might be thrown by internalRegister(Collection)
RepositoryException re = null;
InvalidNodeTypeDefException intde = null;
- // store names of currently registered node types before proceeding
- HashSet oldNTNames = new HashSet(registeredNTDefs.keySet());
-
try {
- // validate and register new node type definitions
- internalRegister(ntDefs);
+ internalRegister(newNTDefs);
+
} catch (RepositoryException e) {
// store exception so it can be re-thrown later on
re = e;
@@ -1117,39 +1114,108 @@
// store exception so it can be re-thrown later on
intde = e;
}
-
- /**
- * build set of names of actually registered new node types
- * (potentially a subset of those specified in ntDefs if an exception
- * had been thrown)
- */
- HashSet newNTNames = new HashSet(registeredNTDefs.keySet());
- newNTNames.removeAll(oldNTNames);
-
- if (newNTNames.size() > 0) {
- // persist new node type definitions
- for (Iterator iter = newNTNames.iterator(); iter.hasNext();) {
- QName ntName = (QName) iter.next();
- customNTDefs.add((NodeTypeDef) registeredNTDefs.get(ntName));
- }
+ boolean allNodeTypeDefsAreValid = re==null && intde==null;
+ if (allNodeTypeDefsAreValid) {
+ Iterator validNTDsIterator = newNTDefs.iterator();
+ while (validNTDsIterator.hasNext()){
+ NodeTypeDef ntd = (NodeTypeDef) validNTDsIterator.next();
+ // store property & child node definitions of new node type by id
+ customNTDefs.add( ntd );
+ }
persistCustomNodeTypeDefs(customNTDefs);
-
// notify listeners
- for (Iterator iter = newNTNames.iterator(); iter.hasNext();) {
- QName ntName = (QName) iter.next();
- notifyRegistered(ntName);
+ for (Iterator iter = newNTDefs.iterator(); iter.hasNext();) {
+ NodeTypeDef ntDef = (NodeTypeDef) iter.next();
+ notifyRegistered(ntDef.getName());
}
+ } else {
+ // re-throw the exception
+ if (re != null) {
+ throw re;
+ } else if (intde != null) {
+ throw intde;
+ }
}
-
- // re-throw exception as necessary
- if (re != null) {
- throw re;
- } else if (intde != null) {
- throw intde;
- }
}
/**
+ * Validates and registers the specified collection of NodeTypeDef
+ * objects. An InvalidNodeTypeDefException is thrown if the
+ * validation of any of the contained NodeTypeDef objects fails.
+ *
+ * Note that in the case an exception is thrown no node type will be registered.
+ *
+ * @param newNTDefs collection of NodeTypeDef objects
+ * @throws InvalidNodeTypeDefException
+ * @throws RepositoryException
+ * @see #registerNodeType
+ */
+ private synchronized void internalRegister(Collection newNTDefs) throws InvalidNodeTypeDefException, RepositoryException {
+
+ // cache of pre-built aggregations of node types
+ EffectiveNodeTypeCache anEntCache = new EffectiveNodeTypeCache(this.entCache);
+
+ // map of node type names and node type definitions
+ Map aRegisteredNTDefCache = new HashMap(this.registeredNTDefs);
+
+ // temporarily register a clone of the node type definition
+ // and do some checks by the way
+ Iterator ntdNameIterator = newNTDefs.iterator();
+ while (ntdNameIterator.hasNext()){
+ Object ntdObject = ntdNameIterator.next();
+ // check if the right type is used
+ if (! (ntdObject instanceof NodeTypeDef) ){
+ String msg = "The specified object is not of type org.apache.jackrabbit.core.nodetype.NodeTypeDef";
+ log.debug(msg);
+ throw new InvalidNodeTypeDefException(msg);
+ } else {
+ // check if the ntd is new
+ NodeTypeDef ntd = (NodeTypeDef) ntdObject;
+ QName name = ntd.getName();
+ if (name != null && registeredNTDefs.containsKey(name)) {
+ String msg = name + " already exists";
+ log.debug(msg);
+ throw new InvalidNodeTypeDefException(msg);
+ }
+ // clone the ntd and add it to the cache
+ NodeTypeDef clonedNTD=null;
+ try {
+ clonedNTD = (NodeTypeDef) ntd.clone();
+ } catch (CloneNotSupportedException e) {
+ // should never get here
+ log.fatal("internal error", e);
+ throw new InternalError(e.getMessage());
+ }
+ aRegisteredNTDefCache.put(clonedNTD.getName(), clonedNTD);
+ }
+ }
+ Iterator ntdIterator = newNTDefs.iterator();
+ while (ntdIterator.hasNext()){
+ NodeTypeDef ntd = (NodeTypeDef) ntdIterator.next();
+
+ EffectiveNodeType ent = validateNodeTypeDef(ntd, anEntCache, aRegisteredNTDefCache);
+
+ // store new effective node type instance
+ anEntCache.put(ent);
+ }
+ // as no exception occured at this point, the ntds are valid
+ Iterator validNTDsIterator = newNTDefs.iterator();
+ while (validNTDsIterator.hasNext()){
+ NodeTypeDef ntd = (NodeTypeDef) validNTDsIterator.next();
+ this.registeredNTDefs.put(ntd.getName(), ntd);
+ // store property & child node definitions of new node type by id
+ PropDef[] pda = ntd.getPropertyDefs();
+ for (int i = 0; i < pda.length; i++) {
+ propDefs.put(pda[i].getId(), pda[i]);
+ }
+ NodeDef[] nda = ntd.getChildNodeDefs();
+ for (int i = 0; i < nda.length; i++) {
+ nodeDefs.put(nda[i].getId(), nda[i]);
+ }
+ }
+ }
+
+ /**
* @param nodeTypeName
* @throws NoSuchNodeTypeException
* @throws RepositoryException
@@ -1216,7 +1282,7 @@
/**
* validate new node type definition
*/
- validateNodeTypeDef(ntd);
+ validateNodeTypeDef(ntd, this.entCache, this.registeredNTDefs);
/**
* build diff of current and new definition and determine type of change
@@ -1810,101 +1876,4 @@
return set.toString() + " (" + weight + ")";
}
}
-
- /**
- * EfectiveNodeTypeCache ...
- */
- private class EffectiveNodeTypeCache {
- // ordered set of keys
- final TreeSet sortedKeys;
- // cache of pre-build aggregations of node types
- final HashMap aggregates;
-
- EffectiveNodeTypeCache() {
- sortedKeys = new TreeSet();
- aggregates = new HashMap();
- }
-
- void put(EffectiveNodeType ent) {
- // we define the weight as the total number of included node types
- // (through aggregation and inheritance)
- int weight = ent.getAllNodeTypes().length;
- // the effective node type is identified by the list of merged
- // (i.e. aggregated) node types
- WeightedKey k = new WeightedKey(ent.getMergedNodeTypes(), weight);
- aggregates.put(k, ent);
- sortedKeys.add(k);
- }
-
- boolean contains(QName[] ntNames) {
- return aggregates.containsKey(new WeightedKey(ntNames));
- }
-
- boolean contains(WeightedKey key) {
- return aggregates.containsKey(key);
- }
-
- EffectiveNodeType get(QName[] ntNames) {
- return (EffectiveNodeType) aggregates.get(new WeightedKey(ntNames));
- }
-
- EffectiveNodeType get(WeightedKey key) {
- return (EffectiveNodeType) aggregates.get(key);
- }
-
- EffectiveNodeType remove(QName[] ntNames) {
- return remove(new WeightedKey(ntNames));
- }
-
- EffectiveNodeType remove(WeightedKey key) {
- EffectiveNodeType removed = (EffectiveNodeType) aggregates.remove(key);
- if (removed != null) {
- // remove index entry
-
- // FIXME: can't simply call TreeSet.remove(key) because the entry
- // in sortedKeys might have a different weight and would thus
- // not be found
- Iterator iter = sortedKeys.iterator();
- while (iter.hasNext()) {
- WeightedKey k = (WeightedKey) iter.next();
- // WeightedKey.equals(Object) ignores the weight
- if (key.equals(k)) {
- sortedKeys.remove(k);
- break;
- }
- }
- }
- return removed;
- }
-
- /**
- * Returns an iterator over the keys. The order of the returned keys is:
- *