This project has retired. For details please refer to its Attic page.
JSONConverter 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.commons.impl;
20  
21  import static org.apache.chemistry.opencmis.commons.impl.JSONConstants.*;
22  
23  import java.lang.reflect.Method;
24  import java.math.BigDecimal;
25  import java.math.BigInteger;
26  import java.util.ArrayList;
27  import java.util.Collections;
28  import java.util.GregorianCalendar;
29  import java.util.HashMap;
30  import java.util.HashSet;
31  import java.util.List;
32  import java.util.Map;
33  import java.util.Set;
34  import java.util.TimeZone;
35  
36  import org.apache.chemistry.opencmis.commons.data.Ace;
37  import org.apache.chemistry.opencmis.commons.data.Acl;
38  import org.apache.chemistry.opencmis.commons.data.AclCapabilities;
39  import org.apache.chemistry.opencmis.commons.data.AllowableActions;
40  import org.apache.chemistry.opencmis.commons.data.ChangeEventInfo;
41  import org.apache.chemistry.opencmis.commons.data.CmisExtensionElement;
42  import org.apache.chemistry.opencmis.commons.data.ExtensionsData;
43  import org.apache.chemistry.opencmis.commons.data.FailedToDeleteData;
44  import org.apache.chemistry.opencmis.commons.data.ObjectData;
45  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderContainer;
46  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderData;
47  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList;
48  import org.apache.chemistry.opencmis.commons.data.ObjectList;
49  import org.apache.chemistry.opencmis.commons.data.ObjectParentData;
50  import org.apache.chemistry.opencmis.commons.data.PermissionMapping;
51  import org.apache.chemistry.opencmis.commons.data.PolicyIdList;
52  import org.apache.chemistry.opencmis.commons.data.Properties;
53  import org.apache.chemistry.opencmis.commons.data.PropertyBoolean;
54  import org.apache.chemistry.opencmis.commons.data.PropertyData;
55  import org.apache.chemistry.opencmis.commons.data.PropertyDateTime;
56  import org.apache.chemistry.opencmis.commons.data.PropertyDecimal;
57  import org.apache.chemistry.opencmis.commons.data.PropertyHtml;
58  import org.apache.chemistry.opencmis.commons.data.PropertyId;
59  import org.apache.chemistry.opencmis.commons.data.PropertyInteger;
60  import org.apache.chemistry.opencmis.commons.data.PropertyString;
61  import org.apache.chemistry.opencmis.commons.data.PropertyUri;
62  import org.apache.chemistry.opencmis.commons.data.RenditionData;
63  import org.apache.chemistry.opencmis.commons.data.RepositoryCapabilities;
64  import org.apache.chemistry.opencmis.commons.data.RepositoryInfo;
65  import org.apache.chemistry.opencmis.commons.definitions.Choice;
66  import org.apache.chemistry.opencmis.commons.definitions.DocumentTypeDefinition;
67  import org.apache.chemistry.opencmis.commons.definitions.PermissionDefinition;
68  import org.apache.chemistry.opencmis.commons.definitions.PropertyBooleanDefinition;
69  import org.apache.chemistry.opencmis.commons.definitions.PropertyDateTimeDefinition;
70  import org.apache.chemistry.opencmis.commons.definitions.PropertyDecimalDefinition;
71  import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
72  import org.apache.chemistry.opencmis.commons.definitions.PropertyHtmlDefinition;
73  import org.apache.chemistry.opencmis.commons.definitions.PropertyIdDefinition;
74  import org.apache.chemistry.opencmis.commons.definitions.PropertyIntegerDefinition;
75  import org.apache.chemistry.opencmis.commons.definitions.PropertyStringDefinition;
76  import org.apache.chemistry.opencmis.commons.definitions.PropertyUriDefinition;
77  import org.apache.chemistry.opencmis.commons.definitions.RelationshipTypeDefinition;
78  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
79  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionContainer;
80  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinitionList;
81  import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
82  import org.apache.chemistry.opencmis.commons.enums.Action;
83  import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
84  import org.apache.chemistry.opencmis.commons.enums.CapabilityAcl;
85  import org.apache.chemistry.opencmis.commons.enums.CapabilityChanges;
86  import org.apache.chemistry.opencmis.commons.enums.CapabilityContentStreamUpdates;
87  import org.apache.chemistry.opencmis.commons.enums.CapabilityJoin;
88  import org.apache.chemistry.opencmis.commons.enums.CapabilityQuery;
89  import org.apache.chemistry.opencmis.commons.enums.CapabilityRenditions;
90  import org.apache.chemistry.opencmis.commons.enums.Cardinality;
91  import org.apache.chemistry.opencmis.commons.enums.ChangeType;
92  import org.apache.chemistry.opencmis.commons.enums.ContentStreamAllowed;
93  import org.apache.chemistry.opencmis.commons.enums.DateTimeResolution;
94  import org.apache.chemistry.opencmis.commons.enums.DecimalPrecision;
95  import org.apache.chemistry.opencmis.commons.enums.PropertyType;
96  import org.apache.chemistry.opencmis.commons.enums.SupportedPermissions;
97  import org.apache.chemistry.opencmis.commons.enums.Updatability;
98  import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
99  import org.apache.chemistry.opencmis.commons.impl.dataobjects.AbstractPropertyData;
100 import org.apache.chemistry.opencmis.commons.impl.dataobjects.AbstractPropertyDefinition;
101 import org.apache.chemistry.opencmis.commons.impl.dataobjects.AbstractTypeDefinition;
102 import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlEntryImpl;
103 import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlListImpl;
104 import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlPrincipalDataImpl;
105 import org.apache.chemistry.opencmis.commons.impl.dataobjects.AclCapabilitiesDataImpl;
106 import org.apache.chemistry.opencmis.commons.impl.dataobjects.AllowableActionsImpl;
107 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ChangeEventInfoDataImpl;
108 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ChoiceImpl;
109 import org.apache.chemistry.opencmis.commons.impl.dataobjects.CmisExtensionElementImpl;
110 import org.apache.chemistry.opencmis.commons.impl.dataobjects.DocumentTypeDefinitionImpl;
111 import org.apache.chemistry.opencmis.commons.impl.dataobjects.FailedToDeleteDataImpl;
112 import org.apache.chemistry.opencmis.commons.impl.dataobjects.FolderTypeDefinitionImpl;
113 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectDataImpl;
114 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderContainerImpl;
115 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderDataImpl;
116 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderListImpl;
117 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectListImpl;
118 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectParentDataImpl;
119 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PermissionDefinitionDataImpl;
120 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PermissionMappingDataImpl;
121 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PolicyIdListImpl;
122 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PolicyTypeDefinitionImpl;
123 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertiesImpl;
124 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyBooleanDefinitionImpl;
125 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyBooleanImpl;
126 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDateTimeDefinitionImpl;
127 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDateTimeImpl;
128 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDecimalDefinitionImpl;
129 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDecimalImpl;
130 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyHtmlDefinitionImpl;
131 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyHtmlImpl;
132 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIdDefinitionImpl;
133 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIdImpl;
134 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIntegerDefinitionImpl;
135 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIntegerImpl;
136 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyStringDefinitionImpl;
137 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyStringImpl;
138 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyUriDefinitionImpl;
139 import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyUriImpl;
140 import org.apache.chemistry.opencmis.commons.impl.dataobjects.RelationshipTypeDefinitionImpl;
141 import org.apache.chemistry.opencmis.commons.impl.dataobjects.RenditionDataImpl;
142 import org.apache.chemistry.opencmis.commons.impl.dataobjects.RepositoryCapabilitiesImpl;
143 import org.apache.chemistry.opencmis.commons.impl.dataobjects.RepositoryInfoBrowserBindingImpl;
144 import org.apache.chemistry.opencmis.commons.impl.dataobjects.TypeDefinitionContainerImpl;
145 import org.apache.chemistry.opencmis.commons.impl.dataobjects.TypeDefinitionListImpl;
146 import org.apache.chemistry.opencmis.commons.impl.json.JSONArray;
147 import org.apache.chemistry.opencmis.commons.impl.json.JSONObject;
148 
149 /**
150  * OpenCMIS objects to JSON converter.
151  */
152 public class JSONConverter {
153 
154     /**
155      * Private constructor.
156      */
157     private JSONConverter() {
158     }
159 
160     /**
161      * Converts a repository info object.
162      */
163     public static JSONObject convert(RepositoryInfo repositoryInfo, String repositoryUrl, String rootUrl) {
164         if (repositoryInfo == null) {
165             return null;
166         }
167 
168         JSONObject result = new JSONObject();
169 
170         result.put(JSON_REPINFO_ID, repositoryInfo.getId());
171         result.put(JSON_REPINFO_NAME, repositoryInfo.getName());
172         result.put(JSON_REPINFO_DESCRIPTION, repositoryInfo.getDescription());
173         result.put(JSON_REPINFO_VENDOR, repositoryInfo.getVendorName());
174         result.put(JSON_REPINFO_PRODUCT, repositoryInfo.getProductName());
175         result.put(JSON_REPINFO_PRODUCT_VERSION, repositoryInfo.getProductVersion());
176         result.put(JSON_REPINFO_ROOT_FOLDER_ID, repositoryInfo.getRootFolderId());
177         result.put(JSON_REPINFO_CAPABILITIES, convert(repositoryInfo.getCapabilities()));
178         setIfNotNull(JSON_REPINFO_ACL_CAPABILITIES, convert(repositoryInfo.getAclCapabilities()), result);
179         result.put(JSON_REPINFO_CHANGE_LOCK_TOKEN, repositoryInfo.getLatestChangeLogToken());
180         result.put(JSON_REPINFO_CMIS_VERSION_SUPPORTED, repositoryInfo.getCmisVersionSupported());
181         setIfNotNull(JSON_REPINFO_THIN_CLIENT_URI, repositoryInfo.getThinClientUri(), result);
182         setIfNotNull(JSON_REPINFO_CHANGES_INCOMPLETE, repositoryInfo.getChangesIncomplete(), result);
183 
184         JSONArray changesOnType = new JSONArray();
185         if (repositoryInfo.getChangesOnType() != null) {
186             for (BaseTypeId type : repositoryInfo.getChangesOnType()) {
187                 changesOnType.add(getJSONStringValue(type.value()));
188             }
189         }
190         result.put(JSON_REPINFO_CHANGES_ON_TYPE, changesOnType);
191 
192         setIfNotNull(JSON_REPINFO_PRINCIPAL_ID_ANONYMOUS, repositoryInfo.getPrincipalIdAnonymous(), result);
193         setIfNotNull(JSON_REPINFO_PRINCIPAL_ID_ANYONE, repositoryInfo.getPrincipalIdAnyone(), result);
194 
195         result.put(JSON_REPINFO_REPOSITORY_URL, repositoryUrl);
196         result.put(JSON_REPINFO_ROOT_FOLDER_URL, rootUrl);
197 
198         convertExtension(repositoryInfo, result);
199 
200         return result;
201     }
202 
203     /**
204      * Converts a capabilities object.
205      */
206     public static JSONObject convert(RepositoryCapabilities capabilities) {
207         if (capabilities == null) {
208             return null;
209         }
210 
211         JSONObject result = new JSONObject();
212 
213         result.put(JSON_CAP_CONTENT_STREAM_UPDATES, getJSONStringValue(capabilities.getContentStreamUpdatesCapability()
214                 .value()));
215         result.put(JSON_CAP_CHANGES, getJSONStringValue(capabilities.getChangesCapability().value()));
216         result.put(JSON_CAP_RENDITIONS, getJSONStringValue(capabilities.getRenditionsCapability().value()));
217         result.put(JSON_CAP_GET_DESCENDANTS, capabilities.isGetDescendantsSupported());
218         result.put(JSON_CAP_GET_FOLDER_TREE, capabilities.isGetFolderTreeSupported());
219         result.put(JSON_CAP_MULTIFILING, capabilities.isMultifilingSupported());
220         result.put(JSON_CAP_UNFILING, capabilities.isUnfilingSupported());
221         result.put(JSON_CAP_VERSION_SPECIFIC_FILING, capabilities.isVersionSpecificFilingSupported());
222         result.put(JSON_CAP_PWC_SEARCHABLE, capabilities.isPwcSearchableSupported());
223         result.put(JSON_CAP_PWC_UPDATABLE, capabilities.isPwcUpdatableSupported());
224         result.put(JSON_CAP_ALL_VERSIONS_SEARCHABLE, capabilities.isAllVersionsSearchableSupported());
225         result.put(JSON_CAP_QUERY, getJSONStringValue(capabilities.getQueryCapability().value()));
226         result.put(JSON_CAP_JOIN, getJSONStringValue(capabilities.getJoinCapability().value()));
227         result.put(JSON_CAP_ACL, getJSONStringValue(capabilities.getAclCapability().value()));
228 
229         convertExtension(capabilities, result);
230 
231         return result;
232     }
233 
234     /**
235      * Converts an ACL capabilities object.
236      */
237     public static JSONObject convert(AclCapabilities capabilities) {
238         if (capabilities == null) {
239             return null;
240         }
241 
242         JSONObject result = new JSONObject();
243 
244         result.put(JSON_ACLCAP_SUPPORTED_PERMISSIONS,
245                 getJSONStringValue(capabilities.getSupportedPermissions().value()));
246         result.put(JSON_ACLCAP_ACL_PROPAGATION, getJSONStringValue(capabilities.getAclPropagation().value()));
247 
248         // permissions
249         if (capabilities.getPermissions() != null) {
250             JSONArray permissions = new JSONArray();
251 
252             for (PermissionDefinition permDef : capabilities.getPermissions()) {
253                 JSONObject permission = new JSONObject();
254                 permission.put(JSON_ACLCAP_PERMISSION_PERMISSION, permDef.getId());
255                 permission.put(JSON_ACLCAP_PERMISSION_DESCRIPTION, permDef.getDescription());
256 
257                 permissions.add(permission);
258             }
259 
260             result.put(JSON_ACLCAP_PERMISSIONS, permissions);
261         }
262 
263         // permission mapping
264         if (capabilities.getPermissionMapping() != null) {
265             JSONArray permissionMapping = new JSONArray();
266 
267             for (PermissionMapping permMap : capabilities.getPermissionMapping().values()) {
268                 JSONArray mappingPermissions = new JSONArray();
269                 if (permMap.getPermissions() != null) {
270                     for (String p : permMap.getPermissions()) {
271                         mappingPermissions.add(p);
272                     }
273                 }
274 
275                 JSONObject mapping = new JSONObject();
276                 mapping.put(JSON_ACLCAP_MAPPING_KEY, permMap.getKey());
277                 mapping.put(JSON_ACLCAP_MAPPING_PERMISSION, mappingPermissions);
278 
279                 permissionMapping.add(mapping);
280             }
281 
282             result.put(JSON_ACLCAP_PERMISSION_MAPPING, permissionMapping);
283         }
284 
285         convertExtension(capabilities, result);
286 
287         return result;
288     }
289 
290     public static RepositoryInfo convertRepositoryInfo(Map<String, Object> json) {
291         if (json == null) {
292             return null;
293         }
294 
295         RepositoryInfoBrowserBindingImpl result = new RepositoryInfoBrowserBindingImpl();
296 
297         result.setId(getString(json, JSON_REPINFO_ID));
298         result.setName(getString(json, JSON_REPINFO_NAME));
299         result.setDescription(getString(json, JSON_REPINFO_DESCRIPTION));
300         result.setVendorName(getString(json, JSON_REPINFO_VENDOR));
301         result.setProductName(getString(json, JSON_REPINFO_PRODUCT));
302         result.setProductVersion(getString(json, JSON_REPINFO_PRODUCT_VERSION));
303         result.setRootFolder(getString(json, JSON_REPINFO_ROOT_FOLDER_ID));
304         result.setRepositoryUrl(getString(json, JSON_REPINFO_REPOSITORY_URL));
305         result.setRootUrl(getString(json, JSON_REPINFO_ROOT_FOLDER_URL));
306         result.setCapabilities(convertRepositoryCapabilities(getMap(json.get(JSON_REPINFO_CAPABILITIES))));
307         result.setAclCapabilities(convertAclCapabilities(getMap(json.get(JSON_REPINFO_ACL_CAPABILITIES))));
308         result.setLatestChangeLogToken(getString(json, JSON_REPINFO_CHANGE_LOCK_TOKEN));
309         result.setCmisVersionSupported(getString(json, JSON_REPINFO_CMIS_VERSION_SUPPORTED));
310         result.setThinClientUri(getString(json, JSON_REPINFO_THIN_CLIENT_URI));
311         result.setChangesIncomplete(getBoolean(json, JSON_REPINFO_CHANGES_INCOMPLETE));
312 
313         List<Object> changesOnType = getList(json.get(JSON_REPINFO_CHANGES_ON_TYPE));
314         List<BaseTypeId> types = new ArrayList<BaseTypeId>();
315         if (changesOnType != null) {
316             for (Object type : changesOnType) {
317                 if (type != null) {
318                     types.add(BaseTypeId.fromValue(type.toString()));
319                 }
320             }
321         }
322         result.setChangesOnType(types);
323 
324         result.setPrincipalAnonymous(getString(json, JSON_REPINFO_PRINCIPAL_ID_ANONYMOUS));
325         result.setPrincipalAnyone(getString(json, JSON_REPINFO_PRINCIPAL_ID_ANYONE));
326 
327         // handle extensions
328         convertExtension(json, result, REPINFO_KEYS);
329 
330         return result;
331     }
332 
333     public static RepositoryCapabilities convertRepositoryCapabilities(Map<String, Object> json) {
334         if (json == null) {
335             return null;
336         }
337 
338         RepositoryCapabilitiesImpl result = new RepositoryCapabilitiesImpl();
339 
340         result.setCapabilityContentStreamUpdates(getEnum(json, JSON_CAP_CONTENT_STREAM_UPDATES,
341                 CapabilityContentStreamUpdates.class));
342         result.setCapabilityChanges(getEnum(json, JSON_CAP_CHANGES, CapabilityChanges.class));
343         result.setCapabilityRendition(getEnum(json, JSON_CAP_RENDITIONS, CapabilityRenditions.class));
344         result.setSupportsGetDescendants(getBoolean(json, JSON_CAP_GET_DESCENDANTS));
345         result.setSupportsGetFolderTree(getBoolean(json, JSON_CAP_GET_FOLDER_TREE));
346         result.setSupportsMultifiling(getBoolean(json, JSON_CAP_MULTIFILING));
347         result.setSupportsUnfiling(getBoolean(json, JSON_CAP_UNFILING));
348         result.setSupportsVersionSpecificFiling(getBoolean(json, JSON_CAP_VERSION_SPECIFIC_FILING));
349         result.setIsPwcSearchable(getBoolean(json, JSON_CAP_PWC_SEARCHABLE));
350         result.setIsPwcUpdatable(getBoolean(json, JSON_CAP_PWC_UPDATABLE));
351         result.setAllVersionsSearchable(getBoolean(json, JSON_CAP_ALL_VERSIONS_SEARCHABLE));
352         result.setCapabilityQuery(getEnum(json, JSON_CAP_QUERY, CapabilityQuery.class));
353         result.setCapabilityJoin(getEnum(json, JSON_CAP_JOIN, CapabilityJoin.class));
354         result.setCapabilityAcl(getEnum(json, JSON_CAP_ACL, CapabilityAcl.class));
355 
356         // handle extensions
357         convertExtension(json, result, CAP_KEYS);
358 
359         return result;
360     }
361 
362     @SuppressWarnings("unchecked")
363     public static AclCapabilities convertAclCapabilities(Map<String, Object> json) {
364         if (json == null) {
365             return null;
366         }
367 
368         AclCapabilitiesDataImpl result = new AclCapabilitiesDataImpl();
369 
370         result.setSupportedPermissions(getEnum(json, JSON_ACLCAP_SUPPORTED_PERMISSIONS, SupportedPermissions.class));
371         result.setAclPropagation(getEnum(json, JSON_ACLCAP_ACL_PROPAGATION, AclPropagation.class));
372 
373         List<Object> permissions = getList(json.get(JSON_ACLCAP_PERMISSIONS));
374         if (permissions != null) {
375             List<PermissionDefinition> permissionDefinitionList = new ArrayList<PermissionDefinition>();
376 
377             for (Object permission : (List<Object>) permissions) {
378                 Map<String, Object> permissionMap = getMap(permission);
379                 if (permissionMap != null) {
380                     PermissionDefinitionDataImpl permDef = new PermissionDefinitionDataImpl();
381 
382                     permDef.setPermission(getString(permissionMap, JSON_ACLCAP_PERMISSION_PERMISSION));
383                     permDef.setDescription(getString(permissionMap, JSON_ACLCAP_PERMISSION_DESCRIPTION));
384 
385                     convertExtension(permissionMap, permDef, ACLCAP_PERMISSION_KEYS);
386 
387                     permissionDefinitionList.add(permDef);
388                 }
389             }
390 
391             result.setPermissionDefinitionData(permissionDefinitionList);
392         }
393 
394         List<Object> permissionMapping = getList(json.get(JSON_ACLCAP_PERMISSION_MAPPING));
395         if (permissionMapping != null) {
396             Map<String, PermissionMapping> permMap = new HashMap<String, PermissionMapping>();
397 
398             for (Object permission : (List<Object>) permissionMapping) {
399                 Map<String, Object> permissionMap = getMap(permission);
400                 if (permissionMap != null) {
401                     PermissionMappingDataImpl mapping = new PermissionMappingDataImpl();
402 
403                     String key = getString(permissionMap, JSON_ACLCAP_MAPPING_KEY);
404                     mapping.setKey(key);
405 
406                     Object perms = permissionMap.get(JSON_ACLCAP_MAPPING_PERMISSION);
407                     if (perms instanceof List) {
408                         List<String> permList = new ArrayList<String>();
409 
410                         for (Object perm : (List<Object>) perms) {
411                             if (perm != null) {
412                                 permList.add(perm.toString());
413                             }
414                         }
415 
416                         mapping.setPermissions(permList);
417                     }
418 
419                     convertExtension(permissionMap, mapping, ACLCAP_MAPPING_KEYS);
420 
421                     permMap.put(key, mapping);
422                 }
423             }
424 
425             result.setPermissionMappingData(permMap);
426         }
427 
428         // handle extensions
429         convertExtension(json, result, ACLCAP_KEYS);
430 
431         return result;
432     }
433 
434     @SuppressWarnings("unchecked")
435     public static TypeDefinition convertTypeDefinition(Map<String, Object> json) {
436         if (json == null) {
437             return null;
438         }
439 
440         AbstractTypeDefinition result = null;
441 
442         String id = getString(json, JSON_TYPE_ID);
443 
444         // find base type
445         BaseTypeId baseType = getEnum(json, JSON_TYPE_BASE_ID, BaseTypeId.class);
446         if (baseType == null) {
447             throw new CmisRuntimeException("Invalid base type: " + id);
448         }
449 
450         switch (baseType) {
451         case CMIS_FOLDER:
452             result = new FolderTypeDefinitionImpl();
453             break;
454         case CMIS_DOCUMENT:
455             result = new DocumentTypeDefinitionImpl();
456 
457             ((DocumentTypeDefinitionImpl) result).setContentStreamAllowed(getEnum(json,
458                     JSON_TYPE_CONTENTSTREAM_ALLOWED, ContentStreamAllowed.class));
459             ((DocumentTypeDefinitionImpl) result).setIsVersionable(getBoolean(json, JSON_TYPE_VERSIONABLE));
460 
461             break;
462         case CMIS_RELATIONSHIP:
463             result = new RelationshipTypeDefinitionImpl();
464 
465             Object allowedSourceTypes = json.get(JSON_TYPE_ALLOWED_SOURCE_TYPES);
466             if (allowedSourceTypes instanceof List) {
467                 List<String> types = new ArrayList<String>();
468                 for (Object type : ((List<Object>) allowedSourceTypes)) {
469                     if (type != null) {
470                         types.add(type.toString());
471                     }
472                 }
473 
474                 ((RelationshipTypeDefinitionImpl) result).setAllowedSourceTypes(types);
475             }
476 
477             Object allowedTargetTypes = json.get(JSON_TYPE_ALLOWED_TARGET_TYPES);
478             if (allowedTargetTypes instanceof List) {
479                 List<String> types = new ArrayList<String>();
480                 for (Object type : ((List<Object>) allowedTargetTypes)) {
481                     if (type != null) {
482                         types.add(type.toString());
483                     }
484                 }
485 
486                 ((RelationshipTypeDefinitionImpl) result).setAllowedTargetTypes(types);
487             }
488 
489             break;
490         case CMIS_POLICY:
491             result = new PolicyTypeDefinitionImpl();
492             break;
493         default:
494             throw new CmisRuntimeException("Type '" + id + "' does not match a base type!");
495         }
496 
497         result.setBaseTypeId(baseType);
498         result.setDescription(getString(json, JSON_TYPE_DESCRIPTION));
499         result.setDisplayName(getString(json, JSON_TYPE_DISPLAYNAME));
500         result.setId(id);
501         result.setIsControllableAcl(getBoolean(json, JSON_TYPE_CONTROLABLE_ACL));
502         result.setIsControllablePolicy(getBoolean(json, JSON_TYPE_CONTROLABLE_POLICY));
503         result.setIsCreatable(getBoolean(json, JSON_TYPE_CREATABLE));
504         result.setIsFileable(getBoolean(json, JSON_TYPE_FILEABLE));
505         result.setIsFulltextIndexed(getBoolean(json, JSON_TYPE_FULLTEXT_INDEXED));
506         result.setIsIncludedInSupertypeQuery(getBoolean(json, JSON_TYPE_INCLUDE_IN_SUPERTYPE_QUERY));
507         result.setIsQueryable(getBoolean(json, JSON_TYPE_QUERYABLE));
508         result.setLocalName(getString(json, JSON_TYPE_LOCALNAME));
509         result.setLocalNamespace(getString(json, JSON_TYPE_LOCALNAMESPACE));
510         result.setParentTypeId(getString(json, JSON_TYPE_PARENT_ID));
511         result.setQueryName(getString(json, JSON_TYPE_QUERYNAME));
512 
513         Map<String, Object> propertyDefinitions = getMap(json.get(JSON_TYPE_PROPERTY_DEFINITIONS));
514         if (propertyDefinitions != null) {
515             for (Object propDef : propertyDefinitions.values()) {
516                 result.addPropertyDefinition(convertPropertyDefinition(getMap(propDef)));
517             }
518         }
519 
520         // handle extensions
521         convertExtension(json, result, TYPE_KEYS);
522 
523         return result;
524     }
525 
526     @SuppressWarnings({ "unchecked", "rawtypes" })
527     public static PropertyDefinition<?> convertPropertyDefinition(Map<String, Object> json) {
528         if (json == null) {
529             return null;
530         }
531 
532         AbstractPropertyDefinition<?> result = null;
533 
534         String id = getString(json, JSON_PROPERTY_ID);
535 
536         // find property type
537         PropertyType propertyType = getEnum(json, JSON_PROPERTY_TYPE_PROPERTY_TYPE, PropertyType.class);
538         if (propertyType == null) {
539             throw new CmisRuntimeException("Invalid property type '" + id + "'! Data type not set!");
540         }
541 
542         // find
543         Cardinality cardinality = getEnum(json, JSON_PROPERTY_TYPE_CARDINALITY, Cardinality.class);
544         if (cardinality == null) {
545             throw new CmisRuntimeException("Invalid property type '" + id + "'! Cardinality not set!");
546         }
547 
548         switch (propertyType) {
549         case STRING:
550             result = new PropertyStringDefinitionImpl();
551             ((PropertyStringDefinitionImpl) result).setMaxLength(getInteger(json, JSON_PROPERTY_TYPE_MAX_LENGTH));
552             ((PropertyStringDefinitionImpl) result)
553                     .setChoices(convertChoicesString(json.get(JSON_PROPERTY_TYPE_CHOICE)));
554             break;
555         case ID:
556             result = new PropertyIdDefinitionImpl();
557             ((PropertyIdDefinitionImpl) result).setChoices(convertChoicesString(json.get(JSON_PROPERTY_TYPE_CHOICE)));
558             break;
559         case BOOLEAN:
560             result = new PropertyBooleanDefinitionImpl();
561             ((PropertyBooleanDefinitionImpl) result).setChoices(convertChoicesBoolean(json
562                     .get(JSON_PROPERTY_TYPE_CHOICE)));
563             break;
564         case INTEGER:
565             result = new PropertyIntegerDefinitionImpl();
566             ((PropertyIntegerDefinitionImpl) result).setMinValue(getInteger(json, JSON_PROPERTY_TYPE_MIN_VALUE));
567             ((PropertyIntegerDefinitionImpl) result).setMaxValue(getInteger(json, JSON_PROPERTY_TYPE_MAX_VALUE));
568             ((PropertyIntegerDefinitionImpl) result).setChoices(convertChoicesInteger(json
569                     .get(JSON_PROPERTY_TYPE_CHOICE)));
570             break;
571         case DATETIME:
572             result = new PropertyDateTimeDefinitionImpl();
573             ((PropertyDateTimeDefinitionImpl) result).setDateTimeResolution(getEnum(json,
574                     JSON_PROPERTY_TYPE_RESOLUTION, DateTimeResolution.class));
575             ((PropertyDateTimeDefinitionImpl) result).setChoices(convertChoicesDateTime(json
576                     .get(JSON_PROPERTY_TYPE_CHOICE)));
577             break;
578         case DECIMAL:
579             result = new PropertyDecimalDefinitionImpl();
580             ((PropertyDecimalDefinitionImpl) result).setMinValue(getDecimal(json, JSON_PROPERTY_TYPE_MIN_VALUE));
581             ((PropertyDecimalDefinitionImpl) result).setMaxValue(getDecimal(json, JSON_PROPERTY_TYPE_MAX_VALUE));
582             ((PropertyDecimalDefinitionImpl) result).setPrecision(getEnum(json, JSON_PROPERTY_TYPE_PRECISION,
583                     DecimalPrecision.class));
584             ((PropertyDecimalDefinitionImpl) result).setChoices(convertChoicesDecimal(json
585                     .get(JSON_PROPERTY_TYPE_CHOICE)));
586             break;
587         case HTML:
588             result = new PropertyHtmlDefinitionImpl();
589             ((PropertyHtmlDefinitionImpl) result).setChoices(convertChoicesString(json.get(JSON_PROPERTY_TYPE_CHOICE)));
590             break;
591         case URI:
592             result = new PropertyUriDefinitionImpl();
593             ((PropertyUriDefinitionImpl) result).setChoices(convertChoicesString(json.get(JSON_PROPERTY_TYPE_CHOICE)));
594             break;
595         default:
596             throw new CmisRuntimeException("Property type '" + id + "' does not match a data type!");
597         }
598 
599         // default value
600         Object defaultValue = json.get(JSON_PROPERTY_TYPE_DEAULT_VALUE);
601         if (defaultValue != null) {
602             if (defaultValue instanceof List) {
603                 List values = new ArrayList();
604                 for (Object value : (List) defaultValue) {
605                     values.add(getCMISValue(value, propertyType));
606                 }
607                 result.setDefaultValue(values);
608             } else {
609                 result.setDefaultValue((List) Collections.singletonList(getCMISValue(defaultValue, propertyType)));
610             }
611         }
612 
613         // generic
614         result.setId(id);
615         result.setPropertyType(propertyType);
616         result.setCardinality(cardinality);
617         result.setLocalName(getString(json, JSON_PROPERTY_TYPE_LOCALNAME));
618         result.setLocalNamespace(getString(json, JSON_PROPERTY_TYPE_LOCALNAMESPACE));
619         result.setQueryName(getString(json, JSON_PROPERTY_TYPE_QUERYNAME));
620         result.setDescription(getString(json, JSON_PROPERTY_TYPE_DESCRIPTION));
621         result.setDisplayName(getString(json, JSON_PROPERTY_TYPE_DISPLAYNAME));
622         result.setIsInherited(getBoolean(json, JSON_PROPERTY_TYPE_INHERITED));
623         result.setIsOpenChoice(getBoolean(json, JSON_PROPERTY_TYPE_OPENCHOICE));
624         result.setIsOrderable(getBoolean(json, JSON_PROPERTY_TYPE_ORDERABLE));
625         result.setIsQueryable(getBoolean(json, JSON_PROPERTY_TYPE_QUERYABLE));
626         result.setIsRequired(getBoolean(json, JSON_PROPERTY_TYPE_REQUIRED));
627         result.setUpdatability(getEnum(json, JSON_PROPERTY_TYPE_UPDATABILITY, Updatability.class));
628 
629         // handle extensions
630         convertExtension(json, result, PROPERTY_TYPE_KEYS);
631 
632         return result;
633     }
634 
635     /**
636      * Converts choices.
637      */
638     @SuppressWarnings({ "rawtypes" })
639     private static List<Choice<String>> convertChoicesString(Object choices) {
640         if (!(choices instanceof List)) {
641             return null;
642         }
643 
644         List<Choice<String>> result = new ArrayList<Choice<String>>();
645 
646         for (Object obj : (List) choices) {
647             Map<String, Object> choiceMap = getMap(obj);
648             if (choiceMap != null) {
649                 ChoiceImpl<String> choice = new ChoiceImpl<String>();
650                 choice.setDisplayName(getString(choiceMap, JSON_PROPERTY_TYPE_CHOICE_DISPLAYNAME));
651 
652                 Object choiceValue = choiceMap.get(JSON_PROPERTY_TYPE_CHOICE_VALUE);
653                 List<String> values = new ArrayList<String>();
654                 if (choiceValue instanceof List) {
655                     for (Object value : (List) choiceValue) {
656                         values.add((String) getCMISValue(value, PropertyType.STRING));
657                     }
658                 } else {
659                     values.add((String) getCMISValue(choiceValue, PropertyType.STRING));
660                 }
661                 choice.setValue(values);
662 
663                 choice.setChoice(convertChoicesString(choiceMap.get(JSON_PROPERTY_TYPE_CHOICE_CHOICE)));
664 
665                 result.add(choice);
666             }
667         }
668 
669         return result;
670     }
671 
672     /**
673      * Converts choices.
674      */
675     @SuppressWarnings({ "rawtypes" })
676     private static List<Choice<Boolean>> convertChoicesBoolean(Object choices) {
677         if (!(choices instanceof List)) {
678             return null;
679         }
680 
681         List<Choice<Boolean>> result = new ArrayList<Choice<Boolean>>();
682 
683         for (Object obj : (List) choices) {
684             Map<String, Object> choiceMap = getMap(obj);
685             if (choiceMap != null) {
686                 ChoiceImpl<Boolean> choice = new ChoiceImpl<Boolean>();
687                 choice.setDisplayName(getString(choiceMap, JSON_PROPERTY_TYPE_CHOICE_DISPLAYNAME));
688 
689                 Object choiceValue = choiceMap.get(JSON_PROPERTY_TYPE_CHOICE_VALUE);
690                 List<Boolean> values = new ArrayList<Boolean>();
691                 if (choiceValue instanceof List) {
692                     for (Object value : (List) choiceValue) {
693                         values.add((Boolean) getCMISValue(value, PropertyType.BOOLEAN));
694                     }
695                 } else {
696                     values.add((Boolean) getCMISValue(choiceValue, PropertyType.BOOLEAN));
697                 }
698                 choice.setValue(values);
699 
700                 choice.setChoice(convertChoicesBoolean(choiceMap.get(JSON_PROPERTY_TYPE_CHOICE_CHOICE)));
701 
702                 result.add(choice);
703             }
704         }
705 
706         return result;
707     }
708 
709     /**
710      * Converts choices.
711      */
712     @SuppressWarnings({ "rawtypes" })
713     private static List<Choice<BigInteger>> convertChoicesInteger(Object choices) {
714         if (!(choices instanceof List)) {
715             return null;
716         }
717 
718         List<Choice<BigInteger>> result = new ArrayList<Choice<BigInteger>>();
719 
720         for (Object obj : (List) choices) {
721             Map<String, Object> choiceMap = getMap(obj);
722             if (choiceMap != null) {
723                 ChoiceImpl<BigInteger> choice = new ChoiceImpl<BigInteger>();
724                 choice.setDisplayName(getString(choiceMap, JSON_PROPERTY_TYPE_CHOICE_DISPLAYNAME));
725 
726                 Object choiceValue = choiceMap.get(JSON_PROPERTY_TYPE_CHOICE_VALUE);
727                 List<BigInteger> values = new ArrayList<BigInteger>();
728                 if (choiceValue instanceof List) {
729                     for (Object value : (List) choiceValue) {
730                         values.add((BigInteger) getCMISValue(value, PropertyType.INTEGER));
731                     }
732                 } else {
733                     values.add((BigInteger) getCMISValue(choiceValue, PropertyType.INTEGER));
734                 }
735                 choice.setValue(values);
736 
737                 choice.setChoice(convertChoicesInteger(choiceMap.get(JSON_PROPERTY_TYPE_CHOICE_CHOICE)));
738 
739                 result.add(choice);
740             }
741         }
742 
743         return result;
744     }
745 
746     /**
747      * Converts choices.
748      */
749     @SuppressWarnings({ "rawtypes" })
750     private static List<Choice<BigDecimal>> convertChoicesDecimal(Object choices) {
751         if (!(choices instanceof List)) {
752             return null;
753         }
754 
755         List<Choice<BigDecimal>> result = new ArrayList<Choice<BigDecimal>>();
756 
757         for (Object obj : (List) choices) {
758             Map<String, Object> choiceMap = getMap(obj);
759             if (choiceMap != null) {
760                 ChoiceImpl<BigDecimal> choice = new ChoiceImpl<BigDecimal>();
761                 choice.setDisplayName(getString(choiceMap, JSON_PROPERTY_TYPE_CHOICE_DISPLAYNAME));
762 
763                 Object choiceValue = choiceMap.get(JSON_PROPERTY_TYPE_CHOICE_VALUE);
764                 List<BigDecimal> values = new ArrayList<BigDecimal>();
765                 if (choiceValue instanceof List) {
766                     for (Object value : (List) choiceValue) {
767                         values.add((BigDecimal) getCMISValue(value, PropertyType.DECIMAL));
768                     }
769                 } else {
770                     values.add((BigDecimal) getCMISValue(choiceValue, PropertyType.DECIMAL));
771                 }
772                 choice.setValue(values);
773 
774                 choice.setChoice(convertChoicesDecimal(choiceMap.get(JSON_PROPERTY_TYPE_CHOICE_CHOICE)));
775 
776                 result.add(choice);
777             }
778         }
779 
780         return result;
781     }
782 
783     /**
784      * Converts choices.
785      */
786     @SuppressWarnings({ "rawtypes" })
787     private static List<Choice<GregorianCalendar>> convertChoicesDateTime(Object choices) {
788         if (!(choices instanceof List)) {
789             return null;
790         }
791 
792         List<Choice<GregorianCalendar>> result = new ArrayList<Choice<GregorianCalendar>>();
793 
794         for (Object obj : (List) choices) {
795             Map<String, Object> choiceMap = getMap(obj);
796             if (choiceMap != null) {
797                 ChoiceImpl<GregorianCalendar> choice = new ChoiceImpl<GregorianCalendar>();
798                 choice.setDisplayName(getString(choiceMap, JSON_PROPERTY_TYPE_CHOICE_DISPLAYNAME));
799 
800                 Object choiceValue = choiceMap.get(JSON_PROPERTY_TYPE_CHOICE_VALUE);
801                 List<GregorianCalendar> values = new ArrayList<GregorianCalendar>();
802                 if (choiceValue instanceof List) {
803                     for (Object value : (List) choiceValue) {
804                         values.add((GregorianCalendar) getCMISValue(value, PropertyType.DATETIME));
805                     }
806                 } else {
807                     values.add((GregorianCalendar) getCMISValue(choiceValue, PropertyType.DATETIME));
808                 }
809                 choice.setValue(values);
810 
811                 choice.setChoice(convertChoicesDateTime(choiceMap.get(JSON_PROPERTY_TYPE_CHOICE_CHOICE)));
812 
813                 result.add(choice);
814             }
815         }
816 
817         return result;
818     }
819 
820     /**
821      * Converts an object.
822      */
823     public static JSONObject convert(ObjectData object, TypeCache typeCache, boolean isQueryResult) {
824         if (object == null) {
825             return null;
826         }
827 
828         JSONObject result = new JSONObject();
829 
830         // properties
831         if (object.getProperties() != null) {
832             JSONObject properties = convert(object.getProperties(), object.getId(), typeCache, isQueryResult);
833             if (properties != null) {
834                 result.put(JSON_OBJECT_PROPERTIES, properties);
835             }
836         }
837 
838         // allowable actions
839         if (object.getAllowableActions() != null) {
840             result.put(JSON_OBJECT_ALLOWABLE_ACTIONS, convert(object.getAllowableActions()));
841         }
842 
843         // relationships
844         if ((object.getRelationships() != null) && (!object.getRelationships().isEmpty())) {
845             JSONArray relationships = new JSONArray();
846 
847             for (ObjectData relationship : object.getRelationships()) {
848                 relationships.add(convert(relationship, typeCache, false));
849             }
850 
851             result.put(JSON_OBJECT_RELATIONSHIPS, relationships);
852         }
853 
854         // change event info
855         if (object.getChangeEventInfo() != null && !isQueryResult) {
856             JSONObject changeEventInfo = new JSONObject();
857 
858             ChangeEventInfo cei = object.getChangeEventInfo();
859             changeEventInfo.put(JSON_CHANGE_EVENT_TYPE, getJSONStringValue(cei.getChangeType().value()));
860             changeEventInfo.put(JSON_CHANGE_EVENT_TIME, getJSONValue(cei.getChangeTime()));
861 
862             result.put(JSON_OBJECT_CHANGE_EVENT_INFO, changeEventInfo);
863         }
864 
865         // ACL
866         if ((object.getAcl() != null) && (object.getAcl().getAces() != null) && !isQueryResult) {
867             result.put(JSON_OBJECT_ACL, convert(object.getAcl()));
868             result.put(JSON_OBJECT_EXACT_ACL, object.isExactAcl());
869         }
870 
871         // policy ids
872         if ((object.getPolicyIds() != null) && (object.getPolicyIds().getPolicyIds() != null)
873                 && (!object.getPolicyIds().getPolicyIds().isEmpty())) {
874             JSONArray policyIds = new JSONArray();
875 
876             for (String pi : object.getPolicyIds().getPolicyIds()) {
877                 policyIds.add(pi);
878             }
879 
880             result.put(JSON_OBJECT_POLICY_IDS, policyIds);
881         }
882 
883         // renditions
884         if ((object.getRenditions() != null) && (!object.getRenditions().isEmpty())) {
885             JSONArray renditions = new JSONArray();
886 
887             for (RenditionData rendition : object.getRenditions()) {
888                 renditions.add(convert(rendition));
889             }
890 
891             result.put(JSON_OBJECT_RENDITIONS, renditions);
892         }
893 
894         convertExtension(object, result);
895 
896         return result;
897     }
898 
899     /**
900      * Converts a bag of properties.
901      */
902     public static JSONObject convert(Properties properties, String objectId, TypeCache typeCache, boolean isQueryResult) {
903         if (properties == null) {
904             return null;
905         }
906 
907         JSONObject result = new JSONObject();
908 
909         for (PropertyData<?> property : properties.getPropertyList()) {
910             TypeDefinition type = null;
911             if (typeCache != null) {
912                 type = typeCache.getTypeDefinitionForObject(objectId);
913             }
914 
915             PropertyDefinition<?> propDef = null;
916             if (type != null) {
917                 propDef = type.getPropertyDefinitions().get(property.getId());
918             }
919 
920             result.put((isQueryResult ? property.getQueryName() : property.getId()), convert(property, propDef));
921         }
922 
923         convertExtension(properties, result);
924 
925         return result;
926     }
927 
928     /**
929      * Converts a property.
930      */
931     public static JSONObject convert(PropertyData<?> property, PropertyDefinition<?> propDef) {
932         if (property == null) {
933             return null;
934         }
935 
936         JSONObject result = new JSONObject();
937 
938         result.put(JSON_PROPERTY_ID, property.getId());
939         setIfNotNull(JSON_PROPERTY_LOCALNAME, property.getLocalName(), result);
940         setIfNotNull(JSON_PROPERTY_DISPLAYNAME, property.getDisplayName(), result);
941         setIfNotNull(JSON_PROPERTY_QUERYNAME, property.getQueryName(), result);
942 
943         if (propDef != null) {
944             result.put(JSON_PROPERTY_DATATYPE, propDef.getPropertyType().value());
945             result.put(JSON_PROPERTY_CARDINALITY, propDef.getCardinality().value());
946 
947             if ((property.getValues() == null) || (property.getValues().size() == 0)) {
948                 result.put(JSON_PROPERTY_VALUE, null);
949             } else if (propDef.getCardinality() == Cardinality.SINGLE) {
950                 result.put(JSON_PROPERTY_VALUE, getJSONValue(property.getValues().get(0)));
951             } else {
952                 JSONArray values = new JSONArray();
953 
954                 for (Object value : property.getValues()) {
955                     values.add(getJSONValue(value));
956                 }
957 
958                 result.put(JSON_PROPERTY_VALUE, values);
959             }
960         } else {
961             result.put(JSON_PROPERTY_DATATYPE, getJSONPropertyDataType(property));
962 
963             if ((property.getValues() == null) || (property.getValues().size() == 0)) {
964                 result.put(JSON_PROPERTY_VALUE, null);
965             } else if (property.getValues().size() > 0) {
966                 JSONArray values = new JSONArray();
967 
968                 for (Object value : property.getValues()) {
969                     values.add(getJSONValue(value));
970                 }
971 
972                 result.put(JSON_PROPERTY_VALUE, values);
973             }
974         }
975 
976         convertExtension(property, result);
977 
978         return result;
979     }
980 
981     /**
982      * Converts allowable actions.
983      */
984     public static JSONObject convert(AllowableActions allowableActions) {
985         if (allowableActions == null) {
986             return null;
987         }
988 
989         JSONObject result = new JSONObject();
990 
991         Set<Action> actionSet = allowableActions.getAllowableActions();
992         for (Action action : Action.values()) {
993             result.put(action.value(), actionSet.contains(action));
994         }
995 
996         convertExtension(allowableActions, result);
997 
998         return result;
999     }
1000 
1001     /**
1002      * Converts an ACL.
1003      */
1004     public static JSONObject convert(Acl acl) {
1005         if ((acl == null) || (acl.getAces() == null)) {
1006             return null;
1007         }
1008 
1009         JSONArray aceObjects = new JSONArray();
1010 
1011         for (Ace ace : acl.getAces()) {
1012             JSONArray permissions = new JSONArray();
1013             if (ace.getPermissions() != null) {
1014                 for (String p : ace.getPermissions()) {
1015                     permissions.add(p);
1016                 }
1017             }
1018 
1019             JSONObject aceObject = new JSONObject();
1020             JSONObject principalObjecy = new JSONObject();
1021             principalObjecy.put(JSON_ACE_PRINCIPAL_ID, ace.getPrincipalId());
1022             aceObject.put(JSON_ACE_PRINCIPAL, principalObjecy);
1023             aceObject.put(JSON_ACE_PERMISSIONS, permissions);
1024             aceObject.put(JSON_ACE_IS_DIRECT, ace.isDirect());
1025 
1026             aceObjects.add(aceObject);
1027         }
1028 
1029         JSONObject result = new JSONObject();
1030         result.put(JSON_ACL_ACES, aceObjects);
1031         setIfNotNull(JSON_ACL_IS_EXACT, acl.isExact(), result);
1032 
1033         convertExtension(acl, result);
1034 
1035         return result;
1036     }
1037 
1038     /**
1039      * Converts a rendition.
1040      */
1041     public static JSONObject convert(RenditionData rendition) {
1042         if (rendition == null) {
1043             return null;
1044         }
1045 
1046         JSONObject result = new JSONObject();
1047 
1048         result.put(JSON_RENDITION_STREAM_ID, rendition.getStreamId());
1049         result.put(JSON_RENDITION_MIMETYPE, rendition.getMimeType());
1050         result.put(JSON_RENDITION_LENGTH, rendition.getBigLength());
1051         result.put(JSON_RENDITION_KIND, rendition.getKind());
1052         setIfNotNull(JSON_RENDITION_TITLE, rendition.getTitle(), result);
1053         setIfNotNull(JSON_RENDITION_HEIGHT, rendition.getBigHeight(), result);
1054         setIfNotNull(JSON_RENDITION_WIDTH, rendition.getBigWidth(), result);
1055         setIfNotNull(JSON_RENDITION_DOCUMENT_ID, rendition.getRenditionDocumentId(), result);
1056 
1057         convertExtension(rendition, result);
1058 
1059         return result;
1060     }
1061 
1062     /**
1063      * Converts a query object list.
1064      */
1065     public static JSONObject convert(ObjectList list, TypeCache typeCache, boolean isQueryResult) {
1066         if (list == null) {
1067             return null;
1068         }
1069 
1070         JSONObject result = new JSONObject();
1071 
1072         JSONArray objects = new JSONArray();
1073         if (list.getObjects() != null) {
1074             for (ObjectData object : list.getObjects()) {
1075                 objects.add(convert(object, typeCache, isQueryResult));
1076             }
1077         }
1078 
1079         if (isQueryResult) {
1080             result.put(JSON_QUERYRESULTLIST_RESULTS, objects);
1081 
1082             setIfNotNull(JSON_QUERYRESULTLIST_HAS_MORE_ITEMS, list.hasMoreItems(), result);
1083             setIfNotNull(JSON_QUERYRESULTLIST_NUM_ITEMS, list.getNumItems(), result);
1084         } else {
1085             result.put(JSON_OBJECTLIST_OBJECTS, objects);
1086 
1087             setIfNotNull(JSON_OBJECTLIST_HAS_MORE_ITEMS, list.hasMoreItems(), result);
1088             setIfNotNull(JSON_OBJECTLIST_NUM_ITEMS, list.getNumItems(), result);
1089         }
1090 
1091         convertExtension(list, result);
1092 
1093         return result;
1094     }
1095 
1096     /**
1097      * Converts an object in a folder list.
1098      */
1099     public static JSONObject convert(ObjectInFolderData objectInFolder, TypeCache typeCache) {
1100         if ((objectInFolder == null) || (objectInFolder.getObject() == null)) {
1101             return null;
1102         }
1103 
1104         JSONObject result = new JSONObject();
1105         result.put(JSON_OBJECTINFOLDER_OBJECT, convert(objectInFolder.getObject(), typeCache, false));
1106         setIfNotNull(JSON_OBJECTINFOLDER_PATH_SEGMENT, objectInFolder.getPathSegment(), result);
1107 
1108         convertExtension(objectInFolder, result);
1109 
1110         return result;
1111     }
1112 
1113     /**
1114      * Converts a folder list.
1115      */
1116     public static JSONObject convert(ObjectInFolderList objectInFolderList, TypeCache typeCache) {
1117         if (objectInFolderList == null) {
1118             return null;
1119         }
1120 
1121         JSONObject result = new JSONObject();
1122 
1123         if (objectInFolderList.getObjects() != null) {
1124             JSONArray objects = new JSONArray();
1125 
1126             for (ObjectInFolderData object : objectInFolderList.getObjects()) {
1127                 objects.add(convert(object, typeCache));
1128             }
1129 
1130             result.put(JSON_OBJECTINFOLDERLIST_OBJECTS, objects);
1131         }
1132 
1133         setIfNotNull(JSON_OBJECTINFOLDERLIST_HAS_MORE_ITEMS, objectInFolderList.hasMoreItems(), result);
1134         setIfNotNull(JSON_OBJECTINFOLDERLIST_NUM_ITEMS, objectInFolderList.getNumItems(), result);
1135 
1136         convertExtension(objectInFolderList, result);
1137 
1138         return result;
1139     }
1140 
1141     /**
1142      * Converts a folder container.
1143      */
1144     public static JSONObject convert(ObjectInFolderContainer container, TypeCache typeCache) {
1145         if (container == null) {
1146             return null;
1147         }
1148 
1149         JSONObject result = new JSONObject();
1150         result.put(JSON_OBJECTINFOLDERCONTAINER_OBJECT, convert(container.getObject(), typeCache));
1151 
1152         if ((container.getChildren() != null) && (container.getChildren().size() > 0)) {
1153             JSONArray children = new JSONArray();
1154             for (ObjectInFolderContainer descendant : container.getChildren()) {
1155                 children.add(JSONConverter.convert(descendant, typeCache));
1156             }
1157 
1158             result.put(JSON_OBJECTINFOLDERCONTAINER_CHILDREN, children);
1159         }
1160 
1161         convertExtension(container, result);
1162 
1163         return result;
1164     }
1165 
1166     /**
1167      * Converts an object parent.
1168      */
1169     public static JSONObject convert(ObjectParentData parent, TypeCache typeCache) {
1170         if ((parent == null) || (parent.getObject() == null)) {
1171             return null;
1172         }
1173 
1174         JSONObject result = new JSONObject();
1175         result.put(JSON_OBJECTPARENTS_OBJECT, convert(parent.getObject(), typeCache, false));
1176         if (parent.getRelativePathSegment() != null) {
1177             result.put(JSON_OBJECTPARENTS_RELATIVE_PATH_SEGMENT, parent.getRelativePathSegment());
1178         }
1179 
1180         convertExtension(parent, result);
1181 
1182         return result;
1183     }
1184 
1185     /**
1186      * Converts a type definition.
1187      */
1188     public static JSONObject convert(TypeDefinition type) {
1189         if (type == null) {
1190             return null;
1191         }
1192 
1193         JSONObject result = new JSONObject();
1194         result.put(JSON_TYPE_ID, type.getId());
1195         result.put(JSON_TYPE_LOCALNAME, type.getLocalName());
1196         result.put(JSON_TYPE_LOCALNAMESPACE, type.getLocalNamespace());
1197         setIfNotNull(JSON_TYPE_DISPLAYNAME, type.getDisplayName(), result);
1198         setIfNotNull(JSON_TYPE_QUERYNAME, type.getQueryName(), result);
1199         setIfNotNull(JSON_TYPE_DESCRIPTION, type.getDescription(), result);
1200         result.put(JSON_TYPE_BASE_ID, type.getBaseTypeId().value());
1201         setIfNotNull(JSON_TYPE_PARENT_ID, type.getParentTypeId(), result);
1202         result.put(JSON_TYPE_CREATABLE, type.isCreatable());
1203         result.put(JSON_TYPE_FILEABLE, type.isFileable());
1204         result.put(JSON_TYPE_QUERYABLE, type.isQueryable());
1205         result.put(JSON_TYPE_FULLTEXT_INDEXED, type.isFulltextIndexed());
1206         result.put(JSON_TYPE_INCLUDE_IN_SUPERTYPE_QUERY, type.isIncludedInSupertypeQuery());
1207         result.put(JSON_TYPE_CONTROLABLE_POLICY, type.isControllablePolicy());
1208         result.put(JSON_TYPE_CONTROLABLE_ACL, type.isControllableAcl());
1209 
1210         if (type instanceof DocumentTypeDefinition) {
1211             result.put(JSON_TYPE_VERSIONABLE, ((DocumentTypeDefinition) type).isVersionable());
1212             result.put(JSON_TYPE_CONTENTSTREAM_ALLOWED, ((DocumentTypeDefinition) type).getContentStreamAllowed()
1213                     .value());
1214         }
1215 
1216         if (type instanceof RelationshipTypeDefinition) {
1217             result.put(JSON_TYPE_ALLOWED_SOURCE_TYPES,
1218                     getJSONArrayFromList(((RelationshipTypeDefinition) type).getAllowedSourceTypeIds()));
1219             result.put(JSON_TYPE_ALLOWED_TARGET_TYPES,
1220                     getJSONArrayFromList(((RelationshipTypeDefinition) type).getAllowedTargetTypeIds()));
1221         }
1222 
1223         if ((type.getPropertyDefinitions() != null) && (!type.getPropertyDefinitions().isEmpty())) {
1224             JSONObject propertyDefs = new JSONObject();
1225 
1226             for (PropertyDefinition<?> pd : type.getPropertyDefinitions().values()) {
1227                 propertyDefs.put(pd.getId(), convert(pd));
1228             }
1229 
1230             result.put(JSON_TYPE_PROPERTY_DEFINITIONS, propertyDefs);
1231         }
1232 
1233         convertExtension(type, result);
1234 
1235         return result;
1236     }
1237 
1238     /**
1239      * Converts a property type definition.
1240      */
1241     public static JSONObject convert(PropertyDefinition<?> propertyDefinition) {
1242         if (propertyDefinition == null) {
1243             return null;
1244         }
1245 
1246         JSONObject result = new JSONObject();
1247 
1248         // type specific
1249         if (propertyDefinition instanceof PropertyStringDefinition) {
1250             setIfNotNull(JSON_PROPERTY_TYPE_MAX_LENGTH, ((PropertyStringDefinition) propertyDefinition).getMaxLength(),
1251                     result);
1252         } else if (propertyDefinition instanceof PropertyIdDefinition) {
1253         } else if (propertyDefinition instanceof PropertyIntegerDefinition) {
1254             setIfNotNull(JSON_PROPERTY_TYPE_MIN_VALUE, ((PropertyIntegerDefinition) propertyDefinition).getMinValue(),
1255                     result);
1256             setIfNotNull(JSON_PROPERTY_TYPE_MAX_VALUE, ((PropertyIntegerDefinition) propertyDefinition).getMaxValue(),
1257                     result);
1258         } else if (propertyDefinition instanceof PropertyDecimalDefinition) {
1259             setIfNotNull(JSON_PROPERTY_TYPE_MIN_VALUE, ((PropertyDecimalDefinition) propertyDefinition).getMinValue(),
1260                     result);
1261             setIfNotNull(JSON_PROPERTY_TYPE_MAX_VALUE, ((PropertyDecimalDefinition) propertyDefinition).getMaxValue(),
1262                     result);
1263             DecimalPrecision precision = ((PropertyDecimalDefinition) propertyDefinition).getPrecision();
1264             if (precision != null) {
1265                 result.put(JSON_PROPERTY_TYPE_PRECISION, precision.value());
1266             }
1267         } else if (propertyDefinition instanceof PropertyBooleanDefinition) {
1268         } else if (propertyDefinition instanceof PropertyDateTimeDefinition) {
1269             DateTimeResolution resolution = ((PropertyDateTimeDefinition) propertyDefinition).getDateTimeResolution();
1270             if (resolution != null) {
1271                 result.put(JSON_PROPERTY_TYPE_RESOLUTION, resolution.value());
1272             }
1273         } else if (propertyDefinition instanceof PropertyHtmlDefinition) {
1274         } else if (propertyDefinition instanceof PropertyUriDefinition) {
1275         }
1276 
1277         // default value
1278         if (propertyDefinition.getDefaultValue() != null) {
1279             if (propertyDefinition.getCardinality() == Cardinality.SINGLE) {
1280                 if (!propertyDefinition.getDefaultValue().isEmpty()) {
1281                     result.put(JSON_PROPERTY_TYPE_DEAULT_VALUE, getJSONValue(propertyDefinition.getDefaultValue()
1282                             .get(0)));
1283                 }
1284             } else {
1285                 JSONArray values = new JSONArray();
1286                 for (Object value : propertyDefinition.getDefaultValue()) {
1287                     values.add(getJSONValue(value));
1288                 }
1289                 result.put(JSON_PROPERTY_TYPE_DEAULT_VALUE, values);
1290             }
1291         }
1292 
1293         // choices
1294         if (propertyDefinition.getChoices() != null && !propertyDefinition.getChoices().isEmpty()) {
1295             result.put(JSON_PROPERTY_TYPE_CHOICE,
1296                     convertChoices(propertyDefinition.getChoices(), propertyDefinition.getCardinality()));
1297         }
1298 
1299         // generic
1300         result.put(JSON_PROPERTY_TYPE_ID, propertyDefinition.getId());
1301         result.put(JSON_PROPERTY_TYPE_LOCALNAME, propertyDefinition.getLocalName());
1302         setIfNotNull(JSON_PROPERTY_TYPE_LOCALNAMESPACE, propertyDefinition.getLocalNamespace(), result);
1303         setIfNotNull(JSON_PROPERTY_TYPE_DISPLAYNAME, propertyDefinition.getDisplayName(), result);
1304         setIfNotNull(JSON_PROPERTY_TYPE_QUERYNAME, propertyDefinition.getQueryName(), result);
1305         setIfNotNull(JSON_PROPERTY_TYPE_DESCRIPTION, propertyDefinition.getDescription(), result);
1306         result.put(JSON_PROPERTY_TYPE_PROPERTY_TYPE, propertyDefinition.getPropertyType().value());
1307         result.put(JSON_PROPERTY_TYPE_CARDINALITY, propertyDefinition.getCardinality().value());
1308         result.put(JSON_PROPERTY_TYPE_UPDATABILITY, propertyDefinition.getUpdatability().value());
1309         setIfNotNull(JSON_PROPERTY_TYPE_INHERITED, propertyDefinition.isInherited(), result);
1310         result.put(JSON_PROPERTY_TYPE_REQUIRED, propertyDefinition.isRequired());
1311         result.put(JSON_PROPERTY_TYPE_QUERYABLE, propertyDefinition.isQueryable());
1312         result.put(JSON_PROPERTY_TYPE_ORDERABLE, propertyDefinition.isOrderable());
1313         setIfNotNull(JSON_PROPERTY_TYPE_OPENCHOICE, propertyDefinition.isOpenChoice(), result);
1314 
1315         convertExtension(propertyDefinition, result);
1316 
1317         return result;
1318     }
1319 
1320     /**
1321      * Converts choices.
1322      */
1323     private static <T> JSONArray convertChoices(List<Choice<T>> choices, Cardinality cardinality) {
1324         if (choices == null) {
1325             return null;
1326         }
1327 
1328         JSONArray result = new JSONArray();
1329 
1330         for (Choice<?> choice : choices) {
1331             JSONObject jsonChoice = new JSONObject();
1332 
1333             jsonChoice.put(JSON_PROPERTY_TYPE_CHOICE_DISPLAYNAME, choice.getDisplayName());
1334 
1335             if (cardinality == Cardinality.SINGLE) {
1336                 if (!choice.getValue().isEmpty()) {
1337                     jsonChoice.put(JSON_PROPERTY_TYPE_CHOICE_VALUE, getJSONValue(choice.getValue().get(0)));
1338                 }
1339             } else {
1340                 JSONArray values = new JSONArray();
1341                 for (Object value : choice.getValue()) {
1342                     values.add(getJSONValue(value));
1343                 }
1344                 jsonChoice.put(JSON_PROPERTY_TYPE_CHOICE_VALUE, values);
1345             }
1346 
1347             if (choice.getChoice() != null && !choice.getChoice().isEmpty()) {
1348                 jsonChoice.put(JSON_PROPERTY_TYPE_CHOICE_CHOICE, convertChoices(choice.getChoice(), cardinality));
1349             }
1350 
1351             result.add(jsonChoice);
1352         }
1353 
1354         return result;
1355     }
1356 
1357     /**
1358      * Converts a type definition list.
1359      */
1360     public static JSONObject convert(TypeDefinitionList list) {
1361         if (list == null) {
1362             return null;
1363         }
1364 
1365         JSONObject result = new JSONObject();
1366 
1367         if (list.getList() != null) {
1368             JSONArray objects = new JSONArray();
1369 
1370             for (TypeDefinition type : list.getList()) {
1371                 objects.add(convert(type));
1372             }
1373 
1374             result.put(JSON_TYPESLIST_TYPES, objects);
1375         }
1376 
1377         setIfNotNull(JSON_TYPESLIST_HAS_MORE_ITEMS, list.hasMoreItems(), result);
1378         setIfNotNull(JSON_TYPESLIST_NUM_ITEMS, list.getNumItems(), result);
1379 
1380         convertExtension(list, result);
1381 
1382         return result;
1383     }
1384 
1385     /**
1386      * Converts a type definition list.
1387      */
1388     @SuppressWarnings({ "rawtypes", "unchecked" })
1389     public static TypeDefinitionList convertTypeChildren(Map<String, Object> json) {
1390         if (json == null) {
1391             return null;
1392         }
1393 
1394         TypeDefinitionListImpl result = new TypeDefinitionListImpl();
1395 
1396         Object typesList = json.get(JSON_TYPESLIST_TYPES);
1397         List<TypeDefinition> types = new ArrayList<TypeDefinition>();
1398 
1399         if (typesList instanceof List) {
1400             for (Object type : (List) typesList) {
1401                 if (type instanceof Map) {
1402                     types.add(convertTypeDefinition((Map<String, Object>) type));
1403                 }
1404             }
1405         }
1406 
1407         result.setList(types);
1408         result.setHasMoreItems(getBoolean(json, JSON_TYPESLIST_HAS_MORE_ITEMS));
1409         result.setNumItems(getInteger(json, JSON_TYPESLIST_NUM_ITEMS));
1410 
1411         convertExtension(json, result, TYPESLIST_KEYS);
1412 
1413         return result;
1414     }
1415 
1416     /**
1417      * Converts a type definition container.
1418      */
1419     public static JSONObject convert(TypeDefinitionContainer container) {
1420         if (container == null) {
1421             return null;
1422         }
1423 
1424         JSONObject result = new JSONObject();
1425         result.put(JSON_TYPESCONTAINER_TYPE, convert(container.getTypeDefinition()));
1426 
1427         if ((container.getChildren() != null) && (container.getChildren().size() > 0)) {
1428             JSONArray children = new JSONArray();
1429             for (TypeDefinitionContainer child : container.getChildren()) {
1430                 children.add(JSONConverter.convert(child));
1431             }
1432 
1433             result.put(JSON_TYPESCONTAINER_CHILDREN, children);
1434         }
1435 
1436         convertExtension(container, result);
1437 
1438         return result;
1439     }
1440 
1441     /**
1442      * Converts a type definition list.
1443      */
1444     @SuppressWarnings({ "unchecked" })
1445     public static List<TypeDefinitionContainer> convertTypeDescendants(List<Object> json) {
1446         if (json == null) {
1447             return null;
1448         }
1449 
1450         if (json.isEmpty()) {
1451             return Collections.emptyList();
1452         }
1453 
1454         List<TypeDefinitionContainer> result = new ArrayList<TypeDefinitionContainer>();
1455 
1456         for (Object obj : json) {
1457             if (obj instanceof Map) {
1458                 Map<String, Object> jsonContainer = (Map<String, Object>) obj;
1459                 TypeDefinitionContainerImpl container = new TypeDefinitionContainerImpl();
1460 
1461                 container.setTypeDefinition(convertTypeDefinition(getMap(jsonContainer.get(JSON_TYPESCONTAINER_TYPE))));
1462 
1463                 Object children = jsonContainer.get(JSON_TYPESCONTAINER_CHILDREN);
1464                 if (children instanceof List) {
1465                     container.setChildren(convertTypeDescendants((List<Object>) children));
1466                 } else {
1467                     container.setChildren((List<TypeDefinitionContainer>) Collections.EMPTY_LIST);
1468                 }
1469 
1470                 convertExtension(jsonContainer, container, TYPESCONTAINER_KEYS);
1471 
1472                 result.add(container);
1473             }
1474         }
1475 
1476         return result;
1477     }
1478 
1479     /**
1480      * Converts an object.
1481      */
1482     public static ObjectData convertObject(Map<String, Object> json) {
1483         if (json == null) {
1484             return null;
1485         }
1486 
1487         ObjectDataImpl result = new ObjectDataImpl();
1488 
1489         result.setAcl(convertAcl(getMap(json.get(JSON_OBJECT_ACL)), getBoolean(json, JSON_OBJECT_EXACT_ACL)));
1490         result.setAllowableActions(convertAllowableActions(getMap(json.get(JSON_OBJECT_ALLOWABLE_ACTIONS))));
1491         Map<String, Object> jsonChangeEventInfo = getMap(json.get(JSON_OBJECT_CHANGE_EVENT_INFO));
1492         if (jsonChangeEventInfo != null) {
1493             ChangeEventInfoDataImpl changeEventInfo = new ChangeEventInfoDataImpl();
1494 
1495             changeEventInfo.setChangeTime(getDateTime(jsonChangeEventInfo, JSON_CHANGE_EVENT_TIME));
1496             changeEventInfo.setChangeType(getEnum(jsonChangeEventInfo, JSON_CHANGE_EVENT_TYPE, ChangeType.class));
1497 
1498             convertExtension(json, result, CHANGE_EVENT_KEYS);
1499 
1500             result.setChangeEventInfo(changeEventInfo);
1501         }
1502         result.setIsExactAcl(getBoolean(json, JSON_OBJECT_EXACT_ACL));
1503         result.setPolicyIds(convertPolicyIds(getList(json.get(JSON_OBJECT_POLICY_IDS))));
1504         result.setProperties(convertProperties(getMap(json.get(JSON_OBJECT_PROPERTIES))));
1505         List<Object> jsonRelationships = getList(json.get(JSON_OBJECT_RELATIONSHIPS));
1506         if (jsonRelationships != null) {
1507             result.setRelationships(convertObjects(jsonRelationships));
1508         }
1509         List<Object> jsonRenditions = getList(json.get(JSON_OBJECT_RENDITIONS));
1510         if (jsonRenditions != null) {
1511             result.setRenditions(convertRenditions(jsonRenditions));
1512         }
1513 
1514         convertExtension(json, result, OBJECT_KEYS);
1515 
1516         return result;
1517     }
1518 
1519     /**
1520      * Converts an object.
1521      */
1522     public static List<ObjectData> convertObjects(List<Object> json) {
1523         if (json == null) {
1524             return null;
1525         }
1526 
1527         List<ObjectData> result = new ArrayList<ObjectData>();
1528         for (Object obj : json) {
1529             ObjectData relationship = convertObject(getMap(obj));
1530             if (relationship != null) {
1531                 result.add(relationship);
1532             }
1533         }
1534 
1535         return result;
1536     }
1537 
1538     /**
1539      * Converts an ACL.
1540      */
1541     public static Acl convertAcl(Map<String, Object> json, Boolean isExact) {
1542         if (json == null) {
1543             return null;
1544         }
1545 
1546         AccessControlListImpl result = new AccessControlListImpl();
1547 
1548         List<Ace> aces = new ArrayList<Ace>();
1549 
1550         List<Object> jsonAces = getList(json.get(JSON_ACL_ACES));
1551         if (jsonAces != null) {
1552             for (Object obj : jsonAces) {
1553                 Map<String, Object> entry = getMap(obj);
1554                 if (entry != null) {
1555                     AccessControlEntryImpl ace = new AccessControlEntryImpl();
1556 
1557                     Boolean isDirect = getBoolean(entry, JSON_ACE_IS_DIRECT);
1558                     ace.setDirect(isDirect != null ? isDirect.booleanValue() : true);
1559 
1560                     List<Object> jsonPermissions = getList(entry.get(JSON_ACE_PERMISSIONS));
1561                     if (jsonPermissions != null) {
1562                         List<String> permissions = new ArrayList<String>();
1563                         for (Object perm : jsonPermissions) {
1564                             if (perm != null) {
1565                                 permissions.add(perm.toString());
1566                             }
1567                         }
1568                         ace.setPermissions(permissions);
1569                     }
1570 
1571                     Map<String, Object> jsonPrincipal = getMap(entry.get(JSON_ACE_PRINCIPAL));
1572                     if (jsonPrincipal != null) {
1573                         AccessControlPrincipalDataImpl principal = new AccessControlPrincipalDataImpl();
1574 
1575                         principal.setPrincipalId(getString(jsonPrincipal, JSON_ACE_PRINCIPAL_ID));
1576 
1577                         convertExtension(jsonPrincipal, principal, PRINCIPAL_KEYS);
1578 
1579                         ace.setPrincipal(principal);
1580                     }
1581 
1582                     convertExtension(entry, ace, ACE_KEYS);
1583 
1584                     aces.add(ace);
1585                 }
1586             }
1587         }
1588 
1589         result.setAces(aces);
1590 
1591         result.setExact(isExact);
1592 
1593         convertExtension(json, result, ACL_KEYS);
1594 
1595         return result;
1596     }
1597 
1598     /**
1599      * Converts allowable actions.
1600      */
1601     public static AllowableActions convertAllowableActions(Map<String, Object> json) {
1602         if (json == null) {
1603             return null;
1604         }
1605 
1606         AllowableActionsImpl result = new AllowableActionsImpl();
1607         Set<Action> allowableActions = new HashSet<Action>();
1608 
1609         for (Action action : Action.values()) {
1610             Boolean value = getBoolean(json, action.value());
1611             if (value != null && value.booleanValue()) {
1612                 allowableActions.add(action);
1613             }
1614         }
1615 
1616         result.setAllowableActions(allowableActions);
1617 
1618         convertExtension(json, result, ALLOWABLE_ACTIONS_KEYS);
1619 
1620         return result;
1621     }
1622 
1623     /**
1624      * Converts a list of policy ids.
1625      */
1626     public static PolicyIdList convertPolicyIds(List<Object> json) {
1627         if (json == null) {
1628             return null;
1629         }
1630 
1631         PolicyIdListImpl result = new PolicyIdListImpl();
1632         List<String> policyIds = new ArrayList<String>();
1633 
1634         for (Object obj : json) {
1635             if (obj instanceof String) {
1636                 policyIds.add((String) obj);
1637             }
1638         }
1639 
1640         result.setPolicyIds(policyIds);
1641 
1642         return result;
1643     }
1644 
1645     /**
1646      * Converts properties.
1647      */
1648     @SuppressWarnings("unchecked")
1649     public static Properties convertProperties(Map<String, Object> json) {
1650         if (json == null) {
1651             return null;
1652         }
1653 
1654         PropertiesImpl result = new PropertiesImpl();
1655 
1656         for (Object jsonProperty : json.values()) {
1657             Map<String, Object> jsonPropertyMap = getMap(jsonProperty);
1658             if (jsonPropertyMap != null) {
1659                 AbstractPropertyData<?> property = null;
1660 
1661                 String id = getString(jsonPropertyMap, JSON_PROPERTY_ID);
1662                 if (id == null) {
1663                     throw new CmisRuntimeException("Invalid property!");
1664                 }
1665 
1666                 PropertyType propertyType = null;
1667                 try {
1668                     propertyType = PropertyType.fromValue(getString(jsonPropertyMap, JSON_PROPERTY_DATATYPE));
1669                 } catch (Exception e) {
1670                     throw new CmisRuntimeException("Invalid property: " + id);
1671                 }
1672 
1673                 Object value = jsonPropertyMap.get(JSON_PROPERTY_VALUE);
1674                 List<Object> values = null;
1675                 if (value instanceof List) {
1676                     values = (List<Object>) value;
1677                 } else if (value != null) {
1678                     values = Collections.singletonList(value);
1679                 }
1680 
1681                 switch (propertyType) {
1682                 case STRING:
1683                     property = new PropertyStringImpl();
1684                     {
1685                         List<String> propertyValues = null;
1686                         if (values != null) {
1687                             propertyValues = new ArrayList<String>();
1688                             for (Object obj : values) {
1689                                 if (obj instanceof String) {
1690                                     propertyValues.add(obj.toString());
1691                                 } else {
1692                                     throw new CmisRuntimeException("Invalid property value: " + obj);
1693                                 }
1694                             }
1695                         }
1696                         ((PropertyStringImpl) property).setValues(propertyValues);
1697                     }
1698                     break;
1699                 case ID:
1700                     property = new PropertyIdImpl();
1701                     {
1702                         List<String> propertyValues = null;
1703                         if (values != null) {
1704                             propertyValues = new ArrayList<String>();
1705                             for (Object obj : values) {
1706                                 if (obj instanceof String) {
1707                                     propertyValues.add(obj.toString());
1708                                 } else {
1709                                     throw new CmisRuntimeException("Invalid property value: " + obj);
1710                                 }
1711                             }
1712                         }
1713                         ((PropertyIdImpl) property).setValues(propertyValues);
1714                     }
1715                     break;
1716                 case BOOLEAN:
1717                     property = new PropertyBooleanImpl();
1718                     {
1719                         List<Boolean> propertyValues = null;
1720                         if (values != null) {
1721                             propertyValues = new ArrayList<Boolean>();
1722                             for (Object obj : values) {
1723                                 if (obj instanceof Boolean) {
1724                                     propertyValues.add((Boolean) obj);
1725                                 } else {
1726                                     throw new CmisRuntimeException("Invalid property value: " + obj);
1727                                 }
1728                             }
1729                         }
1730                         ((PropertyBooleanImpl) property).setValues(propertyValues);
1731                     }
1732                     break;
1733                 case INTEGER:
1734                     property = new PropertyIntegerImpl();
1735                     {
1736                         List<BigInteger> propertyValues = null;
1737                         if (values != null) {
1738                             propertyValues = new ArrayList<BigInteger>();
1739                             for (Object obj : values) {
1740                                 if (obj instanceof BigInteger) {
1741                                     propertyValues.add((BigInteger) obj);
1742                                 } else {
1743                                     throw new CmisRuntimeException("Invalid property value: " + obj);
1744                                 }
1745                             }
1746                         }
1747                         ((PropertyIntegerImpl) property).setValues(propertyValues);
1748                     }
1749                     break;
1750                 case DECIMAL:
1751                     property = new PropertyDecimalImpl();
1752                     {
1753                         List<BigDecimal> propertyValues = null;
1754                         if (values != null) {
1755                             propertyValues = new ArrayList<BigDecimal>();
1756                             for (Object obj : values) {
1757                                 if (obj instanceof BigDecimal) {
1758                                     propertyValues.add((BigDecimal) obj);
1759                                 } else if (obj instanceof BigInteger) {
1760                                     propertyValues.add(new BigDecimal((BigInteger) obj));
1761                                 } else {
1762                                     throw new CmisRuntimeException("Invalid property value: " + obj);
1763                                 }
1764                             }
1765                         }
1766                         ((PropertyDecimalImpl) property).setValues(propertyValues);
1767                     }
1768                     break;
1769                 case DATETIME:
1770                     property = new PropertyDateTimeImpl();
1771                     {
1772                         List<GregorianCalendar> propertyValues = null;
1773                         if (values != null) {
1774                             propertyValues = new ArrayList<GregorianCalendar>();
1775                             for (Object obj : values) {
1776                                 if (obj instanceof Number) {
1777                                     GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
1778                                     cal.setTimeInMillis(((Number) obj).longValue());
1779                                     propertyValues.add(cal);
1780                                 } else {
1781                                     throw new CmisRuntimeException("Invalid property value: " + obj);
1782                                 }
1783                             }
1784                         }
1785                         ((PropertyDateTimeImpl) property).setValues(propertyValues);
1786                     }
1787                     break;
1788                 case HTML:
1789                     property = new PropertyHtmlImpl();
1790                     {
1791                         List<String> propertyValues = null;
1792                         if (values != null) {
1793                             propertyValues = new ArrayList<String>();
1794                             for (Object obj : values) {
1795                                 if (obj instanceof String) {
1796                                     propertyValues.add(obj.toString());
1797                                 } else {
1798                                     throw new CmisRuntimeException("Invalid property value: " + obj);
1799                                 }
1800                             }
1801                         }
1802                         ((PropertyHtmlImpl) property).setValues(propertyValues);
1803                     }
1804                     break;
1805                 case URI:
1806                     property = new PropertyUriImpl();
1807                     {
1808                         List<String> propertyValues = null;
1809                         if (values != null) {
1810                             propertyValues = new ArrayList<String>();
1811                             for (Object obj : values) {
1812                                 if (obj instanceof String) {
1813                                     propertyValues.add(obj.toString());
1814                                 } else {
1815                                     throw new CmisRuntimeException("Invalid property value: " + obj);
1816                                 }
1817                             }
1818                         }
1819                         ((PropertyUriImpl) property).setValues(propertyValues);
1820                     }
1821                     break;
1822                 }
1823 
1824                 property.setId(id);
1825                 property.setDisplayName(getString(jsonPropertyMap, JSON_PROPERTY_DISPLAYNAME));
1826                 property.setQueryName(getString(jsonPropertyMap, JSON_PROPERTY_QUERYNAME));
1827                 property.setLocalName(getString(jsonPropertyMap, JSON_PROPERTY_LOCALNAME));
1828 
1829                 convertExtension(jsonPropertyMap, property, PROPERTY_KEYS);
1830 
1831                 result.addProperty(property);
1832             }
1833         }
1834 
1835         // TODO: properties extensions
1836 
1837         return result;
1838     }
1839 
1840     /**
1841      * Converts a rendition.
1842      */
1843     public static RenditionData convertRendition(Map<String, Object> json) {
1844         if (json == null) {
1845             return null;
1846         }
1847 
1848         RenditionDataImpl result = new RenditionDataImpl();
1849 
1850         result.setBigHeight(getInteger(json, JSON_RENDITION_HEIGHT));
1851         result.setKind(getString(json, JSON_RENDITION_KIND));
1852         result.setBigLength(getInteger(json, JSON_RENDITION_LENGTH));
1853         result.setMimeType(getString(json, JSON_RENDITION_MIMETYPE));
1854         result.setRenditionDocumentId(getString(json, JSON_RENDITION_DOCUMENT_ID));
1855         result.setStreamId(getString(json, JSON_RENDITION_STREAM_ID));
1856         result.setTitle(getString(json, JSON_RENDITION_TITLE));
1857         result.setBigWidth(getInteger(json, JSON_RENDITION_WIDTH));
1858 
1859         convertExtension(json, result, RENDITION_KEYS);
1860 
1861         return result;
1862     }
1863 
1864     /**
1865      * Converts a list of renditions.
1866      */
1867     public static List<RenditionData> convertRenditions(List<Object> json) {
1868         if (json == null) {
1869             return null;
1870         }
1871 
1872         List<RenditionData> result = new ArrayList<RenditionData>();
1873 
1874         for (Object obj : json) {
1875             RenditionData rendition = convertRendition(getMap(obj));
1876             if (rendition != null) {
1877                 result.add(rendition);
1878             }
1879         }
1880 
1881         return result;
1882     }
1883 
1884     /**
1885      * Converts a object list.
1886      */
1887     public static ObjectInFolderList convertObjectInFolderList(Map<String, Object> json) {
1888         if (json == null) {
1889             return null;
1890         }
1891 
1892         ObjectInFolderListImpl result = new ObjectInFolderListImpl();
1893 
1894         List<Object> jsonChildren = getList(json.get(JSON_OBJECTINFOLDERLIST_OBJECTS));
1895         List<ObjectInFolderData> objects = new ArrayList<ObjectInFolderData>();
1896 
1897         if (jsonChildren != null) {
1898             for (Object obj : jsonChildren) {
1899                 Map<String, Object> jsonObject = getMap(obj);
1900                 if (jsonObject != null) {
1901                     objects.add(convertObjectInFolder(jsonObject));
1902                 }
1903             }
1904         }
1905 
1906         result.setObjects(objects);
1907         result.setHasMoreItems(getBoolean(json, JSON_OBJECTINFOLDERLIST_HAS_MORE_ITEMS));
1908         result.setNumItems(getInteger(json, JSON_OBJECTINFOLDERLIST_NUM_ITEMS));
1909 
1910         convertExtension(json, result, OBJECTINFOLDERLIST_KEYS);
1911 
1912         return result;
1913     }
1914 
1915     /**
1916      * Converts an object in a folder.
1917      */
1918     public static ObjectInFolderData convertObjectInFolder(Map<String, Object> json) {
1919         if (json == null) {
1920             return null;
1921         }
1922 
1923         ObjectInFolderDataImpl result = new ObjectInFolderDataImpl();
1924 
1925         result.setObject(convertObject(getMap(json.get(JSON_OBJECTINFOLDER_OBJECT))));
1926         result.setPathSegment(getString(json, JSON_OBJECTINFOLDER_PATH_SEGMENT));
1927 
1928         convertExtension(json, result, OBJECTINFOLDER_KEYS);
1929 
1930         return result;
1931     }
1932 
1933     /**
1934      * Converts a descendants tree.
1935      */
1936     public static List<ObjectInFolderContainer> convertDescendants(List<Object> json) {
1937         if (json == null) {
1938             return null;
1939         }
1940 
1941         List<ObjectInFolderContainer> result = new ArrayList<ObjectInFolderContainer>();
1942 
1943         for (Object obj : json) {
1944             Map<String, Object> desc = getMap(obj);
1945             if (desc != null) {
1946                 result.add(convertDescendant(desc));
1947             }
1948         }
1949 
1950         return result;
1951     }
1952 
1953     /**
1954      * Converts a descendant.
1955      */
1956     public static ObjectInFolderContainer convertDescendant(Map<String, Object> json) {
1957         if (json == null) {
1958             return null;
1959         }
1960 
1961         ObjectInFolderContainerImpl result = new ObjectInFolderContainerImpl();
1962 
1963         result.setObject(convertObjectInFolder(getMap(json.get(JSON_OBJECTINFOLDERCONTAINER_OBJECT))));
1964 
1965         List<ObjectInFolderContainer> containerList = new ArrayList<ObjectInFolderContainer>();
1966         List<Object> jsonContainerList = getList(json.get(JSON_OBJECTINFOLDERCONTAINER_CHILDREN));
1967         if (jsonContainerList != null) {
1968             for (Object obj : jsonContainerList) {
1969                 Map<String, Object> containerChild = getMap(obj);
1970                 if (containerChild != null) {
1971                     containerList.add(convertDescendant(containerChild));
1972                 }
1973             }
1974         }
1975 
1976         result.setChildren(containerList);
1977 
1978         convertExtension(json, result, OBJECTINFOLDERCONTAINER_KEYS);
1979 
1980         return result;
1981     }
1982 
1983     /**
1984      * Converts an object parents list.
1985      */
1986     public static List<ObjectParentData> convertObjectParents(List<Object> json) {
1987         if (json == null) {
1988             return null;
1989         }
1990 
1991         List<ObjectParentData> result = new ArrayList<ObjectParentData>();
1992 
1993         for (Object obj : json) {
1994             Map<String, Object> jsonParent = getMap(obj);
1995             if (jsonParent != null) {
1996                 ObjectParentDataImpl parent = new ObjectParentDataImpl();
1997 
1998                 parent.setObject(convertObject(getMap(jsonParent.get(JSON_OBJECTPARENTS_OBJECT))));
1999                 parent.setRelativePathSegment(getString(jsonParent, JSON_OBJECTPARENTS_RELATIVE_PATH_SEGMENT));
2000 
2001                 convertExtension(jsonParent, parent, OBJECTPARENTS_KEYS);
2002 
2003                 result.add(parent);
2004             }
2005         }
2006 
2007         return result;
2008     }
2009 
2010     /**
2011      * Converts a object list.
2012      */
2013     public static ObjectList convertObjectList(Map<String, Object> json, boolean isQueryResult) {
2014         if (json == null) {
2015             return null;
2016         }
2017 
2018         ObjectListImpl result = new ObjectListImpl();
2019 
2020         List<Object> jsonChildren = getList(json.get(isQueryResult ? JSON_QUERYRESULTLIST_RESULTS
2021                 : JSON_OBJECTLIST_OBJECTS));
2022         List<ObjectData> objects = new ArrayList<ObjectData>();
2023 
2024         if (jsonChildren != null) {
2025             for (Object obj : jsonChildren) {
2026                 Map<String, Object> jsonObject = getMap(obj);
2027                 if (jsonObject != null) {
2028                     objects.add(convertObject(jsonObject));
2029                 }
2030             }
2031         }
2032 
2033         result.setObjects(objects);
2034         result.setHasMoreItems(getBoolean(json, isQueryResult ? JSON_QUERYRESULTLIST_NUM_ITEMS
2035                 : JSON_OBJECTLIST_HAS_MORE_ITEMS));
2036         result.setNumItems(getInteger(json, isQueryResult ? JSON_QUERYRESULTLIST_NUM_ITEMS : JSON_OBJECTLIST_NUM_ITEMS));
2037 
2038         convertExtension(json, result, isQueryResult ? QUERYRESULTLIST_KEYS : OBJECTLIST_KEYS);
2039 
2040         return result;
2041     }
2042 
2043     // -----------------------------------------------------------------
2044 
2045     /**
2046      * Converts FailedToDelete ids.
2047      */
2048     public static JSONObject convert(FailedToDeleteData ftd) {
2049         if (ftd == null) {
2050             return null;
2051         }
2052 
2053         JSONObject result = new JSONObject();
2054 
2055         JSONArray ids = new JSONArray();
2056         if (ftd.getIds() != null) {
2057             for (String id : ftd.getIds()) {
2058                 ids.add(id);
2059             }
2060         }
2061 
2062         result.put(JSON_FAILEDTODELETE_ID, ids);
2063 
2064         convertExtension(ftd, result);
2065 
2066         return result;
2067     }
2068 
2069     /**
2070      * Converts FailedToDelete ids.
2071      */
2072     public static FailedToDeleteData convertFailedToDelete(Map<String, Object> json) {
2073         if (json == null) {
2074             return null;
2075         }
2076 
2077         FailedToDeleteDataImpl result = new FailedToDeleteDataImpl();
2078 
2079         List<String> ids = new ArrayList<String>();
2080         List<Object> jsonIds = getList(json.get(JSON_FAILEDTODELETE_ID));
2081 
2082         if (jsonIds != null) {
2083             for (Object obj : jsonIds) {
2084                 if (obj != null) {
2085                     ids.add(obj.toString());
2086                 }
2087             }
2088         }
2089 
2090         result.setIds(ids);
2091 
2092         convertExtension(json, result, FAILEDTODELETE_KEYS);
2093 
2094         return result;
2095     }
2096 
2097     // -----------------------------------------------------------------
2098 
2099     public static void convertExtension(ExtensionsData source, JSONObject target) {
2100         if (source == null || source.getExtensions() == null) {
2101             return;
2102         }
2103 
2104         for (CmisExtensionElement ext : source.getExtensions()) {
2105             if (ext.getChildren() != null && !ext.getChildren().isEmpty()) {
2106                 target.put(ext.getName(), convertExtensionList(ext.getChildren()));
2107             } else {
2108                 target.put(ext.getName(), ext.getValue());
2109             }
2110         }
2111     }
2112 
2113     private static JSONObject convertExtensionList(List<CmisExtensionElement> extensionList) {
2114         if (extensionList == null) {
2115             return null;
2116         }
2117 
2118         JSONObject result = new JSONObject();
2119 
2120         for (CmisExtensionElement ext : extensionList) {
2121             if (ext.getChildren() != null && !ext.getChildren().isEmpty()) {
2122                 result.put(ext.getName(), convertExtensionList(ext.getChildren()));
2123             } else {
2124                 result.put(ext.getName(), ext.getValue());
2125             }
2126         }
2127 
2128         return result;
2129     }
2130 
2131     @SuppressWarnings("unchecked")
2132     public static void convertExtension(Map<String, Object> source, ExtensionsData target, Set<String> cmisKeys) {
2133         if (source == null) {
2134             return;
2135         }
2136 
2137         List<CmisExtensionElement> extensions = null;
2138 
2139         for (Map.Entry<String, Object> element : source.entrySet()) {
2140             if (cmisKeys.contains(element.getKey())) {
2141                 continue;
2142             }
2143 
2144             if (extensions == null) {
2145                 extensions = new ArrayList<CmisExtensionElement>();
2146             }
2147 
2148             if (element.getValue() instanceof Map) {
2149                 extensions.add(new CmisExtensionElementImpl(null, element.getKey(), null,
2150                         convertExtension((Map<String, Object>) element.getValue())));
2151             } else if (element.getValue() instanceof List) {
2152                 extensions.add(new CmisExtensionElementImpl(null, element.getKey(), null,
2153                         convertExtension((List<Object>) element.getValue())));
2154             } else {
2155                 String value = (element.getValue() == null ? null : element.getValue().toString());
2156                 extensions.add(new CmisExtensionElementImpl(null, element.getKey(), null, value));
2157             }
2158         }
2159 
2160         target.setExtensions(extensions);
2161     }
2162 
2163     @SuppressWarnings("unchecked")
2164     public static List<CmisExtensionElement> convertExtension(Map<String, Object> map) {
2165         if (map == null) {
2166             return null;
2167         }
2168 
2169         List<CmisExtensionElement> extensions = new ArrayList<CmisExtensionElement>();
2170 
2171         for (Map.Entry<String, Object> element : map.entrySet()) {
2172             if (element.getValue() instanceof Map) {
2173                 extensions.add(new CmisExtensionElementImpl(null, element.getKey(), null,
2174                         convertExtension((Map<String, Object>) element.getValue())));
2175             } else if (element.getValue() instanceof List) {
2176                 extensions.add(new CmisExtensionElementImpl(null, element.getKey(), null,
2177                         convertExtension((List<Object>) element.getValue())));
2178             } else {
2179                 String value = (element.getValue() == null ? null : element.getValue().toString());
2180                 extensions.add(new CmisExtensionElementImpl(null, element.getKey(), null, value));
2181             }
2182         }
2183 
2184         return extensions;
2185     }
2186 
2187     @SuppressWarnings("unchecked")
2188     public static List<CmisExtensionElement> convertExtension(List<Object> list) {
2189         if (list == null) {
2190             return null;
2191         }
2192 
2193         List<CmisExtensionElement> extensions = new ArrayList<CmisExtensionElement>();
2194 
2195         int i = 0;
2196         for (Object element : list) {
2197             if (element instanceof Map) {
2198                 extensions.add(new CmisExtensionElementImpl(null, "" + i, null,
2199                         convertExtension((Map<String, Object>) element)));
2200             } else if (element instanceof List) {
2201                 extensions.add(new CmisExtensionElementImpl(null, "" + i, null,
2202                         convertExtension((List<Object>) element)));
2203             } else {
2204                 String value = (element == null ? null : element.toString());
2205                 extensions.add(new CmisExtensionElementImpl(null, "" + i, null, value));
2206             }
2207 
2208             i++;
2209         }
2210 
2211         return extensions;
2212     }
2213 
2214     // -----------------------------------------------------------------
2215 
2216     public static String getJSONStringValue(Object obj) {
2217         if (obj == null) {
2218             return null;
2219         }
2220 
2221         return obj.toString();
2222     }
2223 
2224     public static Object getJSONValue(Object value) {
2225         if (value instanceof GregorianCalendar) {
2226             return ((GregorianCalendar) value).getTimeInMillis();
2227         }
2228 
2229         return value;
2230     }
2231 
2232     public static Object getCMISValue(Object value, PropertyType propertyType) {
2233         if (value == null) {
2234             return null;
2235         }
2236 
2237         switch (propertyType) {
2238         case STRING:
2239         case ID:
2240         case HTML:
2241         case URI:
2242             if (value instanceof String) {
2243                 return value;
2244             }
2245             throw new CmisRuntimeException("Invalid String value!");
2246         case BOOLEAN:
2247             if (value instanceof Boolean) {
2248                 return value;
2249             }
2250             throw new CmisRuntimeException("Invalid Boolean value!");
2251         case INTEGER:
2252             if (value instanceof BigInteger) {
2253                 return (BigInteger) value;
2254             }
2255             throw new CmisRuntimeException("Invalid Integer value!");
2256         case DECIMAL:
2257             if (value instanceof BigDecimal) {
2258                 return (BigDecimal) value;
2259             }
2260             throw new CmisRuntimeException("Invalid Decimal value!");
2261         case DATETIME:
2262             if (value instanceof Number) {
2263                 GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
2264                 cal.setTimeInMillis(((Number) value).longValue());
2265                 return cal;
2266             }
2267             throw new CmisRuntimeException("Invalid DateTime value!");
2268         }
2269 
2270         throw new CmisRuntimeException("Unkown property type!");
2271     }
2272 
2273     public static JSONArray getJSONArrayFromList(List<?> list) {
2274         if (list == null) {
2275             return null;
2276         }
2277 
2278         JSONArray result = new JSONArray();
2279         result.addAll(list);
2280 
2281         return result;
2282     }
2283 
2284     public static String getJSONPropertyDataType(PropertyData<?> property) {
2285         if (property instanceof PropertyBoolean) {
2286             return PropertyType.BOOLEAN.value();
2287         } else if (property instanceof PropertyId) {
2288             return PropertyType.ID.value();
2289         } else if (property instanceof PropertyInteger) {
2290             return PropertyType.INTEGER.value();
2291         } else if (property instanceof PropertyDateTime) {
2292             return PropertyType.DATETIME.value();
2293         } else if (property instanceof PropertyDecimal) {
2294             return PropertyType.DECIMAL.value();
2295         } else if (property instanceof PropertyHtml) {
2296             return PropertyType.HTML.value();
2297         } else if (property instanceof PropertyString) {
2298             return PropertyType.STRING.value();
2299         } else if (property instanceof PropertyUri) {
2300             return PropertyType.URI.value();
2301         }
2302 
2303         return null;
2304     }
2305 
2306     public static void setIfNotNull(String name, Object obj, JSONObject json) {
2307         if (obj != null) {
2308             json.put(name, obj);
2309         }
2310     }
2311 
2312     @SuppressWarnings("unchecked")
2313     public static Map<String, Object> getMap(Object o) {
2314         if (o == null) {
2315             return null;
2316         }
2317 
2318         if (o instanceof Map) {
2319             return (Map<String, Object>) o;
2320         }
2321 
2322         throw new CmisRuntimeException("Expected a JSON object but found a "
2323                 + (o instanceof List ? "JSON array" : o.getClass().getSimpleName()) + ": " + o.toString());
2324     }
2325 
2326     @SuppressWarnings("unchecked")
2327     public static List<Object> getList(Object o) {
2328         if (o == null) {
2329             return null;
2330         }
2331 
2332         if (o instanceof List) {
2333             return (List<Object>) o;
2334         }
2335 
2336         throw new CmisRuntimeException("Expected a JSON array but found a "
2337                 + (o instanceof List ? "JSON object" : o.getClass().getSimpleName()) + ": " + o.toString());
2338     }
2339 
2340     public static String getString(Map<String, Object> json, String key) {
2341         Object obj = json.get(key);
2342         return obj == null ? null : obj.toString();
2343     }
2344 
2345     public static Boolean getBoolean(Map<String, Object> json, String key) {
2346         Object obj = json.get(key);
2347 
2348         if (obj instanceof Boolean) {
2349             return (Boolean) obj;
2350         }
2351 
2352         return null;
2353     }
2354 
2355     public static BigInteger getInteger(Map<String, Object> json, String key) {
2356         Object obj = json.get(key);
2357 
2358         if (obj instanceof BigInteger) {
2359             return (BigInteger) obj;
2360         }
2361 
2362         return null;
2363     }
2364 
2365     public static BigDecimal getDecimal(Map<String, Object> json, String key) {
2366         Object obj = json.get(key);
2367 
2368         if (obj instanceof BigDecimal) {
2369             return (BigDecimal) obj;
2370         }
2371 
2372         return null;
2373     }
2374 
2375     public static GregorianCalendar getDateTime(Map<String, Object> json, String key) {
2376         Object obj = json.get(key);
2377 
2378         if (obj instanceof Number) {
2379             GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
2380             cal.setTimeInMillis(((Number) obj).longValue());
2381             return cal;
2382         }
2383 
2384         return null;
2385     }
2386 
2387     @SuppressWarnings("unchecked")
2388     public static <T extends Enum<T>> T getEnum(Map<String, Object> json, String key, Class<T> clazz) {
2389         String value = getString(json, key);
2390         if (value == null) {
2391             return null;
2392         }
2393 
2394         try {
2395             Method m = clazz.getMethod("fromValue", String.class);
2396             return (T) m.invoke(null, value);
2397         } catch (Exception e) {
2398             if (e instanceof IllegalArgumentException) {
2399                 return null;
2400             } else {
2401                 throw new CmisRuntimeException("Could not parse enum value!", e);
2402             }
2403         }
2404     }
2405 }