/**
* 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);
}
}
}
}