| /* |
| * 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.inmemory.query; |
| |
| import static org.apache.chemistry.opencmis.inmemory.UnitTestTypeSystemCreator.COMPLEX_TYPE; |
| import static org.apache.chemistry.opencmis.inmemory.UnitTestTypeSystemCreator.FOLDER_TYPE; |
| import static org.apache.chemistry.opencmis.inmemory.UnitTestTypeSystemCreator.PROP_ID_BOOLEAN; |
| import static org.apache.chemistry.opencmis.inmemory.UnitTestTypeSystemCreator.PROP_ID_DATETIME; |
| import static org.apache.chemistry.opencmis.inmemory.UnitTestTypeSystemCreator.PROP_ID_DECIMAL; |
| import static org.apache.chemistry.opencmis.inmemory.UnitTestTypeSystemCreator.PROP_ID_INT; |
| import static org.apache.chemistry.opencmis.inmemory.UnitTestTypeSystemCreator.PROP_ID_STRING; |
| import static org.apache.chemistry.opencmis.inmemory.UnitTestTypeSystemCreator.PROP_ID_STRING_MULTI_VALUE; |
| import static org.apache.chemistry.opencmis.inmemory.UnitTestTypeSystemCreator.SECONDARY_INTEGER_PROP; |
| import static org.apache.chemistry.opencmis.inmemory.UnitTestTypeSystemCreator.SECONDARY_STRING_PROP; |
| import static org.apache.chemistry.opencmis.inmemory.UnitTestTypeSystemCreator.SECONDARY_TYPE; |
| import static org.apache.chemistry.opencmis.inmemory.UnitTestTypeSystemCreator.VERSION_PROPERTY_ID; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.fail; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.IOException; |
| import java.math.BigDecimal; |
| import java.math.BigInteger; |
| import java.util.ArrayList; |
| import java.util.GregorianCalendar; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.TimeZone; |
| |
| import org.apache.chemistry.opencmis.commons.PropertyIds; |
| import org.apache.chemistry.opencmis.commons.data.Acl; |
| import org.apache.chemistry.opencmis.commons.data.ContentStream; |
| import org.apache.chemistry.opencmis.commons.data.ExtensionsData; |
| import org.apache.chemistry.opencmis.commons.data.ObjectData; |
| import org.apache.chemistry.opencmis.commons.data.Properties; |
| import org.apache.chemistry.opencmis.commons.data.PropertyData; |
| import org.apache.chemistry.opencmis.commons.enums.BaseTypeId; |
| import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships; |
| import org.apache.chemistry.opencmis.commons.enums.VersioningState; |
| import org.apache.chemistry.opencmis.commons.impl.dataobjects.BindingsObjectFactoryImpl; |
| import org.apache.chemistry.opencmis.commons.spi.BindingsObjectFactory; |
| import org.apache.chemistry.opencmis.commons.spi.Holder; |
| import org.apache.chemistry.opencmis.commons.spi.ObjectService; |
| import org.apache.chemistry.opencmis.commons.spi.VersioningService; |
| import org.apache.chemistry.opencmis.inmemory.UnitTestTypeSystemCreator; |
| import org.apache.chemistry.opencmis.inmemory.storedobj.impl.ContentStreamDataImpl; |
| |
| /** |
| * Utility class that fills the in-memory repository with some test objects that |
| * can be used for query |
| * |
| * This class uses the following data for query testing. We have one |
| * document type "ComplexType" and one folder type "FolderType" The |
| * document type has one property of each of the types boolean, integer, |
| * decimal, string and datetime. id, uri and html are treated like a |
| * string and do not make a difference. |
| * |
| * String Int Double DateTime Boolean |
| * ------------------------------------------------ Alpha -100 -1.6E-5 |
| * 23.05.1618 true Beta -50 -4.0E24 08.05.1945 false Gamma 0 3.141592 |
| * (now) true Delta 50 1.23456E-6 20.01.2038 true Epsilon 100 1.2345E12 |
| * 14.07.2345 false |
| * |
| * For folder and tree tests this series is put in each of the three |
| * test folders |
| */ |
| public class QueryTestDataCreator { |
| |
| private final BindingsObjectFactory fFactory = new BindingsObjectFactoryImpl(); |
| private final String rootFolderId; |
| private final String repositoryId; |
| private final ObjectService fObjSvc; |
| private final VersioningService fVerSvc; |
| private String doc1, doc2, doc3, doc4, doc5; |
| private String folder1; |
| private String folder2; |
| private String folder11; |
| private static final TimeZone TZ = TimeZone.getTimeZone("Zulu"); |
| |
| public QueryTestDataCreator(String repositoryId, String rootFolderId, ObjectService objSvc, VersioningService verSvc) { |
| this.rootFolderId = rootFolderId; |
| this.repositoryId = repositoryId; |
| fObjSvc = objSvc; |
| fVerSvc = verSvc; |
| } |
| |
| public String getFolder1() { |
| return folder1; |
| } |
| |
| public String getFolder2() { |
| return folder2; |
| } |
| |
| public String getFolder11() { |
| return folder11; |
| } |
| |
| public void createBasicTestData() { |
| createTestFolders(); |
| createBasicTestDocuments(); |
| } |
| |
| @SuppressWarnings("serial") |
| public void createBasicTestDocuments() { |
| |
| final GregorianCalendar gc1 = new GregorianCalendar(TZ); |
| gc1.clear(); |
| gc1.set(1945, 4, 8); |
| |
| final Map<String, Object> propertyMap1 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_STRING, "Alpha"); |
| put(PROP_ID_INT, Integer.valueOf(-100)); |
| put(PROP_ID_DECIMAL, Double.valueOf(-4.0E24d)); |
| put(PROP_ID_DATETIME, gc1); |
| put(PROP_ID_BOOLEAN, true); |
| } |
| }; |
| ContentStream content1 = createContent("I have a cat."); |
| doc1 = createDocument("alpha", rootFolderId, COMPLEX_TYPE, propertyMap1, content1); |
| assertNotNull(doc1); |
| |
| final GregorianCalendar gc2 = new GregorianCalendar(TZ); |
| gc2.clear(); |
| gc2.set(1618, 4, 23); |
| |
| final Map<String, Object> propertyMap2 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_STRING, "Beta"); |
| put(PROP_ID_INT, Integer.valueOf(-50)); |
| put(PROP_ID_DECIMAL, Double.valueOf(-1.6E-5d)); |
| put(PROP_ID_DATETIME, gc2); |
| put(PROP_ID_BOOLEAN, false); |
| } |
| }; |
| ContentStream content2 = createContent("I have a cat named Kitty Katty."); |
| doc2 = createDocument("beta", rootFolderId, COMPLEX_TYPE, propertyMap2, content2); |
| assertNotNull(doc2); |
| |
| final Map<String, Object> propertyMap3 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_STRING, "Gamma"); |
| put(PROP_ID_INT, Integer.valueOf(0)); |
| put(PROP_ID_DECIMAL, Double.valueOf(Math.PI)); |
| put(PROP_ID_DATETIME, new GregorianCalendar(TZ)); |
| put(PROP_ID_BOOLEAN, true); |
| } |
| }; |
| |
| ContentStream content3 = createContent("I have a dog."); |
| doc3 = createDocument("gamma", rootFolderId, COMPLEX_TYPE, propertyMap3, content3); |
| assertNotNull(doc3); |
| |
| final GregorianCalendar gc4 = new GregorianCalendar(TZ); |
| gc4.clear(); |
| gc4.set(2038, 0, 20); |
| |
| final Map<String, Object> propertyMap4 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_STRING, "Delta"); |
| put(PROP_ID_INT, Integer.valueOf(50)); |
| put(PROP_ID_DECIMAL, Double.valueOf(1.23456E-6)); |
| put(PROP_ID_DATETIME, gc4); |
| put(PROP_ID_BOOLEAN, true); |
| } |
| }; |
| ContentStream content4 = createContent("I have a cat and a dog."); |
| doc4 = createDocument("delta", rootFolderId, COMPLEX_TYPE, propertyMap4, content4); |
| assertNotNull(doc4); |
| |
| final GregorianCalendar gc5 = new GregorianCalendar(TZ); |
| gc5.clear(); |
| gc5.set(2345, 6, 14); |
| |
| final Map<String, Object> propertyMap5 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_STRING, "Epsilon"); |
| put(PROP_ID_INT, Integer.valueOf(100)); |
| put(PROP_ID_DECIMAL, Double.valueOf(1.2345E12)); |
| put(PROP_ID_DATETIME, gc5); |
| put(PROP_ID_BOOLEAN, false); |
| } |
| }; |
| ContentStream content5 = createContent("I hate having pets."); |
| doc5 = createDocument("epsilon", rootFolderId, COMPLEX_TYPE, propertyMap5, content5); |
| assertNotNull(doc5); |
| |
| final Map<String, Object> propertyMap6 = new HashMap<String, Object>(); |
| doc4 = createDocument("John's Document", rootFolderId, BaseTypeId.CMIS_DOCUMENT.value(), propertyMap6, null); |
| assertNotNull(doc4); |
| |
| } |
| |
| @SuppressWarnings("serial") |
| public void createMultiValueDocuments() { |
| final List<String> mvProps1 = new ArrayList<String>() { |
| { |
| add("red"); |
| add("green"); |
| add("blue"); |
| } |
| }; |
| |
| final Map<String, Object> propertyMap1 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_STRING_MULTI_VALUE, mvProps1); |
| put(PROP_ID_INT, Integer.valueOf(100)); |
| } |
| }; |
| createDocument("mv-alpha", rootFolderId, COMPLEX_TYPE, propertyMap1); |
| |
| final List<String> mvProps2 = new ArrayList<String>() { |
| { |
| add("red"); |
| add("pink"); |
| add("violet"); |
| } |
| }; |
| |
| final Map<String, Object> propertyMap2 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_STRING_MULTI_VALUE, mvProps2); |
| put(PROP_ID_INT, Integer.valueOf(200)); |
| } |
| }; |
| createDocument("mv-beta", rootFolderId, COMPLEX_TYPE, propertyMap2); |
| } |
| |
| @SuppressWarnings("serial") |
| public void createTestFolders() { |
| final Map<String, Object> propertyMap1 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_INT, Integer.valueOf(1234)); |
| put(PROP_ID_STRING, "ABCD"); |
| } |
| }; |
| folder1 = createFolder("Folder 1", rootFolderId, FOLDER_TYPE, propertyMap1); |
| |
| final Map<String, Object> propertyMap2 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_INT, Integer.valueOf(-2345)); |
| put(PROP_ID_STRING, "defg"); |
| } |
| }; |
| folder2 = createFolder("Folder 2", rootFolderId, FOLDER_TYPE, propertyMap2); |
| |
| final Map<String, Object> propertyMap3 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_INT, Integer.valueOf(123)); |
| put(PROP_ID_STRING, "ZZZZ"); |
| } |
| }; |
| folder11 = createFolder("Folder 11", folder1, FOLDER_TYPE, propertyMap3); |
| } |
| |
| @SuppressWarnings("serial") |
| public void createNullTestDocument() { |
| |
| final Map<String, Object> propertyMap1 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_STRING, "DocumentWithNulls"); |
| } |
| }; |
| createDocument("nulldoc", rootFolderId, COMPLEX_TYPE, propertyMap1); |
| } |
| |
| @SuppressWarnings("serial") |
| public void createLikeTestDocuments(String folderId) { |
| |
| final Map<String, Object> propertyMap1 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_STRING, "ABCDEF"); |
| } |
| }; |
| createDocument("likedoc1", folderId, COMPLEX_TYPE, propertyMap1); |
| |
| final Map<String, Object> propertyMap2 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_STRING, "ABC123"); |
| } |
| }; |
| createDocument("likedoc2", folderId, COMPLEX_TYPE, propertyMap2); |
| |
| final Map<String, Object> propertyMap3 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_STRING, "123ABC"); |
| } |
| }; |
| createDocument("likedoc3", folderId, COMPLEX_TYPE, propertyMap3); |
| } |
| |
| @SuppressWarnings("serial") |
| public String createVersionedDocument() { |
| final Map<String, Object> propertyMap1 = new HashMap<String, Object>() { |
| { |
| put(VERSION_PROPERTY_ID, "ver123"); |
| } |
| }; |
| |
| String verIdV1 = createDocument("verdoc1", rootFolderId, UnitTestTypeSystemCreator.VERSIONED_TYPE, |
| propertyMap1, VersioningState.MAJOR, null); |
| ObjectData version = fObjSvc.getObject(repositoryId, verIdV1, "*", false, IncludeRelationships.NONE, null, |
| false, false, null); |
| |
| // get version series id |
| String verIdSer = (String) version.getProperties().getProperties().get(PropertyIds.VERSION_SERIES_ID) |
| .getFirstValue(); |
| |
| // create second version |
| final Map<String, Object> propertyMap2 = new HashMap<String, Object>() { |
| { |
| put(VERSION_PROPERTY_ID, "ver456"); |
| } |
| }; |
| Properties propsV2 = createDocumentProperties(null, null, propertyMap2); |
| |
| Holder<String> idHolder = new Holder<String>(verIdV1); |
| Holder<Boolean> contentCopied = new Holder<Boolean>(false); |
| fVerSvc.checkOut(repositoryId, idHolder, null, contentCopied); |
| |
| idHolder = new Holder<String>(verIdV1); |
| // Test check-in and pass content and properties |
| String checkinComment = "Here comes next version."; |
| fVerSvc.checkIn(repositoryId, idHolder, true, propsV2, null, checkinComment, null, null, null, null); |
| // String verIdV2 = idHolder.getValue(); |
| return verIdSer; |
| } |
| |
| @SuppressWarnings("serial") |
| public void createSecondaryTestDocuments() { |
| |
| final int intPropVal1 = 100; |
| final String stringPropVal1 = "Secondary Property Value"; |
| final int intPropVal2 = 200; |
| final String stringPropVal2 = "Secondary String"; |
| |
| final GregorianCalendar gc1 = new GregorianCalendar(TZ); |
| gc1.clear(); |
| gc1.set(1945, 4, 8); |
| |
| final Map<String, Object> propertyMap1 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_STRING, "Secondary"); |
| put(PROP_ID_INT, Integer.valueOf(-100)); |
| put(PROP_ID_DECIMAL, Double.valueOf(-4.0E24d)); |
| put(PROP_ID_DATETIME, gc1); |
| put(PROP_ID_BOOLEAN, true); |
| put(SECONDARY_STRING_PROP, stringPropVal1); |
| put(SECONDARY_INTEGER_PROP, intPropVal1); |
| put(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, SECONDARY_TYPE); |
| } |
| }; |
| ContentStream content1 = createContent("Some more content."); |
| doc1 = createDocument("docwithsecondary", rootFolderId, COMPLEX_TYPE, propertyMap1, content1); |
| assertNotNull(doc1); |
| |
| final Map<String, Object> propertyMap2 = new HashMap<String, Object>() { |
| { |
| put(PROP_ID_STRING, "Secondary 2"); |
| put(PROP_ID_INT, Integer.valueOf(123)); |
| put(PROP_ID_DECIMAL, Double.valueOf(1.23E24d)); |
| put(PROP_ID_BOOLEAN, false); |
| put(SECONDARY_STRING_PROP, stringPropVal2); |
| put(SECONDARY_INTEGER_PROP, intPropVal2); |
| put(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, SECONDARY_TYPE); |
| } |
| }; |
| ContentStream content2 = createContent("Even still some more content."); |
| doc1 = createDocument("docwithsecondary2", rootFolderId, COMPLEX_TYPE, propertyMap2, content2); |
| assertNotNull(doc1); |
| } |
| |
| private String createFolder(String folderName, String parentFolderId, String typeId, Map<String, Object> properties) { |
| Properties props = createFolderProperties(folderName, typeId, properties); |
| String id = null; |
| try { |
| id = fObjSvc.createFolder(repositoryId, props, parentFolderId, null, null, null, null); |
| if (null == id) { |
| fail("createFolder failed."); |
| } |
| } catch (Exception e) { |
| fail("createFolder() failed with exception: " + e); |
| } |
| return id; |
| } |
| |
| private String createDocument(String name, String folderId, String typeId, Map<String, Object> properties) { |
| return createDocument(name, folderId, typeId, properties, VersioningState.NONE, null); |
| } |
| |
| private String createDocument(String name, String folderId, String typeId, Map<String, Object> properties, |
| ContentStream contentStream) { |
| return createDocument(name, folderId, typeId, properties, VersioningState.NONE, contentStream); |
| } |
| |
| private String createDocument(String name, String folderId, String typeId, Map<String, Object> properties, |
| VersioningState verState, ContentStream contentStream) { |
| List<String> policies = null; |
| Acl addACEs = null; |
| Acl removeACEs = null; |
| ExtensionsData extension = null; |
| |
| Properties props = createDocumentProperties(name, typeId, properties); |
| |
| String id = null; |
| try { |
| id = fObjSvc.createDocument(repositoryId, props, folderId, contentStream, verState, policies, addACEs, |
| removeACEs, extension); |
| if (null == id) { |
| fail("createDocument failed."); |
| } |
| } catch (Exception e) { |
| fail("createDocument() failed with exception: " + e); |
| } |
| return id; |
| |
| } |
| |
| private Properties createDocumentProperties(String name, String typeId, Map<String, Object> propertyMap) { |
| List<PropertyData<?>> properties = new ArrayList<PropertyData<?>>(); |
| if (name != null) { |
| properties.add(fFactory.createPropertyIdData(PropertyIds.NAME, name)); |
| } |
| if (typeId != null) { |
| properties.add(fFactory.createPropertyIdData(PropertyIds.OBJECT_TYPE_ID, typeId)); |
| } |
| for (Map.Entry<String, Object> propEntry : propertyMap.entrySet()) { |
| PropertyData<?> pd = createPropertyData(propEntry.getKey(), propEntry.getValue()); |
| properties.add(pd); |
| } |
| Properties props = fFactory.createPropertiesData(properties); |
| return props; |
| } |
| |
| private Properties createFolderProperties(String folderName, String typeId, Map<String, Object> propertyMap) { |
| List<PropertyData<?>> properties = new ArrayList<PropertyData<?>>(); |
| properties.add(fFactory.createPropertyIdData(PropertyIds.NAME, folderName)); |
| properties.add(fFactory.createPropertyIdData(PropertyIds.OBJECT_TYPE_ID, typeId)); |
| for (Map.Entry<String, Object> propEntry : propertyMap.entrySet()) { |
| PropertyData<?> pd = createPropertyData(propEntry.getKey(), propEntry.getValue()); |
| properties.add(pd); |
| } |
| Properties props = fFactory.createPropertiesData(properties); |
| return props; |
| } |
| |
| /** |
| * Simplified property creation method, create Property of Boolean, String, |
| * Integer, Decimal, or DataTime depending on class of value (Boolean, |
| * String, Integer, Double, or GregorianCalendar. Id, Html and URI are not |
| * supported |
| * |
| * @param propId |
| * @param value |
| * @return |
| */ |
| @SuppressWarnings("unchecked") |
| private PropertyData<?> createPropertyData(String propId, Object value) { |
| Class<?> clazz = value.getClass(); |
| if (clazz.equals(Boolean.class)) { |
| return fFactory.createPropertyBooleanData(propId, (Boolean) value); |
| } else if (clazz.equals(Double.class)) { |
| return fFactory.createPropertyDecimalData(propId, BigDecimal.valueOf((Double) value)); |
| } else if (clazz.equals(Integer.class)) { |
| return fFactory.createPropertyIntegerData(propId, BigInteger.valueOf((Integer) value)); |
| } else if (clazz.equals(String.class)) { |
| return fFactory.createPropertyStringData(propId, (String) value); |
| } else if (clazz.equals(GregorianCalendar.class)) { |
| return fFactory.createPropertyDateTimeData(propId, (GregorianCalendar) value); |
| } else if (value instanceof List) { |
| clazz = ((List<?>) value).get(0).getClass(); |
| if (clazz.equals(Boolean.class)) { |
| return fFactory.createPropertyBooleanData(propId, (List<Boolean>) value); |
| } else if (clazz.equals(Double.class)) { |
| return fFactory.createPropertyDecimalData(propId, (List<BigDecimal>) value); |
| } else if (clazz.equals(Integer.class)) { |
| return fFactory.createPropertyIntegerData(propId, (List<BigInteger>) value); |
| } else if (clazz.equals(String.class)) { |
| return fFactory.createPropertyStringData(propId, (List<String>) value); |
| } else if (clazz.equals(GregorianCalendar.class)) { |
| return fFactory.createPropertyDateTimeData(propId, (List<GregorianCalendar>) value); |
| } else { |
| fail("unsupported type in propery value: " + clazz); |
| } |
| } else { |
| fail("unsupported type in propery value: " + clazz); |
| } |
| return null; |
| } |
| |
| private ContentStream createContent(String text) { |
| ContentStreamDataImpl content = new ContentStreamDataImpl(-1); |
| content.setFileName("data.txt"); |
| content.setMimeType("text/plain"); |
| |
| try { |
| content.setContent(new ByteArrayInputStream(text.getBytes())); |
| } catch (IOException e) { |
| throw new RuntimeException("Failed to fill content stream with data", e); |
| } |
| return content; |
| } |
| |
| } |