stefan 2004/07/09 09:48:45
Modified: proposals/jcrri/src/org/apache/slide/jcr/core NodeImpl.java
Test.java PropertyImpl.java
Log:
jcrri
Revision Changes Path
1.19 +228 -17
jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/NodeImpl.java
Index: NodeImpl.java
===================================================================
RCS file:
/home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/NodeImpl.java,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -r1.18 -r1.19
--- NodeImpl.java 8 Jul 2004 17:34:34 -0000 1.18
+++ NodeImpl.java 9 Jul 2004 16:48:44 -0000 1.19
@@ -53,7 +53,7 @@
private static Logger log = Logger.getLogger(NodeImpl.class);
- protected NodeTypeImpl nodeType;
+ protected final NodeTypeImpl nodeType;
protected NodeDef definition;
@@ -105,6 +105,8 @@
// @todo need a more flexible generic way (callback?) of applying system
generated values
+ NodeState thisState = (NodeState) state;
+
// compute/apply system generated values
NodeTypeImpl nt = (NodeTypeImpl) def.getDeclaringNodeType();
if (nt.getQName().equals(NodeTypeRegistry.MIX_REFERENCEABLE)) {
@@ -126,7 +128,13 @@
genValues = new
InternalValue[]{InternalValue.create(nodeType.getQName())};
} else if (name.equals(PROPNAME_MIXINTYPES)) {
// jcr:mixinTypes property
- // @todo determine value of mixin:nodeTypes property
+ Set mixins = thisState.getMixinTypeNames();
+ ArrayList values = new ArrayList(mixins.size());
+ Iterator iter = mixins.iterator();
+ while (iter.hasNext()) {
+ values.add(InternalValue.create((QName) iter.next()));
+ }
+ genValues = (InternalValue[]) values.toArray(new
InternalValue[values.size()]);
}
}
@@ -135,12 +143,12 @@
protected PropertyImpl getOrCreateProperty(String name, int type)
throws RepositoryException {
- QName qName = QName.fromJCRName(name, ticket.getNamespaceResolver());
try {
return (PropertyImpl) getProperty(name);
} catch (PathNotFoundException pnfe) {
// does not exist yet:
- // find definition for the specified property and create property
+ // find definition for the specified property and create property
+ QName qName = QName.fromJCRName(name, ticket.getNamespaceResolver());
PropertyDefImpl def = nodeType.getApplicablePropertyDef(qName, type);
return createChildProperty(qName, type, def);
}
@@ -219,14 +227,14 @@
// add new child node entry
thisState.addChildNodeEntry(name, nodeState.getUUID());
- // add 'auto-create' properties defined in nodetype
+ // add 'auto-create' properties defined in node type
PropertyDef[] pda = nodeType.getAutoCreatePropertyDefs();
for (int i = 0; i < pda.length; i++) {
PropertyDefImpl pd = (PropertyDefImpl) pda[i];
node.createChildProperty(pd.getQName(), pd.getRequiredType(), pd);
}
- // recursively add 'auto-create' child nodes defined in nodetype
+ // recursively add 'auto-create' child nodes defined in node type
NodeDef[] nda = nodeType.getAutoCreateNodeDefs();
for (int i = 0; i < nda.length; i++) {
NodeDefImpl nd = (NodeDefImpl) nda[i];
@@ -405,6 +413,28 @@
return parentNode.createChildNode(nodeName, def, nodeType);
}
+ private void setMixinTypesProperty(Set mixinNames) throws RepositoryException {
+ NodeState thisState = (NodeState) state;
+ // get or create jcr:mixinTypes property
+ PropertyImpl prop = null;
+ if (thisState.hasPropertyEntry(PROPNAME_MIXINTYPES)) {
+ prop = (PropertyImpl) itemMgr.getItem(new PropertyId(thisState.getUUID(),
PROPNAME_MIXINTYPES));
+ } else {
+ // find definition for the jcr:mixinTypes property and create property
+ PropertyDefImpl def =
nodeType.getApplicablePropertyDef(PROPNAME_MIXINTYPES, PropertyType.STRING);
+ prop = createChildProperty(PROPNAME_MIXINTYPES, PropertyType.STRING, def);
+ }
+ // call internalSetValue for setting the jcr:mixinTypes property
+ // to avoid checking of the 'protected' flag
+ InternalValue[] vals = new InternalValue[mixinNames.size()];
+ Iterator iter = mixinNames.iterator();
+ int cnt = 0;
+ while (iter.hasNext()) {
+ vals[cnt++] = InternalValue.create((QName) iter.next());
+ }
+ prop.internalSetValue(vals, PropertyType.STRING);
+ }
+
protected void makePersistent() throws RepositoryException {
if (!isTransient()) {
log.debug(safeGetJCRPath() + " (" + id + "): there's no transient state to
persist");
@@ -423,6 +453,8 @@
// parent uuid's
persistentState.setParentUUID(transientState.getParentUUID());
persistentState.setParentUUIDs(transientState.getParentUUIDs());
+ // mixin types
+ persistentState.setMixinTypeNames(transientState.getMixinTypeNames());
// child node entries
persistentState.setChildNodeEntries(transientState.getChildNodeEntries());
// property entries
@@ -548,6 +580,7 @@
* Same as <code>[EMAIL PROTECTED] Node#setProperty(String, String)}</code>
except that
* this method takes a <code>QName</code> instead of a <code>String</code>
* value.
+ *
* @param name
* @param value
* @return
@@ -567,6 +600,7 @@
* Same as <code>[EMAIL PROTECTED] Node#setProperty(String, String[])}</code>
except that
* this method takes an array of <code>QName</code> instead of a
* <code>String</code> values.
+ *
* @param name
* @param values
* @return
@@ -1186,11 +1220,30 @@
// check state of this instance
checkItemState();
+ // check primary type
if (nodeTypeName.equals(nodeType.getName())) {
return true;
}
QName ntName = QName.fromJCRName(nodeTypeName, ticket.getNamespaceResolver());
- return nodeType.isDerivedFrom(ntName);
+ if (nodeType.isDerivedFrom(ntName)) {
+ return true;
+ }
+
+ // check mixin types
+ Set mixinNames = ((NodeState) state).getMixinTypeNames();
+ if (mixinNames.isEmpty()) {
+ return false;
+ }
+ NodeTypeManagerImpl ntMgr = (NodeTypeManagerImpl)
ticket.getWorkspace().getNodeTypeManager();
+ NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
+ try {
+ EffectiveNodeType ent = ntReg.buildEffectiveNodeType((QName[])
mixinNames.toArray(new QName[mixinNames.size()]));
+ return ent.includesNodeType(ntName);
+ } catch (NodeTypeConflictException ntce) {
+ String msg = "internal error: invalid mixin node type(s)";
+ log.error(msg, ntce);
+ throw new RepositoryException(msg, ntce);
+ }
}
/**
@@ -1204,8 +1257,18 @@
* @see Node#getMixinNodeTypes()
*/
public NodeType[] getMixinNodeTypes() throws RepositoryException {
- // @todo implement mixin node types support
- throw new RepositoryException("not yet implemented");
+ Set mixinNames = ((NodeState) state).getMixinTypeNames();
+ if (mixinNames.isEmpty()) {
+ return new NodeType[0];
+ }
+ NodeTypeManagerImpl ntMgr = (NodeTypeManagerImpl)
ticket.getWorkspace().getNodeTypeManager();
+ NodeType[] nta = new NodeType[mixinNames.size()];
+ Iterator iter = mixinNames.iterator();
+ int i = 0;
+ while (iter.hasNext()) {
+ nta[i++] = ntMgr.getNodeType((QName) iter.next());
+ }
+ return nta;
}
/**
@@ -1214,8 +1277,58 @@
public void addMixin(String mixinName)
throws NoSuchNodeTypeException, ConstraintViolationException,
RepositoryException {
- // @todo implement mixin node types support
- throw new RepositoryException("not yet implemented");
+ // check state of this instance
+ checkItemState();
+
+ QName ntName = QName.fromJCRName(mixinName, ticket.getNamespaceResolver());
+
+ NodeTypeManagerImpl ntMgr = (NodeTypeManagerImpl)
ticket.getWorkspace().getNodeTypeManager();
+ NodeTypeImpl mixin = ntMgr.getNodeType(ntName);
+ if (!mixin.isMixin()) {
+ throw new RepositoryException(mixinName + ": not a mixin node type");
+ }
+ if (nodeType.isDerivedFrom(ntName)) {
+ throw new RepositoryException(mixinName + ": already contained in primary
node type");
+ }
+
+ // build effective node type of mixins & primary type in order to detect
conflicts
+ NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
+ // existing mixin's
+ HashSet set = new HashSet(((NodeState) state).getMixinTypeNames());
+ // new mixin
+ set.add(ntName);
+ // primary type
+ set.add(nodeType.getQName());
+ try {
+ // try to build effective node type (will throw in case of conflicts)
+ ntReg.buildEffectiveNodeType((QName[]) set.toArray(new QName[set.size()]));
+ } catch (NodeTypeConflictException ntce) {
+ throw new ConstraintViolationException(ntce.getMessage());
+ }
+
+ // modify the state of this node
+ NodeState thisState = (NodeState) getOrCreateTransientItemState();
+ // add mixin name
+ Set mixins = new HashSet(thisState.getMixinTypeNames());
+ mixins.add(ntName);
+ thisState.setMixinTypeNames(mixins);
+
+ // set jcr:mixinTypes property
+ setMixinTypesProperty(mixins);
+
+ // add 'auto-create' properties defined in mixin type
+ PropertyDef[] pda = mixin.getAutoCreatePropertyDefs();
+ for (int i = 0; i < pda.length; i++) {
+ PropertyDefImpl pd = (PropertyDefImpl) pda[i];
+ createChildProperty(pd.getQName(), pd.getRequiredType(), pd);
+ }
+
+ // recursively add 'auto-create' child nodes defined in mixin type
+ NodeDef[] nda = mixin.getAutoCreateNodeDefs();
+ for (int i = 0; i < nda.length; i++) {
+ NodeDefImpl nd = (NodeDefImpl) nda[i];
+ createChildNode(nd.getQName(), nd, (NodeTypeImpl)
nd.getDefaultPrimaryType());
+ }
}
/**
@@ -1224,16 +1337,114 @@
public void removeMixin(String mixinName)
throws NoSuchNodeTypeException, ConstraintViolationException,
RepositoryException {
- // @todo implement mixin node types support
- throw new RepositoryException("not yet implemented");
+ // check state of this instance
+ checkItemState();
+
+ QName ntName = QName.fromJCRName(mixinName, ticket.getNamespaceResolver());
+
+ // check if mixin is assigned
+ if (!((NodeState) state).getMixinTypeNames().contains(ntName)) {
+ throw new NoSuchNodeTypeException(mixinName);
+ }
+
+ if (NodeTypeRegistry.MIX_REFERENCEABLE.equals(ntName)) {
+ /**
+ * mix:referenceable needs special handling because it has
+ * special semantics:
+ * it can only be removed if there no more references to this node
+ *
+ * todo check if there are REFERENCE properties pointing to this node
+ */
+ throw new ConstraintViolationException(mixinName + " can not be removed");
+ }
+
+ // modify the state of this node
+ NodeState thisState = (NodeState) getOrCreateTransientItemState();
+ // remove mixin name
+ Set mixins = new HashSet(thisState.getMixinTypeNames());
+ mixins.remove(ntName);
+ thisState.setMixinTypeNames(mixins);
+
+ // set jcr:mixinTypes property
+ setMixinTypesProperty(mixins);
+
+ NodeTypeManagerImpl ntMgr = (NodeTypeManagerImpl)
ticket.getWorkspace().getNodeTypeManager();
+ NodeTypeImpl mixin = ntMgr.getNodeType(ntName);
+
+ // shortcut
+ if (mixin.getDeclaredChildNodeDefs().length == 0 &&
+ mixin.getDeclaredPropertyDefs().length == 0) {
+ // the node type has neither property nor child node definitions,
+ // i.e. we're done
+ return;
+ }
+
+ // walk through properties and child nodes and remove those that have been
+ // defined by the specified mixin type
+
+ // use temp array to avoid ConcurrentModificationException
+ ArrayList tmp = new ArrayList(thisState.getPropertyEntries());
+ Iterator iter = tmp.iterator();
+ while (iter.hasNext()) {
+ NodeState.PropertyEntry entry = (NodeState.PropertyEntry) iter.next();
+ PropertyImpl prop = (PropertyImpl) itemMgr.getItem(new
PropertyId(thisState.getUUID(), entry.getName()));
+ // check if property has been defined by mixin type
+ NodeTypeImpl declaringNT = (NodeTypeImpl)
prop.getDefinition().getDeclaringNodeType();
+ if (mixin.getQName().equals(declaringNT.getQName())
+ || mixin.isDerivedFrom(declaringNT.getQName())) {
+ // remove property
+ removeChildProperty(entry.getName());
+ }
+ }
+ // use temp array to avoid ConcurrentModificationException
+ tmp = new ArrayList(thisState.getChildNodeEntries());
+ iter = tmp.iterator();
+ while (iter.hasNext()) {
+ NodeState.ChildNodeEntry entry = (NodeState.ChildNodeEntry) iter.next();
+ NodeImpl node = (NodeImpl) itemMgr.getItem(new NodeId(entry.getUUID()));
+ // check if node has been defined by mixin type
+ NodeTypeImpl declaringNT = (NodeTypeImpl)
node.getDefinition().getDeclaringNodeType();
+ if (mixin.getQName().equals(declaringNT.getQName())
+ || mixin.isDerivedFrom(declaringNT.getQName())) {
+ // remove node
+ removeChildNode(entry.getName(), entry.getIndex());
+ }
+ }
}
/**
* @see Node#canAddMixin(String)
*/
public boolean canAddMixin(String mixinName) throws RepositoryException {
- // @todo implement mixin node types support
- throw new RepositoryException("not yet implemented");
+ // check state of this instance
+ checkItemState();
+
+ QName ntName = QName.fromJCRName(mixinName, ticket.getNamespaceResolver());
+
+ NodeTypeManagerImpl ntMgr = (NodeTypeManagerImpl)
ticket.getWorkspace().getNodeTypeManager();
+ NodeTypeImpl mixin = ntMgr.getNodeType(ntName);
+ if (!mixin.isMixin()) {
+ return false;
+ }
+ if (nodeType.isDerivedFrom(ntName)) {
+ return false;
+ }
+
+ // build effective node type of mixins & primary type in order to detect
conflicts
+ NodeTypeRegistry ntReg = ntMgr.getNodeTypeRegistry();
+ // existing mixin's
+ HashSet set = new HashSet(((NodeState) state).getMixinTypeNames());
+ // new mixin
+ set.add(ntName);
+ // primary type
+ set.add(nodeType.getQName());
+ try {
+ ntReg.buildEffectiveNodeType((QName[]) set.toArray(new QName[set.size()]));
+ } catch (NodeTypeConflictException ntce) {
+ return false;
+ }
+
+ return true;
}
/**
1.6 +36 -15
jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/Test.java
Index: Test.java
===================================================================
RCS file:
/home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/Test.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- Test.java 7 Jul 2004 16:05:45 -0000 1.5
+++ Test.java 9 Jul 2004 16:48:44 -0000 1.6
@@ -91,15 +91,34 @@
System.out.println();
dumpTree(root, System.out);
+ if (root.canAddMixin("mix:versionable")) {
+ root.addMixin("mix:versionable");
+ if (root.canAddMixin("mix:accessControllable")) {
+ root.addMixin("mix:accessControllable");
+ }
+ dumpTree(root, System.out);
+ boolean accessControlable = root.isNodeType("mix:accessControllable");
+ root.removeMixin("mix:versionable");
+ dumpTree(root, System.out);
+ root.save();
+ }
+
//root.setProperty("blob", new FileInputStream(new File("d:/temp/jcrri.zip")));
root.setProperty("bla", 1);
root.setProperty("bla", 1.4);
root.setProperty("bla", "blabla");
- root.addNode("blu", "nt:file");
+ Node file = root.addNode("blu", "nt:file");
+ file.addNode("jcr:content");
root.addNode("blu", "nt:folder");
root.addNode("blu");
+ dumpTree(root, System.out);
+ root.orderBefore("blu", null);
+ dumpTree(root, System.out);
+ root.orderBefore("blu[2]", "blu[1]");
+ dumpTree(root, System.out);
+
System.out.println("before save()...");
System.out.println();
dumpTree(root, System.out);
@@ -110,19 +129,21 @@
System.out.println();
dumpTree(root, System.out);
- Property blob = root.getProperty("blob");
- InputStream in = blob.getStream();
- // spool stream to temp file
- FileOutputStream out = new FileOutputStream(new File("d:/temp/scratch.zip"));
- try {
- byte[] buffer = new byte[8192];
- int read = 0;
- while ((read = in.read(buffer)) > 0) {
- out.write(buffer, 0, read);
+ if (root.hasProperty("blob")) {
+ Property blob = root.getProperty("blob");
+ InputStream in = blob.getStream();
+ // spool stream to temp file
+ FileOutputStream out = new FileOutputStream(new
File("d:/temp/scratch.zip"));
+ try {
+ byte[] buffer = new byte[8192];
+ int read = 0;
+ while ((read = in.read(buffer)) > 0) {
+ out.write(buffer, 0, read);
+ }
+ } finally {
+ out.close();
+ in.close();
}
- } finally {
- out.close();
- in.close();
}
Node misc = root.addNode("misc", "nt:unstructured");
@@ -153,7 +174,7 @@
Node n = root.addNode("foo", "nt:folder");
Node n2 = n.addNode("foofile", "nt:file");
- Node n3 = n2.getNode("jcr:content");
+ Node n3 = n2.addNode("jcr:content");
Property p1 = n3.setProperty("prop1", new LongValue(123));
Property p2 = n3.setProperty("prop2", new StringValue("blabla"));
1.15 +62 -12
jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/PropertyImpl.java
Index: PropertyImpl.java
===================================================================
RCS file:
/home/cvs/jakarta-slide/proposals/jcrri/src/org/apache/slide/jcr/core/PropertyImpl.java,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- PropertyImpl.java 7 Jul 2004 16:05:25 -0000 1.14
+++ PropertyImpl.java 9 Jul 2004 16:48:44 -0000 1.15
@@ -140,16 +140,6 @@
// check state of this instance
checkItemState();
- // check protected flag
- if (definition.isProtected()) {
- throw new ConstraintViolationException("cannot set the value of a
protected property " + safeGetJCRPath());
- }
-
- // check multi-value flag
- if (!definition.isMultiple() && values != null && values.length > 1) {
- throw new ConstraintViolationException(safeGetJCRPath() + " is not
multi-valued");
- }
-
// modify the state of this property
PropertyState thisState = (PropertyState) getOrCreateTransientItemState();
@@ -212,6 +202,16 @@
// check state of this instance
checkItemState();
+ // check protected flag
+ if (definition.isProtected()) {
+ throw new ConstraintViolationException("cannot set the value of a
protected property " + safeGetJCRPath());
+ }
+
+ // check multi-value flag
+ if (!definition.isMultiple() && names != null && names.length > 1) {
+ throw new ConstraintViolationException(safeGetJCRPath() + " is not
multi-valued");
+ }
+
// check type according to definition of this property
int reqType = definition.getRequiredType();
if (reqType == PropertyType.UNDEFINED) {
@@ -492,6 +492,11 @@
// check state of this instance
checkItemState();
+ // check protected flag
+ if (definition.isProtected()) {
+ throw new ConstraintViolationException("cannot set the value of a
protected property " + safeGetJCRPath());
+ }
+
// check type according to definition of this property
int reqType = definition.getRequiredType();
if (reqType == PropertyType.UNDEFINED) {
@@ -522,6 +527,11 @@
// check state of this instance
checkItemState();
+ // check protected flag
+ if (definition.isProtected()) {
+ throw new ConstraintViolationException("cannot set the value of a
protected property " + safeGetJCRPath());
+ }
+
// check type according to definition of this property
int reqType = definition.getRequiredType();
if (reqType == PropertyType.UNDEFINED) {
@@ -547,6 +557,11 @@
// check state of this instance
checkItemState();
+ // check protected flag
+ if (definition.isProtected()) {
+ throw new ConstraintViolationException("cannot set the value of a
protected property " + safeGetJCRPath());
+ }
+
// check type according to definition of this property
int reqType = definition.getRequiredType();
if (reqType == PropertyType.UNDEFINED) {
@@ -594,6 +609,16 @@
// check state of this instance
checkItemState();
+ // check protected flag
+ if (definition.isProtected()) {
+ throw new ConstraintViolationException("cannot set the value of a
protected property " + safeGetJCRPath());
+ }
+
+ // check multi-value flag
+ if (!definition.isMultiple() && strings != null && strings.length > 1) {
+ throw new ConstraintViolationException(safeGetJCRPath() + " is not
multi-valued");
+ }
+
// check type according to definition of this property
int reqType = definition.getRequiredType();
if (reqType == PropertyType.UNDEFINED) {
@@ -630,6 +655,11 @@
// check state of this instance
checkItemState();
+ // check protected flag
+ if (definition.isProtected()) {
+ throw new ConstraintViolationException("cannot set the value of a
protected property " + safeGetJCRPath());
+ }
+
// check type according to definition of this property
int reqType = definition.getRequiredType();
if (reqType == PropertyType.UNDEFINED) {
@@ -655,6 +685,11 @@
// check state of this instance
checkItemState();
+ // check protected flag
+ if (definition.isProtected()) {
+ throw new ConstraintViolationException("cannot set the value of a
protected property " + safeGetJCRPath());
+ }
+
// @todo implement correct semantics (i.e. referential integrity) for
REFERENCE values
// check type according to definition of this property
@@ -694,6 +729,11 @@
// check state of this instance
checkItemState();
+ // check protected flag
+ if (definition.isProtected()) {
+ throw new ConstraintViolationException("cannot set the value of a
protected property " + safeGetJCRPath());
+ }
+
// check type according to definition of this property
int reqType = definition.getRequiredType();
if (reqType == PropertyType.UNDEFINED) {
@@ -729,6 +769,16 @@
public void setValue(Value[] values) throws ValueFormatException,
RepositoryException {
// check state of this instance
checkItemState();
+
+ // check protected flag
+ if (definition.isProtected()) {
+ throw new ConstraintViolationException("cannot set the value of a
protected property " + safeGetJCRPath());
+ }
+
+ // check multi-value flag
+ if (!definition.isMultiple() && values != null && values.length > 1) {
+ throw new ConstraintViolationException(safeGetJCRPath() + " is not
multi-valued");
+ }
int reqType = definition.getRequiredType();
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]