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;