This project has retired. For details please refer to its Attic page.
JcrTypeManager xref

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.chemistry.opencmis.jcr;
20  
21  import org.apache.chemistry.opencmis.commons.PropertyIds;
22  import org.apache.chemistry.opencmis.commons.definitions.DocumentTypeDefinition;
23  import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
24  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
25  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer;
26  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionList;
27  import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
28  import org.apache.chemistry.opencmis.commons.enums.Cardinality;
29  import org.apache.chemistry.opencmis.commons.enums.PropertyType;
30  import org.apache.chemistry.opencmis.commons.enums.Updatability;
31  import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
32  import org.apache.chemistry.opencmis.commons.impl.Converter;
33  import org.apache.chemistry.opencmis.commons.impl.dataobjects.AbstractPropertyDefinition;
34  import org.apache.chemistry.opencmis.commons.impl.dataobjects.AbstractTypeDefinition;
35  import org.apache.chemistry.opencmis.commons.impl.dataobjects.DocumentTypeDefinitionImpl;
36  import org.apache.chemistry.opencmis.commons.impl.dataobjects.FolderTypeDefinitionImpl;
37  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyBooleanDefinitionImpl;
38  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDateTimeDefinitionImpl;
39  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDecimalDefinitionImpl;
40  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyHtmlDefinitionImpl;
41  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIdDefinitionImpl;
42  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIntegerDefinitionImpl;
43  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyStringDefinitionImpl;
44  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyUriDefinitionImpl;
45  import org.apache.chemistry.opencmis.commons.impl.dataobjects.TypeDefinitionContainerImpl;
46  import org.apache.chemistry.opencmis.commons.impl.dataobjects.TypeDefinitionListImpl;
47  import org.apache.chemistry.opencmis.server.support.TypeManager;
48  import org.apache.commons.logging.Log;
49  import org.apache.commons.logging.LogFactory;
50  
51  import java.math.BigInteger;
52  import java.util.ArrayList;
53  import java.util.Collection;
54  import java.util.HashMap;
55  import java.util.List;
56  import java.util.Map;
57  
58  /**
59   * Type Manager.
60   */
61  public class JcrTypeManager implements TypeManager { 
62      private static final Log log = LogFactory.getLog(JcrTypeManager.class);
63  
64      public static final String DOCUMENT_TYPE_ID = "cmis:document";
65      public static final String FOLDER_TYPE_ID = "cmis:folder";
66      public static final String RELATIONSHIP_TYPE_ID = "cmis:relationship";
67      public static final String POLICY_TYPE_ID = "cmis:policy";
68      public static final String NAMESPACE = "http://opencmis.org/jcr";
69  
70      private final Map<String, TypeDefinitionContainerImpl> fTypes;
71  
72      public JcrTypeManager() {
73          fTypes = new HashMap<String, TypeDefinitionContainerImpl>();
74      }
75  
76      /**
77       * Adds a type to collection with inheriting base type properties.
78       * @param type  type to add
79       * @return  <code>true</code> iff the type was successfully added
80       */
81      public boolean addType(TypeDefinition type) {
82          if (type == null) {
83              return false;
84          }
85  
86          if (fTypes.containsKey(type.getId())) {
87              // can't overwrite a type
88              return false;
89          }
90  
91          AbstractTypeDefinition newType = (AbstractTypeDefinition) copyTypeDefinition(type);
92  
93          if (!newType.getBaseTypeId().value().equals(newType.getId())) {
94  
95              // find base type
96              TypeDefinition baseType;
97              if (newType.getBaseTypeId() == BaseTypeId.CMIS_DOCUMENT) {
98                  baseType = copyTypeDefinition(fTypes.get(DOCUMENT_TYPE_ID).getTypeDefinition());
99              }
100             else if (newType.getBaseTypeId() == BaseTypeId.CMIS_FOLDER) {
101                 baseType = copyTypeDefinition(fTypes.get(FOLDER_TYPE_ID).getTypeDefinition());
102             }
103             else if (newType.getBaseTypeId() == BaseTypeId.CMIS_RELATIONSHIP) {
104                 baseType = copyTypeDefinition(fTypes.get(RELATIONSHIP_TYPE_ID).getTypeDefinition());
105             }
106             else if (newType.getBaseTypeId() == BaseTypeId.CMIS_POLICY) {
107                 baseType = copyTypeDefinition(fTypes.get(POLICY_TYPE_ID).getTypeDefinition());
108             }
109             else {
110                 return false;
111             }
112 
113             // copy property definition
114             for (PropertyDefinition<?> propDef : baseType.getPropertyDefinitions().values()) {
115                 ((AbstractPropertyDefinition<?>) propDef).setIsInherited(true);
116                 newType.addPropertyDefinition(propDef);
117             }
118 
119         }
120 
121         // add it
122         addTypeInternal(newType);
123 
124         log.info("Added type '" + newType.getId() + "'.");
125 
126         return true;
127     }
128 
129     public TypeDefinition getType(String typeId) {
130         TypeDefinitionContainer tc = fTypes.get(typeId);
131         return tc == null ? null : tc.getTypeDefinition();
132     }
133 
134     public static boolean isVersionable(TypeDefinition typeDef) {
135         return typeDef instanceof DocumentTypeDefinition
136                 ? ((DocumentTypeDefinition) typeDef).isVersionable()
137                 : false;
138     }
139 
140     public static TypeDefinition copyTypeDefinition(TypeDefinition type) {
141         return Converter.convert(Converter.convert(type));
142     }
143     
144     /**
145      * See CMIS 1.0 section 2.2.2.3 getTypeChildren
146      */
147     public TypeDefinitionList getTypeChildren(String typeId, boolean includePropertyDefinitions,
148             BigInteger maxItems, BigInteger skipCount) {
149 
150         TypeDefinitionListImpl result = new TypeDefinitionListImpl(new ArrayList<TypeDefinition>());
151 
152         int skip = skipCount == null ? 0 : skipCount.intValue();
153         if (skip < 0) {
154             skip = 0;
155         }
156 
157         int max = maxItems == null ? Integer.MAX_VALUE : maxItems.intValue();
158         if (max < 1) {
159             return result;
160         }
161 
162         if (typeId == null) {
163             if (skip < 1) {
164                 result.getList().add(copyTypeDefinition(fTypes.get(FOLDER_TYPE_ID).getTypeDefinition()));
165                 max--;
166             }
167             if (skip < 2 && max > 0) {
168                 result.getList().add(copyTypeDefinition(fTypes.get(DOCUMENT_TYPE_ID).getTypeDefinition()));
169             }
170 
171             result.setHasMoreItems(result.getList().size() + skip < 2);
172             result.setNumItems(BigInteger.valueOf(2));
173         }
174         else {
175             TypeDefinitionContainer tc = fTypes.get(typeId);
176             if (tc == null || tc.getChildren() == null) {
177                 return result;
178             }
179 
180             for (TypeDefinitionContainer child : tc.getChildren()) {
181                 if (skip > 0) {
182                     skip--;
183                     continue;
184                 }
185 
186                 result.getList().add(copyTypeDefinition(child.getTypeDefinition()));
187 
188                 max--;
189                 if (max == 0) {
190                     break;
191                 }
192             }
193 
194             result.setHasMoreItems(result.getList().size() + skip < tc.getChildren().size());
195             result.setNumItems(BigInteger.valueOf(tc.getChildren().size()));
196         }
197 
198         if (!includePropertyDefinitions) {
199             for (TypeDefinition type : result.getList()) {
200                 type.getPropertyDefinitions().clear();
201             }
202         }
203 
204         return result;
205     }
206 
207     /**
208      * See CMIS 1.0 section 2.2.2.4 getTypeDescendants
209      */
210     public List<TypeDefinitionContainer> getTypesDescendants(String typeId, BigInteger depth,
211             Boolean includePropertyDefinitions) {
212 
213         List<TypeDefinitionContainer> result = new ArrayList<TypeDefinitionContainer>();
214 
215         // check depth
216         int d = depth == null ? -1 : depth.intValue();
217         if (d == 0) {
218             throw new CmisInvalidArgumentException("Depth must not be 0!");
219         }
220 
221         // set property definition flag to default value if not set
222         boolean ipd = Boolean.TRUE.equals(includePropertyDefinitions);
223 
224         if (typeId == null) {
225             result.add(getTypesDescendants(d, fTypes.get(FOLDER_TYPE_ID), ipd));
226             result.add(getTypesDescendants(d, fTypes.get(DOCUMENT_TYPE_ID), ipd));
227         }
228         else {
229             TypeDefinitionContainer tc = fTypes.get(typeId);
230             if (tc != null) {
231                 result.add(getTypesDescendants(d, tc, ipd));
232             }
233         }
234 
235         return result;
236     }
237 
238     //------------------------------------------< JcrTypeManager >---
239 
240     public TypeDefinitionContainer getTypeById(String typeId) {
241         return fTypes.get(typeId);
242     }
243 
244     public TypeDefinition getTypeByQueryName(String typeQueryName) {
245         for (TypeDefinitionContainerImpl type : fTypes.values()) {
246             TypeDefinition typeDef = type.getTypeDefinition();
247             if (typeDef.getQueryName().equals(typeQueryName)) {
248                 return typeDef;
249             }
250         }
251         
252         return null;
253     }
254 
255     public Collection<TypeDefinitionContainer> getTypeDefinitionList() {
256         Collection<TypeDefinitionContainer> types = new ArrayList<TypeDefinitionContainer>(fTypes.size());
257         types.addAll(fTypes.values());
258         return types;
259     }
260 
261     public List<TypeDefinitionContainer> getRootTypes() {
262         List<TypeDefinitionContainer> types = new ArrayList<TypeDefinitionContainer>(2);
263         types.add(fTypes.get(FOLDER_TYPE_ID));
264         types.add(fTypes.get(DOCUMENT_TYPE_ID));
265         return types; 
266     }
267 
268     public String getPropertyIdForQueryName(TypeDefinition typeDefinition, String propQueryName) {
269         for (PropertyDefinition<?> pd : typeDefinition.getPropertyDefinitions().values()) {
270             if (pd.getQueryName().equals(propQueryName)) {
271                 return pd.getId();
272             }
273         }
274 
275         return null;
276     }
277 
278     public static void addBasePropertyDefinitions(AbstractTypeDefinition type) {
279         type.addPropertyDefinition(createPropDef(PropertyIds.BASE_TYPE_ID, "Base Type Id", "Base Type Id",
280                 PropertyType.ID, Cardinality.SINGLE, Updatability.READONLY, false, true));
281 
282         type.addPropertyDefinition(createPropDef(PropertyIds.OBJECT_ID, "Object Id", "Object Id", PropertyType.ID,
283                 Cardinality.SINGLE, Updatability.READONLY, false, true));
284 
285         type.addPropertyDefinition(createPropDef(PropertyIds.OBJECT_TYPE_ID, "Type Id", "Type Id", PropertyType.ID,
286                 Cardinality.SINGLE, Updatability.ONCREATE, false, true));
287 
288         type.addPropertyDefinition(createPropDef(PropertyIds.NAME, "Name", "Name", PropertyType.STRING,
289                 Cardinality.SINGLE, Updatability.READWRITE, false, true));
290 
291         type.addPropertyDefinition(createPropDef(PropertyIds.CREATED_BY, "Created By", "Created By",
292                 PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, true));
293 
294         type.addPropertyDefinition(createPropDef(PropertyIds.CREATION_DATE, "Creation Date", "Creation Date",
295                 PropertyType.DATETIME, Cardinality.SINGLE, Updatability.READONLY, false, true));
296 
297         type.addPropertyDefinition(createPropDef(PropertyIds.LAST_MODIFIED_BY, "Last Modified By", "Last Modified By",
298                 PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, true));
299 
300         type.addPropertyDefinition(createPropDef(PropertyIds.LAST_MODIFICATION_DATE, "Last Modification Date",
301                 "Last Modification Date", PropertyType.DATETIME, Cardinality.SINGLE, Updatability.READONLY, false, true));
302 
303         type.addPropertyDefinition(createPropDef(PropertyIds.CHANGE_TOKEN, "Change Token", "Change Token",
304                 PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false));
305     }
306 
307     public static void addFolderPropertyDefinitions(FolderTypeDefinitionImpl type) {
308         type.addPropertyDefinition(createPropDef(PropertyIds.PARENT_ID, "Parent Id", "Parent Id", PropertyType.ID,
309                 Cardinality.SINGLE, Updatability.READONLY, false, false));
310 
311         type.addPropertyDefinition(createPropDef(PropertyIds.ALLOWED_CHILD_OBJECT_TYPE_IDS,
312                 "Allowed Child Object Type Ids", "Allowed Child Object Type Ids", PropertyType.ID, Cardinality.MULTI,
313                 Updatability.READONLY, false, false));
314 
315         type.addPropertyDefinition(createPropDef(PropertyIds.PATH, "Path", "Path", PropertyType.STRING,
316                 Cardinality.SINGLE, Updatability.READONLY, false, false));
317     }
318 
319     public static void addDocumentPropertyDefinitions(DocumentTypeDefinitionImpl type) {
320         type.addPropertyDefinition(createPropDef(PropertyIds.IS_IMMUTABLE, "Is Immutable", "Is Immutable",
321                 PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false, false));
322 
323         type.addPropertyDefinition(createPropDef(PropertyIds.IS_LATEST_VERSION, "Is Latest Version",
324                 "Is Latest Version", PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false, false));
325 
326         type.addPropertyDefinition(createPropDef(PropertyIds.IS_MAJOR_VERSION, "Is Major Version", "Is Major Version",
327                 PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false, false));
328 
329         type.addPropertyDefinition(createPropDef(PropertyIds.IS_LATEST_MAJOR_VERSION, "Is Latest Major Version",
330                 "Is Latest Major Version", PropertyType.BOOLEAN, Cardinality.SINGLE, Updatability.READONLY, false,
331                 false));
332 
333         type.addPropertyDefinition(createPropDef(PropertyIds.VERSION_LABEL, "Version Label", "Version Label",
334                 PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false));
335 
336         type.addPropertyDefinition(createPropDef(PropertyIds.VERSION_SERIES_ID, "Version Series Id",
337                 "Version Series Id", PropertyType.ID, Cardinality.SINGLE, Updatability.READONLY, false, true));
338 
339         type.addPropertyDefinition(createPropDef(PropertyIds.IS_VERSION_SERIES_CHECKED_OUT,
340                 "Is Version Series Checked Out", "Is Version Series Checked Out", PropertyType.BOOLEAN,
341                 Cardinality.SINGLE, Updatability.READONLY, false, true));
342 
343         type.addPropertyDefinition(createPropDef(PropertyIds.VERSION_SERIES_CHECKED_OUT_ID,
344                 "Version Series Checked Out Id", "Version Series Checked Out Id", PropertyType.ID, Cardinality.SINGLE,
345                 Updatability.READONLY, false, false));
346 
347         type.addPropertyDefinition(createPropDef(PropertyIds.VERSION_SERIES_CHECKED_OUT_BY,
348                 "Version Series Checked Out By", "Version Series Checked Out By", PropertyType.ID, Cardinality.SINGLE,
349                 Updatability.READONLY, false, false));
350 
351         type.addPropertyDefinition(createPropDef(PropertyIds.CHECKIN_COMMENT, "Checkin Comment", "Checkin Comment",
352                 PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false));
353 
354         type.addPropertyDefinition(createPropDef(PropertyIds.CONTENT_STREAM_LENGTH, "Content Stream Length",
355                 "Content Stream Length", PropertyType.INTEGER, Cardinality.SINGLE, Updatability.READONLY, false, false));
356 
357         type.addPropertyDefinition(createPropDef(PropertyIds.CONTENT_STREAM_MIME_TYPE, "MIME Type", "MIME Type",
358                 PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false));
359 
360         type.addPropertyDefinition(createPropDef(PropertyIds.CONTENT_STREAM_FILE_NAME, "Filename", "Filename",
361                 PropertyType.STRING, Cardinality.SINGLE, Updatability.READONLY, false, false));
362 
363         type.addPropertyDefinition(createPropDef(PropertyIds.CONTENT_STREAM_ID, "Content Stream Id",
364                 "Content Stream Id", PropertyType.ID, Cardinality.SINGLE, Updatability.READONLY, false, false));
365     }
366 
367     /**
368      * Creates a property definition object.
369      */
370     public static PropertyDefinition<?> createPropDef(String id, String displayName, String description,
371             PropertyType datatype, Cardinality cardinality, Updatability updateability, boolean inherited,
372             boolean required) {
373 
374         AbstractPropertyDefinition<?> result;
375 
376         switch (datatype) {
377             case BOOLEAN:
378                 result = new PropertyBooleanDefinitionImpl();
379                 break;
380             case DATETIME:
381                 result = new PropertyDateTimeDefinitionImpl();
382                 break;
383             case DECIMAL:
384                 result = new PropertyDecimalDefinitionImpl();
385                 break;
386             case HTML:
387                 result = new PropertyHtmlDefinitionImpl();
388                 break;
389             case ID:
390                 result = new PropertyIdDefinitionImpl();
391                 break;
392             case INTEGER:
393                 result = new PropertyIntegerDefinitionImpl();
394                 break;
395             case STRING:
396                 result = new PropertyStringDefinitionImpl();
397                 break;
398             case URI:
399                 result = new PropertyUriDefinitionImpl();
400                 break;
401             default:
402                 throw new RuntimeException("Unknown datatype! Spec change?");
403         }
404 
405         result.setId(id);
406         result.setLocalName(id);
407         result.setDisplayName(displayName);
408         result.setDescription(description);
409         result.setPropertyType(datatype);
410         result.setCardinality(cardinality);
411         result.setUpdatability(updateability);
412         result.setIsInherited(inherited);
413         result.setIsRequired(required);
414         result.setIsQueryable(false);
415         result.setQueryName(id);
416 
417         return result;
418     }
419 
420     //------------------------------------------< private >---
421 
422     /**
423      * Adds a type to collection.
424      */
425     private void addTypeInternal(AbstractTypeDefinition type) {
426         if (type == null) {
427             return;
428         }
429 
430         TypeDefinitionContainerImpl tc = new TypeDefinitionContainerImpl();
431         tc.setTypeDefinition(type);
432 
433         // add to parent
434         if (type.getParentTypeId() != null) {
435             TypeDefinitionContainerImpl tdc = fTypes.get(type.getParentTypeId());
436             if (tdc != null) {
437                 if (tdc.getChildren() == null) {
438                     tdc.setChildren(new ArrayList<TypeDefinitionContainer>());
439                 }
440                 tdc.getChildren().add(tc);
441             }
442         }
443 
444         fTypes.put(type.getId(), tc);
445     }
446 
447     /**
448      * Gathers the type descendants tree.
449      */
450     private static TypeDefinitionContainer getTypesDescendants(int depth, TypeDefinitionContainer tc,
451             boolean includePropertyDefinitions) {
452 
453         TypeDefinitionContainerImpl result = new TypeDefinitionContainerImpl();
454 
455         TypeDefinition type = copyTypeDefinition(tc.getTypeDefinition());
456         if (!includePropertyDefinitions) {
457             type.getPropertyDefinitions().clear();
458         }
459 
460         result.setTypeDefinition(type);
461 
462         if (depth != 0) {
463             if (tc.getChildren() != null) {
464                 result.setChildren(new ArrayList<TypeDefinitionContainer>());
465                 for (TypeDefinitionContainer tdc : tc.getChildren()) {
466                     result.getChildren().add(
467                             getTypesDescendants(depth < 0 ? -1 : depth - 1, tdc, includePropertyDefinitions));
468                 }
469             }
470         }
471 
472         return result;
473     }
474 
475 }