content: /*
   * Licensed to the Apache Software Foundation (ASF) under one
   * or more contributor license agreements.  See the NOTICE file
   * distributed with this work for additional information
   * regarding copyright ownership.  The ASF licenses this file
   * to you under the Apache License, Version 2.0 (the
   * "License"); you may not use this file except in compliance
   * with the License.  You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing,
   * software distributed under the License is distributed on an
   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   * KIND, either express or implied.  See the License for the
   * specific language governing permissions and limitations
   * under the License.
   */
  package org.apache.chemistry.opencmis.commons.impl.xml;
  
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertNotNull;
  import static org.junit.Assert.assertTrue;
  
  import java.io.ByteArrayOutputStream;
  import java.io.StringWriter;
  import java.math.BigInteger;
  import java.util.ArrayList;
  import java.util.Collections;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  
  import javax.xml.stream.XMLStreamReader;
  import javax.xml.stream.XMLStreamWriter;
  
  import org.apache.chemistry.opencmis.commons.PropertyIds;
  import org.apache.chemistry.opencmis.commons.data.Ace;
  import org.apache.chemistry.opencmis.commons.data.ObjectData;
  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderContainer;
  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderData;
  import org.apache.chemistry.opencmis.commons.data.ObjectInFolderList;
  import org.apache.chemistry.opencmis.commons.data.ObjectList;
  import org.apache.chemistry.opencmis.commons.data.PropertyBoolean;
  import org.apache.chemistry.opencmis.commons.data.PropertyData;
  import org.apache.chemistry.opencmis.commons.data.PropertyDateTime;
  import org.apache.chemistry.opencmis.commons.data.PropertyDecimal;
  import org.apache.chemistry.opencmis.commons.data.PropertyHtml;
  import org.apache.chemistry.opencmis.commons.data.PropertyId;
  import org.apache.chemistry.opencmis.commons.data.PropertyInteger;
  import org.apache.chemistry.opencmis.commons.data.PropertyString;
  import org.apache.chemistry.opencmis.commons.data.PropertyUri;
  import org.apache.chemistry.opencmis.commons.data.RenditionData;
  import org.apache.chemistry.opencmis.commons.definitions.MutablePropertyDefinition;
  import org.apache.chemistry.opencmis.commons.definitions.PropertyDefinition;
  import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
  import org.apache.chemistry.opencmis.commons.enums.Action;
  import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
  import org.apache.chemistry.opencmis.commons.enums.ChangeType;
  import org.apache.chemistry.opencmis.commons.enums.CmisVersion;
  import org.apache.chemistry.opencmis.commons.enums.DateTimeFormat;
  import org.apache.chemistry.opencmis.commons.enums.PropertyType;
  import org.apache.chemistry.opencmis.commons.impl.JSONConverter;
  import org.apache.chemistry.opencmis.commons.impl.TypeCache;
  import org.apache.chemistry.opencmis.commons.impl.WSConverter;
  import org.apache.chemistry.opencmis.commons.impl.XMLConverter;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlEntryImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlListImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.AccessControlPrincipalDataImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.AllowableActionsImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.ChangeEventInfoDataImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.DocumentTypeDefinitionImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.FolderTypeDefinitionImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectDataImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderContainerImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderDataImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectInFolderListImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectListImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PolicyIdListImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertiesImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyBooleanDefinitionImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDateTimeDefinitionImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyDecimalDefinitionImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyHtmlDefinitionImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIdDefinitionImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyIntegerDefinitionImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyStringDefinitionImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.PropertyUriDefinitionImpl;
  import org.apache.chemistry.opencmis.commons.impl.dataobjects.RenditionDataImpl;
  import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisObjectInFolderContainerType;
  import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisObjectInFolderListType;
  import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisObjectListType;
  import org.apache.chemistry.opencmis.commons.impl.jaxb.CmisObjectType;
  import org.apache.chemistry.opencmis.commons.impl.json.JSONObject;
  import org.apache.chemistry.opencmis.commons.impl.json.parser.JSONParser;
  import org.junit.Test;
  
  public class ObjectConvertTest extends AbstractXMLConverterTest {
  
      @Test
      public void testObjectData() throws Exception {
          // run the test a few times with different values
          for (int i = 0; i < 10; i++) {
              ObjectDataImpl data10 = createObjectData(true, CmisVersion.CMIS_1_0, true, true);
              assertObjectData10(data10, true);
  
              ObjectDataImpl data11 = createObjectData(true, CmisVersion.CMIS_1_1, true, true);
              assertObjectData11(data11, true);
  
              ObjectDataImpl data11j = createObjectData(true, CmisVersion.CMIS_1_1, true, true);
              assertJsonObjectData11(data11j);
              assertJsonObjectData11Succinct(data11j);
          }
      }
  
      @Test
      public void testChildren() throws Exception {
          // run the test a few times with different values
          for (int i = 0; i < 5; i++) {
              List<ObjectData> list1 = new ArrayList<ObjectData>();
              List<ObjectInFolderData> list2 = new ArrayList<ObjectInFolderData>();
  
              for (int j = 0; j < randomInt(10) + 10; j++) {
                  ObjectData data = createObjectData(true, CmisVersion.CMIS_1_1, false, false);
  
                  list1.add(data);
  
                  ObjectInFolderDataImpl dataInFolder = new ObjectInFolderDataImpl(data);
                  dataInFolder.setPathSegment(randomString());
                  list2.add(dataInFolder);
              }
  
              ObjectListImpl children1 = new ObjectListImpl();
              children1.setObjects(list1);
  
              ObjectInFolderListImpl children2 = new ObjectInFolderListImpl();
              children2.setObjects(list2);
  
              if (randomBoolean()) {
                  children1.setNumItems(BigInteger.valueOf(list1.size()));
                  children1.setHasMoreItems(false);
                  children2.setNumItems(BigInteger.valueOf(list2.size()));
                  children2.setHasMoreItems(false);
              } else {
                  children1.setNumItems(BigInteger.valueOf(list1.size() + 1 + randomInt(99)));
                  children1.setHasMoreItems(true);
                  children2.setNumItems(BigInteger.valueOf(list2.size() + 1 + randomInt(99)));
                  children2.setHasMoreItems(true);
              }
  
              assertObjectList(children1, children2);
          }
      }
  
      @Test
      public void testDescendants() throws Exception {
          // run the test a few times with different values
          for (int i = 0; i < 5; i++) {
              ObjectInFolderContainer container = createObjectInFolderContainer(randomInt(7) + 2);
              assertObjectContainer(container);
          }
      }
  
      private ObjectInFolderContainer createObjectInFolderContainer(int level) {
          ObjectInFolderContainerImpl result = new ObjectInFolderContainerImpl();
  
          ObjectInFolderDataImpl dataInFolder = new ObjectInFolderDataImpl(createObjectData(true, CmisVersion.CMIS_1_1,
                  false, false));
          dataInFolder.setPathSegment(randomString());
          result.setObject(dataInFolder);
  
          if (level > 0) {
              List<ObjectInFolderContainer> children = new ArrayList<ObjectInFolderContainer>();
              for (int i = 0; i < randomInt(3); i++) {
                  children.add(createObjectInFolderContainer(level - 1));
              }
  
              result.setChildren(children);
          }
  
          return result;
      }
  
      protected ObjectDataImpl createObjectData(boolean addRelationships, CmisVersion cmisVersion, boolean withChanges,
              boolean withExtensions) {
          ObjectDataImpl result = new ObjectDataImpl();
  
          // properties
          PropertiesImpl properties = new PropertiesImpl();
          properties.addProperty(createIdPropertyData(PropertyIds.BASE_TYPE_ID, BaseTypeId.CMIS_DOCUMENT.value()));
          properties.addProperty(createIdPropertyData(PropertyIds.OBJECT_ID, randomString()));
          properties.addProperty(createIdPropertyData(PropertyIds.OBJECT_TYPE_ID, randomString()));
          properties.addProperty(createPropertyData(PropertyType.BOOLEAN, 0));
          properties.addProperty(createPropertyData(PropertyType.BOOLEAN, 1));
          properties.addProperty(createPropertyData(PropertyType.BOOLEAN, randomInt(8) + 2));
          properties.addProperty(createPropertyData(PropertyType.DATETIME, 0));
          properties.addProperty(createPropertyData(PropertyType.DATETIME, 1));
          properties.addProperty(createPropertyData(PropertyType.DATETIME, randomInt(8) + 2));
          properties.addProperty(createPropertyData(PropertyType.DECIMAL, 0));
          properties.addProperty(createPropertyData(PropertyType.DECIMAL, 1));
          properties.addProperty(createPropertyData(PropertyType.DECIMAL, randomInt(8) + 2));
          properties.addProperty(createPropertyData(PropertyType.HTML, 0));
          properties.addProperty(createPropertyData(PropertyType.HTML, 1));
          properties.addProperty(createPropertyData(PropertyType.HTML, randomInt(8) + 2));
          properties.addProperty(createPropertyData(PropertyType.ID, 0));
          properties.addProperty(createPropertyData(PropertyType.ID, 1));
          properties.addProperty(createPropertyData(PropertyType.ID, randomInt(8) + 2));
          properties.addProperty(createPropertyData(PropertyType.INTEGER, 0));
          properties.addProperty(createPropertyData(PropertyType.INTEGER, 1));
          properties.addProperty(createPropertyData(PropertyType.INTEGER, randomInt(8) + 2));
          properties.addProperty(createPropertyData(PropertyType.STRING, 0));
          properties.addProperty(createPropertyData(PropertyType.STRING, 1));
          properties.addProperty(createPropertyData(PropertyType.STRING, randomInt(8) + 2));
          properties.addProperty(createPropertyData(PropertyType.URI, 0));
          properties.addProperty(createPropertyData(PropertyType.URI, 1));
          properties.addProperty(createPropertyData(PropertyType.URI, randomInt(8) + 2));
          if (withExtensions) {
              properties.setExtensions(createExtensions(3));
          }
          result.setProperties(properties);
  
          // allowable actions
          AllowableActionsImpl allowableActions = new AllowableActionsImpl();
          Set<Action> actions = new HashSet<Action>();
          for (Action action : Action.values()) {
              if (action == Action.CAN_CREATE_ITEM && cmisVersion == CmisVersion.CMIS_1_0) {
                  continue;
              }
              actions.add(action);
          }
          allowableActions.setAllowableActions(actions);
          result.setAllowableActions(allowableActions);
  
          // relationships
          if (addRelationships) {
              List<ObjectData> relationships = new ArrayList<ObjectData>();
              for (int i = 0; i < randomInt(4) + 1; i++) {
                  relationships.add(createObjectData(false, cmisVersion, withChanges, withExtensions));
              }
              result.setRelationships(relationships);
          }
  
          // change event info
          if (withChanges) {
              ChangeEventInfoDataImpl changeEventInfo = new ChangeEventInfoDataImpl();
              changeEventInfo.setChangeTime(randomDateTime());
              changeEventInfo.setChangeType(randomEnum(ChangeType.class));
              result.setChangeEventInfo(changeEventInfo);
          }
  
          // ACL
          AccessControlListImpl acl = new AccessControlListImpl();
          List<Ace> aces = new ArrayList<Ace>();
          for (int i = 0; i < randomInt(9) + 1; i++) {
              AccessControlEntryImpl ace = new AccessControlEntryImpl();
              List<String> permissions = new ArrayList<String>();
              for (int j = 0; j < randomInt(4) + 1; j++) {
                  permissions.add(randomString());
              }
              ace.setPermissions(permissions);
              ace.setDirect(randomBoolean());
              ace.setPrincipal(new AccessControlPrincipalDataImpl(randomString()));
              aces.add(ace);
          }
          acl.setAces(aces);
          result.setAcl(acl);
  
          result.setIsExactAcl(randomBoolean());
  
          // policy ids
          List<String> pIds = new ArrayList<String>();
          for (int i = 0; i < randomInt(9) + 1; i++) {
              pIds.add(randomString());
          }
          PolicyIdListImpl policyList = new PolicyIdListImpl();
          policyList.setPolicyIds(pIds);
          result.setPolicyIds(policyList);
  
          // renditions
          List<RenditionData> renditions = new ArrayList<RenditionData>();
          for (int i = 0; i < randomInt(4) + 1; i++) {
              RenditionDataImpl rendition = new RenditionDataImpl();
              rendition.setKind(randomString());
              rendition.setMimeType(randomString());
              rendition.setRenditionDocumentId(randomString());
              rendition.setStreamId(randomString());
              rendition.setTitle(randomString());
              rendition.setBigLength(randomInteger());
              rendition.setBigHeight(randomInteger());
              rendition.setBigWidth(randomInteger());
  
              renditions.add(rendition);
          }
          result.setRenditions(renditions);
  
          // extensions
          if (withExtensions) {
              result.setExtensions(createExtensions(5));
          }
  
          return result;
      }
  
      // --- asserts ---
  
      protected void assertObjectData10(ObjectData data, boolean validate) throws Exception {
          assertXmlObjectData10(data, validate);
          assertWsObjectData10(data);
      }
  
      protected void assertXmlObjectData10(ObjectData data, boolean validate) throws Exception {
          ByteArrayOutputStream out = new ByteArrayOutputStream();
  
          XMLStreamWriter writer = createWriter(out);
          XMLConverter.writeObject(writer, CmisVersion.CMIS_1_0, TEST_NAMESPACE, data);
          closeWriter(writer);
  
          byte[] xml = out.toByteArray();
  
          if (validate) {
              validate(xml, CmisVersion.CMIS_1_0);
          }
  
          XMLStreamReader parser = createParser(xml);
          ObjectData result = XMLConverter.convertObject(parser);
          closeParser(parser);
  
          assertNotNull(result);
          assertDataObjectsEquals("ObjectData", data, result, null);
          assertNotNull(result.getExtensions());
      }
  
      protected void assertWsObjectData10(ObjectData data) throws Exception {
          CmisObjectType ws = WSConverter.convert(data, CmisVersion.CMIS_1_0);
  
          ObjectData result = WSConverter.convert(ws);
  
          assertNotNull(result);
          assertDataObjectsEquals("ObjectData", data, result, null);
          assertNotNull(result.getExtensions());
      }
  
      protected void assertObjectData11(ObjectData data, boolean validate) throws Exception {
          assertXmlObjectData11(data, validate);
          assertWsObjectData11(data);
      }
  
      protected void assertXmlObjectData11(ObjectData data, boolean validate) throws Exception {
          ByteArrayOutputStream out = new ByteArrayOutputStream();
  
          XMLStreamWriter writer = createWriter(out);
          XMLConverter.writeObject(writer, CmisVersion.CMIS_1_1, TEST_NAMESPACE, data);
          closeWriter(writer);
  
          byte[] xml = out.toByteArray();
  
          if (validate) {
              validate(xml, CmisVersion.CMIS_1_1);
          }
  
          XMLStreamReader parser = createParser(xml);
          ObjectData result = XMLConverter.convertObject(parser);
          closeParser(parser);
  
          assertNotNull(result);
          assertDataObjectsEquals("ObjectData", data, result, null);
          assertNotNull(result.getExtensions());
      }
  
      protected void assertWsObjectData11(ObjectData data) throws Exception {
          CmisObjectType ws = WSConverter.convert(data, CmisVersion.CMIS_1_1);
  
          ObjectData result = WSConverter.convert(ws);
  
          assertNotNull(result);
          assertDataObjectsEquals("ObjectData", data, result, null);
          assertNotNull(result.getExtensions());
      }
  
      protected void assertJsonObjectData11(ObjectData data) throws Exception {
          TypeCache typeCache = null;
  
          StringWriter sw = new StringWriter();
  
          JSONObject jsonObject = JSONConverter.convert(data, typeCache, JSONConverter.PropertyMode.CHANGE, false,
                  DateTimeFormat.SIMPLE);
          jsonObject.writeJSONString(sw);
  
          // test toJSONString()
          assertEquals(sw.toString(), jsonObject.toJSONString());
  
          Object json = (new JSONParser()).parse(sw.toString());
          assertTrue(json instanceof Map<?, ?>);
          @SuppressWarnings("unchecked")
          ObjectData result = JSONConverter.convertObject((Map<String, Object>) json, typeCache);
  
          assertNotNull(result);
          assertDataObjectsEquals("ObjectData", data, result, Collections.singleton("getExtensions"));
          assertExtensionsEquals(data.getExtensions(), result.getExtensions());
      }
  
      protected void assertJsonObjectData11Succinct(ObjectData data) throws Exception {
          TypeCache typeCache = new TestTypeCache(data);
  
          StringWriter sw = new StringWriter();
  
          JSONObject jsonObject = JSONConverter.convert(data, typeCache, JSONConverter.PropertyMode.CHANGE, true,
                  DateTimeFormat.SIMPLE);
          jsonObject.writeJSONString(sw);
  
          // test toJSONString()
          assertEquals(sw.toString(), jsonObject.toJSONString());
  
          Object json = (new JSONParser()).parse(sw.toString());
          assertTrue(json instanceof Map<?, ?>);
          @SuppressWarnings("unchecked")
          ObjectData result = JSONConverter.convertObject((Map<String, Object>) json, typeCache);
  
          assertNotNull(result);
  
          Set<String> ignoreMethods = new HashSet<String>();
          ignoreMethods.add("getProperties");
          ignoreMethods.add("getExtensions");
  
          assertDataObjectsEquals("ObjectData", data, result, ignoreMethods);
          assertExtensionsEquals(data.getExtensions(), result.getExtensions());
  
          assertEquals(data.getProperties().getPropertyList().size(), result.getProperties().getPropertyList().size());
  
          for (PropertyData<?> prop : data.getProperties().getPropertyList()) {
              assertTrue(result.getProperties().getProperties().containsKey(prop.getId()));
  
              Object value = data.getProperties().getProperties().get(prop.getId()).getFirstValue();
              if (value instanceof String) {
                  assertEquals(value, result.getProperties().getProperties().get(prop.getId()).getFirstValue());
              }
          }
      }
  
      protected void assertObjectList(ObjectList children1, ObjectInFolderList children2) throws Exception {
          assertWsObjectList(children1);
          assertJsonObjectList(children1);
          assertWsObjectInFolderList(children2);
          assertJsonObjectInFolderList(children2);
      }
  
      protected void assertWsObjectList(ObjectList children) throws Exception {
          CmisObjectListType ws = WSConverter.convert(children, CmisVersion.CMIS_1_1);
  
          ObjectList result = WSConverter.convert(ws);
  
          assertNotNull(result);
          assertDataObjectsEquals("ObjectList", children, result, null);
      }
  
      protected void assertJsonObjectList(ObjectList children) throws Exception {
          TypeCache typeCache = null;
  
          StringWriter sw = new StringWriter();
  
          JSONConverter.convert(children, typeCache, JSONConverter.PropertyMode.CHANGE, false, DateTimeFormat.SIMPLE)
                  .writeJSONString(sw);
  
          Object json = (new JSONParser()).parse(sw.toString());
          assertTrue(json instanceof Map<?, ?>);
          @SuppressWarnings("unchecked")
          ObjectList result = JSONConverter.convertObjectList((Map<String, Object>) json, typeCache, false);
  
          assertNotNull(result);
          assertDataObjectsEquals("ObjectList", children, result, null);
      }
  
      protected void assertWsObjectInFolderList(ObjectInFolderList children) throws Exception {
          CmisObjectInFolderListType ws = WSConverter.convert(children, CmisVersion.CMIS_1_1);
  
          ObjectInFolderList result = WSConverter.convert(ws);
  
          assertNotNull(result);
          assertDataObjectsEquals("ObjectInFolderList", children, result, null);
      }
  
      protected void assertJsonObjectInFolderList(ObjectInFolderList children) throws Exception {
          TypeCache typeCache = null;
  
          StringWriter sw = new StringWriter();
  
          JSONConverter.convert(children, typeCache, false, DateTimeFormat.SIMPLE).writeJSONString(sw);
  
          Object json = (new JSONParser()).parse(sw.toString());
          assertTrue(json instanceof Map<?, ?>);
          @SuppressWarnings("unchecked")
          ObjectInFolderList result = JSONConverter.convertObjectInFolderList((Map<String, Object>) json, typeCache);
  
          assertNotNull(result);
          assertDataObjectsEquals("ObjectInFolderList", children, result, null);
      }
  
      protected void assertObjectContainer(ObjectInFolderContainer container) throws Exception {
          assertWsObjectContainer(container);
          assertJsonObjectContainer(container);
      }
  
      protected void assertWsObjectContainer(ObjectInFolderContainer container) {
          CmisObjectInFolderContainerType ws = WSConverter.convert(container, CmisVersion.CMIS_1_1);
  
          ObjectInFolderContainer result = WSConverter.convert(ws);
  
          assertNotNull(result);
          assertDataObjectsEquals("ObjectContainer", container, result, null);
      }
  
      protected void assertJsonObjectContainer(ObjectInFolderContainer container) throws Exception {
          TypeCache typeCache = null;
  
          StringWriter sw = new StringWriter();
  
          JSONConverter.convert(container, typeCache, false, DateTimeFormat.EXTENDED).writeJSONString(sw);
  
          Object json = (new JSONParser()).parse(sw.toString());
          assertTrue(json instanceof Map<?, ?>);
          @SuppressWarnings("unchecked")
          ObjectInFolderContainer result = JSONConverter.convertDescendant((Map<String, Object>) json, typeCache);
  
          assertNotNull(result);
          assertDataObjectsEquals("ObjectContainer", container, result, null);
      }
  
      private static class TestTypeCache implements TypeCache {
  
          private DocumentTypeDefinitionImpl objectType;
  
          public TestTypeCache(ObjectData data) {
              objectType = new DocumentTypeDefinitionImpl();
  
              for (PropertyData<?> prop : data.getProperties().getPropertyList()) {
                  MutablePropertyDefinition<?> propDef;
  
                  if (prop instanceof PropertyString) {
                      propDef = new PropertyStringDefinitionImpl();
                  } else if (prop instanceof PropertyId) {
                      propDef = new PropertyIdDefinitionImpl();
                  } else if (prop instanceof PropertyBoolean) {
                      propDef = new PropertyBooleanDefinitionImpl();
                  } else if (prop instanceof PropertyInteger) {
                      propDef = new PropertyIntegerDefinitionImpl();
                  } else if (prop instanceof PropertyDateTime) {
                      propDef = new PropertyDateTimeDefinitionImpl();
                  } else if (prop instanceof PropertyDecimal) {
                      propDef = new PropertyDecimalDefinitionImpl();
                  } else if (prop instanceof PropertyHtml) {
                      propDef = new PropertyHtmlDefinitionImpl();
                  } else if (prop instanceof PropertyUri) {
                      propDef = new PropertyUriDefinitionImpl();
                  } else {
                      throw new IllegalArgumentException("Invalid data type!");
                  }
  
                  propDef.setId(prop.getId());
                  propDef.setDisplayName(prop.getDisplayName());
                  propDef.setLocalName(prop.getLocalName());
                  propDef.setQueryName(prop.getQueryName());
  
                  objectType.addPropertyDefinition(propDef);
              }
          }
  
          @Override
          public TypeDefinition getTypeDefinition(String typeId) {
              if ("cmis:folder".equals(typeId)) {
                  return new FolderTypeDefinitionImpl();
              } else if ("cmis:document".equals(typeId)) {
                  return new DocumentTypeDefinitionImpl();
              } else {
                  return objectType;
              }
          }
  
          @Override
          public TypeDefinition reloadTypeDefinition(String typeId) {
              return null;
          }
  
          @Override
          public TypeDefinition getTypeDefinitionForObject(String objectId) {
              return null;
          }
  
          @Override
          public PropertyDefinition<?> getPropertyDefinition(String propId) {
              return null;
          }
      }
  }
  