diff --git a/README.md b/README.md
index ce44041..36f2cec 100644
--- a/README.md
+++ b/README.md
@@ -153,7 +153,7 @@ repositories {
}
}
-testCompile 'com.twcable.jackalope:jackalope:3.0.0'
+testCompile 'com.twcable.jackalope:jackalope:3.1.0'
```
# LICENSE
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index e075655..29d3071 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,10 @@
# RELEASE NOTES
+## 3.1.0
+
+* Implemented basic mixin support in NodeImpl
+* Implemented basic NamePathResolver and NamespaceRegistry support in SessionImpl
+
## 3.0.0
Updated to support AEM 6.0, from AEM 5.6.1
diff --git a/build.gradle b/build.gradle
index 6547bab..ffdf1b1 100644
--- a/build.gradle
+++ b/build.gradle
@@ -50,7 +50,7 @@ dependencies {
runtime "ch.qos.logback:logback-classic:1.0.4"
testCompile "org.codehaus.groovy:groovy:2.3.6"
- testCompile "org.spockframework:spock-core:0.7-groovy-2.0", {
+ testCompile "org.spockframework:spock-core:1.0-groovy-2.3", {
exclude group: 'org.codehaus.groovy', module: 'groovy-all'
}
}
diff --git a/gradle.properties b/gradle.properties
index 2c207f4..086f698 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,4 +1,4 @@
# suppress inspection "UnusedProperty" for whole file
description = Provides a convenient way of stubbing out Sling and the JCR
group = com.twcable.jackalope
-version = 3.0.0
+version = 3.1.0-SNAPSHOT
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index c93c687..ad9d71b 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,2 +1,2 @@
#Tue Feb 24 15:51:41 MST 2015
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.3-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-bin.zip
diff --git a/src/main/java/com/twcable/jackalope/impl/jcr/NodeImpl.java b/src/main/java/com/twcable/jackalope/impl/jcr/NodeImpl.java
index 049ca22..eb74493 100644
--- a/src/main/java/com/twcable/jackalope/impl/jcr/NodeImpl.java
+++ b/src/main/java/com/twcable/jackalope/impl/jcr/NodeImpl.java
@@ -18,6 +18,8 @@
import com.twcable.jackalope.impl.common.Paths;
import com.twcable.jackalope.impl.common.Values;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.name.NameFactoryImpl;
import javax.annotation.Nonnull;
import javax.jcr.AccessDeniedException;
@@ -45,6 +47,8 @@
import javax.jcr.nodetype.NoSuchNodeTypeException;
import javax.jcr.nodetype.NodeDefinition;
import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.PropertyDefinition;
import javax.jcr.version.ActivityViolationException;
import javax.jcr.version.Version;
import javax.jcr.version.VersionException;
@@ -52,11 +56,12 @@
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.UUID;
+import static java.util.Collections.singletonList;
+
/**
* Implementation of jcr Node interface.
@@ -336,43 +341,122 @@ public boolean hasProperties() throws RepositoryException {
@Override
public NodeType getPrimaryNodeType() throws RepositoryException {
- return new NodeTypeImpl(getProperty("jcr:primaryType").getString());
+ return new NodeTypeImpl(primaryTypeProperty().getString());
+ }
+
+
+ private PropertyImpl primaryTypeProperty() throws RepositoryException {
+ return getOrCreateProperty(getJcrNameForQName(Property.JCR_PRIMARY_TYPE));
}
+ private PropertyImpl mixinProperty() throws RepositoryException {
+ return getOrCreateProperty(getJcrNameForQName(Property.JCR_MIXIN_TYPES));
+ }
+
+
+ /**
+ * Returns the declared mixin node types of this node.
+ *
+ * The default implementation uses the values of the
+ * jcr:mixinTypes property to look up the mixin node types
+ * from the {@link NodeTypeManager} of the current workspace.
+ *
+ * @return mixin node types
+ * @throws RepositoryException if an error occurs
+ */
@Override
public NodeType[] getMixinNodeTypes() throws RepositoryException {
- return new NodeType[0];
+ NodeTypeManager manager = getSession().getWorkspace().getNodeTypeManager();
+ Property property = mixinProperty();
+ Value[] values = property.getValues();
+ if (values == null) return new NodeType[0];
+ NodeType[] types = new NodeType[values.length];
+ for (int i = 0; i < values.length; i++) {
+ types[i] = manager.getNodeType(values[i].getString());
+ }
+ return types;
+ }
+
+
+ private String getJcrNameForQName(String name) throws RepositoryException {
+ return getJcrName(NameFactoryImpl.getInstance().create(name));
+ }
+
+
+ private String getJcrName(Name name) throws RepositoryException {
+ return session.getNamePathResolver().getJCRName(name);
}
@Override
public boolean isNodeType(String nodeTypeName) throws RepositoryException {
- return getProperty("jcr:primaryType").getString().equals(nodeTypeName);
+ return primaryTypeProperty().getString().equals(nodeTypeName);
}
@Override
public void setPrimaryType(String nodeTypeName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException {
- setProperty("jcr:primaryType", nodeTypeName);
+ setProperty(getJcrNameForQName(Property.JCR_PRIMARY_TYPE), nodeTypeName);
}
+ /**
+ * Very simple implementation of Mixin support: Does not check permissions, check for conflicts, etc.
+ */
@Override
public void addMixin(String mixinName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException {
- //Not Implemented
+ Property mixinProperty = mixinProperty();
+ Value[] values = mixinProperty.getValues();
+ final Value[] newValues;
+ if (values == null) {
+ newValues = new Value[1];
+ newValues[0] = new ValueImpl(mixinName);
+ }
+ else {
+ newValues = new Value[values.length + 1];
+ System.arraycopy(values, 0, newValues, 0, values.length);
+ newValues[values.length] = new ValueImpl(mixinName);
+ }
+ mixinProperty.setValue(newValues);
+ session.changeItem(this);
}
@Override
public void removeMixin(String mixinName) throws NoSuchNodeTypeException, VersionException, ConstraintViolationException, LockException, RepositoryException {
- //Not Implemented
+ Property mixinProperty = mixinProperty();
+ Value[] values = mixinProperty.getValues();
+ if (values == null) {
+ throw new NoSuchNodeTypeException(mixinName);
+ }
+
+ boolean found = false;
+ Value[] newValues = new Value[values.length - 1];
+ for (int idx = 0, newIdx = 0; idx < values.length; ) {
+ Value value = values[idx];
+ if (value.getString().equals(mixinName)) {
+ idx++;
+ found = true;
+ }
+ else {
+ if (newIdx < newValues.length)
+ newValues[newIdx] = values[idx];
+ idx++;
+ newIdx++;
+ }
+ }
+
+ if (found) {
+ mixinProperty.setValue(newValues);
+ session.changeItem(this);
+ }
}
@Override
public boolean canAddMixin(String mixinName) throws NoSuchNodeTypeException, RepositoryException {
- return false;
+ return true;
}
@@ -426,7 +510,7 @@ public String getCorrespondingNodePath(String workspaceName) throws ItemNotFound
@Override
public NodeIterator getSharedSet() throws RepositoryException {
- return new NodeIteratorImpl(Arrays.asList((Node)this)); //To change body of implemented methods use File | Settings | File Templates.
+ return new NodeIteratorImpl(singletonList((Node)this));
}
@@ -541,4 +625,5 @@ public void accept(ItemVisitor visitor) throws RepositoryException {
private PropertyImpl getOrCreateProperty(String name) throws RepositoryException {
return hasProperty(name) ? (PropertyImpl)getProperty(name) : new PropertyImpl(session, Paths.resolve(getPath(), name));
}
+
}
diff --git a/src/main/java/com/twcable/jackalope/impl/jcr/NodeTypeImpl.java b/src/main/java/com/twcable/jackalope/impl/jcr/NodeTypeImpl.java
index 5309656..bdaa13d 100644
--- a/src/main/java/com/twcable/jackalope/impl/jcr/NodeTypeImpl.java
+++ b/src/main/java/com/twcable/jackalope/impl/jcr/NodeTypeImpl.java
@@ -25,8 +25,10 @@
/**
* Simple implementation of an {@link NodeType}
*/
+@SuppressWarnings("unused")
public class NodeTypeImpl implements NodeType {
private final String nodeTypeName;
+ private boolean isMixin;
public NodeTypeImpl(String nodeTypeName) {
@@ -60,7 +62,7 @@ public NodeTypeIterator getDeclaredSubtypes() {
@Override
public boolean isNodeType(String nodeTypeName) {
- return this.nodeTypeName.equals(nodeTypeName); //To change body of implemented methods use File | Settings | File Templates.
+ return this.nodeTypeName.equals(nodeTypeName);
}
@@ -136,9 +138,14 @@ public boolean isAbstract() {
}
+ public void setIsMixin(boolean isMixin) {
+ this.isMixin = isMixin;
+ }
+
+
@Override
public boolean isMixin() {
- return false;
+ return this.isMixin;
}
diff --git a/src/main/java/com/twcable/jackalope/impl/jcr/NodeTypeManagerImpl.java b/src/main/java/com/twcable/jackalope/impl/jcr/NodeTypeManagerImpl.java
new file mode 100644
index 0000000..a9e25f4
--- /dev/null
+++ b/src/main/java/com/twcable/jackalope/impl/jcr/NodeTypeManagerImpl.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2015 Time Warner Cable, Inc.
+ *
+ * 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 com.twcable.jackalope.impl.jcr;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.nodetype.InvalidNodeTypeDefinitionException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeDefinitionTemplate;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeDefinition;
+import javax.jcr.nodetype.NodeTypeExistsException;
+import javax.jcr.nodetype.NodeTypeIterator;
+import javax.jcr.nodetype.NodeTypeManager;
+import javax.jcr.nodetype.NodeTypeTemplate;
+import javax.jcr.nodetype.PropertyDefinitionTemplate;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Simple implementation of {@link NodeTypeManager}. Use {@link #registerNodeType(NodeType)} to add NodeTypes.
+ */
+@SuppressWarnings("DuplicateThrows")
+public class NodeTypeManagerImpl implements NodeTypeManager {
+ private Map nameToNodeType = new LinkedHashMap<>();
+
+
+ @Override
+ public NodeType getNodeType(String nodeTypeName) throws NoSuchNodeTypeException, RepositoryException {
+ NodeType nodeType = nameToNodeType.get(nodeTypeName);
+ if (nodeType == null) throw new NoSuchNodeTypeException(nodeTypeName);
+ return nodeType;
+ }
+
+
+ @Override
+ public boolean hasNodeType(String name) throws RepositoryException {
+ return nameToNodeType.containsKey(name);
+ }
+
+
+ @Override
+ public NodeTypeIterator getAllNodeTypes() throws RepositoryException {
+ return new NodeTypeIteratorImpl(nameToNodeType.values().iterator());
+ }
+
+
+ @Override
+ public NodeTypeIterator getPrimaryNodeTypes() throws RepositoryException {
+ ArrayList nodeTypes = new ArrayList<>();
+ for (NodeType nodeType : nameToNodeType.values()) {
+ if (!nodeType.isMixin()) nodeTypes.add(nodeType);
+ }
+ return new NodeTypeIteratorImpl(nodeTypes.iterator());
+ }
+
+
+ @Override
+ public NodeTypeIterator getMixinNodeTypes() throws RepositoryException {
+ ArrayList nodeTypes = new ArrayList<>();
+ for (NodeType nodeType : nameToNodeType.values()) {
+ if (nodeType.isMixin()) nodeTypes.add(nodeType);
+ }
+ return new NodeTypeIteratorImpl(nodeTypes.iterator());
+ }
+
+
+ @Override
+ public NodeTypeTemplate createNodeTypeTemplate() throws UnsupportedRepositoryOperationException, RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public NodeTypeTemplate createNodeTypeTemplate(NodeTypeDefinition ntd) throws UnsupportedRepositoryOperationException, RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public NodeDefinitionTemplate createNodeDefinitionTemplate() throws UnsupportedRepositoryOperationException, RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public PropertyDefinitionTemplate createPropertyDefinitionTemplate() throws UnsupportedRepositoryOperationException, RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public NodeType registerNodeType(NodeTypeDefinition ntd, boolean allowUpdate) throws InvalidNodeTypeDefinitionException, NodeTypeExistsException, UnsupportedRepositoryOperationException, RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @SuppressWarnings("unused")
+ public void registerNodeType(NodeType nt) {
+ nameToNodeType.put(nt.getName(), nt);
+ }
+
+
+ @Override
+ public NodeTypeIterator registerNodeTypes(NodeTypeDefinition[] ntds, boolean allowUpdate) throws InvalidNodeTypeDefinitionException, NodeTypeExistsException, UnsupportedRepositoryOperationException, RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public void unregisterNodeType(String name) throws UnsupportedRepositoryOperationException, NoSuchNodeTypeException, RepositoryException {
+ nameToNodeType.remove(name);
+ }
+
+
+ @Override
+ public void unregisterNodeTypes(String[] names) throws UnsupportedRepositoryOperationException, NoSuchNodeTypeException, RepositoryException {
+ for (String name : names) {
+ unregisterNodeType(name);
+ }
+ }
+
+
+ private static class NodeTypeIteratorImpl implements NodeTypeIterator {
+ private final Iterator iterator;
+
+
+ public NodeTypeIteratorImpl(Iterator iterator) {
+ this.iterator = iterator;
+ }
+
+
+ @Override
+ public NodeType nextNodeType() {
+ return (NodeType)next();
+ }
+
+
+ @Override
+ public void skip(long skipNum) {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public long getSize() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public long getPosition() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+
+ @Override
+ public Object next() {
+ return iterator.next();
+ }
+
+
+ @Override
+ public void remove() {
+ iterator.remove();
+ }
+ }
+}
diff --git a/src/main/java/com/twcable/jackalope/impl/jcr/SessionImpl.java b/src/main/java/com/twcable/jackalope/impl/jcr/SessionImpl.java
index 6d76cda..b5b4a4c 100644
--- a/src/main/java/com/twcable/jackalope/impl/jcr/SessionImpl.java
+++ b/src/main/java/com/twcable/jackalope/impl/jcr/SessionImpl.java
@@ -17,10 +17,14 @@
package com.twcable.jackalope.impl.jcr;
import com.twcable.jackalope.impl.common.Paths;
+import org.apache.jackrabbit.spi.Name;
+import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
+import org.apache.jackrabbit.spi.commons.conversion.NamePathResolver;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import javax.annotation.Nonnull;
+import javax.jcr.AccessDeniedException;
import javax.jcr.Credentials;
import javax.jcr.InvalidSerializedDataException;
import javax.jcr.Item;
@@ -28,6 +32,7 @@
import javax.jcr.ItemNotFoundException;
import javax.jcr.LoginException;
import javax.jcr.NamespaceException;
+import javax.jcr.NamespaceRegistry;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
@@ -47,6 +52,7 @@
import java.io.OutputStream;
import java.security.AccessControlException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -67,6 +73,8 @@ public class SessionImpl implements Session {
private Set changedItems = new HashSet<>();
private Workspace workspace = null;
+ private NamespaceRegistry namespaceRegistry = null;
+ private DefaultNamePathResolver namePathResolver;
@Override
@@ -96,14 +104,28 @@ public Object getAttribute(String name) {
@Override
public Workspace getWorkspace() {
if (workspace == null) {
- WorkspaceImpl workspaceImpl = new WorkspaceImpl();
- workspaceImpl.setSession(this);
- workspace = workspaceImpl;
+ workspace = new WorkspaceImpl(this);
}
return workspace;
}
+ public NamespaceRegistry getNamespaceRegistry() {
+ if (namespaceRegistry == null) {
+ namespaceRegistry = new MyNamespaceRegistry();
+ }
+ return namespaceRegistry;
+ }
+
+
+ public NamePathResolver getNamePathResolver() {
+ if (namePathResolver == null) {
+ namePathResolver = new DefaultNamePathResolver(getNamespaceRegistry());
+ }
+ return namePathResolver;
+ }
+
+
@Override
public Node getRootNode() {
return (Node)itemStore.get("/"); // Added in ctor
@@ -265,24 +287,25 @@ public void exportDocumentView(String absPath, OutputStream out, boolean skipBin
@Override
public void setNamespacePrefix(String prefix, String uri) throws NamespaceException, RepositoryException {
+ namespaceRegistry.registerNamespace(prefix, uri);
}
@Override
public String[] getNamespacePrefixes() throws RepositoryException {
- return new String[0];
+ return namespaceRegistry.getPrefixes();
}
@Override
public String getNamespaceURI(String prefix) throws NamespaceException, RepositoryException {
- return null;
+ return namespaceRegistry.getURI(prefix);
}
@Override
public String getNamespacePrefix(String uri) throws NamespaceException, RepositoryException {
- return null;
+ return namespaceRegistry.getPrefix(uri);
}
@@ -423,4 +446,63 @@ boolean isNew(ItemImpl item) {
boolean isModified(ItemImpl item) {
return changedItems.contains(item.getPath());
}
+
+
+ private static class MyNamespaceRegistry implements NamespaceRegistry {
+ private final Map prefixToUri = new HashMap<>();
+
+
+ public MyNamespaceRegistry() {
+ prefixToUri.put(Name.NS_JCR_PREFIX, Name.NS_JCR_URI);
+ prefixToUri.put(Name.NS_MIX_PREFIX, Name.NS_MIX_URI);
+ prefixToUri.put(Name.NS_NT_PREFIX, Name.NS_NT_URI);
+ prefixToUri.put(Name.NS_REP_PREFIX, Name.NS_REP_URI);
+ }
+
+
+ @Override
+ public void registerNamespace(String prefix, String uri) throws NamespaceException, UnsupportedRepositoryOperationException, AccessDeniedException, RepositoryException {
+ prefixToUri.put(prefix, uri);
+ }
+
+
+ @Override
+ public void unregisterNamespace(String prefix) throws NamespaceException, UnsupportedRepositoryOperationException, AccessDeniedException, RepositoryException {
+ prefixToUri.remove(prefix);
+ }
+
+
+ @Override
+ public String[] getPrefixes() throws RepositoryException {
+ Set keySet = prefixToUri.keySet();
+ return keySet.toArray(new String[keySet.size()]);
+ }
+
+
+ @Override
+ public String[] getURIs() throws RepositoryException {
+ Collection values = prefixToUri.values();
+ return values.toArray(new String[values.size()]);
+ }
+
+
+ @Override
+ public String getURI(String prefix) throws NamespaceException, RepositoryException {
+ String uri = prefixToUri.get(prefix);
+ if (uri == null) {
+ throw new NamespaceException(prefix);
+ }
+ return uri;
+ }
+
+
+ @Override
+ public String getPrefix(String uri) throws NamespaceException, RepositoryException {
+ for (Map.Entry entry : prefixToUri.entrySet()) {
+ if (entry.getValue().equalsIgnoreCase(uri)) return entry.getKey();
+ }
+ throw new NamespaceException(uri);
+ }
+ }
+
}
diff --git a/src/main/java/com/twcable/jackalope/impl/jcr/WorkspaceImpl.java b/src/main/java/com/twcable/jackalope/impl/jcr/WorkspaceImpl.java
index 89f3ac1..a108418 100644
--- a/src/main/java/com/twcable/jackalope/impl/jcr/WorkspaceImpl.java
+++ b/src/main/java/com/twcable/jackalope/impl/jcr/WorkspaceImpl.java
@@ -46,12 +46,18 @@
*/
@SuppressWarnings("DuplicateThrows")
public class WorkspaceImpl implements Workspace {
- private Session session = null;
+ private SessionImpl session = null;
private ObservationManager observationManager = null;
+ private NodeTypeManager nodeTypeManager = null;
protected QueryManager queryManager = null;
+ public WorkspaceImpl(SessionImpl session) {
+ this.session = session;
+ }
+
+
@Override
public Session getSession() {
return session;
@@ -103,13 +109,16 @@ public QueryManager getQueryManager() throws RepositoryException {
@Override
public NamespaceRegistry getNamespaceRegistry() throws RepositoryException {
- return null;
+ return session.getNamespaceRegistry();
}
@Override
public NodeTypeManager getNodeTypeManager() throws RepositoryException {
- return null;
+ if (nodeTypeManager == null) {
+ nodeTypeManager = new NodeTypeManagerImpl();
+ }
+ return nodeTypeManager;
}
@@ -160,12 +169,8 @@ public void deleteWorkspace(String name) throws AccessDeniedException, Unsupport
}
- public void setSession(Session session) {
- this.session = session;
- }
-
-
public void setQueryManager(QueryManager queryManager) {
this.queryManager = queryManager;
}
+
}
diff --git a/src/test/groovy/com/twcable/jackalope/impl/jcr/NodeImplSpec.groovy b/src/test/groovy/com/twcable/jackalope/impl/jcr/NodeImplSpec.groovy
index 5d0257a..7442219 100644
--- a/src/test/groovy/com/twcable/jackalope/impl/jcr/NodeImplSpec.groovy
+++ b/src/test/groovy/com/twcable/jackalope/impl/jcr/NodeImplSpec.groovy
@@ -20,14 +20,18 @@ import com.google.common.collect.Lists
import spock.lang.Specification
import spock.lang.Subject
+import javax.jcr.Node
import javax.jcr.Value
import javax.jcr.nodetype.NodeType
@Subject(NodeImpl)
class NodeImplSpec extends Specification {
+ SessionImpl session = new SessionImpl()
+
+
def "A new node can be created"() {
when:
- def node = new NodeImpl(new SessionImpl(), "test")
+ def node = new NodeImpl(session, "test")
then:
node.isNode()
@@ -36,7 +40,7 @@ class NodeImplSpec extends Specification {
def "Properties can be set on nodes"() {
- def node = new NodeImpl(new SessionImpl(), "test")
+ def node = new NodeImpl(session, "test")
node.getSession().save()
when:
@@ -83,7 +87,7 @@ class NodeImplSpec extends Specification {
def "Nodes have a set of properties"() {
- def node = new NodeImpl(new SessionImpl(), "test")
+ def node = new NodeImpl(session, "test")
node.setProperty("first", "a")
node.setProperty("second", "b")
node.setProperty("third", "c")
@@ -100,7 +104,7 @@ class NodeImplSpec extends Specification {
def "Child nodes can be created"() {
- def node = new NodeImpl(new SessionImpl(), "test")
+ def node = new NodeImpl(session, "test")
node.getSession().save()
when:
@@ -118,7 +122,7 @@ class NodeImplSpec extends Specification {
def "Child nodes can be created with a specific node type"() {
- def node = new NodeImpl(new RepositoryImpl().login(), "test")
+ def node = new NodeImpl(new RepositoryImpl().login() as SessionImpl, "test")
node.getSession().save()
when:
@@ -130,14 +134,14 @@ class NodeImplSpec extends Specification {
def "A node can have multiple child nodes"() {
- def node = new NodeImpl(new SessionImpl(), "test")
+ def node = new NodeImpl(session, "test")
node.addNode("first")
node.addNode("second")
node.addNode("third")
node.getSession().save()
when:
- def nodes = Lists.newArrayList(node.getNodes())
+ def nodes = Lists. newArrayList(node.getNodes())
then:
nodes.find { it.getName() == "first" }
@@ -149,7 +153,7 @@ class NodeImplSpec extends Specification {
def "A node can be saved"() {
when:
- def node = new NodeImpl(new SessionImpl(), "test")
+ def node = new NodeImpl(session, "test")
then:
node.isNew()
node.getSession().hasPendingChanges()
@@ -176,7 +180,7 @@ class NodeImplSpec extends Specification {
def "Saving a node saves its children"() {
when:
- def node = new NodeImpl(new SessionImpl(), "test")
+ def node = new NodeImpl(session, "test")
def child = node.addNode("child")
then:
node.isNew()
@@ -205,8 +209,6 @@ class NodeImplSpec extends Specification {
def "Saving a node does not save any other node"() {
- def session = new SessionImpl()
-
when:
def node1 = new NodeImpl(session, "node1")
def node2 = new NodeImpl(session, "node2")
@@ -246,7 +248,6 @@ class NodeImplSpec extends Specification {
def "remove() deletes the node from the session"() {
- def session = new SessionImpl()
def parent = new NodeImpl(session, "parent")
def child = parent.addNode("child")
session.nodeExists("parent/child")
@@ -260,11 +261,10 @@ class NodeImplSpec extends Specification {
def "remove deletes descendent nodes from the session"() {
- def session = new SessionImpl()
def parent = new NodeImpl(session, "parent")
def child = parent.addNode("child")
def grandchild = child.addNode("grandchild")
- def greatgrandchild = grandchild.addNode("greatgrandchild")
+ grandchild.addNode("greatgrandchild")
session.nodeExists("parent/child")
session.nodeExists("parent/child/grandchild")
session.nodeExists("parent/child/grandchild/greatgrandchild")
@@ -280,7 +280,6 @@ class NodeImplSpec extends Specification {
def "getParent for a standalone node returns the virtual root"() {
- def session = new SessionImpl()
def node = new NodeImpl(session, "node")
when:
@@ -289,4 +288,33 @@ class NodeImplSpec extends Specification {
then:
parent == session.getRootNode()
}
+
+
+ def "can add and remove mixins"() {
+ def nodeTypeManager = session.workspace.nodeTypeManager as NodeTypeManagerImpl
+ nodeTypeManager.registerNodeType(new NodeTypeImpl("fooble"))
+ nodeTypeManager.registerNodeType(new NodeTypeImpl("bobble"))
+
+ def node = new NodeImpl(session, "/node")
+
+ when:
+ node.addMixin("bobble")
+ node.addMixin("fooble")
+
+ then:
+ node.getMixinNodeTypes().collect { it.name } as Set == ["fooble", "bobble"] as Set
+
+ when:
+ node.removeMixin("bobble")
+
+ then:
+ node.getMixinNodeTypes().collect { it.name } as Set == ["fooble"] as Set
+
+ when:
+ node.removeMixin("bzzzt")
+
+ then:
+ node.getMixinNodeTypes().collect { it.name } as Set == ["fooble"] as Set
+ }
+
}
diff --git a/src/test/groovy/com/twcable/jackalope/impl/jcr/NodeTypeImplSpec.groovy b/src/test/groovy/com/twcable/jackalope/impl/jcr/NodeTypeImplSpec.groovy
index 56e8094..c2cd65e 100644
--- a/src/test/groovy/com/twcable/jackalope/impl/jcr/NodeTypeImplSpec.groovy
+++ b/src/test/groovy/com/twcable/jackalope/impl/jcr/NodeTypeImplSpec.groovy
@@ -20,6 +20,7 @@ import spock.lang.Specification
import spock.lang.Subject
@Subject(NodeTypeImpl)
+@SuppressWarnings("GroovyPointlessBoolean")
class NodeTypeImplSpec extends Specification {
def "NodeType has a name"() {
@@ -34,4 +35,16 @@ class NodeTypeImplSpec extends Specification {
!new NodeTypeImpl("nodetype").isNodeType("nodetypex")
}
+
+ def "NodeType can set isMixin"() {
+ given:
+ NodeTypeImpl nodeType = new NodeTypeImpl("aNodeType")
+
+ when:
+ nodeType.setIsMixin(true)
+
+ then:
+ nodeType.isMixin() == true
+ }
+
}
diff --git a/src/test/groovy/com/twcable/jackalope/impl/jcr/NodeTypeManagerImplSpec.groovy b/src/test/groovy/com/twcable/jackalope/impl/jcr/NodeTypeManagerImplSpec.groovy
new file mode 100644
index 0000000..e4e912f
--- /dev/null
+++ b/src/test/groovy/com/twcable/jackalope/impl/jcr/NodeTypeManagerImplSpec.groovy
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2015 Time Warner Cable, Inc.
+ *
+ * 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 com.twcable.jackalope.impl.jcr
+
+import spock.lang.Specification
+import spock.lang.Subject
+
+class NodeTypeManagerImplSpec extends Specification {
+
+ @Subject
+ NodeTypeManagerImpl nodeTypeManager = new NodeTypeManagerImpl()
+
+
+ def "can register and get node types"() {
+ when:
+ nodeTypeManager.registerNodeType(new NodeTypeImpl("jcr:mixinTypes"))
+
+ then:
+ nodeTypeManager.hasNodeType("jcr:mixinTypes")
+ }
+
+}