blob: e61b5fe30bcced043c93be5b5e9206f1ed415ab3 [file] [log] [blame]
/*
* 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.storedobj.impl;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TimeZone;
import org.apache.chemistry.opencmis.commons.PropertyIds;
import org.apache.chemistry.opencmis.commons.data.AllowableActions;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.data.PropertyData;
import org.apache.chemistry.opencmis.commons.impl.IOUtils;
import org.apache.chemistry.opencmis.commons.spi.BindingsObjectFactory;
import org.apache.chemistry.opencmis.inmemory.DataObjectCreator;
import org.apache.chemistry.opencmis.inmemory.FilterParser;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.StoredObject;
/**
* StoredObject is the common superclass of all objects hold in the repository
* Documents, Folders, Relationships and Policies.
*
*/
public class StoredObjectImpl implements StoredObject {
private static final int BUFFER_SIZE = 65536;
private static final String UNKNOWN_USER = "unknown";
protected String fId;
protected String fName;
protected String fTypeId;
protected String fCreatedBy;
protected String fModifiedBy;
protected GregorianCalendar fCreatedAt;
protected GregorianCalendar fModifiedAt;
protected String fRepositoryId;
protected Map<String, PropertyData<?>> fProperties;
protected int fAclId;
protected String description; // CMIS 1.1
protected List<String> secondaryTypeIds; // CMIS 1.1
protected List<String> policyIds;
StoredObjectImpl() { // visibility should be package
GregorianCalendar now = getNow();
now.setTime(new Date());
fCreatedAt = now;
fModifiedAt = now;
secondaryTypeIds = new ArrayList<String>();
policyIds = null;
}
@Override
public String getId() {
return fId;
}
@Override
public void setId(String id) {
fId = id;
}
@Override
public String getName() {
return fName;
}
@Override
public void setName(String name) {
fName = name;
}
@Override
public String getTypeId() {
return fTypeId;
}
@Override
public void setTypeId(String type) {
fTypeId = type;
}
@Override
public String getCreatedBy() {
return fCreatedBy;
}
@Override
public void setCreatedBy(String createdBy) {
this.fCreatedBy = createdBy;
}
@Override
public String getModifiedBy() {
return fModifiedBy;
}
@Override
public void setModifiedBy(String modifiedBy) {
this.fModifiedBy = modifiedBy;
}
@Override
public GregorianCalendar getCreatedAt() {
return fCreatedAt;
}
@Override
public void setCreatedAt(GregorianCalendar createdAt) {
this.fCreatedAt = createdAt;
}
@Override
public GregorianCalendar getModifiedAt() {
return fModifiedAt;
}
@Override
public void setModifiedAtNow() {
GregorianCalendar now = getNow();
// ensure a larger time for modification date and change token:
while (now.getTimeInMillis() == fModifiedAt.getTimeInMillis()) {
try {
Thread.sleep(1);
} catch (InterruptedException ex) {
}
now = getNow();
}
this.fModifiedAt = now;
}
@Override
public void setModifiedAt(GregorianCalendar cal) {
this.fModifiedAt = cal;
}
@Override
public void setRepositoryId(String repositoryId) {
fRepositoryId = repositoryId;
}
@Override
public String getRepositoryId() {
return fRepositoryId;
}
@Override
public List<String> getAppliedPolicies() {
if (null == policyIds) {
return null;
} else {
return Collections.unmodifiableList(policyIds);
}
}
public void setAppliedPolicies(List<String> newPolicies) {
if (null == newPolicies) {
policyIds = null;
} else {
if (null == policyIds) {
policyIds = new ArrayList<String>();
}
policyIds.addAll(newPolicies);
}
}
@Override
public void addAppliedPolicy(String policyId) {
if (null == policyIds) {
policyIds = new ArrayList<String>();
}
if (!policyIds.contains(policyId)) {
policyIds.add(policyId);
}
}
@Override
public void removePolicy(String policyId) {
if (null != policyIds && policyIds.contains(policyId)) {
policyIds.remove(policyId);
if (policyIds.isEmpty()) {
policyIds = null;
}
}
}
// CMIS 1.1:
@Override
public void setDescription(String descr) {
description = descr;
}
// CMIS 1.1:
@Override
public String getDescription() {
return description;
}
@Override
public List<String> getSecondaryTypeIds() {
return Collections.unmodifiableList(secondaryTypeIds);
}
@Override
public void setProperties(Map<String, PropertyData<?>> props) {
fProperties = props;
}
@Override
public Map<String, PropertyData<?>> getProperties() {
return fProperties;
}
@Override
public String getChangeToken() {
GregorianCalendar lastModified = getModifiedAt();
String token = Long.valueOf(lastModified.getTimeInMillis()).toString();
return token;
}
@Override
public void createSystemBasePropertiesWhenCreated(Map<String, PropertyData<?>> properties, String user) {
addSystemBaseProperties(properties, user, true);
}
@Override
public void updateSystemBasePropertiesWhenModified(Map<String, PropertyData<?>> properties, String user) {
addSystemBaseProperties(properties, user, false);
}
@Override
public void fillProperties(Map<String, PropertyData<?>> properties, BindingsObjectFactory objFactory,
List<String> requestedIds) {
if (FilterParser.isContainedInFilter(PropertyIds.NAME, requestedIds)) {
properties.put(PropertyIds.NAME, objFactory.createPropertyStringData(PropertyIds.NAME, getName()));
}
if (FilterParser.isContainedInFilter(PropertyIds.OBJECT_ID, requestedIds)) {
properties.put(PropertyIds.OBJECT_ID, objFactory.createPropertyIdData(PropertyIds.OBJECT_ID, getId()));
}
if (FilterParser.isContainedInFilter(PropertyIds.OBJECT_TYPE_ID, requestedIds)) {
properties.put(PropertyIds.OBJECT_TYPE_ID,
objFactory.createPropertyIdData(PropertyIds.OBJECT_TYPE_ID, getTypeId()));
}
// set the base type id PropertyIds.CMIS_BASE_TYPE_ID outside because it
// requires the type definition
if (FilterParser.isContainedInFilter(PropertyIds.CREATED_BY, requestedIds)) {
properties.put(PropertyIds.CREATED_BY,
objFactory.createPropertyStringData(PropertyIds.CREATED_BY, getCreatedBy()));
}
if (FilterParser.isContainedInFilter(PropertyIds.CREATION_DATE, requestedIds)) {
properties.put(PropertyIds.CREATION_DATE,
objFactory.createPropertyDateTimeData(PropertyIds.CREATION_DATE, getCreatedAt()));
}
if (FilterParser.isContainedInFilter(PropertyIds.LAST_MODIFIED_BY, requestedIds)) {
properties.put(PropertyIds.LAST_MODIFIED_BY,
objFactory.createPropertyStringData(PropertyIds.LAST_MODIFIED_BY, getModifiedBy()));
}
if (FilterParser.isContainedInFilter(PropertyIds.LAST_MODIFICATION_DATE, requestedIds)) {
properties.put(PropertyIds.LAST_MODIFICATION_DATE,
objFactory.createPropertyDateTimeData(PropertyIds.LAST_MODIFICATION_DATE, getModifiedAt()));
}
if (FilterParser.isContainedInFilter(PropertyIds.CHANGE_TOKEN, requestedIds)) {
String token = getChangeToken();
properties.put(PropertyIds.CHANGE_TOKEN,
objFactory.createPropertyStringData(PropertyIds.CHANGE_TOKEN, token));
}
// CMIS 1.1 properties:
if (FilterParser.isContainedInFilter(PropertyIds.DESCRIPTION, requestedIds)) {
properties.put(PropertyIds.DESCRIPTION,
objFactory.createPropertyStringData(PropertyIds.DESCRIPTION, description));
}
if (FilterParser.isContainedInFilter(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, requestedIds)) {
properties.put(PropertyIds.SECONDARY_OBJECT_TYPE_IDS,
objFactory.createPropertyIdData(PropertyIds.SECONDARY_OBJECT_TYPE_IDS, secondaryTypeIds));
}
// add custom properties of type definition to the collection
if (null != fProperties) {
for (Entry<String, PropertyData<?>> prop : fProperties.entrySet()) {
if (FilterParser.isContainedInFilter(prop.getKey(), requestedIds)) {
properties.put(prop.getKey(), prop.getValue());
}
}
}
}
// ///////////////////////////////////////////
// private helper methods
@Override
public void setCustomProperties(Map<String, PropertyData<?>> properties) {
Map<String, PropertyData<?>> propertiesNew = new HashMap<String, PropertyData<?>>(properties);
// get a writablecollection
removeAllSystemProperties(propertiesNew);
setProperties(propertiesNew);
}
private static GregorianCalendar getNow() {
GregorianCalendar now = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
return now;
}
/*
* Add CMIS_CREATED_BY, CMIS_CREATION_DATE, CMIS_LAST_MODIFIED_BY,
* CMIS_LAST_MODIFICATION_DATE, CMIS_CHANGE_TOKEN system properties to the
* list of properties with current values.
*/
@SuppressWarnings("unchecked")
private void addSystemBaseProperties(Map<String, PropertyData<?>> properties, String user, boolean isCreated) {
if (user == null) {
user = UNKNOWN_USER;
}
// Note that initial creation and modification date is set in
// constructor.
setModifiedBy(user);
if (null != properties) {
if (null != properties.get(PropertyIds.DESCRIPTION)) {
setDescription((String) properties.get(PropertyIds.DESCRIPTION).getFirstValue());
}
if (properties.containsKey(PropertyIds.SECONDARY_OBJECT_TYPE_IDS)) {
secondaryTypeIds.clear();
}
PropertyData<?> secondaryTypeProp = properties.get(PropertyIds.SECONDARY_OBJECT_TYPE_IDS);
if (null != secondaryTypeProp) {
secondaryTypeIds.addAll((List<String>) secondaryTypeProp.getValues());
}
}
if (isCreated) {
setCreatedBy(user);
setName((String) properties.get(PropertyIds.NAME).getFirstValue());
setTypeId((String) properties.get(PropertyIds.OBJECT_TYPE_ID).getFirstValue());
} else {
setModifiedAtNow();
}
}
/*
* Add CMIS_CREATED_BY, CMIS_CREATION_DATE, CMIS_LAST_MODIFIED_BY,
* CMIS_LAST_MODIFICATION_DATE, CMIS_CHANGE_TOKEN system properties to the
* list of properties with current values
*/
protected void setSystemBasePropertiesWhenCreatedDirect(String name, String typeId, String user) {
// Note that initial creation and modification date is set in
// constructor.
setModifiedBy(user);
setCreatedBy(user);
setName(name);
setTypeId(typeId);
}
/*
* CMIS_NAME CMIS_OBJECT_ID CMIS_OBJECT_TYPE_ID CMIS_BASE_TYPE_ID
* CMIS_CREATED_BY CMIS_CREATION_DATE CMIS_LAST_MODIFIED_BY
* CMIS_LAST_MODIFICATION_DATE CMIS_CHANGE_TOKEN
*
* // ---- document ---- CMIS_IS_IMMUTABLE CMIS_IS_LATEST_VERSION
* CMIS_IS_MAJOR_VERSION CMIS_IS_LATEST_MAJOR_VERSION CMIS_VERSION_LABEL
* CMIS_VERSION_SERIES_ID CMIS_IS_VERSION_SERIES_CHECKED_OUT
* CMIS_VERSION_SERIES_CHECKED_OUT_BY CMIS_VERSION_SERIES_CHECKED_OUT_ID
* CMIS_CHECKIN_COMMENT CMIS_CONTENT_STREAM_LENGTH
* CMIS_CONTENT_STREAM_MIME_TYPE CMIS_CONTENT_STREAM_FILE_NAME
* CMIS_CONTENT_STREAM_ID
*
* // ---- folder ---- CMIS_PARENT_ID CMIS_ALLOWED_CHILD_OBJECT_TYPE_IDS
* CMIS_PATH
*
* // ---- relationship ---- CMIS_SOURCE_ID CMIS_TARGET_ID
*
* // ---- policy ---- CMIS_POLICY_TEXT
*/
private static void removeAllSystemProperties(Map<String, PropertyData<?>> properties) {
// ---- base ----
if (properties.containsKey(PropertyIds.NAME)) {
properties.remove(PropertyIds.NAME);
}
if (properties.containsKey(PropertyIds.OBJECT_ID)) {
properties.remove(PropertyIds.OBJECT_ID);
}
if (properties.containsKey(PropertyIds.OBJECT_TYPE_ID)) {
properties.remove(PropertyIds.OBJECT_TYPE_ID);
}
if (properties.containsKey(PropertyIds.BASE_TYPE_ID)) {
properties.remove(PropertyIds.BASE_TYPE_ID);
}
if (properties.containsKey(PropertyIds.CREATED_BY)) {
properties.remove(PropertyIds.CREATED_BY);
}
if (properties.containsKey(PropertyIds.CREATION_DATE)) {
properties.remove(PropertyIds.CREATION_DATE);
}
if (properties.containsKey(PropertyIds.LAST_MODIFIED_BY)) {
properties.remove(PropertyIds.LAST_MODIFIED_BY);
}
if (properties.containsKey(PropertyIds.LAST_MODIFICATION_DATE)) {
properties.remove(PropertyIds.LAST_MODIFICATION_DATE);
}
if (properties.containsKey(PropertyIds.CHANGE_TOKEN)) {
properties.remove(PropertyIds.CHANGE_TOKEN);
}
// ---- document ----
if (properties.containsKey(PropertyIds.IS_IMMUTABLE)) {
properties.remove(PropertyIds.IS_IMMUTABLE);
}
if (properties.containsKey(PropertyIds.IS_LATEST_VERSION)) {
properties.remove(PropertyIds.IS_LATEST_VERSION);
}
if (properties.containsKey(PropertyIds.IS_MAJOR_VERSION)) {
properties.remove(PropertyIds.IS_MAJOR_VERSION);
}
if (properties.containsKey(PropertyIds.IS_LATEST_MAJOR_VERSION)) {
properties.remove(PropertyIds.IS_LATEST_MAJOR_VERSION);
}
if (properties.containsKey(PropertyIds.VERSION_LABEL)) {
properties.remove(PropertyIds.VERSION_LABEL);
}
if (properties.containsKey(PropertyIds.VERSION_SERIES_ID)) {
properties.remove(PropertyIds.VERSION_SERIES_ID);
}
if (properties.containsKey(PropertyIds.IS_VERSION_SERIES_CHECKED_OUT)) {
properties.remove(PropertyIds.IS_VERSION_SERIES_CHECKED_OUT);
}
if (properties.containsKey(PropertyIds.VERSION_SERIES_CHECKED_OUT_BY)) {
properties.remove(PropertyIds.VERSION_SERIES_CHECKED_OUT_BY);
}
if (properties.containsKey(PropertyIds.VERSION_SERIES_CHECKED_OUT_ID)) {
properties.remove(PropertyIds.VERSION_SERIES_CHECKED_OUT_ID);
}
if (properties.containsKey(PropertyIds.CHECKIN_COMMENT)) {
properties.remove(PropertyIds.CHECKIN_COMMENT);
}
if (properties.containsKey(PropertyIds.CONTENT_STREAM_LENGTH)) {
properties.remove(PropertyIds.CONTENT_STREAM_LENGTH);
}
if (properties.containsKey(PropertyIds.CONTENT_STREAM_MIME_TYPE)) {
properties.remove(PropertyIds.CONTENT_STREAM_MIME_TYPE);
}
if (properties.containsKey(PropertyIds.CONTENT_STREAM_FILE_NAME)) {
properties.remove(PropertyIds.CONTENT_STREAM_FILE_NAME);
}
if (properties.containsKey(PropertyIds.CONTENT_STREAM_ID)) {
properties.remove(PropertyIds.CONTENT_STREAM_ID);
}
// ---- folder ----
if (properties.containsKey(PropertyIds.PARENT_ID)) {
properties.remove(PropertyIds.PARENT_ID);
}
if (properties.containsKey(PropertyIds.ALLOWED_CHILD_OBJECT_TYPE_IDS)) {
properties.remove(PropertyIds.ALLOWED_CHILD_OBJECT_TYPE_IDS);
}
if (properties.containsKey(PropertyIds.PATH)) {
properties.remove(PropertyIds.PATH);
}
// ---- relationship ----
if (properties.containsKey(PropertyIds.SOURCE_ID)) {
properties.remove(PropertyIds.SOURCE_ID);
}
if (properties.containsKey(PropertyIds.TARGET_ID)) {
properties.remove(PropertyIds.TARGET_ID);
}
// ---- policy ----
if (properties.containsKey(PropertyIds.POLICY_TEXT)) {
properties.remove(PropertyIds.POLICY_TEXT);
}
}
@Override
public int getAclId() {
return fAclId;
}
public void setAclId(int aclId) {
fAclId = aclId;
}
@Override
public AllowableActions getAllowableActions(String user) {
AllowableActions actions = DataObjectCreator.fillAllowableActions(this, user);
return actions;
}
@Override
public boolean hasRendition(String user) {
return false;
}
protected ContentStream getIconFromResourceDir(String name) throws IOException {
InputStream imageStream = StoredObjectImpl.class.getResourceAsStream(name);
ByteArrayOutputStream ba = new ByteArrayOutputStream();
byte[] buffer = new byte[BUFFER_SIZE];
int noBytesRead = 0;
try {
while ((noBytesRead = imageStream.read(buffer)) >= 0) {
ba.write(buffer, 0, noBytesRead);
}
} finally {
IOUtils.closeQuietly(ba);
IOUtils.closeQuietly(imageStream);
}
ContentStreamDataImpl content = new ContentStreamDataImpl(0);
content.setFileName(name);
content.setMimeType("image/png");
content.setContent(new ByteArrayInputStream(ba.toByteArray()));
return content;
}
protected boolean testRenditionFilterForImage(String[] formats) {
if (formats.length == 1 && null != formats[0] && formats[0].equals("cmis:none")) {
return false;
} else {
return arrayContainsString(formats, "*") || arrayContainsString(formats, "image/*")
|| arrayContainsString(formats, "image/jpeg");
}
}
private boolean arrayContainsString(String[] formats, String val) {
for (String s : formats) {
if (val.equals(s)) {
return true;
}
}
return false;
}
}