diff --git a/config/alfresco/application-context.xml b/config/alfresco/application-context.xml
index 25df276103..5cb650346c 100644
--- a/config/alfresco/application-context.xml
+++ b/config/alfresco/application-context.xml
@@ -23,6 +23,7 @@
+
diff --git a/config/alfresco/jcr-api-context.xml b/config/alfresco/jcr-api-context.xml
new file mode 100644
index 0000000000..2b12957e2d
--- /dev/null
+++ b/config/alfresco/jcr-api-context.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+ SpacesStore
+
+
+
+
+
+ alfresco/model/jcrModel.xml
+
+
+
+
+
diff --git a/config/alfresco/jcr-context.xml b/config/alfresco/jcr-context.xml
new file mode 100644
index 0000000000..b95c728d2d
--- /dev/null
+++ b/config/alfresco/jcr-context.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/config/alfresco/model/jcrModel.xml b/config/alfresco/model/jcrModel.xml
new file mode 100644
index 0000000000..686d587f6f
--- /dev/null
+++ b/config/alfresco/model/jcrModel.xml
@@ -0,0 +1,62 @@
+
+
+ JCR Model Definitions
+ 1.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ d:qname
+ true
+ true
+
+
+ d:qname
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+ d:text
+ true
+ true
+
+
+
+
+
+
+
+ d:text
+
+
+ d:boolean
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/project-build.xml b/project-build.xml
index 384778a65f..0e8964351e 100644
--- a/project-build.xml
+++ b/project-build.xml
@@ -21,9 +21,9 @@
author="true" version="true" doctitle="Alfresco Content Management Service API Specification"
windowtitle="Alfresco Content Management Service API" classpathref="classpath.compile">
${javadoc.copyright}
-
+
-
+
@@ -51,5 +51,37 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/project.properties b/project.properties
index f27368e16c..937e555f8c 100644
--- a/project.properties
+++ b/project.properties
@@ -1,2 +1,6 @@
file.jibx.binding=${dir.src.java}/org/alfresco/repo/dictionary/m2binding.xml
dir.javadoc.api.service=${dir.docs}/java-public-service-api
+
+tck.webinf.lib.excludes=${webinf.lib.excludes},jcr-1.0.jar
+tck.file.name.war=alfresco-jcr-tck.war
+tck.dir.deploy=/jcr-tck-1.0
\ No newline at end of file
diff --git a/source/java/org/alfresco/jcr/api/JCRNodeRef.java b/source/java/org/alfresco/jcr/api/JCRNodeRef.java
new file mode 100644
index 0000000000..c7dff4055b
--- /dev/null
+++ b/source/java/org/alfresco/jcr/api/JCRNodeRef.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.api;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.StoreRef;
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.util.ParameterCheck;
+
+
+/**
+ * Helper to retrieve an Alfresco Node Reference from a JCR Node
+ *
+ * @author David Caruana
+ */
+public class JCRNodeRef
+{
+
+ /**
+ * Gets the Node Reference for the specified Node
+ *
+ * @param node JCR Node
+ * @return Alfresco Node Reference
+ * @throws RepositoryException
+ */
+ public static NodeRef getNodeRef(Node node)
+ throws RepositoryException
+ {
+ ParameterCheck.mandatory("Node", node);
+
+ Property protocol = node.getProperty(NamespaceService.SYSTEM_MODEL_PREFIX + ":" + ContentModel.PROP_STORE_PROTOCOL.getLocalName());
+ Property identifier = node.getProperty(NamespaceService.SYSTEM_MODEL_PREFIX + ":" + ContentModel.PROP_STORE_IDENTIFIER.getLocalName());
+ Property uuid = node.getProperty(NamespaceService.SYSTEM_MODEL_PREFIX + ":" + ContentModel.PROP_NODE_UUID.getLocalName());
+
+ return new NodeRef(new StoreRef(protocol.getString(), identifier.getString()), uuid.getString());
+ }
+
+
+}
diff --git a/source/java/org/alfresco/jcr/dictionary/ClassMap.java b/source/java/org/alfresco/jcr/dictionary/ClassMap.java
new file mode 100644
index 0000000000..2f1da30e72
--- /dev/null
+++ b/source/java/org/alfresco/jcr/dictionary/ClassMap.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.dictionary;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.RepositoryException;
+
+import org.alfresco.jcr.session.SessionImpl;
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.namespace.QName;
+
+
+/**
+ * Responsible for mapping Alfresco Classes to JCR Types / Mixins and vice versa.
+ *
+ * @author David Caruana
+ */
+public class ClassMap
+{
+ /** Map of Alfresco Class to JCR Class */
+ private static Map JCRToAlfresco = new HashMap();
+ static
+ {
+ JCRToAlfresco.put(NodeTypeImpl.MIX_REFERENCEABLE, ContentModel.ASPECT_REFERENCEABLE);
+ JCRToAlfresco.put(NodeTypeImpl.MIX_LOCKABLE, ContentModel.ASPECT_LOCKABLE);
+ JCRToAlfresco.put(NodeTypeImpl.MIX_VERSIONABLE, ContentModel.ASPECT_VERSIONABLE);
+ }
+
+ /** Map of JCR Class to Alfresco Class */
+ private static Map AlfrescoToJCR = new HashMap();
+ static
+ {
+ AlfrescoToJCR.put(ContentModel.ASPECT_REFERENCEABLE, NodeTypeImpl.MIX_REFERENCEABLE);
+ AlfrescoToJCR.put(ContentModel.ASPECT_LOCKABLE, NodeTypeImpl.MIX_LOCKABLE);
+ AlfrescoToJCR.put(ContentModel.ASPECT_VERSIONABLE, NodeTypeImpl.MIX_VERSIONABLE);
+ }
+
+ /** Map of JCR to Alfresco "Add Aspect" Behaviours */
+ private static Map addMixin = new HashMap();
+ static
+ {
+ addMixin.put(ContentModel.ASPECT_VERSIONABLE, new VersionableMixin());
+ }
+
+ /** Map of JCR to Alfresco "Remove Aspect" Behaviours */
+ private static Map removeMixin = new HashMap();
+ static
+ {
+ removeMixin.put(ContentModel.ASPECT_VERSIONABLE, new VersionableMixin());
+ }
+
+
+ /**
+ * Convert an Alfresco Class to a JCR Type
+ *
+ * @param jcrType JCR Type
+ * @return Alfresco Class
+ * @throws RepositoryException
+ */
+ public static QName convertTypeToClass(QName jcrType)
+ {
+ return JCRToAlfresco.get(jcrType);
+ }
+
+ /**
+ * Convert an Alfresco Class to a JCR Type
+ *
+ * @param alfrescoClass Alfresco Class
+ * @return JCR Type
+ * @throws RepositoryException
+ */
+ public static QName convertClassToType(QName alfrescoClass)
+ {
+ return JCRToAlfresco.get(alfrescoClass);
+ }
+
+ /**
+ * Get 'Add Mixin' JCR behaviour
+ *
+ * @param alfrescoClass
+ * @return AddMixin behaviour
+ */
+ public static AddMixin getAddMixin(QName alfrescoClass)
+ {
+ return addMixin.get(alfrescoClass);
+ }
+
+ /**
+ * Get 'Remove Mixin' JCR behaviour
+ *
+ * @param alfrescoClass
+ * @return RemoveMixin behaviour
+ */
+ public static RemoveMixin getRemoveMixin(QName alfrescoClass)
+ {
+ return removeMixin.get(alfrescoClass);
+ }
+
+ /**
+ * Add Mixin Behaviour
+ *
+ * Encapsulates mapping of JCR behaviour to Alfresco
+ */
+ public interface AddMixin
+ {
+ public Map preAddMixin(SessionImpl session, NodeRef nodeRef);
+ public void postAddMixin(SessionImpl session, NodeRef nodeRef);
+ }
+
+ /**
+ * Remove Mixin Behaviour
+ *
+ * Encapsulates mapping of JCR behaviour to Alfresco
+ */
+ public interface RemoveMixin
+ {
+ public void preRemoveMixin(SessionImpl session, NodeRef nodeRef);
+ public void postRemoveMixin(SessionImpl session, NodeRef nodeRef);
+ }
+
+}
diff --git a/source/java/org/alfresco/jcr/dictionary/DataTypeMap.java b/source/java/org/alfresco/jcr/dictionary/DataTypeMap.java
new file mode 100644
index 0000000000..5f1215a998
--- /dev/null
+++ b/source/java/org/alfresco/jcr/dictionary/DataTypeMap.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.dictionary;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+
+import org.alfresco.error.AlfrescoRuntimeException;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
+import org.alfresco.service.namespace.QName;
+
+
+/**
+ * Responsible for mapping Alfresco Data Types to JCR Property Types and vice versa.
+ *
+ * @author David Caruana
+ */
+public class DataTypeMap
+{
+
+ /** Map of Alfresco Data Type to JCR Property Type */
+ private static Map dataTypeToPropertyType = new HashMap();
+ static
+ {
+ dataTypeToPropertyType.put(DataTypeDefinition.TEXT, PropertyType.STRING);
+ dataTypeToPropertyType.put(DataTypeDefinition.CONTENT, PropertyType.BINARY);
+ dataTypeToPropertyType.put(DataTypeDefinition.INT, PropertyType.LONG);
+ dataTypeToPropertyType.put(DataTypeDefinition.LONG, PropertyType.LONG);
+ dataTypeToPropertyType.put(DataTypeDefinition.FLOAT, PropertyType.DOUBLE);
+ dataTypeToPropertyType.put(DataTypeDefinition.DOUBLE, PropertyType.DOUBLE);
+ dataTypeToPropertyType.put(DataTypeDefinition.DATE, PropertyType.DATE);
+ dataTypeToPropertyType.put(DataTypeDefinition.DATETIME, PropertyType.DATE);
+ dataTypeToPropertyType.put(DataTypeDefinition.BOOLEAN, PropertyType.BOOLEAN);
+ dataTypeToPropertyType.put(DataTypeDefinition.QNAME, PropertyType.NAME);
+ dataTypeToPropertyType.put(DataTypeDefinition.CATEGORY, PropertyType.STRING); // TODO: Check this mapping
+ dataTypeToPropertyType.put(DataTypeDefinition.NODE_REF, PropertyType.REFERENCE);
+ dataTypeToPropertyType.put(DataTypeDefinition.PATH, PropertyType.PATH);
+ dataTypeToPropertyType.put(DataTypeDefinition.ANY, PropertyType.UNDEFINED);
+ }
+
+ /** Map of JCR Property Type to Alfresco Data Type */
+ private static Map propertyTypeToDataType = new HashMap();
+ static
+ {
+ propertyTypeToDataType.put(PropertyType.STRING, DataTypeDefinition.TEXT);
+ propertyTypeToDataType.put(PropertyType.BINARY, DataTypeDefinition.CONTENT);
+ propertyTypeToDataType.put(PropertyType.LONG, DataTypeDefinition.LONG);
+ propertyTypeToDataType.put(PropertyType.DOUBLE, DataTypeDefinition.DOUBLE);
+ propertyTypeToDataType.put(PropertyType.DATE, DataTypeDefinition.DATETIME);
+ propertyTypeToDataType.put(PropertyType.BOOLEAN, DataTypeDefinition.BOOLEAN);
+ propertyTypeToDataType.put(PropertyType.NAME, DataTypeDefinition.QNAME);
+ propertyTypeToDataType.put(PropertyType.REFERENCE, DataTypeDefinition.NODE_REF);
+ propertyTypeToDataType.put(PropertyType.PATH, DataTypeDefinition.PATH);
+ propertyTypeToDataType.put(PropertyType.UNDEFINED, DataTypeDefinition.ANY);
+ }
+
+ /**
+ * Convert an Alfresco Data Type to a JCR Property Type
+ *
+ * @param datatype alfresco data type
+ * @return JCR property type
+ * @throws RepositoryException
+ */
+ public static int convertDataTypeToPropertyType(QName datatype)
+ {
+ Integer propertyType = dataTypeToPropertyType.get(datatype);
+ if (propertyType == null)
+ {
+ throw new AlfrescoRuntimeException("Cannot map Alfresco data type " + datatype + " to JCR property type.");
+ }
+ return propertyType;
+ }
+
+ /**
+ * Convert a JCR Property Type to an Alfresco Data Type
+ *
+ * @param propertyType JCR property type
+ * @return alfresco data type
+ * @throws RepositoryException
+ */
+ public static QName convertPropertyTypeToDataType(int propertyType)
+ {
+ QName type = propertyTypeToDataType.get(propertyType);
+ if (type == null)
+ {
+ throw new AlfrescoRuntimeException("Cannot map JCR property type " + propertyType + " to Alfresco data type.");
+ }
+ return type;
+ }
+
+}
diff --git a/source/java/org/alfresco/jcr/dictionary/JCRNamespace.java b/source/java/org/alfresco/jcr/dictionary/JCRNamespace.java
new file mode 100644
index 0000000000..b7967f929d
--- /dev/null
+++ b/source/java/org/alfresco/jcr/dictionary/JCRNamespace.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.dictionary;
+
+
+/**
+ * JCR Namespace definitions
+ *
+ * @author David Caruana
+ */
+public class JCRNamespace
+{
+ public static String XML_PREFIX = "xml";
+
+ public static String JCR_URI = "http://www.jcp.org/jcr/1.0";
+ public static String JCR_PREFIX = "jcr";
+
+ public static String NT_URI = "http://www.jcp.org/jcr/nt/1.0";
+ public static String NT_PREFIX = "nt";
+
+ public static String MIX_URI = "http://www.jcp.org/jcr/mix/1.0";
+ public static String MIX_PREFIX = "mix";
+
+ public static String SV_URI = "http://www.jcp.org/jcr/sv/1.0";
+ public static String SV_PREFIX = "sv";
+}
diff --git a/source/java/org/alfresco/jcr/dictionary/JCRNamespacePrefixResolver.java b/source/java/org/alfresco/jcr/dictionary/JCRNamespacePrefixResolver.java
new file mode 100644
index 0000000000..2bdc6aeaa5
--- /dev/null
+++ b/source/java/org/alfresco/jcr/dictionary/JCRNamespacePrefixResolver.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.dictionary;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.alfresco.service.namespace.NamespaceException;
+import org.alfresco.service.namespace.NamespacePrefixResolver;
+import org.alfresco.service.namespace.NamespaceService;
+
+
+/**
+ * JCR Namespace Resolver
+ *
+ * @author David Caruana
+ */
+public class JCRNamespacePrefixResolver implements NamespaceService
+{
+ // delegate
+ private NamespacePrefixResolver delegate;
+
+ // prefix -> uri
+ private Map prefixes = new HashMap();
+
+ // uri -> prefix
+ private Map uris = new HashMap();
+
+
+ /**
+ * Construct
+ *
+ * @param delegate namespace delegate
+ */
+ public JCRNamespacePrefixResolver(NamespacePrefixResolver delegate)
+ {
+ this.delegate = delegate;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.namespace.NamespacePrefixResolver#getPrefixes(java.lang.String)
+ */
+ public Collection getPrefixes(String namespaceURI) throws NamespaceException
+ {
+ String prefix = uris.get(namespaceURI);
+ if (prefix == null)
+ {
+ return delegate.getPrefixes(namespaceURI);
+ }
+ List prefixes = new ArrayList();
+ prefixes.add(prefix);
+ return prefixes;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.namespace.NamespacePrefixResolver#getPrefixes()
+ */
+ public Collection getPrefixes()
+ {
+ List prefixes = new ArrayList();
+ Collection uris = getURIs();
+ for (String uri : uris)
+ {
+ Collection uriPrefixes = getPrefixes(uri);
+ prefixes.addAll(uriPrefixes);
+ }
+ return prefixes;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.namespace.NamespaceService#registerNamespace(java.lang.String, java.lang.String)
+ */
+ public void registerNamespace(String prefix, String uri)
+ {
+ //
+ // Check re-mapping according to JCR specification
+ //
+
+ // Cannot map any prefix that starts with xml
+ if (prefix.toLowerCase().startsWith(JCRNamespace.XML_PREFIX))
+ {
+ throw new NamespaceException("Cannot map prefix " + prefix + " as it is reserved");
+ }
+
+ // Cannot remap a prefix that is already assigned to a uri
+ String existingUri = delegate.getNamespaceURI(prefix);
+ if (existingUri != null)
+ {
+ throw new NamespaceException("Cannot map prefix " + prefix + " as it is already assigned to uri " + existingUri);
+ }
+
+ // Cannot map a prefix to a non-existent uri
+ Collection existingURIs = delegate.getURIs();
+ if (existingURIs.contains(uri) == false)
+ {
+ throw new NamespaceException("Cannot map prefix " + prefix + " to uri " + uri + " which does not exist");
+ }
+
+ prefixes.put(prefix, uri);
+ uris.put(uri, prefix);
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.namespace.NamespaceService#unregisterNamespace(java.lang.String)
+ */
+ public void unregisterNamespace(String prefix)
+ {
+ String uri = prefixes.get(prefix);
+ if (uri != null)
+ {
+ uris.remove(uri);
+ }
+ prefixes.remove(prefix);
+ }
+
+ public String getNamespaceURI(String prefix) throws NamespaceException
+ {
+ String uri = prefixes.get(prefix);
+ if (uri == null)
+ {
+ return delegate.getNamespaceURI(prefix);
+ }
+ return uri;
+ }
+
+ /* (non-Javadoc)
+ * @see org.alfresco.service.namespace.NamespacePrefixResolver#getURIs()
+ */
+ public Collection getURIs()
+ {
+ return delegate.getURIs();
+ }
+
+}
diff --git a/source/java/org/alfresco/jcr/dictionary/NamespaceRegistryImpl.java b/source/java/org/alfresco/jcr/dictionary/NamespaceRegistryImpl.java
new file mode 100644
index 0000000000..69f948aadd
--- /dev/null
+++ b/source/java/org/alfresco/jcr/dictionary/NamespaceRegistryImpl.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.dictionary;
+
+import java.util.Collection;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.NamespaceException;
+import javax.jcr.NamespaceRegistry;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+
+import org.alfresco.service.namespace.NamespaceService;
+
+
+/**
+ * Alfresco implementation of a JCR Namespace registry
+ *
+ * @author David Caruana
+ */
+public class NamespaceRegistryImpl implements NamespaceRegistry
+{
+
+ private boolean allowRegistration;
+ private NamespaceService namespaceService;
+
+
+ /**
+ * Construct
+ *
+ * @param namespaceService namespace service
+ */
+ public NamespaceRegistryImpl(boolean allowRegistraton, NamespaceService namespaceService)
+ {
+ this.allowRegistration = allowRegistraton;
+ this.namespaceService = namespaceService;
+ }
+
+ /**
+ * Get the namespace prefix resolver
+ *
+ * @return the namespace prefix resolver
+ */
+ public NamespaceService getNamespaceService()
+ {
+ return this.namespaceService;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.NamespaceRegistry#registerNamespace(java.lang.String, java.lang.String)
+ */
+ public void registerNamespace(String prefix, String uri) throws NamespaceException, UnsupportedRepositoryOperationException, AccessDeniedException, RepositoryException
+ {
+ try
+ {
+ if (!allowRegistration)
+ {
+ throw new UnsupportedRepositoryOperationException();
+ }
+ namespaceService.registerNamespace(prefix, uri);
+ }
+ catch(org.alfresco.service.namespace.NamespaceException e)
+ {
+ throw new NamespaceException(e);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.NamespaceRegistry#unregisterNamespace(java.lang.String)
+ */
+ public void unregisterNamespace(String prefix) throws NamespaceException, UnsupportedRepositoryOperationException, AccessDeniedException, RepositoryException
+ {
+ try
+ {
+ if (!allowRegistration)
+ {
+ throw new UnsupportedRepositoryOperationException();
+ }
+ namespaceService.unregisterNamespace(prefix);
+ }
+ catch(org.alfresco.service.namespace.NamespaceException e)
+ {
+ throw new NamespaceException(e);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.NamespaceRegistry#getPrefixes()
+ */
+ public String[] getPrefixes() throws RepositoryException
+ {
+ Collection prefixes = namespaceService.getPrefixes();
+ return prefixes.toArray(new String[prefixes.size()]);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.NamespaceRegistry#getURIs()
+ */
+ public String[] getURIs() throws RepositoryException
+ {
+ Collection uris = namespaceService.getURIs();
+ return uris.toArray(new String[uris.size()]);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.NamespaceRegistry#getURI(java.lang.String)
+ */
+ public String getURI(String prefix) throws NamespaceException, RepositoryException
+ {
+ String uri = namespaceService.getNamespaceURI(prefix);
+ if (uri == null)
+ {
+ throw new NamespaceException("Prefix " + prefix + " is unknown.");
+ }
+ return uri;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.NamespaceRegistry#getPrefix(java.lang.String)
+ */
+ public String getPrefix(String uri) throws NamespaceException, RepositoryException
+ {
+ Collection prefixes = namespaceService.getPrefixes(uri);
+ if (prefixes.size() == 0)
+ {
+ throw new NamespaceException("URI " + uri + " is unknown.");
+ }
+ // Return first prefix registered for uri
+ return prefixes.iterator().next();
+ }
+
+}
diff --git a/source/java/org/alfresco/jcr/dictionary/NodeDefinitionImpl.java b/source/java/org/alfresco/jcr/dictionary/NodeDefinitionImpl.java
new file mode 100644
index 0000000000..e41feab558
--- /dev/null
+++ b/source/java/org/alfresco/jcr/dictionary/NodeDefinitionImpl.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.dictionary;
+
+
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.version.OnParentVersionAction;
+
+import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition;
+import org.alfresco.service.cmr.dictionary.ClassDefinition;
+
+
+/**
+ * Alfresco implementation of a JCR Node Definition
+ *
+ * @author David Caruana
+ *
+ */
+public class NodeDefinitionImpl implements NodeDefinition
+{
+ private NodeTypeManagerImpl typeManager;
+ private ChildAssociationDefinition assocDef;
+
+ /**
+ * Construct
+ *
+ * @param typeManager
+ * @param assocDef
+ */
+ public NodeDefinitionImpl(NodeTypeManagerImpl typeManager, ChildAssociationDefinition assocDef)
+ {
+ this.typeManager = typeManager;
+ this.assocDef = assocDef;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeDefinition#getRequiredPrimaryTypes()
+ */
+ public NodeType[] getRequiredPrimaryTypes()
+ {
+ // Note: target class is mandatory in Alfresco
+ ClassDefinition target = assocDef.getTargetClass();
+ return new NodeType[] { typeManager.getNodeTypeImpl(target.getName()) };
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeDefinition#getDefaultPrimaryType()
+ */
+ public NodeType getDefaultPrimaryType()
+ {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeDefinition#allowsSameNameSiblings()
+ */
+ public boolean allowsSameNameSiblings()
+ {
+ return assocDef.getDuplicateChildNamesAllowed();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.ItemDefinition#getDeclaringNodeType()
+ */
+ public NodeType getDeclaringNodeType()
+ {
+ return typeManager.getNodeTypeImpl(assocDef.getSourceClass().getName());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.ItemDefinition#getName()
+ */
+ public String getName()
+ {
+ return assocDef.getName().toPrefixString(typeManager.getNamespaceService());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.ItemDefinition#isAutoCreated()
+ */
+ public boolean isAutoCreated()
+ {
+ return isMandatory();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.ItemDefinition#isMandatory()
+ */
+ public boolean isMandatory()
+ {
+ return assocDef.isTargetMandatory();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.ItemDefinition#getOnParentVersion()
+ */
+ public int getOnParentVersion()
+ {
+ // TODO: Check this correct
+ return OnParentVersionAction.INITIALIZE;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.ItemDefinition#isProtected()
+ */
+ public boolean isProtected()
+ {
+ return assocDef.isProtected();
+ }
+
+}
diff --git a/source/java/org/alfresco/jcr/dictionary/NodeTypeImpl.java b/source/java/org/alfresco/jcr/dictionary/NodeTypeImpl.java
new file mode 100644
index 0000000000..82ce28c51c
--- /dev/null
+++ b/source/java/org/alfresco/jcr/dictionary/NodeTypeImpl.java
@@ -0,0 +1,426 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.dictionary;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.PropertyDefinition;
+
+import org.alfresco.jcr.item.ValueImpl;
+import org.alfresco.jcr.item.property.JCRMixinTypesProperty;
+import org.alfresco.jcr.item.property.JCRPrimaryTypeProperty;
+import org.alfresco.service.cmr.dictionary.ChildAssociationDefinition;
+import org.alfresco.service.cmr.dictionary.ClassDefinition;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.namespace.QName;
+
+/**
+ * Alfresco implementation of a Node Type Definition
+ *
+ * @author David Caruana
+ */
+public class NodeTypeImpl implements NodeType
+{
+ // The required nt:base type specified by JCR
+ public static QName NT_BASE = QName.createQName(JCRNamespace.NT_URI, "base");
+
+ // The optional mix:referenceable specified by JCR
+ public static QName MIX_REFERENCEABLE = QName.createQName(JCRNamespace.MIX_URI, "referenceable");
+ // The optional mix:lockable specified by JCR
+ public static QName MIX_LOCKABLE = QName.createQName(JCRNamespace.MIX_URI, "lockable");
+ // The optional mix:versionable specified by JCR
+ public static QName MIX_VERSIONABLE = QName.createQName(JCRNamespace.MIX_URI, "versionable");
+
+
+ private NodeTypeManagerImpl typeManager;
+ private ClassDefinition classDefinition;
+
+
+ /**
+ * Construct
+ *
+ * @param classDefinition Alfresco class definition
+ */
+ public NodeTypeImpl(NodeTypeManagerImpl typeManager, ClassDefinition classDefinition)
+ {
+ this.typeManager = typeManager;
+ this.classDefinition = classDefinition;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#getName()
+ */
+ public String getName()
+ {
+ return classDefinition.getName().toPrefixString(typeManager.getNamespaceService());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#isMixin()
+ */
+ public boolean isMixin()
+ {
+ return classDefinition.isAspect();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#hasOrderableChildNodes()
+ */
+ public boolean hasOrderableChildNodes()
+ {
+ // Note: For now, we don't expose this through JCR
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#getPrimaryItemName()
+ */
+ public String getPrimaryItemName()
+ {
+ // NOTE: Alfresco does not support the notion of PrimaryItem (not yet anyway)
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#getSupertypes()
+ */
+ public NodeType[] getSupertypes()
+ {
+ List nodeTypes = new ArrayList();
+ NodeType[] declaredSupertypes = getDeclaredSupertypes();
+ while (declaredSupertypes.length > 0)
+ {
+ // Alfresco supports single inheritence only
+ NodeType supertype = declaredSupertypes[0];
+ nodeTypes.add(supertype);
+ declaredSupertypes = supertype.getDeclaredSupertypes();
+ }
+ return nodeTypes.toArray(new NodeType[nodeTypes.size()]);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#getDeclaredSupertypes()
+ */
+ public NodeType[] getDeclaredSupertypes()
+ {
+ // return no supertype when type is nt:base
+ if (classDefinition.getName().equals(NT_BASE))
+ {
+ return new NodeType[] {};
+ }
+
+ // return root type when no parent (nt:base if a type hierarchy)
+ QName parent = classDefinition.getParentName();
+ if (parent == null)
+ {
+ if (classDefinition.isAspect())
+ {
+ return new NodeType[] {};
+ }
+ else
+ {
+ return new NodeType[] { typeManager.getNodeTypeImpl(NT_BASE) };
+ }
+ }
+
+ // return the supertype
+ return new NodeType[] { typeManager.getNodeTypeImpl(parent) };
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#isNodeType(java.lang.String)
+ */
+ public boolean isNodeType(String nodeTypeName)
+ {
+ QName name = QName.createQName(nodeTypeName, typeManager.getNamespaceService());
+
+ // is it one of standard types
+ if (name.equals(NodeTypeImpl.NT_BASE))
+ {
+ return true;
+ }
+
+ // is it part of this class hierarchy
+ return typeManager.getSession().getRepositoryImpl().getServiceRegistry().getDictionaryService().isSubClass(name, classDefinition.getName());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#getPropertyDefinitions()
+ */
+ public PropertyDefinition[] getPropertyDefinitions()
+ {
+ Map propDefs = classDefinition.getProperties();
+ PropertyDefinition[] defs = new PropertyDefinition[propDefs.size() + (classDefinition.isAspect() ? 0 : 2)];
+ int i = 0;
+ for (org.alfresco.service.cmr.dictionary.PropertyDefinition propDef : propDefs.values())
+ {
+ defs[i++] = new PropertyDefinitionImpl(typeManager, propDef);
+ }
+
+ if (!classDefinition.isAspect())
+ {
+ // add nt:base properties
+ defs[i++] = typeManager.getPropertyDefinitionImpl(JCRPrimaryTypeProperty.PROPERTY_NAME);
+ defs[i++] = typeManager.getPropertyDefinitionImpl(JCRMixinTypesProperty.PROPERTY_NAME);
+ }
+
+ return defs;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#getDeclaredPropertyDefinitions()
+ */
+ public PropertyDefinition[] getDeclaredPropertyDefinitions()
+ {
+ Map propDefs = classDefinition.getProperties();
+ List defs = new ArrayList();
+ for (org.alfresco.service.cmr.dictionary.PropertyDefinition propDef : propDefs.values())
+ {
+ if (propDef.getContainerClass().equals(classDefinition))
+ {
+ defs.add(new PropertyDefinitionImpl(typeManager, propDef));
+ }
+ }
+
+ if (classDefinition.equals(NT_BASE))
+ {
+ // add nt:base properties
+ defs.add(typeManager.getPropertyDefinitionImpl(JCRPrimaryTypeProperty.PROPERTY_NAME));
+ defs.add(typeManager.getPropertyDefinitionImpl(JCRMixinTypesProperty.PROPERTY_NAME));
+ }
+
+ return defs.toArray(new PropertyDefinition[defs.size()]);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#getChildNodeDefinitions()
+ */
+ public NodeDefinition[] getChildNodeDefinitions()
+ {
+ Map assocDefs = classDefinition.getChildAssociations();
+ NodeDefinition[] defs = new NodeDefinition[assocDefs.size()];
+ int i = 0;
+ for (ChildAssociationDefinition assocDef : assocDefs.values())
+ {
+ defs[i++] = new NodeDefinitionImpl(typeManager, assocDef);
+ }
+ return defs;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#getDeclaredChildNodeDefinitions()
+ */
+ public NodeDefinition[] getDeclaredChildNodeDefinitions()
+ {
+ Map assocDefs = classDefinition.getChildAssociations();
+ List defs = new ArrayList();
+ for (ChildAssociationDefinition assocDef : assocDefs.values())
+ {
+ if (assocDef.getSourceClass().equals(classDefinition))
+ {
+ defs.add(new NodeDefinitionImpl(typeManager, assocDef));
+ }
+ }
+ return defs.toArray(new NodeDefinition[defs.size()]);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#canSetProperty(java.lang.String, javax.jcr.Value)
+ */
+ public boolean canSetProperty(String propertyName, Value value)
+ {
+ try
+ {
+ // is an attempt to remove property being made
+ if (value == null)
+ {
+ return canRemoveItem(propertyName);
+ }
+
+ // retrieve property definition
+ QName propertyQName = QName.createQName(propertyName, typeManager.getNamespaceService());
+ Map propDefs = classDefinition.getProperties();
+ org.alfresco.service.cmr.dictionary.PropertyDefinition propDef = propDefs.get(propertyQName);
+ if (propDef == null)
+ {
+ // Alfresco doesn't have residual properties yet
+ return false;
+ }
+
+ // is property read-write
+ if (propDef.isProtected() || propDef.isMultiValued())
+ {
+ return false;
+ }
+
+ // get required type to convert to
+ int requiredType = DataTypeMap.convertDataTypeToPropertyType(propDef.getDataType().getName());
+ if (requiredType == PropertyType.UNDEFINED)
+ {
+ requiredType = value.getType();
+ }
+
+ // convert value to required type
+ // Note: Invalid conversion will throw exception
+ ValueImpl.getValue(typeManager.getSession().getTypeConverter(), requiredType, value);
+
+ // Note: conversion succeeded
+ return true;
+ }
+ catch(RepositoryException e)
+ {
+ // Note: Not much can be done really
+ }
+
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#canSetProperty(java.lang.String, javax.jcr.Value[])
+ */
+ public boolean canSetProperty(String propertyName, Value[] values)
+ {
+ try
+ {
+ // is an attempt to remove property being made
+ if (values == null)
+ {
+ return canRemoveItem(propertyName);
+ }
+
+ // retrieve property definition
+ QName propertyQName = QName.createQName(propertyName, typeManager.getNamespaceService());
+ Map propDefs = classDefinition.getProperties();
+ org.alfresco.service.cmr.dictionary.PropertyDefinition propDef = propDefs.get(propertyQName);
+ if (propDef == null)
+ {
+ // Alfresco doesn't have residual properties yet
+ return false;
+ }
+
+ // is property read write
+ if (propDef.isProtected() || !propDef.isMultiValued())
+ {
+ return false;
+ }
+
+ // determine type of values to check
+ int valueType = PropertyType.UNDEFINED;
+ for (Value value : values)
+ {
+ if (value != null)
+ {
+ if (valueType != PropertyType.UNDEFINED && value.getType() != valueType)
+ {
+ // do not allow collection mixed type values
+ return false;
+ }
+ valueType = value.getType();
+ }
+ }
+
+ // get required type to convert to
+ int requiredType = DataTypeMap.convertDataTypeToPropertyType(propDef.getDataType().getName());
+ if (requiredType == PropertyType.UNDEFINED)
+ {
+ requiredType = valueType;
+ }
+
+ // convert values to required format
+ // Note: Invalid conversion will throw exception
+ for (Value value : values)
+ {
+ if (value != null)
+ {
+ ValueImpl.getValue(typeManager.getSession().getTypeConverter(), requiredType, value);
+ }
+ }
+
+ // Note: conversion succeeded
+ return true;
+ }
+ catch(RepositoryException e)
+ {
+ // Note: Not much can be done really
+ }
+
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#canAddChildNode(java.lang.String)
+ */
+ public boolean canAddChildNode(String childNodeName)
+ {
+ // NOTE: Alfresco does not have default primary type notion
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#canAddChildNode(java.lang.String, java.lang.String)
+ */
+ public boolean canAddChildNode(String childNodeName, String nodeTypeName)
+ {
+ boolean canAdd = false;
+ Map assocDefs = classDefinition.getChildAssociations();
+ QName childNodeQName = QName.createQName(childNodeName, typeManager.getNamespaceService());
+ ChildAssociationDefinition assocDef = assocDefs.get(childNodeQName);
+ if (assocDef != null)
+ {
+ QName nodeTypeQName = QName.createQName(nodeTypeName, typeManager.getNamespaceService());
+ DictionaryService dictionaryService = typeManager.getSession().getRepositoryImpl().getServiceRegistry().getDictionaryService();
+ canAdd = dictionaryService.isSubClass(nodeTypeQName, assocDef.getTargetClass().getName());
+ }
+ return canAdd;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeType#canRemoveItem(java.lang.String)
+ */
+ public boolean canRemoveItem(String itemName)
+ {
+ boolean isProtected = false;
+ boolean isMandatory = false;
+
+ // TODO: Property and Association names can clash? What to do?
+ QName itemQName = QName.createQName(itemName, typeManager.getNamespaceService());
+ Map propDefs = classDefinition.getProperties();
+ org.alfresco.service.cmr.dictionary.PropertyDefinition propDef = propDefs.get(itemQName);
+ if (propDef != null)
+ {
+ isProtected = propDef.isProtected();
+ isMandatory = propDef.isMandatory();
+ }
+ Map assocDefs = classDefinition.getChildAssociations();
+ ChildAssociationDefinition assocDef = assocDefs.get(itemQName);
+ if (assocDef != null)
+ {
+ isProtected |= assocDef.isProtected();
+ isMandatory |= assocDef.isTargetMandatory();
+ }
+
+ return !isProtected && !isMandatory;
+ }
+
+}
diff --git a/source/java/org/alfresco/jcr/dictionary/NodeTypeManagerImpl.java b/source/java/org/alfresco/jcr/dictionary/NodeTypeManagerImpl.java
new file mode 100644
index 0000000000..f8410f6bc9
--- /dev/null
+++ b/source/java/org/alfresco/jcr/dictionary/NodeTypeManagerImpl.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.dictionary;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.nodetype.NoSuchNodeTypeException;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeIterator;
+import javax.jcr.nodetype.NodeTypeManager;
+
+import org.alfresco.jcr.session.SessionImpl;
+import org.alfresco.service.cmr.dictionary.ClassDefinition;
+import org.alfresco.service.cmr.dictionary.PropertyDefinition;
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
+
+
+/**
+ * Alfresco implementation of JCR Node Type Manager
+ *
+ * @author David Caruana
+ */
+public class NodeTypeManagerImpl implements NodeTypeManager
+{
+ private SessionImpl session;
+ private NamespaceService namespaceService;
+
+ /**
+ * Construct
+ *
+ * @param dictionaryService dictionary service
+ * @param namespaceService namespace service (global repository registry)
+ */
+ public NodeTypeManagerImpl(SessionImpl session, NamespaceService namespaceService)
+ {
+ this.session = session;
+ this.namespaceService = namespaceService;
+ }
+
+ /**
+ * Get Dictionary Service
+ *
+ * @return the dictionary service
+ */
+ public SessionImpl getSession()
+ {
+ return session;
+ }
+
+ /**
+ * Get Namespace Service
+ *
+ * @return the namespace service
+ */
+ public NamespaceService getNamespaceService()
+ {
+ return namespaceService;
+ }
+
+ /**
+ * Get Node Type Implementation for given Class Name
+ *
+ * @param nodeTypeName alfresco class name
+ * @return the node type
+ */
+ public NodeTypeImpl getNodeTypeImpl(QName nodeTypeName)
+ {
+ // TODO: Might be worth caching here... wait and see
+ NodeTypeImpl nodeType = null;
+ ClassDefinition definition = session.getRepositoryImpl().getServiceRegistry().getDictionaryService().getClass(nodeTypeName);
+ if (definition != null)
+ {
+ nodeType = new NodeTypeImpl(this, definition);
+ }
+ return nodeType;
+ }
+
+ /**
+ * Get Property Definition Implementation for given Property Name
+ *
+ * @param propertyName alfresco property name
+ * @return the property
+ */
+ public PropertyDefinitionImpl getPropertyDefinitionImpl(QName propertyName)
+ {
+ // TODO: Might be worth caching here... wait and see
+ PropertyDefinitionImpl propDef = null;
+ PropertyDefinition definition = session.getRepositoryImpl().getServiceRegistry().getDictionaryService().getProperty(propertyName);
+ if (definition != null)
+ {
+ propDef = new PropertyDefinitionImpl(this, definition);
+ }
+ return propDef;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeTypeManager#getNodeType(java.lang.String)
+ */
+ public NodeType getNodeType(String nodeTypeName) throws NoSuchNodeTypeException, RepositoryException
+ {
+ QName name = QName.createQName(nodeTypeName, namespaceService);
+ NodeTypeImpl nodeTypeImpl = getNodeTypeImpl(name);
+ if (nodeTypeImpl == null)
+ {
+ throw new NoSuchNodeTypeException("Node type " + nodeTypeName + " does not exist");
+ }
+ return nodeTypeImpl;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeTypeManager#getAllNodeTypes()
+ */
+ public NodeTypeIterator getAllNodeTypes() throws RepositoryException
+ {
+ Collection typeNames = session.getRepositoryImpl().getServiceRegistry().getDictionaryService().getAllTypes();
+ Collection aspectNames = session.getRepositoryImpl().getServiceRegistry().getDictionaryService().getAllAspects();
+ List typesList = new ArrayList(typeNames.size() + aspectNames.size());
+ typesList.addAll(typeNames);
+ typesList.addAll(aspectNames);
+ return new NodeTypeNameIterator(this, typesList);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeTypeManager#getPrimaryNodeTypes()
+ */
+ public NodeTypeIterator getPrimaryNodeTypes() throws RepositoryException
+ {
+ Collection typeNames = session.getRepositoryImpl().getServiceRegistry().getDictionaryService().getAllTypes();
+ List typesList = new ArrayList(typeNames.size());
+ typesList.addAll(typeNames);
+ return new NodeTypeNameIterator(this, typesList);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeTypeManager#getMixinNodeTypes()
+ */
+ public NodeTypeIterator getMixinNodeTypes() throws RepositoryException
+ {
+ Collection typeNames = session.getRepositoryImpl().getServiceRegistry().getDictionaryService().getAllAspects();
+ List typesList = new ArrayList(typeNames.size());
+ typesList.addAll(typeNames);
+ return new NodeTypeNameIterator(this, typesList);
+ }
+
+}
diff --git a/source/java/org/alfresco/jcr/dictionary/NodeTypeNameIterator.java b/source/java/org/alfresco/jcr/dictionary/NodeTypeNameIterator.java
new file mode 100644
index 0000000000..fe96982f09
--- /dev/null
+++ b/source/java/org/alfresco/jcr/dictionary/NodeTypeNameIterator.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.dictionary;
+
+import java.util.List;
+
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.NodeTypeIterator;
+
+import org.alfresco.jcr.util.AbstractRangeIterator;
+import org.alfresco.service.namespace.QName;
+
+
+/**
+ * Alfresco implementation of a Node Type Iterator
+ *
+ * @author David Caruana
+ */
+public class NodeTypeNameIterator extends AbstractRangeIterator
+ implements NodeTypeIterator
+{
+ private NodeTypeManagerImpl typeManager;
+ private List nodeTypeNames;
+
+
+ /**
+ * Construct
+ *
+ * @param context session context
+ * @param nodeTypes node type list
+ */
+ public NodeTypeNameIterator(NodeTypeManagerImpl typeManager, List nodeTypeNames)
+ {
+ this.typeManager = typeManager;
+ this.nodeTypeNames = nodeTypeNames;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.NodeTypeIterator#nextNodeType()
+ */
+ public NodeType nextNodeType()
+ {
+ long position = skip();
+ QName name = nodeTypeNames.get((int)position);
+ return typeManager.getNodeTypeImpl(name);
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.RangeIterator#getSize()
+ */
+ public long getSize()
+ {
+ return nodeTypeNames.size();
+ }
+
+ /* (non-Javadoc)
+ * @see java.util.Iterator#next()
+ */
+ public Object next()
+ {
+ return nextNodeType();
+ }
+
+}
diff --git a/source/java/org/alfresco/jcr/dictionary/PropertyDefinitionImpl.java b/source/java/org/alfresco/jcr/dictionary/PropertyDefinitionImpl.java
new file mode 100644
index 0000000000..39f9a4161c
--- /dev/null
+++ b/source/java/org/alfresco/jcr/dictionary/PropertyDefinitionImpl.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.dictionary;
+
+import javax.jcr.Value;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.version.OnParentVersionAction;
+
+import org.alfresco.jcr.item.ValueImpl;
+import org.alfresco.jcr.item.property.JCRMixinTypesProperty;
+import org.alfresco.jcr.item.property.JCRPrimaryTypeProperty;
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.dictionary.ClassDefinition;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
+
+/**
+ * Alfresco implementation of a JCR Property Definition
+ *
+ * @author David Caruana
+ */
+public class PropertyDefinitionImpl implements PropertyDefinition
+{
+ /** Session */
+ private NodeTypeManagerImpl typeManager;
+
+ /** Alfresco Property Definition */
+ private org.alfresco.service.cmr.dictionary.PropertyDefinition propDef;
+
+
+ /**
+ * Construct
+ *
+ * @param propDef Alfresco Property Definition
+ */
+ public PropertyDefinitionImpl(NodeTypeManagerImpl typeManager, org.alfresco.service.cmr.dictionary.PropertyDefinition propDef)
+ {
+ this.typeManager = typeManager;
+ this.propDef = propDef;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.PropertyDefinition#getRequiredType()
+ */
+ public int getRequiredType()
+ {
+ // TODO: Switch on data type
+ if (propDef.getName().equals(ContentModel.PROP_CONTENT))
+ {
+ return DataTypeMap.convertDataTypeToPropertyType(DataTypeDefinition.CONTENT);
+ }
+ return DataTypeMap.convertDataTypeToPropertyType(propDef.getDataType().getName());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.PropertyDefinition#getValueConstraints()
+ */
+ public String[] getValueConstraints()
+ {
+ return new String[] {};
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.PropertyDefinition#getDefaultValues()
+ */
+ public Value[] getDefaultValues()
+ {
+ String defaultValue = propDef.getDefaultValue();
+ if (defaultValue == null)
+ {
+ return null;
+ }
+ return new Value[] { new ValueImpl(typeManager.getSession(), getRequiredType(), defaultValue) };
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.PropertyDefinition#isMultiple()
+ */
+ public boolean isMultiple()
+ {
+ return propDef.isMultiValued();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.ItemDefinition#getDeclaringNodeType()
+ */
+ public NodeType getDeclaringNodeType()
+ {
+ ClassDefinition declaringClass = propDef.getContainerClass();
+ return typeManager.getNodeTypeImpl(declaringClass.getName());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.ItemDefinition#getName()
+ */
+ public String getName()
+ {
+ return propDef.getName().toPrefixString(typeManager.getNamespaceService());
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.ItemDefinition#isAutoCreated()
+ */
+ public boolean isAutoCreated()
+ {
+ return isMandatory();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.ItemDefinition#isMandatory()
+ */
+ public boolean isMandatory()
+ {
+ return propDef.isMandatory();
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.ItemDefinition#getOnParentVersion()
+ */
+ public int getOnParentVersion()
+ {
+ // TODO: There's no equivalent in Alfresco, so hard code for now
+ if (propDef.getName().equals(JCRPrimaryTypeProperty.PROPERTY_NAME) ||
+ propDef.getName().equals(JCRMixinTypesProperty.PROPERTY_NAME))
+ {
+ return OnParentVersionAction.COMPUTE;
+ }
+
+ // TODO: Check this
+ return OnParentVersionAction.INITIALIZE;
+ }
+
+ /* (non-Javadoc)
+ * @see javax.jcr.nodetype.ItemDefinition#isProtected()
+ */
+ public boolean isProtected()
+ {
+ return propDef.isProtected();
+ }
+
+}
diff --git a/source/java/org/alfresco/jcr/dictionary/VersionableMixin.java b/source/java/org/alfresco/jcr/dictionary/VersionableMixin.java
new file mode 100644
index 0000000000..c924ac6f8a
--- /dev/null
+++ b/source/java/org/alfresco/jcr/dictionary/VersionableMixin.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.dictionary;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+
+import org.alfresco.jcr.session.SessionImpl;
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.namespace.QName;
+
+/**
+ * Encapsulate Versionable Mixin behaviour mapping to Alfresco
+ *
+ * @author davidc
+ */
+public class VersionableMixin implements ClassMap.AddMixin, ClassMap.RemoveMixin
+{
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.jcr.dictionary.ClassMap.AddMixin#preAddMixin(org.alfresco.jcr.session.SessionImpl, org.alfresco.service.cmr.repository.NodeRef)
+ */
+ public Map preAddMixin(SessionImpl session, NodeRef nodeRef)
+ {
+ // switch off auto-versioning
+ Map properties = new HashMap();
+ properties.put(ContentModel.PROP_INITIAL_VERSION, false);
+ properties.put(ContentModel.PROP_AUTO_VERSION, false);
+ return properties;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.jcr.dictionary.ClassMap.AddMixin#postAddMixin(org.alfresco.jcr.session.SessionImpl, org.alfresco.service.cmr.repository.NodeRef)
+ */
+ public void postAddMixin(SessionImpl session, NodeRef nodeRef)
+ {
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.jcr.dictionary.ClassMap.RemoveMixin#preRemoveMixin(org.alfresco.jcr.session.SessionImpl, org.alfresco.service.cmr.repository.NodeRef)
+ */
+ public void preRemoveMixin(SessionImpl session, NodeRef nodeRef)
+ {
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.alfresco.jcr.dictionary.ClassMap.RemoveMixin#postRemoveMixin(org.alfresco.jcr.session.SessionImpl, org.alfresco.service.cmr.repository.NodeRef)
+ */
+ public void postRemoveMixin(SessionImpl session, NodeRef nodeRef)
+ {
+ }
+
+}
diff --git a/source/java/org/alfresco/jcr/example/MixedExample.java b/source/java/org/alfresco/jcr/example/MixedExample.java
new file mode 100644
index 0000000000..9c7f1f41f2
--- /dev/null
+++ b/source/java/org/alfresco/jcr/example/MixedExample.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.example;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.Repository;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+
+import org.alfresco.jcr.api.JCRNodeRef;
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.ServiceRegistry;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+
+
+/**
+ * Example that demonstrate use of JCR and Alfresco API calls.
+ *
+ * @author David Caruana
+ */
+public class MixedExample
+{
+
+ public static void main(String[] args)
+ throws Exception
+ {
+ // Setup Spring and Transaction Service
+ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:alfresco/application-context.xml");
+ ServiceRegistry registry = (ServiceRegistry)context.getBean(ServiceRegistry.SERVICE_REGISTRY);
+ NodeService nodeService = (NodeService)registry.getNodeService();
+
+ // Retrieve Repository
+ Repository repository = (Repository)context.getBean("JCR.Repository");
+
+ // Login to workspace
+ // Note: Default workspace is the one used by Alfresco Web Client which contains all the Spaces
+ // and their documents
+ Session session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
+
+ try
+ {
+ // Retrieve Company Home
+ Node root = session.getRootNode();
+ Node companyHome = root.getNode("app:company_home");
+
+ // Read Company Home Name
+ Property name = companyHome.getProperty("cm:name");
+ System.out.println("Name = " + name.getString());
+
+ // Update Node via Alfresco Node Service API
+ NodeRef companyHomeRef = JCRNodeRef.getNodeRef(companyHome);
+ nodeService.setProperty(companyHomeRef, ContentModel.PROP_NAME, "Updated Company Home Name");
+
+ // Re-read via JCR
+ System.out.println("Updated name = " + name.getString());
+ }
+ finally
+ {
+ session.logout();
+ System.exit(0);
+ }
+ }
+
+}
diff --git a/source/java/org/alfresco/jcr/example/SimpleExample.java b/source/java/org/alfresco/jcr/example/SimpleExample.java
new file mode 100644
index 0000000000..fdb9f28751
--- /dev/null
+++ b/source/java/org/alfresco/jcr/example/SimpleExample.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.example;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.Repository;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+
+
+/**
+ * Simple Example that demonstrate login and retrieval of top-level Spaces
+ * under Company Home.
+ *
+ * @author David Caruana
+ */
+public class SimpleExample
+{
+
+ public static void main(String[] args)
+ throws Exception
+ {
+ // Setup Spring and Transaction Service
+ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:alfresco/application-context.xml");
+
+ // Retrieve Repository
+ Repository repository = (Repository)context.getBean("JCR.Repository");
+
+ // Login to workspace
+ // Note: Default workspace is the one used by Alfresco Web Client which contains all the Spaces
+ // and their documents
+ Session session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
+
+ try
+ {
+ // Retrieve Company Home
+ Node root = session.getRootNode();
+ Node companyHome = root.getNode("app:company_home");
+
+ // Iterator through children of Company Home
+ NodeIterator iterator = companyHome.getNodes();
+ while(iterator.hasNext())
+ {
+ Node child = iterator.nextNode();
+ System.out.println(child.getName());
+
+ PropertyIterator propIterator = child.getProperties();
+ while(propIterator.hasNext())
+ {
+ Property prop = propIterator.nextProperty();
+ if (!prop.getDefinition().isMultiple())
+ {
+ System.out.println(" " + prop.getName() + " = " + prop.getString());
+ }
+ }
+ }
+ }
+ finally
+ {
+ session.logout();
+ System.exit(0);
+ }
+
+ }
+
+}
diff --git a/source/java/org/alfresco/jcr/example/WIKIExample.java b/source/java/org/alfresco/jcr/example/WIKIExample.java
new file mode 100644
index 0000000000..76ae7a8908
--- /dev/null
+++ b/source/java/org/alfresco/jcr/example/WIKIExample.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.example;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.Calendar;
+
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.PathNotFoundException;
+import javax.jcr.Property;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.Value;
+import javax.jcr.Workspace;
+import javax.jcr.query.Query;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.QueryResult;
+import javax.jcr.version.Version;
+import javax.jcr.version.VersionHistory;
+import javax.jcr.version.VersionIterator;
+
+import org.alfresco.jcr.api.JCRNodeRef;
+import org.alfresco.model.ContentModel;
+import org.alfresco.repo.content.MimetypeMap;
+import org.alfresco.service.ServiceRegistry;
+import org.alfresco.service.cmr.repository.ContentData;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.security.PermissionService;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.springframework.core.io.ClassPathResource;
+
+
+/**
+ * Example that demonstrates read and write of a simple WIKI model
+ *
+ * Please refer to http://www.alfresco.org/mediawiki/index.php/Introducing_the_Alfresco_Java_Content_Repository_API
+ * for a complete description of this example.
+ *
+ * @author David Caruana
+ */
+public class WIKIExample
+{
+
+ public static void main(String[] args)
+ throws Exception
+ {
+ //
+ // Repository Initialisation
+ //
+
+ // access the Alfresco JCR Repository (here it's via programmatic approach, but it could also be injected)
+ System.out.println("Initialising Repository...");
+ ApplicationContext context = new ClassPathXmlApplicationContext("classpath:org/alfresco/jcr/example/wiki-context.xml");
+ Repository repository = (Repository)context.getBean("JCR.Repository");
+
+ // display information about the repository
+ System.out.println("Repository Description...");
+ String[] keys = repository.getDescriptorKeys();
+ for (String key : keys)
+ {
+ String value = repository.getDescriptor(key);
+ System.out.println(" " + key + " = " + value);
+ }
+
+ //
+ // Create a WIKI structure
+ //
+ // Note: Here we're using the Alfresco Content Model and custom WIKI model to create
+ // WIKI pages and Content that are accessible via the Alfresco Web Client
+ //
+
+ // login to workspace (here we rely on the default workspace defined by JCR.Repository bean)
+ Session session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
+
+ try
+ {
+ System.out.println("Creating WIKI...");
+
+ // first, access the company home
+ Node rootNode = session.getRootNode();
+ System.out.println("Root node: path=" + rootNode.getPath() + ", type=" + rootNode.getPrimaryNodeType().getName());
+ Node companyHome = rootNode.getNode("app:company_home");
+ System.out.println("Company home node: path=" + companyHome.getPath() + ", type=" + companyHome.getPrimaryNodeType().getName());
+
+ // remove the WIKI structure if it already exists
+ try
+ {
+ Node encyclopedia = companyHome.getNode("wiki:encyclopedia");
+ encyclopedia.remove();
+ System.out.println("Existing WIKI found and removed");
+ }
+ catch(PathNotFoundException e)
+ {
+ // doesn't exist, no need to remove
+ }
+
+ // create the root WIKI folder
+ Node encyclopedia = companyHome.addNode("wiki:encyclopedia", "cm:folder");
+ encyclopedia.setProperty("cm:name", "WIKI Encyclopedia");
+ encyclopedia.setProperty("cm:description", "");
+
+ // create first wiki page
+ Node page1 = encyclopedia.addNode("wiki:entry1", "wiki:page");
+ page1.setProperty("cm:name", "Rose");
+ page1.setProperty("cm:description", "");
+ page1.setProperty("cm:title", "The rose");
+ page1.setProperty("cm:content", "A rose is a flowering shrub.");
+ page1.setProperty("wiki:category", new String[] {"flower", "plant", "rose"});
+
+ // create second wiki page
+ Node page2 = encyclopedia.addNode("wiki:entry2", "wiki:page");
+ page2.setProperty("cm:name", "Shakespeare");
+ page2.setProperty("cm:description", "");
+ page2.setProperty("cm:title", "William Shakespeare");
+ page2.setProperty("cm:content", "A famous poet who likes roses.");
+ page2.setProperty("wiki:restrict", true);
+ page2.setProperty("wiki:category", new String[] {"poet"});
+
+ // create an image (note: we're using an input stream to allow setting of binary content)
+ Node contentNode = encyclopedia.addNode("wiki:image", "cm:content");
+ contentNode.setProperty("cm:name", "Dog");
+ contentNode.setProperty("cm:description", "");
+ contentNode.setProperty("cm:title", "My dog at New Year party");
+ ClassPathResource resource = new ClassPathResource("org/alfresco/jcr/example/wikiImage.gif");
+ contentNode.setProperty("cm:content", resource.getInputStream());
+
+ session.save();
+ System.out.println("WIKI created");
+ }
+ finally
+ {
+ session.logout();
+ }
+
+ //
+ // Access the WIKI structure
+ //
+
+ // login to workspace (here we rely on the default workspace defined by JCR.Repository bean)
+ session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
+
+ try
+ {
+ System.out.println("Accessing WIKI...");
+
+ // access a wiki node directly from root node (by path and by UUID)
+ Node rootNode = session.getRootNode();
+ Node encyclopedia = rootNode.getNode("app:company_home/wiki:encyclopedia");
+ Node direct = session.getNodeByUUID(encyclopedia.getUUID());
+ System.out.println("Found WIKI root correctly: " + encyclopedia.equals(direct));
+
+ // access a wiki property directly from root node
+ Node entry1 = rootNode.getNode("app:company_home/wiki:encyclopedia/wiki:entry1");
+ String title = entry1.getProperty("cm:title").getString();
+ System.out.println("Found WIKI page 1 title: " + title);
+ Calendar modified = entry1.getProperty("cm:modified").getDate();
+ System.out.println("Found WIKI page 1 last modified date: " + modified.getTime());
+
+ // browse all wiki entries
+ System.out.println("WIKI browser:");
+ NodeIterator entries = encyclopedia.getNodes();
+ while (entries.hasNext())
+ {
+ Node entry = entries.nextNode();
+ outputContentNode(entry);
+ }
+
+ // perform a search
+ System.out.println("Search results:");
+ Workspace workspace = session.getWorkspace();
+ QueryManager queryManager = workspace.getQueryManager();
+ Query query = queryManager.createQuery("//app:company_home/wiki:encyclopedia/*[@cm:title = 'The rose']", Query.XPATH);
+ //Query query = queryManager.createQuery("//app:company_home/wiki:encyclopedia/*[jcr:contains(., 'rose')]", Query.XPATH);
+ QueryResult result = query.execute();
+ NodeIterator it = result.getNodes();
+ while (it.hasNext())
+ {
+ Node n = it.nextNode();
+ outputContentNode(n);
+ }
+
+ // export content (system view format)
+ File systemView = new File("systemview.xml");
+ FileOutputStream systemViewOut = new FileOutputStream(systemView);
+ session.exportSystemView("/app:company_home/wiki:encyclopedia", systemViewOut, false, false);
+
+ // export content (document view format)
+ File docView = new File("docview.xml");
+ FileOutputStream docViewOut = new FileOutputStream(docView);
+ session.exportDocumentView("/app:company_home/wiki:encyclopedia", docViewOut, false, false);
+
+ System.out.println("WIKI exported");
+
+ }
+ finally
+ {
+ session.logout();
+ }
+
+
+ //
+ // Advanced Usage
+ //
+
+ // 1) Check-out / Check-in and version history retrieval
+ session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
+
+ try
+ {
+ //
+ // Version WIKI Page 1
+ //
+
+ // first, access the page
+ Node rootNode = session.getRootNode();
+ Node entry1 = rootNode.getNode("app:company_home/wiki:encyclopedia/wiki:entry1");
+
+ // enable versioning capability
+ entry1.addMixin("mix:versionable");
+
+ // update the properties and content
+ entry1.setProperty("cm:title", "The Rise");
+ entry1.setProperty("cm:content", "A rose is a flowering shrub of the genus Rosa.");
+ Value[] categories = entry1.getProperty("wiki:category").getValues();
+ Value[] newCategories = new Value[categories.length + 1];
+ System.arraycopy(categories, 0, newCategories, 0, categories.length);
+ newCategories[categories.length] = session.getValueFactory().createValue("poet");
+ entry1.setProperty("wiki:category", newCategories);
+
+ // and checkin the changes
+ entry1.checkin();
+
+ // checkout, fix wiki title and checkin again
+ entry1.checkout();
+ entry1.setProperty("cm:title", "The Rose");
+ entry1.checkin();
+
+ session.save();
+ System.out.println("Versioned WIKI Page 1");
+ }
+ finally
+ {
+ session.logout();
+ }
+
+ // 2) Permission checks
+ session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
+
+ try
+ {
+ //
+ // Browse WIKI Page 1 Version History
+ //
+
+ // first, access the page
+ Node rootNode = session.getRootNode();
+ Node entry1 = rootNode.getNode("app:company_home/wiki:encyclopedia/wiki:entry1");
+
+ // retrieve the history for thte page
+ VersionHistory versionHistory = entry1.getVersionHistory();
+ VersionIterator versionIterator = versionHistory.getAllVersions();
+
+ // for each version, output the node as it was versioned
+ while (versionIterator.hasNext())
+ {
+ Version version = versionIterator.nextVersion();
+ NodeIterator nodeIterator = version.getNodes();
+
+ while (nodeIterator.hasNext())
+ {
+ Node versionedNode = nodeIterator.nextNode();
+ System.out.println(" Version: " + version.getName());
+ System.out.println(" Created: " + version.getCreated().getTime());
+ outputContentNode(versionedNode);
+ }
+ }
+
+
+ //
+ // Permission Checks
+ //
+
+ System.out.println("Testing Permissions:");
+
+ // check for JCR 'read' permission
+ session.checkPermission("app:company_home/wiki:encyclopedia/wiki:entry1", "read");
+ System.out.println("Session has 'read' permission on app:company_home/wiki:encyclopedia/wiki:entry1");
+
+ // check for Alfresco 'Take Ownership' permission
+ session.checkPermission("app:company_home/wiki:encyclopedia/wiki:entry1", PermissionService.TAKE_OWNERSHIP);
+ System.out.println("Session has 'take ownership' permission on app:company_home/wiki:encyclopedia/wiki:entry1");
+ }
+ finally
+ {
+ session.logout();
+ }
+
+
+ //
+ // Mixing JCR and Alfresco API calls
+ //
+ // Provide mimetype for WIKI content properties
+ //
+
+ session = repository.login(new SimpleCredentials("admin", "admin".toCharArray()));
+
+ try
+ {
+ // Retrieve the Alfresco Repository Service Registry
+ ServiceRegistry registry = (ServiceRegistry)context.getBean(ServiceRegistry.SERVICE_REGISTRY);
+
+ // set the mime type on both WIKI pages and Image
+ Node rootNode = session.getRootNode();
+
+ // note: we have to checkout entry1 first - it's versioned
+ Node entry1 = rootNode.getNode("app:company_home/wiki:encyclopedia/wiki:entry1");
+ entry1.checkout();
+ setMimetype(registry, entry1, "cm:content", MimetypeMap.MIMETYPE_TEXT_PLAIN);
+ entry1.checkin();
+
+ Node entry2 = rootNode.getNode("app:company_home/wiki:encyclopedia/wiki:entry2");
+ setMimetype(registry, entry2, "cm:content", MimetypeMap.MIMETYPE_TEXT_PLAIN);
+ Node image = rootNode.getNode("app:company_home/wiki:encyclopedia/wiki:image");
+ setMimetype(registry, image, "cm:content", MimetypeMap.MIMETYPE_IMAGE_GIF);
+
+ // save the changes
+ session.save();
+ System.out.println("Updated WIKI mimetypes via Alfresco calls");
+ }
+ finally
+ {
+ session.logout();
+ }
+
+ // exit
+ System.out.println("Completed successfully.");
+ System.exit(0);
+ }
+
+
+ private static void outputContentNode(Node node)
+ throws RepositoryException
+ {
+ // output common content properties
+ System.out.println(" Node " + node.getUUID());
+ System.out.println(" title: " + node.getProperty("cm:title").getString());
+
+ // output properties specific to WIKI page
+ if (node.getPrimaryNodeType().getName().equals("wiki:page"))
+ {
+ System.out.println(" content: " + node.getProperty("cm:content").getString());
+ System.out.println(" restrict: " + node.getProperty("wiki:restrict").getString());
+
+ // output multi-value property
+ Property categoryProperty = node.getProperty("wiki:category");
+ Value[] categories = categoryProperty.getValues();
+ for (Value category : categories)
+ {
+ System.out.println(" category: " + category.getString());
+ }
+ }
+ }
+
+
+ private static void setMimetype(ServiceRegistry registry, Node node, String propertyName, String mimeType)
+ throws RepositoryException
+ {
+ // convert the JCR Node to an Alfresco Node Reference
+ NodeRef nodeRef = JCRNodeRef.getNodeRef(node);
+
+ // retrieve the Content Property (represented as a ContentData object in Alfresco)
+ NodeService nodeService = registry.getNodeService();
+ ContentData content = (ContentData)nodeService.getProperty(nodeRef, ContentModel.PROP_CONTENT);
+
+ // update the Mimetype
+ content = ContentData.setMimetype(content, mimeType);
+ nodeService.setProperty(nodeRef, ContentModel.PROP_CONTENT, content);
+ }
+
+}
diff --git a/source/java/org/alfresco/jcr/example/wiki-context.xml b/source/java/org/alfresco/jcr/example/wiki-context.xml
new file mode 100644
index 0000000000..005230ed3f
--- /dev/null
+++ b/source/java/org/alfresco/jcr/example/wiki-context.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+ org/alfresco/jcr/example/wikiModel.xml
+
+
+
+
+
diff --git a/source/java/org/alfresco/jcr/example/wikiImage.gif b/source/java/org/alfresco/jcr/example/wikiImage.gif
new file mode 100644
index 0000000000..a3e1ca59bd
Binary files /dev/null and b/source/java/org/alfresco/jcr/example/wikiImage.gif differ
diff --git a/source/java/org/alfresco/jcr/example/wikiModel.xml b/source/java/org/alfresco/jcr/example/wikiModel.xml
new file mode 100644
index 0000000000..1b0642a7b5
--- /dev/null
+++ b/source/java/org/alfresco/jcr/example/wikiModel.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WIKI Page
+ cm:content
+
+
+ d:boolean
+ false
+
+
+ d:text
+ true
+
+
+
+ cm:titled
+
+
+
+
+
+
diff --git a/source/java/org/alfresco/jcr/exporter/JCRDocumentXMLExporter.java b/source/java/org/alfresco/jcr/exporter/JCRDocumentXMLExporter.java
new file mode 100644
index 0000000000..d33715f041
--- /dev/null
+++ b/source/java/org/alfresco/jcr/exporter/JCRDocumentXMLExporter.java
@@ -0,0 +1,491 @@
+/*
+ * Copyright (C) 2005 Alfresco, Inc.
+ *
+ * Licensed under the Mozilla Public License version 1.1
+ * with a permitted attribution clause. You may obtain a
+ * copy of the License at
+ *
+ * http://www.alfresco.org/legal/license.txt
+ *
+ * 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 org.alfresco.jcr.exporter;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFormatException;
+
+import org.alfresco.jcr.dictionary.JCRNamespace;
+import org.alfresco.jcr.item.NodeImpl;
+import org.alfresco.jcr.item.PropertyImpl;
+import org.alfresco.jcr.item.property.JCRMixinTypesProperty;
+import org.alfresco.jcr.item.property.JCRPrimaryTypeProperty;
+import org.alfresco.jcr.item.property.JCRUUIDProperty;
+import org.alfresco.jcr.session.SessionImpl;
+import org.alfresco.service.cmr.repository.ContentData;
+import org.alfresco.service.cmr.repository.NodeRef;
+import org.alfresco.service.cmr.repository.NodeService;
+import org.alfresco.service.cmr.repository.Path;
+import org.alfresco.service.cmr.security.AccessPermission;
+import org.alfresco.service.cmr.view.Exporter;
+import org.alfresco.service.cmr.view.ExporterContext;
+import org.alfresco.service.cmr.view.ExporterException;
+import org.alfresco.service.namespace.QName;
+import org.alfresco.util.Base64;
+import org.alfresco.util.ISO9075;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+
+/**
+ * Alfresco Implementation of JCR Document XML Exporter
+ *
+ * @author David Caruana
+ */
+public class JCRDocumentXMLExporter implements Exporter
+{
+
+ private SessionImpl session;
+ private ContentHandler contentHandler;
+ private List currentProperties = new ArrayList();
+ private List