/* * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: */ package org.eclipse.ecr.opencmis.impl.server; import java.io.IOException; import java.io.Serializable; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.GregorianCalendar; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.chemistry.opencmis.commons.PropertyIds; import org.apache.chemistry.opencmis.commons.data.ContentStream; 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.definitions.PropertyDefinition; import org.apache.chemistry.opencmis.commons.enums.Cardinality; import org.apache.chemistry.opencmis.commons.enums.PropertyType; import org.apache.chemistry.opencmis.commons.enums.Updatability; import org.apache.chemistry.opencmis.commons.exceptions.CmisContentAlreadyExistsException; import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException; import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException; import org.apache.chemistry.opencmis.commons.exceptions.CmisStreamNotSupportedException; import org.apache.chemistry.opencmis.commons.server.CallContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.eclipse.ecr.core.api.Blob; import org.eclipse.ecr.core.api.ClientException; import org.eclipse.ecr.core.api.CoreSession; import org.eclipse.ecr.core.api.DocumentModel; import org.eclipse.ecr.core.api.DocumentRef; import org.eclipse.ecr.core.api.IdRef; import org.eclipse.ecr.core.api.blobholder.BlobHolder; import org.eclipse.ecr.core.api.impl.blob.InputStreamBlob; import org.eclipse.ecr.core.api.model.Property; import org.eclipse.ecr.core.api.model.PropertyNotFoundException; import org.eclipse.ecr.core.query.sql.NXQL; import org.eclipse.ecr.core.schema.types.Type; /** * Nuxeo implementation of an object's property, backed by a property of a * {@link DocumentModel}. */ public abstract class NuxeoPropertyData<T> extends NuxeoPropertyDataBase<T> { protected final String name; protected final boolean readOnly; // TODO unused public static final Map<String, String> propertyNameToNXQL; static { Map<String, String> map = new HashMap<String, String>(); map.put(PropertyIds.OBJECT_ID, NXQL.ECM_UUID); map.put(PropertyIds.OBJECT_TYPE_ID, NXQL.ECM_PRIMARYTYPE); map.put(PropertyIds.PARENT_ID, NXQL.ECM_PARENTID); map.put(PropertyIds.NAME, NXQL.ECM_NAME); map.put(PropertyIds.CREATED_BY, NuxeoTypeHelper.NX_DC_CREATOR); map.put(PropertyIds.CREATION_DATE, NuxeoTypeHelper.NX_DC_CREATED); map.put(PropertyIds.LAST_MODIFIED_BY, "dc:contributors"); map.put(PropertyIds.LAST_MODIFICATION_DATE, NuxeoTypeHelper.NX_DC_MODIFIED); propertyNameToNXQL = Collections.unmodifiableMap(map); } public NuxeoPropertyData(PropertyDefinition<T> propertyDefinition, DocumentModel doc, String name, boolean readOnly) { super(propertyDefinition, doc); this.name = name; this.readOnly = readOnly; } /** * Factory for a new Property. */ @SuppressWarnings("unchecked") public static <U> PropertyData<U> construct(NuxeoObjectData data, PropertyDefinition<U> pd, CallContext callContext) { DocumentModel doc = data.doc; String name = pd.getId(); if (PropertyIds.OBJECT_ID.equals(name)) { return (PropertyData<U>) new NuxeoPropertyIdDataFixed( (PropertyDefinition<String>) pd, doc.getId()); } else if (PropertyIds.OBJECT_TYPE_ID.equals(name)) { return (PropertyData<U>) new NuxeoPropertyIdDataFixed( (PropertyDefinition<String>) pd, NuxeoTypeHelper.mappedId(doc.getType())); } else if (PropertyIds.BASE_TYPE_ID.equals(name)) { return (PropertyData<U>) new NuxeoPropertyIdDataFixed( (PropertyDefinition<String>) pd, NuxeoTypeHelper.getBaseTypeId(doc).value()); } else if (PropertyIds.CREATED_BY.equals(name)) { return (PropertyData<U>) new NuxeoPropertyStringData( (PropertyDefinition<String>) pd, doc, NuxeoTypeHelper.NX_DC_CREATOR, true); } else if (PropertyIds.CREATION_DATE.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDateTimeData( (PropertyDefinition<GregorianCalendar>) pd, doc, NuxeoTypeHelper.NX_DC_CREATED, true); } else if (PropertyIds.LAST_MODIFIED_BY.equals(name)) { return (PropertyData<U>) new NuxeoPropertyStringData( (PropertyDefinition<String>) pd, doc, NuxeoTypeHelper.NX_DC_LAST_CONTRIBUTOR, true); } else if (PropertyIds.LAST_MODIFICATION_DATE.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDateTimeData( (PropertyDefinition<GregorianCalendar>) pd, doc, NuxeoTypeHelper.NX_DC_MODIFIED, true); } else if (PropertyIds.CHANGE_TOKEN.equals(name)) { return (PropertyData<U>) new NuxeoPropertyStringDataFixed( (PropertyDefinition<String>) pd, null); } else if (PropertyIds.NAME.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDataName( (PropertyDefinition<String>) pd, doc); } else if (PropertyIds.IS_IMMUTABLE.equals(name)) { // TODO check write return (PropertyData<U>) new NuxeoPropertyBooleanDataFixed( (PropertyDefinition<Boolean>) pd, Boolean.FALSE); } else if (PropertyIds.IS_LATEST_VERSION.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDataIsLatestVersion( (PropertyDefinition<Boolean>) pd, doc); } else if (PropertyIds.IS_LATEST_MAJOR_VERSION.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDataIsLatestMajorVersion( (PropertyDefinition<Boolean>) pd, doc); } else if (PropertyIds.IS_MAJOR_VERSION.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDataIsMajorVersion( (PropertyDefinition<Boolean>) pd, doc); } else if (PropertyIds.VERSION_LABEL.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDataVersionLabel( (PropertyDefinition<String>) pd, doc); } else if (PropertyIds.VERSION_SERIES_ID.equals(name)) { // doesn't change once computed, no need to have a dynamic prop String versionSeriesId; try { versionSeriesId = doc.getVersionSeriesId(); } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } return (PropertyData<U>) new NuxeoPropertyIdDataFixed( (PropertyDefinition<String>) pd, versionSeriesId); } else if (PropertyIds.IS_VERSION_SERIES_CHECKED_OUT.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDataIsVersionSeriesCheckedOut( (PropertyDefinition<Boolean>) pd, doc); } else if (PropertyIds.VERSION_SERIES_CHECKED_OUT_BY.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDataVersionSeriesCheckedOutBy( (PropertyDefinition<String>) pd, doc, callContext); } else if (PropertyIds.VERSION_SERIES_CHECKED_OUT_ID.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDataVersionSeriesCheckedOutId( (PropertyDefinition<String>) pd, doc); } else if (PropertyIds.CHECKIN_COMMENT.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDataCheckInComment( (PropertyDefinition<String>) pd, doc); } else if (PropertyIds.CONTENT_STREAM_LENGTH.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDataContentStreamLength( (PropertyDefinition<BigInteger>) pd, doc); } else if (PropertyIds.CONTENT_STREAM_MIME_TYPE.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDataContentStreamMimeType( (PropertyDefinition<String>) pd, doc); } else if (PropertyIds.CONTENT_STREAM_FILE_NAME.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDataContentStreamFileName( (PropertyDefinition<String>) pd, doc); } else if (PropertyIds.CONTENT_STREAM_ID.equals(name)) { return (PropertyData<U>) new NuxeoPropertyIdDataFixed( (PropertyDefinition<String>) pd, null); } else if (PropertyIds.PARENT_ID.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDataParentId( (PropertyDefinition<String>) pd, doc); } else if (PropertyIds.PATH.equals(name)) { return (PropertyData<U>) new NuxeoPropertyDataPath( (PropertyDefinition<String>) pd, doc); } else if (PropertyIds.ALLOWED_CHILD_OBJECT_TYPE_IDS.equals(name)) { return (PropertyData<U>) new NuxeoPropertyIdMultiDataFixed( (PropertyDefinition<String>) pd, Collections.<String> emptyList()); } else if (PropertyIds.SOURCE_ID.equals(name)) { return (PropertyData<U>) new NuxeoPropertyIdData( (PropertyDefinition<String>) pd, doc, NuxeoTypeHelper.NX_REL_SOURCE, false); } else if (PropertyIds.TARGET_ID.equals(name)) { return (PropertyData<U>) new NuxeoPropertyIdData( (PropertyDefinition<String>) pd, doc, NuxeoTypeHelper.NX_REL_TARGET, false); } else if (PropertyIds.POLICY_TEXT.equals(name)) { return (PropertyData<U>) new NuxeoPropertyStringDataFixed( (PropertyDefinition<String>) pd, null); } else { boolean readOnly = pd.getUpdatability() != Updatability.READWRITE; // TODO WHEN_CHECKED_OUT, ON_CREATE switch (pd.getPropertyType()) { case BOOLEAN: return (PropertyData<U>) new NuxeoPropertyBooleanData( (PropertyDefinition<Boolean>) pd, doc, name, readOnly); case DATETIME: return (PropertyData<U>) new NuxeoPropertyDateTimeData( (PropertyDefinition<GregorianCalendar>) pd, doc, name, readOnly); case DECIMAL: return (PropertyData<U>) new NuxeoPropertyDecimalData( (PropertyDefinition<BigDecimal>) pd, doc, name, readOnly); case HTML: return (PropertyData<U>) new NuxeoPropertyHtmlData( (PropertyDefinition<String>) pd, doc, name, readOnly); case ID: return (PropertyData<U>) new NuxeoPropertyIdData( (PropertyDefinition<String>) pd, doc, name, readOnly); case INTEGER: return (PropertyData<U>) new NuxeoPropertyIntegerData( (PropertyDefinition<BigInteger>) pd, doc, name, readOnly); case STRING: return (PropertyData<U>) new NuxeoPropertyStringData( (PropertyDefinition<String>) pd, doc, name, readOnly); case URI: return (PropertyData<U>) new NuxeoPropertyUriData( (PropertyDefinition<String>) pd, doc, name, readOnly); default: throw new AssertionError(pd.getPropertyType().toString()); } } } public static ContentStream getContentStream(DocumentModel doc) throws CmisRuntimeException { BlobHolder blobHolder = doc.getAdapter(BlobHolder.class); if (blobHolder == null) { throw new CmisStreamNotSupportedException(); } Blob blob; try { blob = blobHolder.getBlob(); } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } return blob == null ? null : new NuxeoContentStream(blob); } public static void setContentStream(DocumentModel doc, ContentStream contentStream, boolean overwrite) throws IOException, CmisContentAlreadyExistsException, CmisRuntimeException { BlobHolder blobHolder = doc.getAdapter(BlobHolder.class); if (blobHolder == null) { throw new CmisContentAlreadyExistsException(); } if (!overwrite) { Blob blob; try { blob = blobHolder.getBlob(); } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } if (blob != null) { throw new CmisContentAlreadyExistsException(); } } Blob blob = contentStream == null ? null : new InputStreamBlob( contentStream.getStream(), contentStream.getMimeType(), null, contentStream.getFileName(), null); try { blobHolder.setBlob(blob); } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } } /** * Conversion from Nuxeo values to CMIS ones. * * @return either a primitive type or a List of them, or {@code null} */ @Override @SuppressWarnings("unchecked") public <U> U getValue() { try { Property prop = doc.getProperty(name); Serializable value = prop.getValue(); if (value == null) { return null; } Type type = prop.getType(); if (type.isListType()) { // array/list List<Object> values; if (value instanceof Object[]) { values = Arrays.asList((Object[]) value); } else if (value instanceof List<?>) { values = (List<Object>) value; } else { throw new CmisRuntimeException("Unknown value type: " + value.getClass().getName()); } List<Object> list = new ArrayList<Object>(values); for (int i = 0; i < list.size(); i++) { list.set(i, convertToCMIS(list.get(i))); } return (U) list; } else { // primitive type return (U) convertToCMIS(value); } } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } } // conversion from Nuxeo value types to CMIS ones protected static Object convertToCMIS(Object value) { if (value instanceof Double) { return BigDecimal.valueOf(((Double) value).doubleValue()); } else if (value instanceof Integer) { return BigInteger.valueOf(((Integer) value).intValue()); } else if (value instanceof Long) { return BigInteger.valueOf(((Long) value).longValue()); } else { return value; } } // conversion from CMIS value types to Nuxeo ones protected static Object convertToNuxeo(Object value) { if (value instanceof BigDecimal) { return Double.valueOf(((BigDecimal) value).doubleValue()); } else if (value instanceof BigInteger) { return Long.valueOf(((BigInteger) value).longValue()); } else { return value; } } /** * Validates a CMIS value according to a property definition. */ @SuppressWarnings("unchecked") public static <T> void validateCMISValue(Object value, PropertyDefinition<T> pd) { if (value == null) { return; } List<T> values; if (value instanceof List<?>) { if (pd.getCardinality() != Cardinality.MULTI) { throw new CmisInvalidArgumentException( "Property is single-valued: " + pd.getId()); } values = (List<T>) value; if (values.isEmpty()) { return; } } else { if (pd.getCardinality() != Cardinality.SINGLE) { throw new CmisInvalidArgumentException( "Property is multi-valued: " + pd.getId()); } values = Collections.singletonList((T) value); } PropertyType type = pd.getPropertyType(); for (Object v : values) { if (v == null) { throw new CmisInvalidArgumentException( "Null values not allowed: " + values); } boolean ok; switch (type) { case STRING: case ID: case URI: case HTML: ok = v instanceof String; break; case INTEGER: ok = v instanceof BigInteger || v instanceof Byte || v instanceof Short || v instanceof Integer || v instanceof Long; break; case DECIMAL: ok = v instanceof BigDecimal; break; case BOOLEAN: ok = v instanceof Boolean; break; case DATETIME: ok = v instanceof GregorianCalendar; break; default: throw new RuntimeException(type.toString()); } if (!ok) { throw new CmisInvalidArgumentException( "Value does not match property type " + type + ": " + v); } } } @SuppressWarnings("unchecked") @Override public T getFirstValue() { Object value = getValue(); if (value == null) { return null; } if (value instanceof List) { List<?> list = (List<?>) value; if (list.isEmpty()) { return null; } return (T) list.get(0); } else { return (T) value; } } @SuppressWarnings("unchecked") @Override public List<T> getValues() { Object value = getValue(); if (value == null) { return Collections.emptyList(); } if (value instanceof List) { return (List<T>) value; } else { return (List<T>) Collections.singletonList(value); } } @Override public void setValue(Object value) { try { if (readOnly) { super.setValue(value); } else { Object propValue; if (value instanceof List<?>) { @SuppressWarnings("unchecked") List<Object> list = new ArrayList<Object>( (List<Object>) value); for (int i = 0; i < list.size(); i++) { list.set(i, convertToNuxeo(list.get(i))); } if (list.isEmpty()) { list = null; } propValue = list; } else { propValue = convertToNuxeo(value); } doc.setPropertyValue(name, (Serializable) propValue); } } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } } protected static Blob getBlob(DocumentModel doc) throws CmisRuntimeException { BlobHolder blobHolder = doc.getAdapter(BlobHolder.class); if (blobHolder == null) { return null; } try { return blobHolder.getBlob(); } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } } public static class NuxeoPropertyStringData extends NuxeoPropertyData<String> implements PropertyString { public NuxeoPropertyStringData( PropertyDefinition<String> propertyDefinition, DocumentModel doc, String name, boolean readOnly) { super(propertyDefinition, doc, name, readOnly); } } public static class NuxeoPropertyIdData extends NuxeoPropertyData<String> implements PropertyId { public NuxeoPropertyIdData( PropertyDefinition<String> propertyDefinition, DocumentModel doc, String name, boolean readOnly) { super(propertyDefinition, doc, name, readOnly); } } public static class NuxeoPropertyBooleanData extends NuxeoPropertyData<Boolean> implements PropertyBoolean { public NuxeoPropertyBooleanData( PropertyDefinition<Boolean> propertyDefinition, DocumentModel doc, String name, boolean readOnly) { super(propertyDefinition, doc, name, readOnly); } } public static class NuxeoPropertyIntegerData extends NuxeoPropertyData<BigInteger> implements PropertyInteger { public NuxeoPropertyIntegerData( PropertyDefinition<BigInteger> propertyDefinition, DocumentModel doc, String name, boolean readOnly) { super(propertyDefinition, doc, name, readOnly); } } public static class NuxeoPropertyDecimalData extends NuxeoPropertyData<BigDecimal> implements PropertyDecimal { public NuxeoPropertyDecimalData( PropertyDefinition<BigDecimal> propertyDefinition, DocumentModel doc, String name, boolean readOnly) { super(propertyDefinition, doc, name, readOnly); } } public static class NuxeoPropertyDateTimeData extends NuxeoPropertyData<GregorianCalendar> implements PropertyDateTime { public NuxeoPropertyDateTimeData( PropertyDefinition<GregorianCalendar> propertyDefinition, DocumentModel doc, String name, boolean readOnly) { super(propertyDefinition, doc, name, readOnly); } } public static class NuxeoPropertyHtmlData extends NuxeoPropertyData<String> implements PropertyHtml { public NuxeoPropertyHtmlData( PropertyDefinition<String> propertyDefinition, DocumentModel doc, String name, boolean readOnly) { super(propertyDefinition, doc, name, readOnly); } } public static class NuxeoPropertyUriData extends NuxeoPropertyData<String> implements PropertyUri { public NuxeoPropertyUriData( PropertyDefinition<String> propertyDefinition, DocumentModel doc, String name, boolean readOnly) { super(propertyDefinition, doc, name, readOnly); } } /** * Property for cmis:contentStreamFileName. */ public static class NuxeoPropertyDataContentStreamFileName extends NuxeoPropertyDataBase<String> implements PropertyString { protected NuxeoPropertyDataContentStreamFileName( PropertyDefinition<String> propertyDefinition, DocumentModel doc) { super(propertyDefinition, doc); } @Override public String getFirstValue() { Blob blob = getBlob(doc); return blob == null ? null : blob.getFilename(); } // @Override // public void setValue(Serializable value) { // BlobHolder blobHolder = docHolder.getDocumentModel().getAdapter( // BlobHolder.class); // if (blobHolder == null) { // throw new StreamNotSupportedException(); // } // Blob blob; // try { // blob = blobHolder.getBlob(); // } catch (ClientException e) { // throw new CmisRuntimeException(e.toString(), e); // } // if (blob != null) { // blob.setFilename((String) value); // } // } } /** * Property for cmis:contentStreamLength. */ public static class NuxeoPropertyDataContentStreamLength extends NuxeoPropertyDataBase<BigInteger> implements PropertyInteger { protected NuxeoPropertyDataContentStreamLength( PropertyDefinition<BigInteger> propertyDefinition, DocumentModel doc) { super(propertyDefinition, doc); } @Override public BigInteger getFirstValue() { Blob blob = getBlob(doc); return blob == null ? null : BigInteger.valueOf(blob.getLength()); } } /** * Property for cmis:contentMimeTypeLength. */ public static class NuxeoPropertyDataContentStreamMimeType extends NuxeoPropertyDataBase<String> implements PropertyString { protected NuxeoPropertyDataContentStreamMimeType( PropertyDefinition<String> propertyDefinition, DocumentModel doc) { super(propertyDefinition, doc); } @Override public String getFirstValue() { Blob blob = getBlob(doc); return blob == null ? null : blob.getMimeType(); } } /** * Property for cmis:name. */ public static class NuxeoPropertyDataName extends NuxeoPropertyDataBase<String> implements PropertyString { private static final Log log = LogFactory.getLog(NuxeoPropertyDataName.class); protected NuxeoPropertyDataName( PropertyDefinition<String> propertyDefinition, DocumentModel doc) { super(propertyDefinition, doc); } /** * Gets the value for the cmis:name property. */ public static String getValue(DocumentModel doc) { if (doc.getPath() == null) { // not a real doc (content changes) return ""; } if (doc.getPath().isRoot()) { return ""; // Nuxeo root } String name; try { name = doc.getTitle(); } catch (ClientException e) { name = ""; } return name; } @Override public String getFirstValue() { return getValue(doc); } @Override public void setValue(Object value) { try { doc.setPropertyValue(NuxeoTypeHelper.NX_DC_TITLE, (String) value); } catch (PropertyNotFoundException e) { // trying to set the name of a type with no dublincore // ignore log.debug("Cannot set CMIS name on type: " + doc.getType()); } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } } } /** * Property for cmis:parentId. */ public static class NuxeoPropertyDataParentId extends NuxeoPropertyDataBase<String> implements PropertyId { protected NuxeoPropertyDataParentId( PropertyDefinition<String> propertyDefinition, DocumentModel doc) { super(propertyDefinition, doc); } @Override public String getFirstValue() { if (doc.getName() == null) { return null; } else { DocumentRef parentRef = doc.getParentRef(); if (parentRef instanceof IdRef) { return ((IdRef) parentRef).value; } else { try { return doc.getCoreSession().getDocument(parentRef).getId(); } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } } } } } /** * Property for cmis:path. */ public static class NuxeoPropertyDataPath extends NuxeoPropertyDataBase<String> implements PropertyString { protected NuxeoPropertyDataPath( PropertyDefinition<String> propertyDefinition, DocumentModel doc) { super(propertyDefinition, doc); } @Override public String getFirstValue() { String path = doc.getPathAsString(); return path == null ? "" : path; } } protected static boolean isLiveDocumentMajorVersion(DocumentModel doc) throws ClientException { return !doc.isCheckedOut() && doc.getVersionLabel().endsWith(".0"); } /** * Property for cmis:isMajorVersion. */ public static class NuxeoPropertyDataIsMajorVersion extends NuxeoPropertyDataBase<Boolean> implements PropertyBoolean { protected NuxeoPropertyDataIsMajorVersion( PropertyDefinition<Boolean> propertyDefinition, DocumentModel doc) { super(propertyDefinition, doc); } @Override public Boolean getFirstValue() { try { if (doc.isVersion() || doc.isProxy()) { return Boolean.valueOf(doc.isMajorVersion()); } // checked in doc considered latest version return Boolean.valueOf(isLiveDocumentMajorVersion(doc)); } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } } } /** * Property for cmis:isLatestVersion. */ public static class NuxeoPropertyDataIsLatestVersion extends NuxeoPropertyDataBase<Boolean> implements PropertyBoolean { protected NuxeoPropertyDataIsLatestVersion( PropertyDefinition<Boolean> propertyDefinition, DocumentModel doc) { super(propertyDefinition, doc); } @Override public Boolean getFirstValue() { try { if (doc.isVersion() || doc.isProxy()) { return Boolean.valueOf(doc.isLatestVersion()); } // checked in doc considered latest version return Boolean.valueOf(!doc.isCheckedOut()); } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } } } /** * Property for cmis:isLatestMajorVersion. */ public static class NuxeoPropertyDataIsLatestMajorVersion extends NuxeoPropertyDataBase<Boolean> implements PropertyBoolean { protected NuxeoPropertyDataIsLatestMajorVersion( PropertyDefinition<Boolean> propertyDefinition, DocumentModel doc) { super(propertyDefinition, doc); } @Override public Boolean getFirstValue() { try { if (doc.isVersion() || doc.isProxy()) { return Boolean.valueOf(doc.isLatestMajorVersion()); } // checked in doc considered latest version return Boolean.valueOf(isLiveDocumentMajorVersion(doc)); } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } } } /** * Property for cmis:isVersionSeriesCheckedOut. */ public static class NuxeoPropertyDataIsVersionSeriesCheckedOut extends NuxeoPropertyDataBase<Boolean> implements PropertyBoolean { protected NuxeoPropertyDataIsVersionSeriesCheckedOut( PropertyDefinition<Boolean> propertyDefinition, DocumentModel doc) { super(propertyDefinition, doc); } @Override public Boolean getFirstValue() { try { return Boolean.valueOf(doc.isVersionSeriesCheckedOut()); } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } } } /** * Property for cmis:versionSeriesCheckedOutId. */ public static class NuxeoPropertyDataVersionSeriesCheckedOutId extends NuxeoPropertyDataBase<String> implements PropertyId { protected NuxeoPropertyDataVersionSeriesCheckedOutId( PropertyDefinition<String> propertyDefinition, DocumentModel doc) { super(propertyDefinition, doc); } @Override public String getFirstValue() { try { if (!doc.isVersionSeriesCheckedOut()) { return null; } DocumentModel pwc = doc.getCoreSession().getWorkingCopy( doc.getRef()); return pwc == null ? null : pwc.getId(); } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } } } /** * Property for cmis:versionSeriesCheckedOutBy. */ public static class NuxeoPropertyDataVersionSeriesCheckedOutBy extends NuxeoPropertyDataBase<String> implements PropertyString { protected final CallContext callContext; protected NuxeoPropertyDataVersionSeriesCheckedOutBy( PropertyDefinition<String> propertyDefinition, DocumentModel doc, CallContext callContext) { super(propertyDefinition, doc); this.callContext = callContext; } @Override public String getFirstValue() { try { if (!doc.isVersionSeriesCheckedOut()) { return null; } DocumentModel pwc = doc.getCoreSession().getWorkingCopy( doc.getRef()); // TODO not implemented return pwc == null ? null : callContext.getUsername(); } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } } } /** * Property for cmis:versionLabel. */ public static class NuxeoPropertyDataVersionLabel extends NuxeoPropertyDataBase<String> implements PropertyString { protected NuxeoPropertyDataVersionLabel( PropertyDefinition<String> propertyDefinition, DocumentModel doc) { super(propertyDefinition, doc); } @Override public String getFirstValue() { try { if (doc.isVersion() || doc.isProxy()) { return doc.getVersionLabel(); } return doc.isCheckedOut() ? null : doc.getVersionLabel(); } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } } } /** * Property for cmis:checkinComment. */ public static class NuxeoPropertyDataCheckInComment extends NuxeoPropertyDataBase<String> implements PropertyString { protected NuxeoPropertyDataCheckInComment( PropertyDefinition<String> propertyDefinition, DocumentModel doc) { super(propertyDefinition, doc); } @Override public String getFirstValue() { try { if (doc.isVersion() || doc.isProxy()) { return doc.getCheckinComment(); } if (doc.isCheckedOut()) { return null; } CoreSession session = doc.getCoreSession(); DocumentRef v = session.getBaseVersion(doc.getRef()); DocumentModel ver = session.getDocument(v); return ver.getCheckinComment(); } catch (ClientException e) { throw new CmisRuntimeException(e.toString(), e); } } } }