You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by fm...@apache.org on 2010/03/23 17:14:48 UTC
svn commit: r926642 - in /incubator/chemistry/trunk/opencmis/opencmis-client:
opencmis-client-api/src/main/java/org/apache/opencmis/client/api/
opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/
opencmis-client-impl/src/main/java/or...
Author: fmui
Date: Tue Mar 23 16:14:48 2010
New Revision: 926642
URL: http://svn.apache.org/viewvc?rev=926642&view=rev
Log:
improved property update
more thread-safe code
Modified:
incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-api/src/main/java/org/apache/opencmis/client/api/CmisObject.java
incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/AbstractPersistentCmisObject.java
incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/OperationContextImpl.java
incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/PersistentSessionImpl.java
incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/cache/CacheImpl.java
incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/repository/PersistentObjectFactoryImpl.java
Modified: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-api/src/main/java/org/apache/opencmis/client/api/CmisObject.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-api/src/main/java/org/apache/opencmis/client/api/CmisObject.java?rev=926642&r1=926641&r2=926642&view=diff
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-api/src/main/java/org/apache/opencmis/client/api/CmisObject.java (original)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-api/src/main/java/org/apache/opencmis/client/api/CmisObject.java Tue Mar 23 16:14:48 2010
@@ -20,6 +20,7 @@ package org.apache.opencmis.client.api;
import java.util.GregorianCalendar;
import java.util.List;
+import java.util.Map;
import org.apache.opencmis.client.api.objecttype.ObjectType;
import org.apache.opencmis.client.api.util.PagingList;
@@ -116,6 +117,8 @@ public interface CmisObject extends Obje
ObjectId updateProperties();
+ ObjectId updateProperties(Map<String, Object> properties);
+
// relationship service
PagingList<Relationship> getRelationships(boolean includeSubRelationshipTypes,
Modified: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/AbstractPersistentCmisObject.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/AbstractPersistentCmisObject.java?rev=926642&r1=926641&r2=926642&view=diff
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/AbstractPersistentCmisObject.java (original)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/AbstractPersistentCmisObject.java Tue Mar 23 16:14:48 2010
@@ -47,6 +47,7 @@ import org.apache.opencmis.commons.Prope
import org.apache.opencmis.commons.api.PropertyDefinition;
import org.apache.opencmis.commons.enums.AclPropagation;
import org.apache.opencmis.commons.enums.BaseObjectTypeIds;
+import org.apache.opencmis.commons.enums.Cardinality;
import org.apache.opencmis.commons.enums.RelationshipDirection;
import org.apache.opencmis.commons.enums.Updatability;
import org.apache.opencmis.commons.provider.CmisProvider;
@@ -264,6 +265,7 @@ public abstract class AbstractPersistent
updatebility.add(Updatability.WHENCHECKEDOUT);
}
+ // it's time to update
getProvider().getObjectService().updateProperties(getRepositoryId(), objectIdHolder,
changeTokenHolder,
getObjectFactory().convertProperties(this.properties.values(), updatebility), null);
@@ -279,6 +281,59 @@ public abstract class AbstractPersistent
}
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.apache.opencmis.client.api.CmisObject#updateProperties(java.util.Map)
+ */
+ public ObjectId updateProperties(Map<String, Object> updateProperties) {
+ if ((updateProperties == null) || (updateProperties.isEmpty())) {
+ throw new IllegalArgumentException("Properties must not be empty!");
+ }
+
+ readLock();
+ try {
+ String objectId = getObjectId();
+ Holder<String> objectIdHolder = new Holder<String>(objectId);
+
+ String changeToken = getChangeToken();
+ Holder<String> changeTokenHolder = new Holder<String>(changeToken);
+
+ Set<Updatability> updatebility = new HashSet<Updatability>();
+ updatebility.add(Updatability.READWRITE);
+
+ // check if checked out
+ Boolean isCheckedOut = getPropertyValue(PropertyIds.CMIS_IS_VERSION_SERIES_CHECKED_OUT);
+ if ((isCheckedOut != null) && isCheckedOut.booleanValue()) {
+ updatebility.add(Updatability.WHENCHECKEDOUT);
+ }
+
+ // build property list
+ ObjectFactory of = getObjectFactory();
+ List<Property<?>> propertyList = new ArrayList<Property<?>>();
+ for (Map.Entry<String, Object> property : updateProperties.entrySet()) {
+ PropertyDefinition<?> propertyDefinition = checkProperty(property.getKey(), property
+ .getValue());
+
+ // create property
+ propertyList.add(of.createProperty(propertyDefinition, property.getValue()));
+ }
+
+ // it's time to update
+ getProvider().getObjectService().updateProperties(getRepositoryId(), objectIdHolder,
+ changeTokenHolder, of.convertProperties(propertyList, updatebility), null);
+
+ if (objectIdHolder.getValue() == null) {
+ return null;
+ }
+
+ return getSession().createObjectId(objectIdHolder.getValue());
+ }
+ finally {
+ readUnlock();
+ }
+ }
+
// --- properties ---
/*
@@ -445,8 +500,27 @@ public abstract class AbstractPersistent
*
* @see org.apache.opencmis.client.api.CmisObject#setProperty(java.lang.String, java.lang.Object)
*/
+ @SuppressWarnings("unchecked")
public <T> void setProperty(String id, T value) {
- setPropertyMultivalue(id, (value == null ? null : Collections.singletonList(value)));
+ PropertyDefinition<?> propertyDefinition = checkProperty(id, value);
+
+ // check updatability
+ if (propertyDefinition.getUpdatability() == Updatability.READONLY) {
+ throw new IllegalArgumentException("Property is read-only!");
+ }
+
+ // create property
+ Property<T> newProperty = (Property<T>) getObjectFactory().createProperty(
+ (PropertyDefinition<T>) propertyDefinition, value);
+
+ writeLock();
+ try {
+ setChanged();
+ this.properties.put(id, newProperty);
+ }
+ finally {
+ writeUnlock();
+ }
}
/*
@@ -457,67 +531,19 @@ public abstract class AbstractPersistent
*/
@SuppressWarnings("unchecked")
public <T> void setPropertyMultivalue(String id, List<T> value) {
- writeLock();
- try {
- // get and check property type
- PropertyDefinition<?> propertyDefinition = getObjectType().getPropertyDefintions().get(id);
- if (propertyDefinition == null) {
- throw new IllegalArgumentException("Unknown property!");
- }
-
- // check updatability
- if (propertyDefinition.getUpdatability() == Updatability.READONLY) {
- throw new IllegalArgumentException("Property is read-only!");
- }
-
- boolean typeMatch = false;
-
- if ((value == null) || (value.isEmpty())) {
- typeMatch = true;
- if (value != null) {
- value = null;
- }
- }
- else {
- // check if list contains null values
- for (Object o : value) {
- if (o == null) {
- throw new IllegalArgumentException("List contains null values!");
- }
- }
-
- // take a sample and test the data type
- Object firstValue = value.get(0);
-
- switch (propertyDefinition.getPropertyType()) {
- case STRING:
- case ID:
- case URI:
- case HTML:
- typeMatch = (firstValue instanceof String);
- break;
- case INTEGER:
- typeMatch = (firstValue instanceof BigInteger);
- break;
- case DECIMAL:
- typeMatch = (firstValue instanceof BigDecimal);
- break;
- case BOOLEAN:
- typeMatch = (firstValue instanceof Boolean);
- break;
- case DATETIME:
- typeMatch = (firstValue instanceof GregorianCalendar);
- break;
- }
- }
+ PropertyDefinition<?> propertyDefinition = checkProperty(id, value);
- if (!typeMatch) {
- throw new IllegalArgumentException("Value does not match property type!");
- }
+ // check updatability
+ if (propertyDefinition.getUpdatability() == Updatability.READONLY) {
+ throw new IllegalArgumentException("Property is read-only!");
+ }
- Property<T> newProperty = (Property<T>) getSession().getObjectFactory()
- .createPropertyMultivalue((PropertyDefinition<T>) propertyDefinition, value);
+ // create property
+ Property<T> newProperty = (Property<T>) getObjectFactory().createPropertyMultivalue(
+ (PropertyDefinition<T>) propertyDefinition, value);
+ writeLock();
+ try {
setChanged();
this.properties.put(id, newProperty);
}
@@ -817,4 +843,83 @@ public abstract class AbstractPersistent
writeUnlock();
}
}
+
+ // --- internal ---
+
+ /**
+ * Checks if a value matches a property definition.
+ */
+ private PropertyDefinition<?> checkProperty(String id, Object value) {
+ PropertyDefinition<?> propertyDefinition = getObjectType().getPropertyDefintions().get(id);
+ if (propertyDefinition == null) {
+ throw new IllegalArgumentException("Unknown property '" + id + "'!");
+ }
+
+ // null values are ok for updates
+ if (value == null) {
+ return propertyDefinition;
+ }
+
+ // single and multi value check
+ List<?> values = null;
+ if (value instanceof List<?>) {
+ if (propertyDefinition.getCardinality() != Cardinality.MULTI) {
+ throw new IllegalArgumentException("Property '" + propertyDefinition.getId()
+ + "' is not a multi value property!");
+ }
+
+ values = (List<?>) value;
+ if (values.isEmpty()) {
+ return propertyDefinition;
+ }
+ }
+ else {
+ if (propertyDefinition.getCardinality() != Cardinality.SINGLE) {
+ throw new IllegalArgumentException("Property '" + propertyDefinition.getId()
+ + "' is not a single value property!");
+ }
+
+ values = Collections.singletonList(value);
+ }
+
+ // check if list contains null values
+ for (Object o : values) {
+ if (o == null) {
+ throw new IllegalArgumentException("Property '" + propertyDefinition.getId()
+ + "' contains null values!");
+ }
+ }
+
+ // take a sample and test the data type
+ boolean typeMatch = false;
+ Object firstValue = values.get(0);
+
+ switch (propertyDefinition.getPropertyType()) {
+ case STRING:
+ case ID:
+ case URI:
+ case HTML:
+ typeMatch = (firstValue instanceof String);
+ break;
+ case INTEGER:
+ typeMatch = (firstValue instanceof BigInteger);
+ break;
+ case DECIMAL:
+ typeMatch = (firstValue instanceof BigDecimal);
+ break;
+ case BOOLEAN:
+ typeMatch = (firstValue instanceof Boolean);
+ break;
+ case DATETIME:
+ typeMatch = (firstValue instanceof GregorianCalendar);
+ break;
+ }
+
+ if (!typeMatch) {
+ throw new IllegalArgumentException("Value of property '" + propertyDefinition.getId()
+ + "' does not match property type!");
+ }
+
+ return propertyDefinition;
+ }
}
Modified: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/OperationContextImpl.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/OperationContextImpl.java?rev=926642&r1=926641&r2=926642&view=diff
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/OperationContextImpl.java (original)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/OperationContextImpl.java Tue Mar 23 16:14:48 2010
@@ -87,7 +87,7 @@ public class OperationContextImpl implem
boolean includeAllowableActions, boolean includePolicies,
IncludeRelationships includeRelationships, Set<String> renditionFilter,
boolean includePathSegments, String orderBy, boolean cacheEnabled) {
- setFilter(filter);
+ setFilter(propertyFilter);
setIncludeAcls(includeAcls);
setIncludeAllowableActions(includeAllowableActions);
setIncludePolicies(includePolicies);
Modified: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/PersistentSessionImpl.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/PersistentSessionImpl.java?rev=926642&r1=926641&r2=926642&view=diff
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/PersistentSessionImpl.java (original)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/PersistentSessionImpl.java Tue Mar 23 16:14:48 2010
@@ -26,6 +26,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -85,6 +86,8 @@ public class PersistentSessionImpl imple
private static Log log = LogFactory.getLog(PersistentSessionImpl.class);
+ private final ReentrantReadWriteLock fLock = new ReentrantReadWriteLock();
+
/*
* default session context (serializable)
*/
@@ -119,7 +122,7 @@ public class PersistentSessionImpl imple
/*
* helper factory (non serializable)
*/
- private transient ObjectFactory objectFactory = PersistentObjectFactoryImpl.newInstance(this);
+ private final ObjectFactory objectFactory = PersistentObjectFactoryImpl.newInstance(this);
/**
* required for serialization
@@ -195,22 +198,25 @@ public class PersistentSessionImpl imple
* @see org.apache.opencmis.client.api.Session#clear()
*/
public void clear() {
- /*
- * clear cache
- */
- int cacheSize = this.determineCacheSize(this.parameters);
- if (cacheSize == -1) {
- this.cache = CacheImpl.newInstance();
+ fLock.writeLock().lock();
+ try {
+ int cacheSize = this.determineCacheSize(this.parameters);
+ if (cacheSize == -1) {
+ this.cache = CacheImpl.newInstance();
+ }
+ else {
+ this.cache = CacheImpl.newInstance(cacheSize);
+ }
+ PersistentSessionImpl.log.info("Session Cache Size: " + this.cache.getCacheSize());
+
+ /*
+ * clear provider cache
+ */
+ getProvider().clearAllCaches();
}
- else {
- this.cache = CacheImpl.newInstance(cacheSize);
+ finally {
+ fLock.writeLock().unlock();
}
- PersistentSessionImpl.log.info("Session Cache Size: " + this.cache.getCacheSize());
-
- /*
- * clear provider cache
- */
- getProvider().clearAllCaches();
}
/*
@@ -297,7 +303,13 @@ public class PersistentSessionImpl imple
* @see org.apache.opencmis.client.api.Session#getDefaultContext()
*/
public OperationContext getDefaultContext() {
- return this.context;
+ fLock.readLock().lock();
+ try {
+ return this.context;
+ }
+ finally {
+ fLock.readLock().unlock();
+ }
}
/*
@@ -307,7 +319,13 @@ public class PersistentSessionImpl imple
* OperationContext)
*/
public void setDefaultContext(OperationContext context) {
- this.context = (context == null ? DEFAULT_CONTEXT : context);
+ fLock.writeLock().lock();
+ try {
+ this.context = (context == null ? DEFAULT_CONTEXT : context);
+ }
+ finally {
+ fLock.writeLock().unlock();
+ }
}
/*
@@ -442,20 +460,39 @@ public class PersistentSessionImpl imple
* @see org.apache.opencmis.client.api.Session#getRepositoryInfo()
*/
public RepositoryInfo getRepositoryInfo() {
- if (this.repositoryInfo == null) {
- /* get initial repository id from session parameter */
- String repositoryId = this.determineRepositoryId(this.parameters);
- if (repositoryId == null) {
- throw new IllegalStateException("Repository Id is not set!");
- }
+ fLock.readLock().lock();
+ try {
+ if (this.repositoryInfo == null) {
+ fLock.readLock().unlock();
+ fLock.writeLock().lock();
+ try {
+ // try again
+ if (this.repositoryInfo != null) {
+ return this.repositoryInfo;
+ }
- RepositoryInfoData data = getProvider().getRepositoryService().getRepositoryInfo(
- repositoryId, null);
+ /* get initial repository id from session parameter */
+ String repositoryId = this.determineRepositoryId(this.parameters);
+ if (repositoryId == null) {
+ throw new IllegalStateException("Repository Id is not set!");
+ }
- this.repositoryInfo = new RepositoryInfoImpl(data);
- }
+ RepositoryInfoData data = getProvider().getRepositoryService().getRepositoryInfo(
+ repositoryId, null);
+
+ this.repositoryInfo = new RepositoryInfoImpl(data);
+ }
+ finally {
+ fLock.writeLock().unlock();
+ fLock.readLock().lock();
+ }
+ }
- return this.repositoryInfo;
+ return this.repositoryInfo;
+ }
+ finally {
+ fLock.readLock().unlock();
+ }
}
/*
@@ -641,22 +678,45 @@ public class PersistentSessionImpl imple
* InMemory} provider is selected.
*/
public void connect() {
- this.provider = CmisProviderHelper.createProvider(this.parameters);
+ fLock.writeLock().lock();
+ try {
+ this.provider = CmisProviderHelper.createProvider(this.parameters);
+ }
+ finally {
+ fLock.writeLock().unlock();
+ }
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.apache.opencmis.client.api.Session#getProvider()
+ */
public CmisProvider getProvider() {
- return this.provider;
+ fLock.readLock().lock();
+ try {
+ return this.provider;
+ }
+ finally {
+ fLock.readLock().unlock();
+ }
}
public Cache getCache() {
- return this.cache;
+ fLock.readLock().lock();
+ try {
+ return this.cache;
+ }
+ finally {
+ fLock.readLock().unlock();
+ }
}
/**
* Returns the repository id.
*/
public String getRepositoryId() {
- return this.getRepositoryInfo().getId();
+ return getRepositoryInfo().getId();
}
// creates
Modified: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/cache/CacheImpl.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/cache/CacheImpl.java?rev=926642&r1=926641&r2=926642&view=diff
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/cache/CacheImpl.java (original)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/cache/CacheImpl.java Tue Mar 23 16:14:48 2010
@@ -202,12 +202,14 @@ public class CacheImpl implements Cache,
CmisObject object = getById(id, cacheKey);
if ((object == null) && (!objectMap.containsKey(id))) {
// clean up
+ fLock.readLock().unlock();
fLock.writeLock().lock();
try {
pathToIdMap.remove(path);
}
finally {
fLock.writeLock().unlock();
+ fLock.readLock().lock();
}
}
Modified: incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/repository/PersistentObjectFactoryImpl.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/repository/PersistentObjectFactoryImpl.java?rev=926642&r1=926641&r2=926642&view=diff
==============================================================================
--- incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/repository/PersistentObjectFactoryImpl.java (original)
+++ incubator/chemistry/trunk/opencmis/opencmis-client/opencmis-client-impl/src/main/java/org/apache/opencmis/client/runtime/repository/PersistentObjectFactoryImpl.java Tue Mar 23 16:14:48 2010
@@ -19,6 +19,7 @@
package org.apache.opencmis.client.runtime.repository;
import java.io.InputStream;
+import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
@@ -90,7 +91,9 @@ import org.apache.opencmis.commons.provi
/**
* Persistent model object factory.
*/
-public class PersistentObjectFactoryImpl implements ObjectFactory {
+public class PersistentObjectFactoryImpl implements ObjectFactory, Serializable {
+
+ private static final long serialVersionUID = 1L;
private PersistentSessionImpl session = null;