diff --git a/config/alfresco/application-context.xml b/config/alfresco/application-context.xml
index a5eab11b75..954291fef2 100644
--- a/config/alfresco/application-context.xml
+++ b/config/alfresco/application-context.xml
@@ -46,6 +46,7 @@
+
diff --git a/config/alfresco/cmis-api-context.xml b/config/alfresco/cmis-api-context.xml
new file mode 100644
index 0000000000..7ead43bf1e
--- /dev/null
+++ b/config/alfresco/cmis-api-context.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+ alfresco/model/cmisModel.xml
+
+
+
+
+
\ No newline at end of file
diff --git a/config/alfresco/model/cmisModel.xml b/config/alfresco/model/cmisModel.xml
new file mode 100644
index 0000000000..e27ddc83ae
--- /dev/null
+++ b/config/alfresco/model/cmisModel.xml
@@ -0,0 +1,348 @@
+
+
+ CMIS Model Definitions
+ 1.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Document
+ Document Type
+
+
+ Is Immutable
+ Is the document immutable?
+ d:boolean
+ true
+ false
+ false
+
+
+
+ Is Latest Version
+ Is this the latest version of the document?
+ d:boolean
+ true
+ true
+ false
+
+ true
+
+
+
+ Is Major Version
+ Is this a major version of the document?
+ d:boolean
+ true
+ false
+ false
+
+ true
+
+
+
+ Is Latest Major Version
+ Is this the latest major version of the document?
+ d:boolean
+ true
+ false
+ false
+
+ true
+
+
+
+ Version Series Is Checked Out
+ Is the version series checked out?
+ d:boolean
+ true
+ true
+ false
+
+ true
+
+
+
+ Version Series Checked Out By
+ The authority who checked out this document version series
+ d:text
+ true
+ false
+ false
+
+ true
+
+
+
+ Version Series Checked Out Id
+ The checked out version series id
+ d:noderef
+ true
+ false
+ false
+
+ true
+
+
+
+ Checkin Comment
+ The checkin comment
+ d:text
+ true
+ false
+ false
+
+ true
+
+
+
+ Content Stream Allowed
+ Is a content stream allowed?
+ d:boolean
+ true
+ true
+ false
+
+ true
+
+
+
+ Content Stream Length
+ The length of the content stream
+ d:int
+ true
+ false
+ false
+
+ true
+
+
+
+ Content Stream MIME Type
+ The content stream MIME type
+ d:text
+ true
+ false
+ false
+
+ true
+
+
+
+ Content Stream Filename
+ The content stream filename
+ d:text
+ false
+ false
+ false
+
+ true
+
+
+
+ Content Stream URI
+ The content stream URI
+ d:text
+ true
+ false
+ false
+
+ true
+
+
+
+
+ cmis:NAMED
+
+
+
+
+
+ Folder
+ Folder Type
+
+
+ Parent
+ The parent of the folder
+ d:noderef
+ true
+ true
+ false
+
+ false
+
+
+
+ Allowed Child Object Types
+ The allowed child object types
+ d:qname
+ true
+ false
+ true
+
+ false
+
+
+
+
+ cmis:NAMED
+
+
+
+
+ Relationship
+ Relationship Type
+
+
+ Source Id
+ The source id for the relationship
+ d:noderef
+ true
+ true
+ false
+
+ false
+
+
+
+ Target Id
+ The target id for the relationship
+ d:noderef
+ true
+ true
+ false
+
+ false
+
+
+
+
+ cmis:CORE
+
+
+
+
+
+
+
+
+
+ Object Id
+ The unique object id (a node ref)
+ d:noderef
+ true
+ true
+ false
+
+ false
+
+
+
+ URI
+ URI
+ d:text
+ true
+ false
+ false
+
+ false
+
+
+
+ Object Type Id
+ The object type id
+ d:qname
+ true
+ true
+ false
+
+ false
+
+
+
+ Created by
+ The authority who created this object
+ d:text
+ true
+ true
+ false
+
+ false
+
+
+
+ Creation Date
+ The object creation date
+ d:datetime
+ true
+ true
+ false
+
+ false
+
+
+
+ Last Modified By
+ The authority who last modified this object
+ d:text
+ true
+ true
+ false
+
+ false
+
+
+
+ Last Modified Date
+ The date this object was last modified
+ d:datetime
+ true
+ true
+ false
+
+ false
+
+
+
+ Change token
+ Change Token
+ d:text
+ true
+ true
+ false
+
+ false
+
+
+
+
+
+
+ cmis:CORE
+
+
+ Name
+ Name
+ d:text
+ false
+ true
+ false
+
+ both
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/source/java/org/alfresco/cmis/dictionary/BaseCMISTest.java b/source/java/org/alfresco/cmis/dictionary/BaseCMISTest.java
new file mode 100644
index 0000000000..f35afecc16
--- /dev/null
+++ b/source/java/org/alfresco/cmis/dictionary/BaseCMISTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.cmis.dictionary;
+
+import javax.transaction.Status;
+import javax.transaction.UserTransaction;
+
+import junit.framework.TestCase;
+
+import org.alfresco.repo.security.authentication.AuthenticationComponent;
+import org.alfresco.repo.security.authentication.AuthenticationUtil;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.transaction.TransactionService;
+import org.alfresco.util.ApplicationContextHelper;
+import org.springframework.context.ApplicationContext;
+
+/**
+ * Base CMIS test
+ * Basic TX control and authentication
+ *
+ * @author andyh
+ *
+ */
+public abstract class BaseCMISTest extends TestCase
+{
+ private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
+
+ protected CMISDictionaryService cmisDictionaryService;
+
+ protected DictionaryService dictionaryService;
+
+ protected TransactionService transactionService;
+
+ protected AuthenticationComponent authenticationComponent;
+
+ protected UserTransaction testTX;
+
+ public void setUp() throws Exception
+ {
+ cmisDictionaryService = (CMISDictionaryService) ctx.getBean("CMISDictionaryService");
+ dictionaryService = (DictionaryService) ctx.getBean("dictionaryService");
+
+ transactionService = (TransactionService) ctx.getBean("transactionComponent");
+ authenticationComponent = (AuthenticationComponent) ctx.getBean("authenticationComponent");
+
+ testTX = transactionService.getUserTransaction();
+ testTX.begin();
+ this.authenticationComponent.setSystemUserAsCurrentUser();
+
+
+ }
+
+ @Override
+ protected void tearDown() throws Exception
+ {
+
+ if (testTX.getStatus() == Status.STATUS_ACTIVE)
+ {
+ testTX.rollback();
+ }
+ AuthenticationUtil.clearCurrentSecurityContext();
+ super.tearDown();
+ }
+}
diff --git a/source/java/org/alfresco/cmis/dictionary/CMISCardinality.java b/source/java/org/alfresco/cmis/dictionary/CMISCardinality.java
new file mode 100644
index 0000000000..fc186eae48
--- /dev/null
+++ b/source/java/org/alfresco/cmis/dictionary/CMISCardinality.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.cmis.dictionary;
+
+/**
+ * Cardinality for property definitions
+ *
+ * @author andyh
+ *
+ */
+public enum CMISCardinality
+{
+ /**
+ * Single-valued
+ */
+ SINGLE_VALUED,
+ /**
+ * Multi-valued
+ */
+ MULTI_VALUED;
+}
diff --git a/source/java/org/alfresco/cmis/dictionary/CMISChoice.java b/source/java/org/alfresco/cmis/dictionary/CMISChoice.java
new file mode 100644
index 0000000000..1f4489498d
--- /dev/null
+++ b/source/java/org/alfresco/cmis/dictionary/CMISChoice.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.cmis.dictionary;
+
+import java.util.Collection;
+
+/**
+ * Choice for property definitions
+ *
+ * @author andyh
+ *
+ */
+public class CMISChoice
+{
+ /**
+ * Get the name of the choice
+ * @return
+ */
+ public String getName()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get the value when chosen
+ * @return
+ */
+ public CMISPropertyValue getValue()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get the index that determined the choices position amongst it siblings
+ * @return
+ */
+ public int getIndex()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Get sub-choices
+ * @return
+ */
+ public Collection getChildren()
+ {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/source/java/org/alfresco/cmis/dictionary/CMISDictionaryService.java b/source/java/org/alfresco/cmis/dictionary/CMISDictionaryService.java
new file mode 100644
index 0000000000..f858bb9a3f
--- /dev/null
+++ b/source/java/org/alfresco/cmis/dictionary/CMISDictionaryService.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.cmis.dictionary;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.alfresco.service.cmr.dictionary.AspectDefinition;
+import org.alfresco.service.cmr.dictionary.AssociationDefinition;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.cmr.dictionary.TypeDefinition;
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
+
+/**
+ * Service to query the CMIS meta model
+ *
+ * @author andyh
+ */
+public class CMISDictionaryService
+{
+
+ private DictionaryService dictionaryService;
+
+ private NamespaceService namespaceService;
+
+ private boolean strict = true;
+
+ /**
+ * Set the dictionary Service
+ *
+ * @param dictionaryService
+ */
+ public void setDictionaryService(DictionaryService dictionaryService)
+ {
+ this.dictionaryService = dictionaryService;
+ }
+
+ /**
+ * Set the namespace service
+ *
+ * @param namespaceService
+ */
+ public void setNamespaceService(NamespaceService namespaceService)
+ {
+ this.namespaceService = namespaceService;
+ }
+
+ /**
+ * Is the service strict (CMIS types only)
+ *
+ * @return
+ */
+ public boolean isStrict()
+ {
+ return strict;
+ }
+
+ /**
+ * Set strict mode. In strict mode only CMIS types and properties are returned
+ *
+ * @param strict
+ */
+ public void setStrict(boolean strict)
+ {
+ this.strict = strict;
+ }
+
+ /**
+ * Get the all the object types ids TODO: Note there can be name collisions between types and associations. e.g.
+ * app:configurations
+ *
+ * @return
+ */
+ public Collection getAllObjectTypeIds()
+ {
+ Collection alfrescoTypeQNames;
+ Collection alfrescoAssociationQNames;
+
+ if (strict)
+ {
+ alfrescoTypeQNames = dictionaryService.getTypes(CMISMapping.CMIS_MODEL_QNAME);
+ alfrescoAssociationQNames = dictionaryService.getAssociations(CMISMapping.CMIS_MODEL_QNAME);
+ }
+ else
+ {
+ alfrescoTypeQNames = dictionaryService.getAllTypes();
+ alfrescoAssociationQNames = dictionaryService.getAllAssociations();
+ }
+
+ Collection answer = new HashSet(alfrescoTypeQNames.size() + alfrescoAssociationQNames.size());
+
+ for (QName typeQName : alfrescoTypeQNames)
+ {
+ if (CMISMapping.isValidCmisType(dictionaryService, typeQName))
+ {
+ answer.add(CMISMapping.getCmisTypeId(typeQName));
+ }
+ }
+
+ for (QName associationName : alfrescoAssociationQNames)
+ {
+ if (CMISMapping.isValidCmisAssociation(dictionaryService, associationName))
+ {
+ answer.add(CMISMapping.getCmisTypeId(associationName));
+ }
+ }
+
+ return answer;
+ }
+
+ /**
+ * Get the object type definition TODO: Note there can be name collisions between types and associations. e.g.
+ * app:configurations Currently clashing types will give inconsistent behaviour
+ *
+ * @param typeId
+ * @return
+ */
+ public CMISTypeDefinition getType(CMISTypeId typeId)
+ {
+ // Types
+ QName typeQName = CMISMapping.getTypeQname(typeId);
+ TypeDefinition typeDefinition = dictionaryService.getType(typeQName);
+ if (typeDefinition != null)
+ {
+ if (CMISMapping.isValidCmisType(dictionaryService, typeQName))
+ {
+ return new CMISTypeDefinition(dictionaryService, namespaceService, typeQName);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ // Associations
+ AssociationDefinition associationDefinition = dictionaryService.getAssociation(typeQName);
+ if (associationDefinition != null)
+ {
+ if (CMISMapping.isValidCmisAssociation(dictionaryService, typeQName))
+ {
+ return new CMISTypeDefinition(dictionaryService, namespaceService, typeQName);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ // Unknown type
+ return null;
+ }
+
+ /**
+ * Get all the property definitions for a type
+ *
+ * @param typeId
+ * @return
+ */
+ public Map getPropertyDefinitions(CMISTypeId typeId)
+ {
+ HashMap properties = new HashMap();
+
+ QName typeQName = CMISMapping.getTypeQname(typeId);
+ TypeDefinition typeDefinition = dictionaryService.getType(typeQName);
+ if (typeDefinition != null)
+ {
+ if (CMISMapping.isValidCmisType(dictionaryService, typeQName))
+ {
+ for (QName qname : typeDefinition.getProperties().keySet())
+ {
+ if (CMISMapping.getPropertyType(dictionaryService, qname) != null)
+ {
+ CMISPropertyDefinition cmisPropDefinition = new CMISPropertyDefinition(dictionaryService, namespaceService, qname);
+ properties.put(cmisPropDefinition.getPropertyName(), cmisPropDefinition);
+ }
+ }
+ for (AspectDefinition aspect : typeDefinition.getDefaultAspects())
+ {
+ for (QName qname : aspect.getProperties().keySet())
+ {
+ if (CMISMapping.getPropertyType(dictionaryService, qname) != null)
+ {
+ CMISPropertyDefinition cmisPropDefinition = new CMISPropertyDefinition(dictionaryService, namespaceService, qname);
+ properties.put(cmisPropDefinition.getPropertyName(), cmisPropDefinition);
+ }
+ }
+ }
+ }
+ else
+ {
+ return properties;
+ }
+ }
+
+ // Associations
+ AssociationDefinition associationDefinition = dictionaryService.getAssociation(typeQName);
+ if (associationDefinition != null)
+ {
+ if (CMISMapping.isValidCmisAssociation(dictionaryService, typeQName))
+ {
+ return getPropertyDefinitions(new CMISTypeId(CMISMapping.RELATIONSHIP_OBJECT_TYPE));
+ }
+ else
+ {
+ return properties;
+ }
+ }
+
+ // Unknown type
+ return properties;
+ }
+
+ /**
+ * Get a single property definition
+ *
+ * @param typeId
+ * @param propertyName
+ * @return
+ */
+ public CMISPropertyDefinition getPropertyDefinition(CMISTypeId typeId, String propertyName)
+ {
+ return getPropertyDefinitions(typeId).get(propertyName);
+ }
+}
diff --git a/source/java/org/alfresco/cmis/dictionary/CMISDictionaryTest.java b/source/java/org/alfresco/cmis/dictionary/CMISDictionaryTest.java
new file mode 100644
index 0000000000..bdc770429d
--- /dev/null
+++ b/source/java/org/alfresco/cmis/dictionary/CMISDictionaryTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.cmis.dictionary;
+
+public class CMISDictionaryTest extends BaseCMISTest
+{
+ public void testBasicTypes()
+ {
+ cmisDictionaryService.setStrict(true);
+ for (CMISTypeId name : cmisDictionaryService.getAllObjectTypeIds())
+ {
+ System.out.println(name);
+ }
+ assertEquals(3, cmisDictionaryService.getAllObjectTypeIds().size());
+
+ }
+
+ public void testBasicTypeDefinitions()
+ {
+ cmisDictionaryService.setStrict(false);
+ for (CMISTypeId name : cmisDictionaryService.getAllObjectTypeIds())
+ {
+ System.out.println(cmisDictionaryService.getType(name));
+ }
+
+ }
+
+ public void testBasicProperties()
+ {
+ cmisDictionaryService.setStrict(false);
+ for (CMISTypeId name : cmisDictionaryService.getAllObjectTypeIds())
+ {
+ for (String propertyName : cmisDictionaryService.getPropertyDefinitions(name).keySet())
+ {
+ System.out.println(name +" -> "+ propertyName);
+ }
+ }
+
+ }
+
+ public void testBasicPropertyDefinitions()
+ {
+ cmisDictionaryService.setStrict(true);
+ for (CMISTypeId name : cmisDictionaryService.getAllObjectTypeIds())
+ {
+ for (CMISPropertyDefinition proDef : cmisDictionaryService.getPropertyDefinitions(name).values())
+ {
+ System.out.println(proDef);
+ }
+ }
+
+ }
+}
diff --git a/source/java/org/alfresco/cmis/dictionary/CMISMapping.java b/source/java/org/alfresco/cmis/dictionary/CMISMapping.java
new file mode 100644
index 0000000000..77bd8cc8cb
--- /dev/null
+++ b/source/java/org/alfresco/cmis/dictionary/CMISMapping.java
@@ -0,0 +1,373 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.cmis.dictionary;
+
+import java.util.Collection;
+import java.util.HashMap;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.dictionary.AssociationDefinition;
+import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.cmr.dictionary.PropertyDefinition;
+import org.alfresco.service.namespace.NamespaceException;
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
+
+/**
+ * CMIS <-> Alfresco mappings
+ *
+ * @author andyh
+ */
+public class CMISMapping
+{
+ /**
+ * The Alfresco CMIS model URI.
+ */
+ public static String CMIS_MODEL_URI = "http://www.alfresco.org/model/cmis/0.3";
+
+ /**
+ * The Alfresco CMIS Model name.
+ */
+ public static String CMIS_MODEL_NAME = "cmismodel";
+
+ /**
+ * The QName for the Alfresco CMIS Model.
+ */
+ public static QName CMIS_MODEL_QNAME = QName.createQName(CMIS_MODEL_URI, CMIS_MODEL_NAME);
+
+ /**
+ * Type id for CMIS documents, from the spec.
+ */
+ public static String DOCUMENT_OBJECT_TYPE = "DOCUMENT_OBJECT_TYPE";
+
+ /**
+ * Type is for CMIS folders, from the spec.
+ */
+ public static String FOLDER_OBJECT_TYPE = "FOLDER_OBJECT_TYPE";
+
+ /**
+ * Type Id for CMIS Relationships, from the spec.
+ */
+ public static String RELATIONSHIP_OBJECT_TYPE = "RELATIONSHIP_OBJECT_TYPE";
+
+ /**
+ * QName for CMIS documents in the Alfresco CMIS model.
+ */
+ public static QName DOCUMENT_QNAME = QName.createQName(CMIS_MODEL_URI, DOCUMENT_OBJECT_TYPE);
+
+ /**
+ * QName for CMIS folders in the Alfresco CMIS model
+ */
+ public static QName FOLDER_QNAME = QName.createQName(CMIS_MODEL_URI, FOLDER_OBJECT_TYPE);
+
+ /**
+ * QName for CMIS relationships in the the Alfresco CMIS model.
+ */
+ public static QName RELATIONSHIP_QNAME = QName.createQName(CMIS_MODEL_URI, RELATIONSHIP_OBJECT_TYPE);
+
+
+
+ // Mappings
+ // - no entry means no mapping and pass through as is
+ private static HashMap cmisTypeIdToTypeQName = new HashMap();
+
+ private static HashMap qNameToCmisTypeId = new HashMap();
+
+ private static HashMap cmisToAlfrecsoTypes = new HashMap();
+
+ private static HashMap alfrescoToCmisTypes = new HashMap();
+
+ private static HashMap alfrescoPropertyTypesToCimsPropertyTypes = new HashMap();
+ /**
+ * Set up mappings
+ */
+ static
+ {
+ cmisTypeIdToTypeQName.put(new CMISTypeId(DOCUMENT_OBJECT_TYPE), DOCUMENT_QNAME);
+ cmisTypeIdToTypeQName.put(new CMISTypeId(FOLDER_OBJECT_TYPE), FOLDER_QNAME);
+ cmisTypeIdToTypeQName.put(new CMISTypeId(RELATIONSHIP_OBJECT_TYPE), RELATIONSHIP_QNAME);
+
+ qNameToCmisTypeId.put(DOCUMENT_QNAME, new CMISTypeId(DOCUMENT_OBJECT_TYPE));
+ qNameToCmisTypeId.put(FOLDER_QNAME, new CMISTypeId(FOLDER_OBJECT_TYPE));
+ qNameToCmisTypeId.put(RELATIONSHIP_QNAME, new CMISTypeId(RELATIONSHIP_OBJECT_TYPE));
+
+ cmisToAlfrecsoTypes.put(DOCUMENT_QNAME, ContentModel.TYPE_CONTENT);
+ cmisToAlfrecsoTypes.put(FOLDER_QNAME, ContentModel.TYPE_FOLDER);
+ cmisToAlfrecsoTypes.put(RELATIONSHIP_QNAME, null);
+
+ alfrescoToCmisTypes.put(ContentModel.TYPE_CONTENT, DOCUMENT_QNAME);
+ alfrescoToCmisTypes.put(ContentModel.TYPE_FOLDER, FOLDER_QNAME);
+
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.ANY, null);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.ASSOC_REF, null);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.BOOLEAN, CMISPropertyType.BOOLEAN);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.CATEGORY, CMISPropertyType.ID);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.CHILD_ASSOC_REF, null);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.CONTENT, null);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.DATE, CMISPropertyType.DATE_TIME);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.DATETIME, CMISPropertyType.DATE_TIME);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.DOUBLE, CMISPropertyType.DECIMAL);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.FLOAT, CMISPropertyType.DECIMAL);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.INT, CMISPropertyType.INTEGER);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.LOCALE, null);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.LONG, CMISPropertyType.INTEGER);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.MLTEXT, CMISPropertyType.STRING);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.NODE_REF, CMISPropertyType.ID);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.PATH, null);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.QNAME, null);
+ alfrescoPropertyTypesToCimsPropertyTypes.put(DataTypeDefinition.TEXT, CMISPropertyType.STRING);
+
+ }
+
+ /**
+ * Id this a CMIS core type defined in the Alfresco CMIS model
+ *
+ * @param typeQName
+ * @return
+ */
+ public static boolean isCmisCoreType(QName typeQName)
+ {
+ return qNameToCmisTypeId.get(typeQName) != null;
+ }
+
+ /**
+ * Get the CMIS Type Id given the Alfresco QName for the type in any Alfresco model
+ *
+ * @param typeQName
+ * @return
+ */
+ public static CMISTypeId getCmisTypeId(QName typeQName)
+ {
+ CMISTypeId typeId = qNameToCmisTypeId.get(typeQName);
+ if (typeId == null)
+ {
+ return new CMISTypeId(typeQName.toString());
+ }
+ else
+ {
+ return typeId;
+ }
+ }
+
+ /**
+ * Given a type id - get the appropriate Alfresco QName
+ *
+ * @param typeId
+ * @return
+ */
+ public static QName getTypeQname(CMISTypeId typeId)
+ {
+ QName typeQName = cmisTypeIdToTypeQName.get(typeId);
+ if (typeQName != null)
+ {
+ return typeQName;
+ }
+ else
+ {
+ return QName.createQName(typeId.getTypeId());
+ }
+ }
+
+ /**
+ * Get the query name for Alfresco qname
+ *
+ * @param namespaceService
+ * @param typeQName
+ * @return
+ */
+ public static String getQueryName(NamespaceService namespaceService, QName typeQName)
+ {
+ return buildPrefixEncodedString(namespaceService, typeQName);
+ }
+
+ private static String buildPrefixEncodedString(NamespaceService namespaceService, QName qname)
+ {
+ StringBuilder builder = new StringBuilder(128);
+
+ if (!qname.getNamespaceURI().equals(CMIS_MODEL_URI))
+ {
+ Collection prefixes = namespaceService.getPrefixes(qname.getNamespaceURI());
+ if (prefixes.size() == 0)
+ {
+ throw new NamespaceException("A namespace prefix is not registered for uri " + qname.getNamespaceURI());
+ }
+ String resolvedPrefix = prefixes.iterator().next();
+
+ builder.append(resolvedPrefix);
+ builder.append("_");
+ }
+
+ builder.append(qname.getLocalName());
+ return builder.toString();
+ }
+
+ /**
+ * Is this a valid CMIS type The type must be a core CMIS type or extend cm:content or cm:folder The alfresco types
+ * cm:content and cm:folder are hidden by the CMIS types
+ *
+ * @param dictionaryService
+ * @param typeQName
+ * @return
+ */
+ public static boolean isValidCmisType(DictionaryService dictionaryService, QName typeQName)
+ {
+ if (CMISMapping.isCmisCoreType(typeQName))
+ {
+ return true;
+ }
+
+ if (dictionaryService.isSubClass(typeQName, ContentModel.TYPE_CONTENT) || dictionaryService.isSubClass(typeQName, ContentModel.TYPE_FOLDER))
+ {
+ if (typeQName.equals(ContentModel.TYPE_CONTENT))
+ {
+ return false;
+ }
+ else if (typeQName.equals(ContentModel.TYPE_FOLDER))
+ {
+ return false;
+ }
+
+ else
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Is an association valid in CMIS? It must be a non-child relationship and the source and target must both be valid
+ * CMIS types.
+ *
+ * @param dictionaryService
+ * @param associationQName
+ * @return
+ */
+ public static boolean isValidCmisAssociation(DictionaryService dictionaryService, QName associationQName)
+ {
+ AssociationDefinition associationDefinition = dictionaryService.getAssociation(associationQName);
+ if (associationDefinition == null)
+ {
+ return false;
+ }
+ if (associationDefinition.isChild())
+ {
+ return false;
+ }
+ if (!isValidCmisType(dictionaryService, getCmisType(associationDefinition.getSourceClass().getName())))
+ {
+ return false;
+ }
+ if (!isValidCmisType(dictionaryService, getCmisType(associationDefinition.getTargetClass().getName())))
+ {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Given an Alfresco model type map it to the appropriate type. Maps cm:folder and cm:content to the CMIS
+ * definitions
+ *
+ * @param typeQName
+ * @return
+ */
+ public static QName getCmisType(QName typeQName)
+ {
+ QName mapped = alfrescoToCmisTypes.get(typeQName);
+ if (mapped != null)
+ {
+ return mapped;
+ }
+ return typeQName;
+ }
+
+ /**
+ * Get the root CMIS object (in the alfresco model) for any type.
+ *
+ * @param dictionaryService
+ * @param typeQName
+ * @return
+ */
+ public static QName getCmisRootType(DictionaryService dictionaryService, QName typeQName)
+ {
+ if (isCmisCoreType(typeQName))
+ {
+ return typeQName;
+ }
+ if (dictionaryService.isSubClass(typeQName, ContentModel.TYPE_CONTENT))
+ {
+ return DOCUMENT_QNAME;
+ }
+ if (dictionaryService.isSubClass(typeQName, ContentModel.TYPE_FOLDER))
+ {
+ return FOLDER_QNAME;
+ }
+ if (isValidCmisAssociation(dictionaryService, typeQName))
+ {
+ return RELATIONSHIP_QNAME;
+ }
+ throw new UnsupportedOperationException();
+
+ }
+
+ public static String getCmisPropertyName(NamespaceService namespaceService, QName propertyQName)
+ {
+ return buildPrefixEncodedString(namespaceService, propertyQName);
+ }
+
+ public static CMISPropertyType getPropertyType(DictionaryService dictionaryService, QName propertyQName)
+ {
+ PropertyDefinition propertyDefinition = dictionaryService.getProperty(propertyQName);
+ DataTypeDefinition dataTypeDefinition = propertyDefinition.getDataType();
+ QName dQName = dataTypeDefinition.getName();
+ if(propertyQName.getNamespaceURI().equals(CMIS_MODEL_URI) && dQName.equals(DataTypeDefinition.QNAME))
+ {
+ return CMISPropertyType.TYPE_ID;
+ }
+ return alfrescoPropertyTypesToCimsPropertyTypes.get(dQName);
+
+ }
+
+ public static QName getPropertyQName(DictionaryService dictionaryService, NamespaceService namespaceService, String cmisPropertyName)
+ {
+ // Try the cmis model first - it it matches we are done
+ QName cmisPropertyQName = QName.createQName(CMIS_MODEL_URI, cmisPropertyName);
+ if(dictionaryService.getProperty(cmisPropertyQName) != null)
+ {
+ return cmisPropertyQName;
+ }
+
+ int split = cmisPropertyName.indexOf('_');
+ String prefix = cmisPropertyName.substring(0, split);
+ String localName = cmisPropertyName.substring(split+1);
+
+ QName qname = QName.createQName(prefix, localName, namespaceService);
+ return qname;
+
+ }
+}
diff --git a/source/java/org/alfresco/cmis/dictionary/CMISPropertyDefinition.java b/source/java/org/alfresco/cmis/dictionary/CMISPropertyDefinition.java
new file mode 100644
index 0000000000..bc0fa9dff0
--- /dev/null
+++ b/source/java/org/alfresco/cmis/dictionary/CMISPropertyDefinition.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.cmis.dictionary;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.alfresco.repo.dictionary.IndexTokenisationMode;
+import org.alfresco.repo.search.impl.lucene.analysis.DateTimeAnalyser;
+import org.alfresco.repo.search.impl.lucene.analysis.DoubleAnalyser;
+import org.alfresco.repo.search.impl.lucene.analysis.FloatAnalyser;
+import org.alfresco.repo.search.impl.lucene.analysis.IntegerAnalyser;
+import org.alfresco.repo.search.impl.lucene.analysis.LongAnalyser;
+import org.alfresco.repo.search.impl.lucene.analysis.PathAnalyser;
+import org.alfresco.repo.search.impl.lucene.analysis.VerbatimAnalyser;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.cmr.dictionary.PropertyDefinition;
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
+
+/**
+ * A CMIS property definition
+ *
+ * @author andyh
+ */
+public class CMISPropertyDefinition
+{
+ private String propertyName;
+
+ private String displayName;
+
+ private String description;
+
+ private CMISPropertyType propertyType;
+
+ private CMISCardinality cardinality;
+
+ private int maximumLength = -1;
+
+ private String schemaURI = null;
+
+ private String encoding = null;
+
+ private Collection choices = new HashSet();
+
+ private boolean isOpenChoice = false;
+
+ private boolean required;
+
+ private String defaultValue;
+
+ private CMISUpdatability updatability;
+
+ private boolean queryable;
+
+ private boolean orderable;
+
+ public CMISPropertyDefinition(DictionaryService dictionaryService, NamespaceService namespaceService, QName propertyQName)
+ {
+ PropertyDefinition propDef = dictionaryService.getProperty(propertyQName);
+ if (propDef.getContainerClass().getName().equals(CMISMapping.RELATIONSHIP_QNAME))
+ {
+ // Properties of associations - all the same
+ propertyName = CMISMapping.getCmisPropertyName(namespaceService, propertyQName);
+ displayName = propDef.getTitle();
+ description = propDef.getDescription();
+ propertyType = CMISMapping.getPropertyType(dictionaryService, propertyQName);
+ cardinality = propDef.isMultiValued() ? CMISCardinality.MULTI_VALUED : CMISCardinality.SINGLE_VALUED;
+ required = propDef.isMandatory();
+ defaultValue = propDef.getDefaultValue();
+ updatability = propDef.isProtected() ? CMISUpdatability.READ_ONLY : CMISUpdatability.READ_AND_WRITE;
+ queryable = false;
+ orderable = false;
+ }
+ else
+ {
+
+ propertyName = CMISMapping.getCmisPropertyName(namespaceService, propertyQName);
+ displayName = propDef.getTitle();
+ description = propDef.getDescription();
+ propertyType = CMISMapping.getPropertyType(dictionaryService, propertyQName);
+ cardinality = propDef.isMultiValued() ? CMISCardinality.MULTI_VALUED : CMISCardinality.SINGLE_VALUED;
+ required = propDef.isMandatory();
+ defaultValue = propDef.getDefaultValue();
+ updatability = propDef.isProtected() ? CMISUpdatability.READ_ONLY : CMISUpdatability.READ_AND_WRITE;
+ queryable = propDef.isIndexed();
+ IndexTokenisationMode indexTokenisationMode = IndexTokenisationMode.TRUE;
+ if(propDef.getIndexTokenisationMode() != null)
+ {
+ indexTokenisationMode = propDef.getIndexTokenisationMode();
+ }
+ switch (indexTokenisationMode)
+ {
+ case BOTH:
+ case FALSE:
+ orderable = true;
+ break;
+ case TRUE:
+ default:
+ String analyserClassName = propDef.getDataType().getAnalyserClassName();
+ if (analyserClassName.equals(DateTimeAnalyser.class.getCanonicalName())
+ || analyserClassName.equals(DoubleAnalyser.class.getCanonicalName()) || analyserClassName.equals(FloatAnalyser.class.getCanonicalName())
+ || analyserClassName.equals(IntegerAnalyser.class.getCanonicalName()) || analyserClassName.equals(LongAnalyser.class.getCanonicalName())
+ || analyserClassName.equals(PathAnalyser.class.getCanonicalName()) || analyserClassName.equals(VerbatimAnalyser.class.getCanonicalName()))
+ {
+ orderable = true;
+ }
+ else
+ {
+ orderable = false;
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Get the property name
+ * @return
+ */
+ public String getPropertyName()
+ {
+ return propertyName;
+ }
+
+ /**
+ * Get the display name
+ * @return
+ */
+ public String getDisplayName()
+ {
+ return displayName;
+ }
+
+ /**
+ * Get the description
+ * @return
+ */
+ public String getDescription()
+ {
+ return description;
+ }
+
+ /**
+ * Get the property type
+ * @return
+ */
+ public CMISPropertyType getPropertyType()
+ {
+ return propertyType;
+ }
+
+ /**
+ * Get the cardinality
+ * @return
+ */
+ public CMISCardinality getCardinality()
+ {
+ return cardinality;
+ }
+
+ /**
+ * For variable length properties, get the maximum length allowed.
+ * Unsupported.
+ *
+ * @return
+ */
+ public int getMaximumLength()
+ {
+ return maximumLength;
+ }
+
+ /**
+ * For properties of type CMISPropertyType.XML the schema to which the property must conform. Unsupported
+ *
+ * @return - the schema URI
+ */
+ public String getSchemaURI()
+ {
+ return schemaURI;
+ }
+
+ /**
+ * For properties of type CMISPropertyType.XML the encoding used for the property value
+ *
+ * @return the encoding
+ */
+ public String getEncoding()
+ {
+ return encoding;
+ }
+
+ /**
+ * Get the choices available as values for this property
+ * TODO: not implemented yet
+ * @return
+ */
+ public Collection getChioces()
+ {
+ return choices;
+ }
+
+ /**
+ * Is this a choice where a user can enter other values (ie a list with common options)
+ * @return
+ */
+ public boolean isOpenChioce()
+ {
+ return isOpenChoice;
+ }
+
+ /**
+ * Is this property required?
+ * @return
+ */
+ public boolean isRequired()
+ {
+ return required;
+ }
+
+ /**
+ * get the default value as a String
+ *
+ * @return
+ */
+ public String getDefaultValue()
+ {
+ return defaultValue;
+ }
+
+ /**
+ * Is this property updatable?
+ * @return
+ */
+ public CMISUpdatability getUpdatability()
+ {
+ return updatability;
+ }
+
+ /**
+ * Is this property queryable?
+ * @return
+ */
+ public boolean isQueryable()
+ {
+ return queryable;
+ }
+
+ /**
+ * Is this property orderable in queries?
+ * @return
+ */
+ public boolean isOrderable()
+ {
+ return orderable;
+ }
+
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder();
+ builder.append("CMISPropertyDefinition[");
+ builder.append("PropertyName=").append(getPropertyName()).append(", ");
+ builder.append("DisplayName=").append(getDisplayName()).append(", ");
+ builder.append("Description=").append(getDescription()).append(", ");
+ builder.append("PropertyType=").append(getPropertyType()).append(", ");
+ builder.append("Cardinality=").append(getCardinality()).append(", ");
+ builder.append("MaximumLength=").append(getMaximumLength()).append(", ");
+ builder.append("SchemaURI=").append(getSchemaURI()).append(", ");
+ builder.append("Encoding=").append(getEncoding()).append(", ");
+ builder.append("Choices=").append(getChioces()).append(", ");
+ builder.append("IsOpenChoice=").append(isOpenChioce()).append(", ");
+ builder.append("Required=").append(isRequired()).append(", ");
+ builder.append("Default=").append(getDefaultValue()).append(", ");
+ builder.append("Updatable=").append(getUpdatability()).append(", ");
+ builder.append("Queryable=").append(isQueryable()).append(", ");
+ builder.append("Orderable=").append(isOrderable());
+ builder.append("]");
+ return builder.toString();
+ }
+
+}
diff --git a/source/java/org/alfresco/cmis/dictionary/CMISPropertyType.java b/source/java/org/alfresco/cmis/dictionary/CMISPropertyType.java
new file mode 100644
index 0000000000..04b9b89fec
--- /dev/null
+++ b/source/java/org/alfresco/cmis/dictionary/CMISPropertyType.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.cmis.dictionary;
+
+/**
+ * CMIS Property Types
+ * @author andyh
+ *
+ */
+public enum CMISPropertyType
+{
+ /**
+ * String
+ */
+ STRING,
+ /**
+ * Decimal
+ */
+ DECIMAL,
+ /**
+ * Integer
+ */
+ INTEGER,
+ /**
+ * Boolean
+ */
+ BOOLEAN,
+ /**
+ * Date-time
+ */
+ DATE_TIME,
+ /**
+ * URI
+ */
+ URI,
+ /**
+ * HTML
+ */
+ HTML,
+ /**
+ * XML
+ */
+ XML,
+ /**
+ * ID
+ */
+ ID,
+ /**
+ * Type Id
+ */
+ TYPE_ID;
+}
diff --git a/source/java/org/alfresco/cmis/dictionary/CMISPropertyValue.java b/source/java/org/alfresco/cmis/dictionary/CMISPropertyValue.java
new file mode 100644
index 0000000000..a2868c4b52
--- /dev/null
+++ b/source/java/org/alfresco/cmis/dictionary/CMISPropertyValue.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.cmis.dictionary;
+
+public interface CMISPropertyValue
+{
+
+}
diff --git a/source/java/org/alfresco/cmis/dictionary/CMISTypeDefinition.java b/source/java/org/alfresco/cmis/dictionary/CMISTypeDefinition.java
new file mode 100644
index 0000000000..f970571c27
--- /dev/null
+++ b/source/java/org/alfresco/cmis/dictionary/CMISTypeDefinition.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+
+package org.alfresco.cmis.dictionary;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import org.alfresco.model.ContentModel;
+import org.alfresco.service.cmr.dictionary.AspectDefinition;
+import org.alfresco.service.cmr.dictionary.AssociationDefinition;
+import org.alfresco.service.cmr.dictionary.DictionaryService;
+import org.alfresco.service.cmr.dictionary.TypeDefinition;
+import org.alfresco.service.namespace.NamespaceService;
+import org.alfresco.service.namespace.QName;
+
+/**
+ * The base type definition for CMIS
+ *
+ * @author andyh
+ */
+public class CMISTypeDefinition
+{
+ private CMISTypeId objectTypeId;
+
+ private String objectTypeQueryName;
+
+ private String displayName;
+
+ private CMISTypeId parentTypeId;
+
+ private String rootTypeQueryName;
+
+ private String description;
+
+ private boolean queryable;
+
+ private boolean versionable;
+
+ private String constraints = "";
+
+ private boolean isAssociation;
+
+ private ArrayList allowedSourceTypes = new ArrayList(1);
+
+ private ArrayList allowedTargetTypes = new ArrayList(1);
+
+ public CMISTypeDefinition(DictionaryService dictionaryService, NamespaceService namespaceService, QName typeQName)
+ {
+ isAssociation = (typeQName.equals(CMISMapping.RELATIONSHIP_QNAME) || (dictionaryService.getAssociation(typeQName) != null));
+
+ if (isAssociation)
+ {
+ AssociationDefinition associationDefinition = dictionaryService.getAssociation(typeQName);
+ if (associationDefinition != null)
+ {
+ objectTypeId = CMISMapping.getCmisTypeId(typeQName);
+ objectTypeQueryName = CMISMapping.getQueryName(namespaceService, typeQName);
+ displayName = associationDefinition.getTitle();
+ parentTypeId = CMISMapping.getCmisTypeId(CMISMapping.RELATIONSHIP_QNAME);
+ rootTypeQueryName = CMISMapping.getQueryName(namespaceService, CMISMapping.RELATIONSHIP_QNAME);
+ description = associationDefinition.getDescription();
+ queryable = false;
+ versionable = false;
+ isAssociation = true;
+ allowedSourceTypes.add(CMISMapping.getCmisTypeId(CMISMapping.getCmisType(associationDefinition.getSourceClass().getName())));
+ allowedTargetTypes.add(CMISMapping.getCmisTypeId(CMISMapping.getCmisType(associationDefinition.getTargetClass().getName())));
+ }
+ else
+ {
+ // TODO: Add CMIS Association mapping??
+ TypeDefinition typeDefinition = dictionaryService.getType(typeQName);
+ objectTypeId = CMISMapping.getCmisTypeId(typeQName);
+ objectTypeQueryName = CMISMapping.getQueryName(namespaceService, typeQName);
+ displayName = typeDefinition.getTitle();
+ parentTypeId = CMISMapping.getCmisTypeId(CMISMapping.RELATIONSHIP_QNAME);
+ rootTypeQueryName = CMISMapping.getQueryName(namespaceService, CMISMapping.RELATIONSHIP_QNAME);
+ description = typeDefinition.getDescription();
+ queryable = false;
+ versionable = false;
+ isAssociation = true;
+ }
+ }
+ else
+ {
+ TypeDefinition typeDefinition = dictionaryService.getType(typeQName);
+ if (typeDefinition != null)
+ {
+ objectTypeId = CMISMapping.getCmisTypeId(typeQName);
+
+ objectTypeQueryName = CMISMapping.getQueryName(namespaceService, typeQName);
+
+ displayName = typeDefinition.getTitle();
+
+ QName parentTypeQName = CMISMapping.getCmisType(typeDefinition.getParentName());
+ if (parentTypeQName == null)
+ {
+ // Core and unknown types
+ parentTypeId = null;
+ }
+ else
+ {
+ if (CMISMapping.isValidCmisType(dictionaryService, typeQName))
+ {
+ parentTypeId = CMISMapping.getCmisTypeId(parentTypeQName);
+ }
+ }
+
+ rootTypeQueryName = CMISMapping.getQueryName(namespaceService, CMISMapping.getCmisRootType(dictionaryService, typeQName));
+
+ description = typeDefinition.getDescription();
+
+ queryable = true;
+
+ versionable = false;
+ List defaultAspects = typeDefinition.getDefaultAspects();
+ for (AspectDefinition aspectDefinition : defaultAspects)
+ {
+ if (aspectDefinition.getName().equals(ContentModel.ASPECT_VERSIONABLE))
+ {
+ versionable = true;
+ break;
+ }
+ }
+ }
+
+ }
+
+ }
+
+ /**
+ * Get the unique identifier for the type
+ *
+ * @return - the type id
+ */
+ public CMISTypeId getObjectTypeId()
+ {
+ return objectTypeId;
+ }
+
+ /**
+ * Get the table name used for queries against the type. This is also a unique identifier for the type. The string
+ * conforms to SQL table naming conventions. TODO: Should we impose a maximum length and if so how do we avoid
+ * collisions from truncations?
+ *
+ * @return the sql table name
+ */
+ public String getObjectTypeQueryName()
+ {
+ return objectTypeQueryName;
+ }
+
+ /**
+ * Get the display name for the type.
+ *
+ * @return - the display name
+ */
+ public String getObjectTypeDisplayName()
+ {
+ return displayName;
+ }
+
+ /**
+ * Get the type id for the parent
+ *
+ * @return - the parent type id
+ */
+ public CMISTypeId getParentTypeId()
+ {
+ return parentTypeId;
+ }
+
+ /**
+ * Get the sql table name for the root type of this type This will be getObjectTypeQueryName() for the base folder,
+ * document or association
+ *
+ * @return - the sql table name for the root type
+ */
+ public String getRootTypeQueryName()
+ {
+ return rootTypeQueryName;
+ }
+
+ /**
+ * Get the description for the type
+ *
+ * @return - the description
+ */
+ public String getDescription()
+ {
+ return description;
+ }
+
+ /**
+ * Is this type queryable? If not, the type may not appear in the FROM clause of a query. This property of the type
+ * is not inherited in the type hierarchy. It is set on each type.
+ *
+ * @return true if queryable
+ */
+ public boolean isQueryable()
+ {
+ return queryable;
+ }
+
+ /**
+ * Is this type versionable? If true this implies all instances of the type are versionable.
+ *
+ * @return true if versionable
+ */
+ public boolean isVersionable()
+ {
+ return versionable;
+ }
+
+ /**
+ * Get the constraints for the type. These are not currently supported.
+ *
+ * @return
+ */
+ public String getConstraints()
+ {
+ return constraints;
+ }
+
+ /**
+ * Is this an association type?
+ *
+ * @return true for an association type.
+ */
+ public boolean isAssociation()
+ {
+ return isAssociation;
+ }
+
+ /**
+ * For an association, get the collection of valid source types. For non-associations the collection will be empty.
+ *
+ * @return
+ */
+ public Collection getAllowedSourceTypes()
+ {
+ return allowedSourceTypes;
+ }
+
+ /**
+ * For an association, get the collection of valid target types. For non-associations the collection will be empty.
+ *
+ * @return
+ */
+ public Collection getAllowedTargetTypes()
+ {
+ return allowedTargetTypes;
+ }
+
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder();
+ builder.append("CMISTypeDefinition[");
+ builder.append("ObjectTypeId=").append(getObjectTypeId()).append(", ");
+ builder.append("ObjectTypeQueryName=").append(getObjectTypeQueryName()).append(", ");
+ builder.append("ObjectTypeDisplayName=").append(getObjectTypeDisplayName()).append(", ");
+ builder.append("ParentTypeId=").append(getParentTypeId()).append(", ");
+ builder.append("RootTypeQueryName=").append(getRootTypeQueryName()).append(", ");
+ builder.append("Description=").append(getDescription()).append(", ");
+ builder.append("Queryable=").append(isQueryable()).append(", ");
+ builder.append("Versionable=").append(isVersionable()).append(", ");
+ builder.append("Constraints=").append(getConstraints()).append(", ");
+ builder.append("IsAssociation=").append(isAssociation()).append(", ");
+ builder.append("AllowedSourceTypes=").append(getAllowedSourceTypes()).append(", ");
+ builder.append("AllowedTargetTypes=").append(getAllowedTargetTypes());
+ builder.append("]");
+ return builder.toString();
+ }
+}
diff --git a/source/java/org/alfresco/cmis/dictionary/CMISTypeId.java b/source/java/org/alfresco/cmis/dictionary/CMISTypeId.java
new file mode 100644
index 0000000000..610a8ceb40
--- /dev/null
+++ b/source/java/org/alfresco/cmis/dictionary/CMISTypeId.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.cmis.dictionary;
+
+public class CMISTypeId implements CMISPropertyValue
+{
+ private String typeId;
+
+ public CMISTypeId(String typeId)
+ {
+ this.typeId = typeId;
+ }
+
+ public String getTypeId()
+ {
+ return typeId;
+ }
+
+ public String toString()
+ {
+ return getTypeId();
+ }
+
+ @Override
+ public int hashCode()
+ {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((typeId == null) ? 0 : typeId.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final CMISTypeId other = (CMISTypeId) obj;
+ if (typeId == null)
+ {
+ if (other.typeId != null)
+ return false;
+ }
+ else if (!typeId.equals(other.typeId))
+ return false;
+ return true;
+ }
+
+
+}
diff --git a/source/java/org/alfresco/cmis/dictionary/CMISUpdatability.java b/source/java/org/alfresco/cmis/dictionary/CMISUpdatability.java
new file mode 100644
index 0000000000..312d32e462
--- /dev/null
+++ b/source/java/org/alfresco/cmis/dictionary/CMISUpdatability.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.cmis.dictionary;
+
+public enum CMISUpdatability
+{
+ READ_ONLY, READ_AND_WRITE, READ_AND_WRITE_WHEN_CHECKED_OUT;
+}
diff --git a/source/java/org/alfresco/repo/dictionary/CompiledModel.java b/source/java/org/alfresco/repo/dictionary/CompiledModel.java
index ebcea6d9e4..91cb837f4d 100644
--- a/source/java/org/alfresco/repo/dictionary/CompiledModel.java
+++ b/source/java/org/alfresco/repo/dictionary/CompiledModel.java
@@ -404,6 +404,15 @@ import org.apache.commons.logging.LogFactory;
return associations.get(name);
}
+ /**
+ * @return the compiled associations
+ */
+ public Collection getAssociations()
+ {
+ return associations.values();
+ }
+
+
/* (non-Javadoc)
* @see org.alfresco.repo.dictionary.impl.ModelQuery#getConstraint(QName)
*/
diff --git a/source/java/org/alfresco/repo/dictionary/DictionaryComponent.java b/source/java/org/alfresco/repo/dictionary/DictionaryComponent.java
index 8aa908a603..7446deb8f0 100644
--- a/source/java/org/alfresco/repo/dictionary/DictionaryComponent.java
+++ b/source/java/org/alfresco/repo/dictionary/DictionaryComponent.java
@@ -161,6 +161,19 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
}
return aspects;
}
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.dictionary.DictionaryService#getAllAssociations()
+ */
+ public Collection getAllAssociations()
+ {
+ Collection associations = new ArrayList(64);
+ for (QName model : getAllModels())
+ {
+ associations.addAll(getAssociations(model));
+ }
+ return associations;
+ }
/* (non-Javadoc)
@@ -185,6 +198,20 @@ public class DictionaryComponent implements DictionaryService, TenantDeployer
}
return qnames;
}
+
+ /* (non-Javadoc)
+ * @see org.alfresco.repo.dictionary.DictionaryService#getAssociations(org.alfresco.repo.ref.QName)
+ */
+ public Collection getAssociations(QName model)
+ {
+ Collection associations = dictionaryDAO.getAssociations(model);
+ Collection qnames = new ArrayList(associations.size());
+ for (AssociationDefinition def : associations)
+ {
+ qnames.add(def.getName());
+ }
+ return qnames;
+ }
/* (non-Javadoc)
diff --git a/source/java/org/alfresco/repo/dictionary/DictionaryDAO.java b/source/java/org/alfresco/repo/dictionary/DictionaryDAO.java
index 330efea401..f57f1edbb2 100644
--- a/source/java/org/alfresco/repo/dictionary/DictionaryDAO.java
+++ b/source/java/org/alfresco/repo/dictionary/DictionaryDAO.java
@@ -27,6 +27,7 @@ package org.alfresco.repo.dictionary;
import java.util.Collection;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
+import org.alfresco.service.cmr.dictionary.AssociationDefinition;
import org.alfresco.service.cmr.dictionary.ModelDefinition;
import org.alfresco.service.cmr.dictionary.DataTypeDefinition;
import org.alfresco.service.cmr.dictionary.NamespaceDefinition;
@@ -79,6 +80,13 @@ public interface DictionaryDAO extends ModelQuery
*/
public Collection getAspects(QName model);
+
+ /**
+ * @param model the model to retrieve associations for
+ * @return the associations of the model
+ */
+ public Collection getAssociations(QName model);
+
/**
* @param superAspect
* @param follow true => follow up the super-class hierarchy, false => immediate sub aspects only
diff --git a/source/java/org/alfresco/repo/dictionary/DictionaryDAOImpl.java b/source/java/org/alfresco/repo/dictionary/DictionaryDAOImpl.java
index 827af87cc2..58eb58f6b2 100644
--- a/source/java/org/alfresco/repo/dictionary/DictionaryDAOImpl.java
+++ b/source/java/org/alfresco/repo/dictionary/DictionaryDAOImpl.java
@@ -688,6 +688,12 @@ public class DictionaryDAOImpl implements DictionaryDAO
return null;
}
+ public Collection getAssociations(QName modelName)
+ {
+ CompiledModel model = getCompiledModel(modelName);
+ return model.getAssociations();
+ }
+
/* (non-Javadoc)
* @see org.alfresco.repo.dictionary.impl.DictionaryDAO#getModels()
diff --git a/source/java/org/alfresco/repo/dictionary/IndexTokenisationMode.java b/source/java/org/alfresco/repo/dictionary/IndexTokenisationMode.java
new file mode 100644
index 0000000000..f7ae53df77
--- /dev/null
+++ b/source/java/org/alfresco/repo/dictionary/IndexTokenisationMode.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+package org.alfresco.repo.dictionary;
+
+/**
+ * How tokenisation is supported in the index.
+ *
+ *
+ * @author andyh
+ *
+ */
+public enum IndexTokenisationMode {
+ /**
+ * Tokenise the property. If the analyser supported ordering then the field
+ * supports ordering FTS is supported via analysis.
+ */
+ TRUE,
+ /**
+ * Do not tokenise the property. The field supports ordering and pattern
+ * matching.
+ */
+ FALSE,
+ /**
+ * There may be two indexes - one to support ordering and one to support
+ * search.
+ */
+ BOTH;
+
+ public static String serializer(IndexTokenisationMode indexTokenisationMode) {
+ return indexTokenisationMode.toString();
+ }
+
+ public static IndexTokenisationMode deserializer(String value) {
+ if (value == null) {
+ return null;
+ } else if (value.equalsIgnoreCase(TRUE.toString())) {
+ return TRUE;
+ } else if (value.equalsIgnoreCase(FALSE.toString())) {
+ return FALSE;
+ } else if (value.equalsIgnoreCase(BOTH.toString())) {
+ return BOTH;
+ } else {
+ throw new IllegalArgumentException(
+ "Invalid IndexTokenisationMode: " + value);
+ }
+ }
+}
diff --git a/source/java/org/alfresco/repo/dictionary/M2Property.java b/source/java/org/alfresco/repo/dictionary/M2Property.java
index a14e4ccd91..ba06ca00d6 100644
--- a/source/java/org/alfresco/repo/dictionary/M2Property.java
+++ b/source/java/org/alfresco/repo/dictionary/M2Property.java
@@ -50,7 +50,7 @@ public class M2Property
private boolean isIndexed = true;
private boolean isIndexedAtomically = true;
private boolean isStoredInIndex = false;
- private boolean isTokenisedInIndex = true;
+ private IndexTokenisationMode indexTokenisationMode = IndexTokenisationMode.TRUE;
private List constraints;
/*package*/ M2Property()
@@ -204,15 +204,15 @@ public class M2Property
}
- public boolean isTokenisedInIndex()
+ public IndexTokenisationMode getIndexTokenisationMode()
{
- return isTokenisedInIndex;
+ return indexTokenisationMode;
}
- public void setTokenisedInIndex(boolean isTokenisedInIndex)
+ public void setIndexTokenisationMode(IndexTokenisationMode indexTokenisationMode)
{
- this.isTokenisedInIndex = isTokenisedInIndex;
+ this.indexTokenisationMode = indexTokenisationMode;
}
diff --git a/source/java/org/alfresco/repo/dictionary/M2PropertyDefinition.java b/source/java/org/alfresco/repo/dictionary/M2PropertyDefinition.java
index 26c5f718f9..d9c5a447e0 100644
--- a/source/java/org/alfresco/repo/dictionary/M2PropertyDefinition.java
+++ b/source/java/org/alfresco/repo/dictionary/M2PropertyDefinition.java
@@ -214,7 +214,7 @@ import org.alfresco.service.namespace.QName;
property.setProtected(propertyDef.isProtected());
property.setStoredInIndex(propertyDef.isStoredInIndex());
property.setTitle(propertyDef.getTitle());
- property.setTokenisedInIndex(propertyDef.isTokenisedInIndex());
+ property.setIndexTokenisationMode(propertyDef.getIndexTokenisationMode());
return property;
}
@@ -240,7 +240,7 @@ import org.alfresco.service.namespace.QName;
sb.append("isIndexed: " + isIndexed() + "\n");
sb.append("isStoredInIndex: " + isStoredInIndex() + "\n");
sb.append("isIndexedAtomically: " + isIndexedAtomically() + "\n");
- sb.append("isTokenisedInIndex: " + isTokenisedInIndex() + "\n");
+ sb.append("indexTokenisationMode: " + getIndexTokenisationMode() + "\n");
return sb.toString();
}
@@ -378,9 +378,9 @@ import org.alfresco.service.namespace.QName;
/* (non-Javadoc)
* @see org.alfresco.repo.dictionary.PropertyDefinition#isTokenisedInIndex()
*/
- public boolean isTokenisedInIndex()
+ public IndexTokenisationMode getIndexTokenisationMode()
{
- return m2Property.isTokenisedInIndex();
+ return m2Property.getIndexTokenisationMode();
}
diff --git a/source/java/org/alfresco/repo/dictionary/m2binding.xml b/source/java/org/alfresco/repo/dictionary/m2binding.xml
index b24e31c3ce..01b6641f8b 100644
--- a/source/java/org/alfresco/repo/dictionary/m2binding.xml
+++ b/source/java/org/alfresco/repo/dictionary/m2binding.xml
@@ -114,7 +114,7 @@
-
+
diff --git a/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java b/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java
index 9eda94ba6a..da7e8a8fe3 100644
--- a/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java
+++ b/source/java/org/alfresco/repo/rule/RuleServiceCoverageTest.java
@@ -57,6 +57,7 @@ import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.transform.AbstractContentTransformerTest;
import org.alfresco.repo.content.transform.ContentTransformerRegistry;
import org.alfresco.repo.dictionary.DictionaryDAO;
+import org.alfresco.repo.dictionary.IndexTokenisationMode;
import org.alfresco.repo.dictionary.M2Aspect;
import org.alfresco.repo.dictionary.M2Model;
import org.alfresco.repo.dictionary.M2Property;
@@ -224,7 +225,7 @@ public class RuleServiceCoverageTest extends TestCase
genCatProp.setMandatory(true);
genCatProp.setMultiValued(true);
genCatProp.setStoredInIndex(true);
- genCatProp.setTokenisedInIndex(true);
+ genCatProp.setIndexTokenisationMode(IndexTokenisationMode.TRUE);
genCatProp.setType("d:" + DataTypeDefinition.CATEGORY.getLocalName());
// Save the mode
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneCategoryTest.java b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneCategoryTest.java
index 7427456857..39414c4a06 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneCategoryTest.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/ADMLuceneCategoryTest.java
@@ -39,6 +39,7 @@ import junit.framework.TestCase;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.dictionary.DictionaryDAO;
+import org.alfresco.repo.dictionary.IndexTokenisationMode;
import org.alfresco.repo.dictionary.M2Aspect;
import org.alfresco.repo.dictionary.M2Model;
import org.alfresco.repo.dictionary.M2Property;
@@ -286,7 +287,7 @@ public class ADMLuceneCategoryTest extends TestCase
genCatProp.setMandatory(true);
genCatProp.setMultiValued(true);
genCatProp.setStoredInIndex(true);
- genCatProp.setTokenisedInIndex(false);
+ genCatProp.setIndexTokenisationMode(IndexTokenisationMode.FALSE);
genCatProp.setType("d:" + DataTypeDefinition.CATEGORY.getLocalName());
assetClassCategorisationQName = QName.createQName(TEST_NAMESPACE, "assetClass");
@@ -298,7 +299,7 @@ public class ADMLuceneCategoryTest extends TestCase
acProp.setMandatory(true);
acProp.setMultiValued(true);
acProp.setStoredInIndex(true);
- acProp.setTokenisedInIndex(false);
+ acProp.setIndexTokenisationMode(IndexTokenisationMode.FALSE);
acProp.setType("d:" + DataTypeDefinition.CATEGORY.getLocalName());
investmentRegionCategorisationQName = QName.createQName(TEST_NAMESPACE, "investmentRegion");
@@ -310,7 +311,7 @@ public class ADMLuceneCategoryTest extends TestCase
irProp.setMandatory(true);
irProp.setMultiValued(true);
irProp.setStoredInIndex(true);
- irProp.setTokenisedInIndex(false);
+ irProp.setIndexTokenisationMode(IndexTokenisationMode.FALSE);
irProp.setType("d:" + DataTypeDefinition.CATEGORY.getLocalName());
marketingRegionCategorisationQName = QName.createQName(TEST_NAMESPACE, "marketingRegion");
@@ -322,7 +323,7 @@ public class ADMLuceneCategoryTest extends TestCase
mrProp.setMandatory(true);
mrProp.setMultiValued(true);
mrProp.setStoredInIndex(true);
- mrProp.setTokenisedInIndex(false);
+ mrProp.setIndexTokenisationMode(IndexTokenisationMode.FALSE);
mrProp.setType("d:" + DataTypeDefinition.CATEGORY.getLocalName());
dictionaryDAO.putModel(model);
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexerImpl.java b/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexerImpl.java
index f22db494ab..f0bed4513a 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexerImpl.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/AVMLuceneIndexerImpl.java
@@ -51,9 +51,9 @@ import org.alfresco.repo.avm.util.SimplePath;
import org.alfresco.repo.content.ContentStore;
import org.alfresco.repo.content.MimetypeMap;
import org.alfresco.repo.content.transform.ContentTransformer;
+import org.alfresco.repo.dictionary.IndexTokenisationMode;
import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.repo.search.IndexMode;
-import org.alfresco.repo.search.Indexer;
import org.alfresco.repo.search.impl.lucene.analysis.DateTimeAnalyser;
import org.alfresco.repo.search.impl.lucene.fts.FTSIndexerAware;
import org.alfresco.repo.search.impl.lucene.fts.FullTextSearchIndexer;
@@ -677,7 +677,7 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl
boolean store = true;
boolean index = true;
- boolean tokenise = true;
+ IndexTokenisationMode tokenise = IndexTokenisationMode.TRUE;
@SuppressWarnings("unused")
boolean atomic = true;
boolean isContent = false;
@@ -690,7 +690,7 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl
{
index = propertyDef.isIndexed();
store = propertyDef.isStoredInIndex();
- tokenise = propertyDef.isTokenisedInIndex();
+ tokenise = propertyDef.getIndexTokenisationMode();
atomic = propertyDef.isIndexedAtomically();
isContent = propertyDef.getDataType().getName().equals(DataTypeDefinition.CONTENT);
isMultiLingual = propertyDef.getDataType().getName().equals(DataTypeDefinition.MLTEXT);
@@ -874,21 +874,22 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl
Field.Store fieldStore = store ? Field.Store.YES : Field.Store.NO;
Field.Index fieldIndex;
- if (index)
+ if (index)
{
- if (tokenise)
- {
- fieldIndex = Field.Index.TOKENIZED;
- }
- else
- {
- fieldIndex = Field.Index.UN_TOKENIZED;
- }
- }
- else
- {
- fieldIndex = Field.Index.NO;
- }
+ switch (tokenise) {
+ case TRUE:
+ case BOTH:
+ default:
+ fieldIndex = Field.Index.TOKENIZED;
+ break;
+ case FALSE:
+ fieldIndex = Field.Index.UN_TOKENIZED;
+ break;
+
+ }
+ } else {
+ fieldIndex = Field.Index.NO;
+ }
if ((fieldIndex != Field.Index.NO) || (fieldStore != Field.Store.NO))
{
@@ -926,15 +927,26 @@ public class AVMLuceneIndexerImpl extends AbstractLuceneIndexerImpl impl
{
locale = I18NUtil.getLocale();
}
- if (tokenise)
+
+ StringBuilder builder;
+ switch(tokenise)
{
- StringBuilder builder = new StringBuilder();
+ default:
+ case TRUE:
+ builder = new StringBuilder();
builder.append("\u0000").append(locale.toString()).append("\u0000").append(strValue);
doc.add(new Field(attributeName, builder.toString(), fieldStore, fieldIndex, Field.TermVector.NO));
- }
- else
- {
+ break;
+ case FALSE:
+ doc.add(new Field(attributeName, strValue, fieldStore, fieldIndex, Field.TermVector.NO));
+ break;
+ case BOTH:
+ builder = new StringBuilder();
+ builder.append("\u0000").append(locale.toString()).append("\u0000").append(strValue);
+ doc.add(new Field(attributeName, builder.toString(), fieldStore, fieldIndex, Field.TermVector.NO));
+
doc.add(new Field(attributeName, strValue, fieldStore, fieldIndex, Field.TermVector.NO));
+ break;
}
}
else if (isDateTime)
diff --git a/source/java/org/alfresco/repo/search/impl/lucene/LuceneAnalyser.java b/source/java/org/alfresco/repo/search/impl/lucene/LuceneAnalyser.java
index b4039b7723..f16250c0f4 100644
--- a/source/java/org/alfresco/repo/search/impl/lucene/LuceneAnalyser.java
+++ b/source/java/org/alfresco/repo/search/impl/lucene/LuceneAnalyser.java
@@ -29,6 +29,7 @@ import java.util.HashMap;
import java.util.Map;
import org.alfresco.model.ContentModel;
+import org.alfresco.repo.dictionary.IndexTokenisationMode;
import org.alfresco.repo.search.MLAnalysisMode;
import org.alfresco.repo.search.impl.lucene.analysis.AlfrescoStandardAnalyser;
import org.alfresco.repo.search.impl.lucene.analysis.LongAnalyser;
@@ -178,7 +179,7 @@ public class LuceneAnalyser extends Analyzer
PropertyDefinition propertyDef = dictionaryService.getProperty(propertyQName);
if (propertyDef != null)
{
- if (propertyDef.isTokenisedInIndex())
+ if ((propertyDef.getIndexTokenisationMode() == IndexTokenisationMode.BOTH) || (propertyDef.getIndexTokenisationMode() == IndexTokenisationMode.TRUE))
{
DataTypeDefinition dataType = propertyDef.getDataType();
if (dataType.getName().equals(DataTypeDefinition.CONTENT))
diff --git a/source/java/org/alfresco/repo/search/impl/parsers/CMIS.g b/source/java/org/alfresco/repo/search/impl/parsers/CMIS.g
new file mode 100644
index 0000000000..684bfb4914
--- /dev/null
+++ b/source/java/org/alfresco/repo/search/impl/parsers/CMIS.g
@@ -0,0 +1,568 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+
+/*
+ * Parser for the CMIS query language
+ *
+ * The semantics of multivalued properties are ignored for the initial parse of the language.
+ * They are applied in a second pass, when we have enough information to determine the column type.
+ */
+
+grammar CMIS;
+
+options
+{
+ output=AST;
+}
+
+tokens
+{
+ QUERY;
+ ALL_COLUMNS;
+ COLUMN;
+ COLUMNS;
+ COLUMN_REF;
+ QUALIFIER;
+ STRING_FUNCTION;
+ NUMERIC_FUNCTION;
+ SOURCE;
+ TABLE;
+ TABLE_REF;
+ PARAMETER;
+
+ CONJUNCTION;
+ DISJUNCTION;
+ NEGATION;
+ PRED_COMPARISON;
+ PRED_IN;
+ PRED_EXISTS;
+ PRED_LIKE;
+ PRED_FTS;
+ LIST;
+ PRED_CHILD;
+ PRED_DESCENDANT;
+ SORT_SPECIFICATION;
+
+ NUMERIC_LITERAL;
+ STRING_LITERAL;
+}
+
+/*
+ * Instance methods and properties for the parser.
+ * Realisations of the parser should over-ride these as required
+ */
+
+@members
+{
+ /**
+ * CMIS strict
+ */
+ public boolean strict()
+ {
+ return true;
+ }
+}
+
+/**
+ * This is mostly a direct take fom the CMIS spec.
+ * The only significant chnanges are to remove left recursion which is not supported in antlr
+ *
+ * The top level rule for the parser
+ */
+query
+ : SELECT selectList fromClause whereClause? orderByClause?
+ -> ^(QUERY selectList fromClause whereClause? orderByClause?)
+ ;
+
+
+selectList
+ : STAR
+ -> ^(ALL_COLUMNS)
+ | selectSubList ( COMMA selectSubList )*
+ -> ^(COLUMNS selectSubList+)
+ ;
+
+
+selectSubList
+ : (valueExpression)=> valueExpression ( AS? columnName )?
+ -> ^(COLUMN valueExpression columnName?)
+ | qualifier DOTSTAR
+ -> ^(ALL_COLUMNS qualifier)
+ | multiValuedColumnReference
+ -> /* No AST - MVCs are included in value expressions */
+ ;
+
+valueExpression
+ : columnReference
+ -> columnReference
+ | stringValueFunction
+ -> stringValueFunction
+ | numericValueFunction
+ -> numericValueFunction
+ ;
+
+columnReference
+ : ( qualifier DOT )? columnName
+ -> ^(COLUMN_REF columnName qualifier?)
+ ;
+
+/*
+ * This production is proteted by a dynamic predicate.
+ * TODO Add look a head and perform the test
+ */
+multiValuedColumnReference
+ : ( qualifier DOT )? multiValuedColumnName
+ -> ^(COLUMN_REF multiValuedColumnName qualifier?)
+ ;
+
+stringValueFunction
+ : ( functionName=UPPER | functionName=LOWER ) LPAREN columnReference RPAREN
+ -> ^(STRING_FUNCTION $functionName columnReference)
+ ;
+
+numericValueFunction
+ : functionName=SCORE LPAREN qualifier? RPAREN
+ -> ^(NUMERIC_FUNCTION $functionName qualifier?)
+ ;
+
+qualifier
+ : (tableName) => tableName
+ -> tableName
+ | correlationName
+ -> correlationName
+ ;
+
+fromClause
+ : FROM tableReference
+ -> tableReference
+ ;
+
+tableReference
+ : singleTable ((joinedTable) => joinedTable)*
+ -> ^(SOURCE singleTable joinedTable*)
+ ;
+
+/*
+ * Created to avoid left recursion between tableReference and joinedTable.
+ */
+singleTable
+ : tableName ( AS? correlationName )?
+ -> ^(TABLE_REF tableName correlationName?)
+ | LPAREN joinedTables RPAREN
+ -> ^(TABLE joinedTables)
+ ;
+
+joinedTable
+ : joinType? JOIN tableReference ((joinSpecification) => joinSpecification)?
+ -> ^(JOIN tableReference joinType? joinSpecification?)
+ ;
+
+
+joinedTables
+ : singleTable joinedTable+
+ -> singleTable joinedTable+
+ ;
+
+joinType
+ : INNER
+ -> INNER
+ | LEFT OUTER?
+ -> LEFT OUTER?
+ ;
+
+joinSpecification
+ : ON LPAREN lhs=columnReference EQUALS rhs=columnReference RPAREN
+ -> ^(ON $lhs EQUALS $rhs)
+ ;
+
+
+/*
+ * Broken out the left recursion from the spec
+ */
+whereClause
+ : WHERE searchOrCondition
+ -> searchOrCondition
+ ;
+
+/**
+ * Broken left recursion.
+ */
+searchOrCondition
+ : searchAndCondition (OR searchAndCondition)*
+ -> ^(DISJUNCTION searchAndCondition+)
+ ;
+
+
+/**
+ * Broken left recursion.
+ */
+searchAndCondition
+ : searchNotCondition (AND searchNotCondition)*
+ -> ^(CONJUNCTION searchNotCondition+)
+ ;
+
+searchNotCondition
+ : NOT searchTest
+ -> ^(NEGATION searchTest)
+ | searchTest
+ -> searchTest
+ ;
+
+searchTest
+ : predicate
+ -> predicate
+ | LPAREN searchOrCondition RPAREN
+ -> searchOrCondition
+ ;
+
+predicate
+ : comparisonPredicate
+ | inPredicate
+ | likePredicate
+ | nullPredicate
+ | quantifiedComparisonPredicate
+ | quantifiedInPredicate
+ | textSearchPredicate
+ | folderPredicate
+ ;
+
+comparisonPredicate
+ : valueExpression compOp literalOrParameterName
+ -> ^(PRED_COMPARISON ANY valueExpression compOp literalOrParameterName)
+ ;
+
+compOp
+ : EQUALS
+ | NOTEQUALS
+ | LESSTHAN
+ | GREATERTHAN
+ | LESSTHANOREQUALS
+ | GREATERTHANOREQUALS
+ ;
+
+literalOrParameterName
+ : literal
+ | parameterName
+ ;
+
+literal
+ : signedNumericLiteral
+ | characterStringLiteral
+ ;
+
+inPredicate
+ : columnReference NOT? IN LPAREN inValueList RPAREN
+ -> ^(PRED_IN ANY columnReference NOT? inValueList)
+ ;
+
+inValueList
+ : literalOrParameterName (COMMA literalOrParameterName )*
+ -> ^(LIST literalOrParameterName+)
+ ;
+
+likePredicate
+ : columnReference NOT? LIKE characterStringLiteral
+ -> ^(PRED_LIKE columnReference NOT? characterStringLiteral)
+ ;
+
+nullPredicate
+ : ( (columnReference)=> columnReference | multiValuedColumnReference) IS NOT? NULL
+ -> ^(PRED_EXISTS columnReference NOT?)
+ ;
+
+quantifiedComparisonPredicate
+ : literalOrParameterName compOp ANY multiValuedColumnReference
+ -> ^(PRED_COMPARISON ANY literalOrParameterName compOp multiValuedColumnReference)
+ ;
+
+
+quantifiedInPredicate
+ : ANY multiValuedColumnReference NOT? IN LPAREN inValueList RPAREN
+ -> ^(PRED_IN ANY multiValuedColumnReference NOT? inValueList)
+ ;
+
+textSearchPredicate
+ : CONTAINS LPAREN (qualifier COMMA | COMMA)? textSearchExpression RPAREN
+ -> ^(PRED_FTS textSearchExpression qualifier)
+ ;
+
+folderPredicate
+ : IN_FOLDER folderPredicateArgs
+ -> ^(PRED_CHILD folderPredicateArgs)
+ | IN_TREE folderPredicateArgs
+ -> ^(PRED_DESCENDANT folderPredicateArgs)
+ ;
+
+folderPredicateArgs
+ : LPAREN (qualifier COMMA | COMMA)? folderId RPAREN
+ -> folderId qualifier?
+ ;
+
+orderByClause
+ : ORDER BY sortSpecification ( COMMA sortSpecification )*
+ -> ^(ORDER sortSpecification+)
+ ;
+
+sortSpecification
+ : columnName
+ -> ^(SORT_SPECIFICATION columnName ASC)
+ | columnName ( by=ASC | by=DESC )
+ -> ^(SORT_SPECIFICATION columnName $by)
+ ;
+
+correlationName
+ : identifier
+ ;
+
+/*
+ * Parse time validation of the table name
+ * TODO wire up the look a head
+ */
+tableName
+ : identifier
+ -> identifier
+ ;
+
+columnName
+ : identifier
+ -> identifier
+ ;
+
+multiValuedColumnName
+ : identifier
+ -> identifier
+ ;
+
+parameterName
+ : COLON identifier
+ -> ^(PARAMETER identifier)
+ ;
+
+folderId
+ : characterStringLiteral
+ -> characterStringLiteral
+ ;
+
+textSearchExpression
+ : QUOTED_STRING
+ ;
+
+identifier
+ : ID
+ -> ID
+ | DOUBLE_QUOTE keyWordOrId DOUBLE_QUOTE
+ -> ^(keyWordOrId)
+ ;
+
+signedNumericLiteral
+ : FLOATING_POINT_LITERAL
+ -> ^(NUMERIC_LITERAL FLOATING_POINT_LITERAL)
+ | integerLiteral
+ -> integerLiteral
+ ;
+
+integerLiteral
+ : DECIMAL_INTEGER_LITERAL
+ -> ^(NUMERIC_LITERAL DECIMAL_INTEGER_LITERAL)
+ ;
+
+characterStringLiteral
+ : QUOTED_STRING
+ -> ^(STRING_LITERAL QUOTED_STRING)
+ ;
+
+
+keyWord : SELECT
+ | AS
+ | UPPER
+ | LOWER
+ | FROM
+ | JOIN
+ | INNER
+ | LEFT
+ | OUTER
+ | ON
+ | WHERE
+ | OR
+ | AND
+ | NOT
+ | IN
+ | LIKE
+ | IS
+ | NULL
+ | ANY
+ | CONTAINS
+ | IN_FOLDER
+ | IN_TREE
+ | ORDER
+ | BY
+ | ASC
+ | DESC
+ | SCORE
+ ;
+
+keyWordOrId
+ : keyWord
+ -> keyWord
+ | ID
+ -> ID
+ ;
+
+/*
+ * LEXER
+ */
+
+SELECT : ('S'|'s')('E'|'e')('L'|'l')('E'|'e')('C'|'c')('T'|'t');
+AS : ('A'|'a')('S'|'s');
+UPPER : ('U'|'u')('P'|'p')('P'|'p')('E'|'e')('R'|'r');
+LOWER : ('L'|'l')('O'|'o')('W'|'w')('E'|'e')('R'|'r');
+FROM : ('F'|'f')('R'|'r')('O'|'o')('M'|'m');
+JOIN : ('J'|'j')('O'|'o')('I'|'i')('N'|'n');
+INNER : ('I'|'i')('N'|'n')('N'|'n')('E'|'e')('R'|'r');
+LEFT : ('L'|'l')('E'|'e')('F'|'f')('T'|'t');
+OUTER : ('O'|'o')('U'|'u')('T'|'t')('E'|'e')('R'|'r');
+ON : ('O'|'o')('N'|'n');
+WHERE : ('W'|'w')('H'|'h')('E'|'e')('R'|'r')('E'|'e');
+OR : ('O'|'o')('R'|'r');
+AND : ('A'|'a')('N'|'n')('D'|'d');
+NOT : ('N'|'n')('O'|'o')('T'|'t');
+IN : ('I'|'i')('N'|'n');
+LIKE : ('L'|'l')('I'|'i')('K'|'k')('E'|'e');
+IS : ('I'|'i')('S'|'s');
+NULL : ('N'|'n')('U'|'u')('L'|'l')('L'|'l');
+ANY : ('A'|'a')('N'|'n')('Y'|'y');
+CONTAINS: ('C'|'c')('O'|'o')('N'|'n')('T'|'t')('A'|'a')('I'|'i')('N'|'n')('S'|'s');
+IN_FOLDER
+ : ('I'|'i')('N'|'n')'_'('F'|'f')('O'|'o')('L'|'l')('D'|'d')('E'|'e')('R'|'r');
+IN_TREE : ('I'|'i')('N'|'n')'_'('T'|'t')('R'|'r')('E'|'e')('E'|'e');
+ORDER : ('O'|'o')('R'|'r')('D'|'d')('E'|'e')('R'|'r');
+BY : ('B'|'b')('Y'|'y');
+ASC : ('A'|'a')('S'|'s')('C'|'c');
+DESC : ('D'|'d')('E'|'e')('S'|'s')('C'|'c');
+SCORE : ('S'|'s')('C'|'c')('O'|'o')('R'|'r')('E'|'e');
+LPAREN : '(' ;
+RPAREN : ')' ;
+STAR : '*' ;
+COMMA : ',' ;
+DOTSTAR : '.*' ;
+DOT : '.' ;
+DOTDOT : '..' ;
+EQUALS : '=' ;
+TILDA : '~' ;
+NOTEQUALS
+ : '<>' ;
+GREATERTHAN
+ : '>' ;
+LESSTHAN
+ : '<' ;
+GREATERTHANOREQUALS
+ : '>=' ;
+LESSTHANOREQUALS
+ : '<=' ;
+COLON : ':' ;
+
+SINGLE_QUOTE
+ : '\'';
+
+DOUBLE_QUOTE
+ : '"'
+ ;
+
+QUOTED_STRING
+ : SINGLE_QUOTE ( ~SINGLE_QUOTE | ESCAPED_SINGLE_QUOTE)* SINGLE_QUOTE
+ ;
+
+
+/*
+ * Decimal adapted from the Java spec
+ */
+DECIMAL_INTEGER_LITERAL
+ : ( PLUS | MINUS )? DECIMAL_NUMERAL
+ ;
+
+/*
+ * Floating point adapted from the Java spec
+ */
+FLOATING_POINT_LITERAL
+ : DIGIT+ DOT DIGIT* EXPONENT?
+ | DOT DIGIT+ EXPONENT?
+ | DIGIT+ EXPONENT
+ ;
+
+
+ID : ('a'..'z'|'A'..'Z'|'_')('a'..'z'|'A'..'Z'|'0'..'0'|'_'|'$'|'#')* ;
+WS : ( ' ' | '\t' | '\r' | '\n' )+ { $channel = HIDDEN; } ;
+
+/*
+ * Fragments for quoted strings
+ */
+
+fragment
+ESCAPED_SINGLE_QUOTE
+ : '\'\'';
+
+/**
+ * Fragments for decimal
+ */
+
+fragment
+DECIMAL_NUMERAL
+ : ZERO_DIGIT
+ | NON_ZERO_DIGIT DIGIT*
+ ;
+fragment
+DIGIT : ZERO_DIGIT | NON_ZERO_DIGIT ;
+fragment
+ZERO_DIGIT
+ : '0' ;
+fragment
+NON_ZERO_DIGIT
+ : '1'..'9' ;
+fragment
+PLUS : '+' ;
+fragment
+MINUS : '-' ;
+
+fragment
+E : ('e' | 'E') ;
+
+
+
+
+/*
+ * Fragments for floating point
+ */
+
+fragment
+EXPONENT
+ : E SIGNED_INTEGER
+ ;
+fragment
+SIGNED_INTEGER
+ : (PLUS | MINUS)? DIGIT+
+ ;
+
+
+
diff --git a/source/java/org/alfresco/repo/search/impl/parsers/FTS.g b/source/java/org/alfresco/repo/search/impl/parsers/FTS.g
new file mode 100644
index 0000000000..55cb00978b
--- /dev/null
+++ b/source/java/org/alfresco/repo/search/impl/parsers/FTS.g
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2005-2007 Alfresco Software Limited.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+ * As a special exception to the terms and conditions of version 2.0 of
+ * the GPL, you may redistribute this Program in connection with Free/Libre
+ * and Open Source Software ("FLOSS") applications as described in Alfresco's
+ * FLOSS exception. You should have recieved a copy of the text describing
+ * the FLOSS exception, and it is also available here:
+ * http://www.alfresco.com/legal/licensing"
+ */
+
+/*
+ * Parser for the CMIS query language
+ *
+ * The semantics of multivalued properties are ignored for the initial parse of the language.
+ * They are applied in a second pass, when we have enough information to determine the column type.
+ */
+
+grammar FTS;
+
+options
+{
+ output=AST;
+}
+
+tokens
+{
+ FTS;
+ DISJUNCTION;
+ CONJUNCTION;
+ NEGATION;
+ TERM;
+ EXACT_TERM;
+ PHRASE;
+ SYNONYM;
+
+ FIELD_DISJUNCTION;
+ FIELD_CONJUNCTION;
+ FIELD_NEGATION;
+ FIELD_GROUP;
+ FG_TERM;
+ FG_EXACT_TERM;
+ FG_PHRASE;
+ FG_SYNONYM;
+ FG_PROXIMITY;
+ FG_RANGE;
+
+ COLUMN_REF;
+}
+
+@members
+{
+
+ public boolean defaultConjunction()
+ {
+ return true;
+ }
+
+ public boolean defaultFieldConjunction()
+ {
+ return true;
+ }
+
+
+}
+
+fts : ftsImplicitConjunctionOrDisjunction
+ -> ftsImplicitConjunctionOrDisjunction
+ ;
+
+ftsImplicitConjunctionOrDisjunction
+ : {defaultConjunction()}? ftsExplicitDisjunction (ftsExplicitDisjunction)*
+ -> ^(CONJUNCTION ftsExplicitDisjunction+)
+ | ftsExplicitDisjunction (ftsExplicitDisjunction)*
+ -> ^(DISJUNCTION ftsExplicitDisjunction+)
+ ;
+
+ftsExplicitDisjunction
+ : ftsExplictConjunction (OR ftsExplictConjunction)*
+ -> ^(DISJUNCTION ftsExplictConjunction+)
+ ;
+
+ftsExplictConjunction
+ : ftsNot (AND ftsNot)*
+ -> ^(CONJUNCTION ftsNot)
+ ;
+
+
+ftsNot : MINUS ftsTest
+ -> ^(NEGATION ftsTest)
+ | ftsTest
+ -> ftsTest
+ ;
+
+ftsTest : ftsTerm
+ -> ^(TERM ftsTerm)
+ | ftsExactTerm
+ -> ^(EXACT_TERM ftsExactTerm)
+ | ftsPhrase
+ -> ^(PHRASE ftsPhrase)
+ | ftsSynonym
+ -> ^(SYNONYM ftsSynonym)
+ | ftsFieldGroupProximity
+ -> ^(FG_PROXIMITY ftsFieldGroupProximity)
+ | ftsFieldGroupRange
+ -> ^(FG_RANGE ftsFieldGroupRange)
+ | ftsFieldGroup
+ | LPAREN ftsImplicitConjunctionOrDisjunction RPAREN
+ -> ftsImplicitConjunctionOrDisjunction
+ ;
+
+ftsTerm
+ : (columnReference COLON)? FTSWORD
+ -> FTSWORD columnReference?
+ ;
+
+ftsExactTerm
+ : PLUS ftsTerm
+ -> ftsTerm
+ ;
+
+ftsPhrase
+ : (columnReference COLON)? FTSPHRASE
+ -> FTSPHRASE columnReference?
+ ;
+
+ftsSynonym
+ : TILDA ftsTerm
+ -> ftsTerm
+ ;
+
+
+ftsFieldGroup
+ : columnReference COLON LPAREN ftsFieldGroupImplicitConjunctionOrDisjunction RPAREN
+ -> ^(FIELD_GROUP columnReference ftsFieldGroupImplicitConjunctionOrDisjunction)
+ ;
+
+ftsFieldGroupImplicitConjunctionOrDisjunction
+ : {defaultFieldConjunction}? ftsFieldGroupExplicitDisjunction (ftsFieldGroupExplicitDisjunction)*
+ -> ^(FIELD_CONJUNCTION ftsFieldGroupExplicitDisjunction+)
+ | ftsFieldGroupExplicitDisjunction (ftsFieldGroupExplicitDisjunction)*
+ -> ^(FIELD_DISJUNCTION ftsFieldGroupExplicitDisjunction+)
+ ;
+
+ftsFieldGroupExplicitDisjunction
+ : ftsFieldGroupExplictConjunction (OR ftsFieldGroupExplictConjunction)*
+ -> ^(FIELD_DISJUNCTION ftsFieldGroupExplictConjunction+)
+ ;
+
+ftsFieldGroupExplictConjunction
+ : ftsFieldGroupNot (AND ftsFieldGroupNot)*
+ -> ^(FIELD_CONJUNCTION ftsFieldGroupNot+)
+ ;
+
+
+ftsFieldGroupNot : MINUS ftsFieldGroupTest
+ -> FIELD_NEGATION ftsFieldGroupTest
+ | ftsFieldGroupTest
+ -> ftsFieldGroupTest
+ ;
+
+
+ftsFieldGroupTest
+ : ftsFieldGroupTerm
+ -> ^(FG_TERM ftsFieldGroupTerm)
+ | ftsFieldGroupExactTerm
+ -> ^(FG_EXACT_TERM ftsFieldGroupExactTerm)
+ | ftsFieldGroupPhrase
+ -> ^(FG_PHRASE ftsFieldGroupPhrase)
+ | ftsFieldGroupSynonym
+ -> ^(FG_SYNONYM ftsFieldGroupSynonym)
+ | ftsFieldGroupProximity
+ -> ^(FG_PROXIMITY ftsFieldGroupProximity)
+ | ftsFieldGroupRange
+ -> ^(FG_RANGE ftsFieldGroupRange)
+ | LPAREN ftsFieldGroupImplicitConjunctionOrDisjunction RPAREN
+ -> ftsFieldGroupImplicitConjunctionOrDisjunction
+ ;
+
+ftsFieldGroupTerm
+ : FTSWORD
+ ;
+
+ftsFieldGroupExactTerm
+ : PLUS ftsFieldGroupTerm
+ -> ftsFieldGroupTerm
+ ;
+
+ftsFieldGroupPhrase
+ : FTSPHRASE
+ ;
+
+ftsFieldGroupSynonym
+ : TILDA ftsFieldGroupTerm
+ -> ftsFieldGroupTerm
+ ;
+
+ftsFieldGroupProximity
+ : ftsFieldGroupTerm STAR ftsFieldGroupTerm
+ -> ftsFieldGroupTerm ftsFieldGroupTerm
+ ;
+
+ftsFieldGroupRange: ftsFieldGroupTerm DOTDOT ftsFieldGroupTerm
+ -> ftsFieldGroupTerm ftsFieldGroupTerm
+ ;
+
+columnReference
+ : ( qualifier=identifier DOT )? name=identifier
+ -> ^(COLUMN_REF $name $qualifier?)
+ ;
+
+identifier
+ : ID
+ ;
+
+OR : ('O'|'o')('R'|'r');
+AND : ('A'|'a')('N'|'n')('D'|'d');
+NOT : ('N'|'n')('O'|'o')('T'|'t');
+TILDA : '~' ;
+LPAREN : '(' ;
+RPAREN : ')' ;
+PLUS : '+' ;
+MINUS : '-' ;
+COLON : ':' ;
+STAR : '*' ;
+DOTDOT : '..' ;
+DOT : '.' ;
+
+FTSWORD : INWORD+;
+
+fragment
+INWORD : '\u0041' .. '\u005A'
+ | '\u0061' .. '\u007A'
+ | '\u00C0' .. '\u00D6'
+ | '\u00D8' .. '\u00F6'
+ | '\u00F8' .. '\u00FF'
+ | '\u0100' .. '\u1FFF'
+ | '\u3040' .. '\u318F'
+ | '\u3300' .. '\u337F'
+ | '\u3400' .. '\u3D2D'
+ | '\u4E00' .. '\u9FFF'
+ | '\uF900' .. '\uFAFF'
+ | '\uAC00' .. '\uD7AF'
+ | '\u0030' .. '\u0039'
+ | '\u0660' .. '\u0669'
+ | '\u06F0' .. '\u06F9'
+ | '\u0966' .. '\u096F'
+ | '\u09E6' .. '\u09EF'
+ | '\u0A66' .. '\u0A6F'
+ | '\u0AE6' .. '\u0AEF'
+ | '\u0B66' .. '\u0B6F'
+ | '\u0BE7' .. '\u0BEF'
+ | '\u0C66' .. '\u0C6F'
+ | '\u0CE6' .. '\u0CEF'
+ | '\u0D66' .. '\u0D6F'
+ | '\u0E50' .. '\u0E59'
+ | '\u0ED0' .. '\u0ED9'
+ | '\u1040' .. '\u1049'
+ ;
+
+FTSPHRASE
+ : '"' (~'"' | '""')* '"' ;
+
+ID : ('a'..'z'|'A'..'Z'|'_')('a'..'z'|'A'..'Z'|'0'..'0'|'_'|'$'|'#')* ;
+
+WS : ( ' ' | '\t' | '\r' | '\n' )+ { $channel = HIDDEN; } ;
diff --git a/source/java/org/alfresco/service/cmr/dictionary/DictionaryService.java b/source/java/org/alfresco/service/cmr/dictionary/DictionaryService.java
index ef007ed2ed..16ebe35b82 100644
--- a/source/java/org/alfresco/service/cmr/dictionary/DictionaryService.java
+++ b/source/java/org/alfresco/service/cmr/dictionary/DictionaryService.java
@@ -149,6 +149,13 @@ public interface DictionaryService
@NotAuditable
Collection getAspects(QName model);
+ /**
+ * @param model the model to retrieve associations for
+ * @return the names of all associations defined within the specified model
+ */
+ @NotAuditable
+ public Collection getAssociations(QName model);
+
/**
* @param name the name of the aspect to retrieve
* @return the aspect definition (or null, if it doesn't exist)
@@ -231,7 +238,7 @@ public interface DictionaryService
Collection getProperties(QName model, QName dataType);
/**
- * Get all poroperties for the specified model
+ * Get all properties for the specified model
*
* @param model
* @return
@@ -247,6 +254,14 @@ public interface DictionaryService
@NotAuditable
AssociationDefinition getAssociation(QName associationName);
+ /**
+ * Get all the association definitions
+
+ * @return all the association qnames
+ */
+ @NotAuditable
+ Collection getAllAssociations();
+
// TODO: Behaviour definitions
}
diff --git a/source/java/org/alfresco/service/cmr/dictionary/PropertyDefinition.java b/source/java/org/alfresco/service/cmr/dictionary/PropertyDefinition.java
index c1ffea7b44..a83f590009 100644
--- a/source/java/org/alfresco/service/cmr/dictionary/PropertyDefinition.java
+++ b/source/java/org/alfresco/service/cmr/dictionary/PropertyDefinition.java
@@ -26,6 +26,7 @@ package org.alfresco.service.cmr.dictionary;
import java.util.List;
+import org.alfresco.repo.dictionary.IndexTokenisationMode;
import org.alfresco.service.namespace.QName;
/**
@@ -103,9 +104,9 @@ public interface PropertyDefinition
public boolean isStoredInIndex();
/**
- * @return true => tokenised when it is indexed (the stored value will not be tokenised)
+ * @return IndexTokenisationMode.TREU => tokenised when it is indexed (the stored value will not be tokenised)
*/
- public boolean isTokenisedInIndex();
+ public IndexTokenisationMode getIndexTokenisationMode();
/**
* All non atomic properties will be indexed at the same time.