/** * Copyright (C) 2010 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xcmis.sp.inmemory; import org.xcmis.spi.BaseContentStream; import org.xcmis.spi.CmisConstants; import org.xcmis.spi.CmisRuntimeException; import org.xcmis.spi.ContentStream; import org.xcmis.spi.DocumentData; import org.xcmis.spi.ItemsIterator; import org.xcmis.spi.NameConstraintViolationException; import org.xcmis.spi.PolicyData; import org.xcmis.spi.RelationshipData; import org.xcmis.spi.StorageException; import org.xcmis.spi.UpdateConflictException; import org.xcmis.spi.VersioningException; import org.xcmis.spi.model.AccessControlEntry; import org.xcmis.spi.model.Property; import org.xcmis.spi.model.RelationshipDirection; import org.xcmis.spi.model.TypeDefinition; import org.xcmis.spi.utils.MimeType; import java.io.IOException; import java.math.BigInteger; import java.util.Calendar; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArraySet; /** * @author <a href="mailto:andrew00x@gmail.com">Andrey Parfonov</a> * @version $Id: DocumentDataImpl.java 1197 2010-05-28 08:15:37Z * alexey.zavizionov@gmail.com $ */ class DocumentDataImpl extends BaseObjectData implements DocumentData { public DocumentDataImpl(Entry entry, TypeDefinition type, StorageImpl storage) { super(entry, type, storage); } /** * {@inheritDoc} */ public void cancelCheckout() throws UpdateConflictException, VersioningException, StorageException { synchronized (storage) { String vsId = getVersionSeriesId(); String pwcId = storage.workingCopies.get(vsId); if (pwcId == null) { return; } for (String parent : storage.parents.get(pwcId)) { storage.children.get(parent).remove(pwcId); } storage.parents.remove(pwcId); storage.unfiled.remove(pwcId); storage.workingCopies.remove(vsId); storage.entries.remove(pwcId); for (Iterator<String> iterator = storage.versions.get(getVersionSeriesId()).iterator(); iterator.hasNext();) { String version = iterator.next(); Entry ventry = storage.entries.get(version); ventry.setValue(CmisConstants.IS_VERSION_SERIES_CHECKED_OUT, new BooleanValue(false)); ventry.setValue(CmisConstants.VERSION_SERIES_CHECKED_OUT_ID, /*new StringValue()*/null); } } } /** * {@inheritDoc} */ public DocumentData checkin(boolean major, String checkinComment, Map<String, Property<?>> properties, ContentStream contentStream, List<AccessControlEntry> acl, Collection<PolicyData> policies) throws NameConstraintViolationException, UpdateConflictException, StorageException { if (!isPWC()) { throw new CmisRuntimeException("Current object is not Private Working Copy."); } synchronized (storage) { String pwcId = getObjectId(); int i = 1; for (Iterator<String> iterator = storage.versions.get(getVersionSeriesId()).iterator(); iterator.hasNext();) { String version = iterator.next(); Entry ventry = storage.entries.get(version); ventry.setValue(CmisConstants.IS_VERSION_SERIES_CHECKED_OUT, new BooleanValue(false)); ventry.setValue(CmisConstants.IS_LATEST_VERSION, new BooleanValue(false)); ventry.setValue(CmisConstants.IS_LATEST_MAJOR_VERSION, new BooleanValue(false)); ventry.setValue(CmisConstants.VERSION_SERIES_CHECKED_OUT_BY, null); ventry.setValue(CmisConstants.VERSION_SERIES_CHECKED_OUT_ID, null); // update version labels ventry.setValue(CmisConstants.VERSION_LABEL, new StringValue("" + i++)); } if (properties != null) { for (Property<?> property : properties.values()) { doSetProperty(property); } } try { if (contentStream != null) { doSetContentStream(contentStream); } } catch (IOException ioe) { throw new StorageException("Unable checkin PWC. " + ioe.getMessage(), ioe); } if (acl != null && acl.size() > 0) { setACL(acl); } if (policies != null && policies.size() > 0) { for (PolicyData p : policies) { applyPolicy(p); } } entry.setValue(CmisConstants.VERSION_LABEL, new StringValue(PropertyDefinitions.LATEST_LABEL)); entry.setValue(CmisConstants.IS_LATEST_VERSION, new BooleanValue(true)); entry.setValue(CmisConstants.IS_MAJOR_VERSION, new BooleanValue(major)); entry.setValue(CmisConstants.IS_LATEST_MAJOR_VERSION, new BooleanValue(major)); entry.setValue(CmisConstants.IS_VERSION_SERIES_CHECKED_OUT, new BooleanValue(false)); entry.setValue(CmisConstants.VERSION_SERIES_CHECKED_OUT_ID, null); entry.setValue(CmisConstants.VERSION_SERIES_CHECKED_OUT_BY, null); if (checkinComment != null) { entry.setValue(CmisConstants.CHECKIN_COMMENT, new StringValue(checkinComment)); } storage.workingCopies.remove(getVersionSeriesId()); storage.versions.get(getVersionSeriesId()).add(pwcId); } return this; } /** * {@inheritDoc} */ public DocumentData checkout() throws UpdateConflictException, VersioningException, StorageException { synchronized (storage) { if (storage.workingCopies.get(getVersionSeriesId()) != null) { throw new VersioningException("Version series already checked-out. " + "Not allowed have more then one PWC for version series at a time."); } Entry pwc = new Entry(); pwc.setValue(CmisConstants.OBJECT_TYPE_ID, new StringValue(type.getId())); pwc.setValue(CmisConstants.BASE_TYPE_ID, new StringValue(type.getBaseId().value())); pwc.setValue(CmisConstants.IS_IMMUTABLE, new BooleanValue(false)); pwc.setValue(CmisConstants.VERSION_SERIES_ID, new StringValue(this.getVersionSeriesId())); String pwcId = StorageImpl.generateId(); pwc.setValue(CmisConstants.OBJECT_ID, new StringValue(pwcId)); pwc.setValue(CmisConstants.NAME, new StringValue(getName())); String userId = storage.getCurrentUser(); pwc.setValue(CmisConstants.CREATED_BY, new StringValue(userId)); pwc.setValue(CmisConstants.LAST_MODIFIED_BY, new StringValue(userId)); Calendar cal = Calendar.getInstance(); pwc.setValue(CmisConstants.CREATION_DATE, new DateValue(cal)); pwc.setValue(CmisConstants.LAST_MODIFICATION_DATE, new DateValue(cal)); pwc.setValue(CmisConstants.IS_LATEST_VERSION, new BooleanValue(false)); pwc.setValue(CmisConstants.IS_MAJOR_VERSION, new BooleanValue(false)); pwc.setValue(CmisConstants.VERSION_LABEL, new StringValue(PropertyDefinitions.PWC_LABEL)); pwc.setValue(CmisConstants.IS_VERSION_SERIES_CHECKED_OUT, new BooleanValue(true)); pwc.setValue(CmisConstants.VERSION_SERIES_CHECKED_OUT_ID, new StringValue(pwcId)); pwc.setValue(CmisConstants.VERSION_SERIES_CHECKED_OUT_BY, new StringValue(userId)); ByteArrayValue contentValue = (ByteArrayValue)entry.getValue(PropertyDefinitions.CONTENT); if (contentValue != null) { // check is max memory size reached byte[] src = contentValue.getBytes(); storage.validateMemSize(src); byte[] bytes = new byte[src.length]; System.arraycopy(src, 0, bytes, 0, bytes.length); pwc.setValue(PropertyDefinitions.CONTENT, new ByteArrayValue(bytes)); String mimeType = getContentStreamMimeType(); if (mimeType != null) { pwc.setValue(CmisConstants.CONTENT_STREAM_MIME_TYPE, new StringValue(mimeType)); } String charset = getString(CmisConstants.CHARSET); if (charset != null) { pwc.setValue(CmisConstants.CHARSET, new StringValue(charset)); } pwc.setValue(CmisConstants.CONTENT_STREAM_LENGTH, new IntegerValue(BigInteger.valueOf(bytes.length))); pwc.setValue(CmisConstants.CONTENT_STREAM_ID, new StringValue(pwcId)); pwc.setValue(CmisConstants.CONTENT_STREAM_FILE_NAME, new StringValue(getName())); } for (Iterator<String> iterator = storage.versions.get(getVersionSeriesId()).iterator(); iterator.hasNext();) { String version = iterator.next(); Entry ventry = storage.entries.get(version); ventry.setValue(CmisConstants.IS_VERSION_SERIES_CHECKED_OUT, new BooleanValue(true)); ventry.setValue(CmisConstants.VERSION_SERIES_CHECKED_OUT_ID, new StringValue(pwcId)); ventry.setValue(CmisConstants.VERSION_SERIES_CHECKED_OUT_BY, new StringValue(userId)); } storage.entries.put(pwcId, pwc); for (String parent : storage.parents.get(getObjectId())) { storage.children.get(parent).add(pwcId); } storage.parents.put(pwcId, new CopyOnWriteArraySet<String>(storage.parents.get(getObjectId()))); storage.workingCopies.put(getVersionSeriesId(), pwcId); DocumentDataImpl pwcObject = new DocumentDataImpl(pwc, // new TypeDefinition(type.getId(), type.getBaseId(), type.getQueryName(), type.getLocalName(), type .getLocalNamespace(), type.getParentId(), type.getDisplayName(), type.getDescription(), type .isCreatable(), type.isFileable(), type.isQueryable(), type.isFulltextIndexed(), type .isIncludedInSupertypeQuery(), type.isControllablePolicy(), type.isControllableACL(), type .isVersionable(), type.getAllowedSourceTypes(), type.getAllowedTargetTypes(), type .getContentStreamAllowed(), PropertyDefinitions.getAll(getTypeId())), // storage); return pwcObject; } } /** * {@inheritDoc} */ public ContentStream getContentStream() { ByteArrayValue contentValue = (ByteArrayValue)entry.getValue(PropertyDefinitions.CONTENT); if (contentValue != null/* && contentValue.getBytes().length > 0*/) { MimeType mimeType = MimeType.fromString(getString(CmisConstants.CONTENT_STREAM_MIME_TYPE)); String charset = getString(CmisConstants.CHARSET); if (charset != null) { mimeType.getParameters().put(CmisConstants.CHARSET, charset); } return new BaseContentStream(contentValue.getBytes(), getContentStreamFileName(), mimeType); } return null; } /** * {@inheritDoc} */ public ContentStream getContentStream(String streamId) { if (streamId == null || streamId.equals(getString(CmisConstants.CONTENT_STREAM_ID))) { return getContentStream(); } try { if (storage.renditionManager != null) { return storage.renditionManager.getStream(this, streamId); } return null; } catch (Exception e) { throw new CmisRuntimeException("Unable get rendition stream. " + e.getMessage(), e); } } /** * {@inheritDoc} */ public String getContentStreamMimeType() { return getString(CmisConstants.CONTENT_STREAM_MIME_TYPE); } /** * {@inheritDoc} */ public String getContentStreamFileName() { String contentStreamFileName = getString(CmisConstants.CONTENT_STREAM_FILE_NAME); if (contentStreamFileName == null) { contentStreamFileName = getName(); } return contentStreamFileName; } /** * {@inheritDoc} */ public String getVersionLabel() { return getString(CmisConstants.VERSION_LABEL); } /** * {@inheritDoc} */ public String getVersionSeriesCheckedOutBy() { return getString(CmisConstants.VERSION_SERIES_CHECKED_OUT_BY); } /** * {@inheritDoc} */ public String getVersionSeriesCheckedOutId() { return getString(CmisConstants.VERSION_SERIES_CHECKED_OUT_ID); } /** * {@inheritDoc} */ public String getVersionSeriesId() { return getString(CmisConstants.VERSION_SERIES_ID); } /** * {@inheritDoc} */ public boolean hasContent() { ByteArrayValue cv = (ByteArrayValue)entry.getValue(PropertyDefinitions.CONTENT); return cv != null && cv.getBytes().length > 0; } /** * {@inheritDoc} */ public boolean isLatestMajorVersion() { return isLatestVersion() && isMajorVersion(); } /** * {@inheritDoc} */ public boolean isLatestVersion() { Boolean latest = getBoolean(CmisConstants.IS_LATEST_VERSION); return latest == null ? true : latest; } /** * {@inheritDoc} */ public boolean isMajorVersion() { Boolean major = getBoolean(CmisConstants.IS_MAJOR_VERSION); return major == null ? false : major; } /** * {@inheritDoc} */ public boolean isPWC() { return getObjectId().equals(getVersionSeriesCheckedOutId()); } /** * {@inheritDoc} */ public boolean isVersionSeriesCheckedOut() { Boolean checkout = getBoolean(CmisConstants.IS_VERSION_SERIES_CHECKED_OUT); return checkout == null ? false : checkout; } /** * {@inheritDoc} */ public void setContentStream(ContentStream contentStream) throws IOException, UpdateConflictException, VersioningException, StorageException { doSetContentStream(contentStream); save(); } private void doSetContentStream(ContentStream contentStream) throws IOException, StorageException { if (contentStream == null || contentStream.getStream() == null) { entry.setValue(PropertyDefinitions.CONTENT, null); entry.setValue(CmisConstants.CONTENT_STREAM_MIME_TYPE, null); entry.setValue(CmisConstants.CHARSET, null); entry.setValue(CmisConstants.CONTENT_STREAM_LENGTH, new IntegerValue(BigInteger.valueOf(0))); entry.setValue(CmisConstants.CONTENT_STREAM_ID, null); entry.setValue(CmisConstants.CONTENT_STREAM_FILE_NAME, null); } else { ByteArrayValue cv = ByteArrayValue.fromStream(contentStream.getStream()); storage.validateMemSize(cv.getBytes()); MimeType mimeType = contentStream.getMediaType(); entry.setValue(PropertyDefinitions.CONTENT, cv); entry.setValue(CmisConstants.CONTENT_STREAM_MIME_TYPE, new StringValue(mimeType.getBaseType())); String charset = mimeType.getParameter(CmisConstants.CHARSET); if (charset != null) { entry.setValue(CmisConstants.CHARSET, new StringValue(charset)); } entry .setValue(CmisConstants.CONTENT_STREAM_LENGTH, new IntegerValue(BigInteger.valueOf(cv.getBytes().length))); entry.setValue(CmisConstants.CONTENT_STREAM_ID, new StringValue(getObjectId())); entry.setValue(CmisConstants.CONTENT_STREAM_FILE_NAME, new StringValue(getName())); } } protected void delete() throws StorageException, UpdateConflictException, VersioningException { TypeDefinition relationshipType = storage.types.get(CmisConstants.RELATIONSHIP); ItemsIterator<RelationshipData> relationships = getRelationships(RelationshipDirection.EITHER, relationshipType, true); if (relationships.hasNext()) { throw new StorageException("Object can't be deleted cause to storage referential integrity. " + "Object is source or target at least one Relationship."); } if (isPWC()) { cancelCheckout(); } else { String objectId = getObjectId(); String vsId = getVersionSeriesId(); storage.entries.remove(objectId); for (String parent : storage.parents.get(objectId)) { storage.children.get(parent).remove(objectId); } storage.parents.remove(objectId); storage.unfiled.remove(objectId); for (String version : storage.versions.get(getVersionSeriesId())) { storage.entries.remove(version); } storage.versions.remove(vsId); String pwcId = storage.workingCopies.remove(vsId); if (pwcId != null) { storage.entries.remove(pwcId); } } } }