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 2015/05/23 22:48:21 UTC
svn commit: r1681380 [2/2] - in /chemistry/opencmis/trunk:
chemistry-opencmis-client/chemistry-opencmis-client-api/src/main/java/org/apache/chemistry/opencmis/client/api/
chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache...
Added: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/async/AbstractExecutorServiceAsyncSession.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/async/AbstractExecutorServiceAsyncSession.java?rev=1681380&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/async/AbstractExecutorServiceAsyncSession.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/async/AbstractExecutorServiceAsyncSession.java Sat May 23 20:48:20 2015
@@ -0,0 +1,784 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.runtime.async;
+
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.chemistry.opencmis.client.api.AsyncSession;
+import org.apache.chemistry.opencmis.client.api.CmisObject;
+import org.apache.chemistry.opencmis.client.api.Document;
+import org.apache.chemistry.opencmis.client.api.ObjectId;
+import org.apache.chemistry.opencmis.client.api.ObjectType;
+import org.apache.chemistry.opencmis.client.api.OperationContext;
+import org.apache.chemistry.opencmis.client.api.Policy;
+import org.apache.chemistry.opencmis.client.api.Session;
+import org.apache.chemistry.opencmis.commons.data.Ace;
+import org.apache.chemistry.opencmis.commons.data.Acl;
+import org.apache.chemistry.opencmis.commons.data.ContentStream;
+import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
+import org.apache.chemistry.opencmis.commons.enums.AclPropagation;
+import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
+import org.apache.chemistry.opencmis.commons.enums.VersioningState;
+import org.apache.chemistry.opencmis.commons.impl.IOUtils;
+
+/**
+ * An abstract implementation of the {@link AsyncSession} interface that uses an
+ * {@link ExecutorService} object for running asynchronous tasks.
+ */
+public abstract class AbstractExecutorServiceAsyncSession<E extends ExecutorService> extends AbstractAsyncSession {
+
+ public AbstractExecutorServiceAsyncSession(Session session) {
+ super(session);
+ }
+
+ /**
+ * Returns the {@link ExecutorService} object.
+ */
+ public abstract E getExecutorService();
+
+ /**
+ * A {@link Callable} that has a {@link Session} object.
+ */
+ public static abstract class SessionCallable<V> implements Callable<V> {
+
+ protected Session session;
+
+ public SessionCallable(Session session) {
+ if (session == null) {
+ throw new IllegalArgumentException("Session must be set!");
+ }
+
+ this.session = session;
+ }
+ }
+
+ /**
+ * Submits a task for execution.
+ *
+ * @see ExecutorService#submit(Callable)
+ */
+ public <T> Future<T> submit(SessionCallable<T> task) {
+ return getExecutorService().submit(task);
+ }
+
+ // --- types ---
+
+ protected static class GetTypeDefinitonCallable extends SessionCallable<ObjectType> {
+ private String typeId;
+
+ public GetTypeDefinitonCallable(Session session, String typeId) {
+ super(session);
+ this.typeId = typeId;
+ }
+
+ @Override
+ public ObjectType call() throws Exception {
+ return session.getTypeDefinition(typeId);
+ }
+ }
+
+ @Override
+ public Future<ObjectType> getTypeDefinition(String typeId) {
+ return submit(new GetTypeDefinitonCallable(session, typeId));
+ }
+
+ protected static class CreateTypeCallable extends SessionCallable<ObjectType> {
+ private TypeDefinition type;
+
+ public CreateTypeCallable(Session session, TypeDefinition type) {
+ super(session);
+ this.type = type;
+ }
+
+ @Override
+ public ObjectType call() throws Exception {
+ return session.createType(type);
+ }
+ }
+
+ @Override
+ public Future<ObjectType> createType(TypeDefinition type) {
+ return submit(new CreateTypeCallable(session, type));
+ }
+
+ protected static class UpdateTypeCallable extends SessionCallable<ObjectType> {
+ private TypeDefinition type;
+
+ public UpdateTypeCallable(Session session, TypeDefinition type) {
+ super(session);
+ this.type = type;
+ }
+
+ @Override
+ public ObjectType call() throws Exception {
+ return session.updateType(type);
+ }
+ }
+
+ @Override
+ public Future<ObjectType> updateType(TypeDefinition type) {
+ return submit(new UpdateTypeCallable(session, type));
+ }
+
+ protected static class DeleteTypeCallable extends SessionCallable<Object> {
+ private String typeId;
+
+ public DeleteTypeCallable(Session session, String typeId) {
+ super(session);
+ this.typeId = typeId;
+ }
+
+ @Override
+ public Object call() throws Exception {
+ session.deleteType(typeId);
+ return null;
+ }
+ }
+
+ @Override
+ public Future<?> deleteType(String typeId) {
+ return submit(new DeleteTypeCallable(session, typeId));
+ }
+
+ // --- objects ---
+
+ protected static class GetObjectCallable extends SessionCallable<CmisObject> {
+ private ObjectId objectId;
+ private String objectIdStr;
+ private OperationContext context;
+
+ public GetObjectCallable(Session session, ObjectId objectId) {
+ this(session, objectId, null);
+ }
+
+ public GetObjectCallable(Session session, ObjectId objectId, OperationContext context) {
+ super(session);
+ this.objectId = objectId;
+ this.context = context;
+ }
+
+ public GetObjectCallable(Session session, String objectId) {
+ this(session, objectId, null);
+ }
+
+ public GetObjectCallable(Session session, String objectId, OperationContext context) {
+ super(session);
+ this.objectIdStr = objectId;
+ this.context = context;
+ }
+
+ @Override
+ public CmisObject call() throws Exception {
+ if (objectId != null) {
+ if (context != null) {
+ return session.getObject(objectId, context);
+ } else {
+ return session.getObject(objectId);
+ }
+ } else {
+ if (context != null) {
+ return session.getObject(objectIdStr, context);
+ } else {
+ return session.getObject(objectIdStr);
+ }
+ }
+ }
+ }
+
+ @Override
+ public Future<CmisObject> getObject(ObjectId objectId, OperationContext context) {
+ return submit(new GetObjectCallable(session, objectId, context));
+ }
+
+ @Override
+ public Future<CmisObject> getObject(String objectId, OperationContext context) {
+ return submit(new GetObjectCallable(session, objectId, context));
+ }
+
+ protected static class GetObjectByPathCallable extends SessionCallable<CmisObject> {
+ private String path;
+ private String parentPath;
+ private String name;
+ private OperationContext context;
+
+ public GetObjectByPathCallable(Session session, String path) {
+ this(session, path, (OperationContext) null);
+ }
+
+ public GetObjectByPathCallable(Session session, String path, OperationContext context) {
+ super(session);
+ this.path = path;
+ this.context = context;
+ }
+
+ public GetObjectByPathCallable(Session session, String parentPath, String name) {
+ this(session, parentPath, name, null);
+ }
+
+ public GetObjectByPathCallable(Session session, String parentPath, String name, OperationContext context) {
+ super(session);
+ this.parentPath = parentPath;
+ this.name = name;
+ this.context = context;
+ }
+
+ @Override
+ public CmisObject call() throws Exception {
+ if (parentPath != null) {
+ if (context != null) {
+ return session.getObjectByPath(parentPath, name, context);
+ } else {
+ return session.getObjectByPath(parentPath, name);
+ }
+ } else {
+ if (context != null) {
+ return session.getObjectByPath(path, context);
+ } else {
+ return session.getObjectByPath(path);
+ }
+ }
+ }
+ }
+
+ @Override
+ public Future<CmisObject> getObjectByPath(String path, OperationContext context) {
+ return submit(new GetObjectByPathCallable(session, path, context));
+ }
+
+ @Override
+ public Future<CmisObject> getObjectByPath(String parentPath, String name, OperationContext context) {
+ return submit(new GetObjectByPathCallable(session, parentPath, name, context));
+ }
+
+ protected static class GetLatestDocumentVersionCallable extends SessionCallable<Document> {
+ private ObjectId objectId;
+ private String objectIdStr;
+ private boolean major;
+ private OperationContext context;
+
+ public GetLatestDocumentVersionCallable(Session session, ObjectId objectId) {
+ this(session, objectId, false, null);
+ }
+
+ public GetLatestDocumentVersionCallable(Session session, ObjectId objectId, boolean major,
+ OperationContext context) {
+ super(session);
+ this.objectId = objectId;
+ this.major = major;
+ this.context = context;
+ }
+
+ public GetLatestDocumentVersionCallable(Session session, String objectId) {
+ this(session, objectId, false, null);
+ }
+
+ public GetLatestDocumentVersionCallable(Session session, String objectId, boolean major,
+ OperationContext context) {
+ super(session);
+ this.objectIdStr = objectId;
+ this.major = major;
+ this.context = context;
+ }
+
+ @Override
+ public Document call() throws Exception {
+ if (objectId != null) {
+ if (context != null) {
+ return session.getLatestDocumentVersion(objectId, major, context);
+ } else {
+ return session.getLatestDocumentVersion(objectId);
+ }
+ } else {
+ if (context != null) {
+ return session.getLatestDocumentVersion(objectIdStr, major, context);
+ } else {
+ return session.getLatestDocumentVersion(objectIdStr);
+ }
+ }
+ }
+ }
+
+ @Override
+ public Future<Document> getLatestDocumentVersion(ObjectId objectId, boolean major, OperationContext context) {
+ return submit(new GetLatestDocumentVersionCallable(session, objectId, major, context));
+ }
+
+ @Override
+ public Future<Document> getLatestDocumentVersion(String objectId, boolean major, OperationContext context) {
+ return submit(new GetLatestDocumentVersionCallable(session, objectId, major, context));
+ }
+
+ // --- create ---
+
+ protected static class CreateDocumentCallable extends SessionCallable<ObjectId> {
+ private Map<String, ?> properties;
+ private ObjectId folderId;
+ private ContentStream contentStream;
+ private VersioningState versioningState;
+ private List<Policy> policies;
+ private List<Ace> addAces;
+ private List<Ace> removeAces;
+
+ public CreateDocumentCallable(Session session, Map<String, ?> properties, ObjectId folderId,
+ ContentStream contentStream, VersioningState versioningState, List<Policy> policies, List<Ace> addAces,
+ List<Ace> removeAces) {
+ super(session);
+ this.properties = properties;
+ this.folderId = folderId;
+ this.contentStream = contentStream;
+ this.versioningState = versioningState;
+ this.policies = policies;
+ this.addAces = addAces;
+ this.removeAces = removeAces;
+ }
+
+ @Override
+ public ObjectId call() throws Exception {
+ return session.createDocument(properties, folderId, contentStream, versioningState, policies, addAces,
+ removeAces);
+ }
+ }
+
+ @Override
+ public Future<ObjectId> createDocument(Map<String, ?> properties, ObjectId folderId, ContentStream contentStream,
+ VersioningState versioningState, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces) {
+ return submit(new CreateDocumentCallable(session, properties, folderId, contentStream, versioningState,
+ policies, addAces, removeAces));
+ }
+
+ protected static class CreateDocumentFromSourceCallable extends SessionCallable<ObjectId> {
+ private ObjectId source;
+ private Map<String, ?> properties;
+ private ObjectId folderId;
+ private VersioningState versioningState;
+ private List<Policy> policies;
+ private List<Ace> addAces;
+ private List<Ace> removeAces;
+
+ public CreateDocumentFromSourceCallable(Session session, ObjectId source, Map<String, ?> properties,
+ ObjectId folderId, VersioningState versioningState, List<Policy> policies, List<Ace> addAces,
+ List<Ace> removeAces) {
+ super(session);
+ this.source = source;
+ this.properties = properties;
+ this.folderId = folderId;
+ this.versioningState = versioningState;
+ this.policies = policies;
+ this.addAces = addAces;
+ this.removeAces = removeAces;
+ }
+
+ @Override
+ public ObjectId call() throws Exception {
+ return session.createDocumentFromSource(source, properties, folderId, versioningState, policies, addAces,
+ removeAces);
+ }
+ }
+
+ @Override
+ public Future<ObjectId> createDocumentFromSource(ObjectId source, Map<String, ?> properties, ObjectId folderId,
+ VersioningState versioningState, List<Policy> policies, List<Ace> addAces, List<Ace> removeAces) {
+ return submit(new CreateDocumentFromSourceCallable(session, source, properties, folderId, versioningState,
+ policies, addAces, removeAces));
+ }
+
+ protected static class CreateFolderCallable extends SessionCallable<ObjectId> {
+
+ private Map<String, ?> properties;
+ private ObjectId folderId;
+ private List<Policy> policies;
+ private List<Ace> addAces;
+ private List<Ace> removeAces;
+
+ public CreateFolderCallable(Session session, Map<String, ?> properties, ObjectId folderId,
+ List<Policy> policies, List<Ace> addAces, List<Ace> removeAces) {
+ super(session);
+ this.properties = properties;
+ this.folderId = folderId;
+ this.policies = policies;
+ this.addAces = addAces;
+ this.removeAces = removeAces;
+ }
+
+ @Override
+ public ObjectId call() throws Exception {
+ return session.createFolder(properties, folderId, policies, addAces, removeAces);
+ }
+ }
+
+ @Override
+ public Future<ObjectId> createFolder(Map<String, ?> properties, ObjectId folderId, List<Policy> policies,
+ List<Ace> addAces, List<Ace> removeAces) {
+ return submit(new CreateFolderCallable(session, properties, folderId, policies, addAces, removeAces));
+ }
+
+ protected static class CreatePolicyCallable extends SessionCallable<ObjectId> {
+ private Map<String, ?> properties;
+ private ObjectId folderId;
+ private List<Policy> policies;
+ private List<Ace> addAces;
+ private List<Ace> removeAces;
+
+ public CreatePolicyCallable(Session session, Map<String, ?> properties, ObjectId folderId,
+ List<Policy> policies, List<Ace> addAces, List<Ace> removeAces) {
+ super(session);
+ this.properties = properties;
+ this.folderId = folderId;
+ this.policies = policies;
+ this.addAces = addAces;
+ this.removeAces = removeAces;
+ }
+
+ @Override
+ public ObjectId call() throws Exception {
+ return session.createPolicy(properties, folderId, policies, addAces, removeAces);
+ }
+ }
+
+ @Override
+ public Future<ObjectId> createPolicy(Map<String, ?> properties, ObjectId folderId, List<Policy> policies,
+ List<Ace> addAces, List<Ace> removeAces) {
+ return submit(new CreatePolicyCallable(session, properties, folderId, policies, addAces, removeAces));
+ }
+
+ protected static class CreateItemCallable extends SessionCallable<ObjectId> {
+ private Map<String, ?> properties;
+ private ObjectId folderId;
+ private List<Policy> policies;
+ private List<Ace> addAces;
+ private List<Ace> removeAces;
+
+ public CreateItemCallable(Session session, Map<String, ?> properties, ObjectId folderId, List<Policy> policies,
+ List<Ace> addAces, List<Ace> removeAces) {
+ super(session);
+ this.properties = properties;
+ this.folderId = folderId;
+ this.policies = policies;
+ this.addAces = addAces;
+ this.removeAces = removeAces;
+ }
+
+ @Override
+ public ObjectId call() throws Exception {
+ return session.createItem(properties, folderId, policies, addAces, removeAces);
+ }
+ }
+
+ @Override
+ public Future<ObjectId> createItem(Map<String, ?> properties, ObjectId folderId, List<Policy> policies,
+ List<Ace> addAces, List<Ace> removeAces) {
+ return submit(new CreateItemCallable(session, properties, folderId, policies, addAces, removeAces));
+ }
+
+ protected static class CreateRelationshipCallable extends SessionCallable<ObjectId> {
+ private Map<String, ?> properties;
+ private List<Policy> policies;
+ private List<Ace> addAces;
+ private List<Ace> removeAces;
+
+ public CreateRelationshipCallable(Session session, Map<String, ?> properties, List<Policy> policies,
+ List<Ace> addAces, List<Ace> removeAces) {
+ super(session);
+ this.properties = properties;
+ this.policies = policies;
+ this.addAces = addAces;
+ this.removeAces = removeAces;
+ }
+
+ @Override
+ public ObjectId call() throws Exception {
+ return session.createRelationship(properties, policies, addAces, removeAces);
+ }
+ }
+
+ @Override
+ public Future<ObjectId> createRelationship(Map<String, ?> properties, List<Policy> policies, List<Ace> addAces,
+ List<Ace> removeAces) {
+ return submit(new CreateRelationshipCallable(session, properties, policies, addAces, removeAces));
+ }
+
+ // --- content ---
+
+ protected static class GetContentStreamCallable extends SessionCallable<ContentStream> {
+ private ObjectId docId;
+ private String streamId;
+ private BigInteger offset;
+ private BigInteger length;
+
+ public GetContentStreamCallable(Session session, ObjectId docId, String streamId, BigInteger offset,
+ BigInteger length) {
+ super(session);
+ this.docId = docId;
+ this.streamId = streamId;
+ this.offset = offset;
+ this.length = length;
+ }
+
+ @Override
+ public ContentStream call() throws Exception {
+ return session.getContentStream(docId, streamId, offset, length);
+ }
+ }
+
+ @Override
+ public Future<ContentStream> getContentStream(ObjectId docId, String streamId, BigInteger offset, BigInteger length) {
+ return submit(new GetContentStreamCallable(session, docId, streamId, offset, length));
+ }
+
+ protected static class StoreContentStreamCallable extends GetContentStreamCallable {
+ private OutputStream target;
+
+ public StoreContentStreamCallable(Session session, ObjectId docId, String streamId, BigInteger offset,
+ BigInteger length, OutputStream target) {
+ super(session, docId, streamId, offset, length);
+ this.target = target;
+ }
+
+ @Override
+ public ContentStream call() throws Exception {
+ ContentStream contentStream = super.call();
+ try {
+ if (contentStream != null && contentStream.getStream() != null && target != null) {
+ IOUtils.copy(contentStream.getStream(), target);
+ }
+ } finally {
+ IOUtils.closeQuietly(contentStream);
+ }
+
+ return contentStream;
+ }
+ }
+
+ @Override
+ public Future<ContentStream> storeContentStream(ObjectId docId, String streamId, BigInteger offset,
+ BigInteger length, OutputStream target) {
+ return submit(new StoreContentStreamCallable(session, docId, streamId, offset, length, target));
+ }
+
+ // --- delete ---
+
+ protected static class DeleteCallable extends SessionCallable<Object> {
+ private ObjectId objectId;
+ private boolean allVersions;
+
+ public DeleteCallable(Session session, ObjectId objectId, boolean allVersions) {
+ super(session);
+ this.objectId = objectId;
+ this.allVersions = allVersions;
+ }
+
+ @Override
+ public Object call() throws Exception {
+ session.delete(objectId, allVersions);
+ return null;
+ }
+ }
+
+ @Override
+ public Future<?> delete(ObjectId objectId, boolean allVersions) {
+ return submit(new DeleteCallable(session, objectId, allVersions));
+ }
+
+ protected static class DeleteTreeCallable extends SessionCallable<List<String>> {
+ private ObjectId folderId;
+ private boolean allVersions;
+ private UnfileObject unfile;
+ private boolean continueOnFailure;
+
+ public DeleteTreeCallable(Session session, ObjectId folderId, boolean allVersions, UnfileObject unfile,
+ boolean continueOnFailure) {
+ super(session);
+ this.folderId = folderId;
+ this.allVersions = allVersions;
+ this.unfile = unfile;
+ this.continueOnFailure = continueOnFailure;
+ }
+
+ @Override
+ public List<String> call() throws Exception {
+ return session.deleteTree(folderId, allVersions, unfile, continueOnFailure);
+ }
+ }
+
+ @Override
+ public Future<List<String>> deleteTree(ObjectId folderId, boolean allVersions, UnfileObject unfile,
+ boolean continueOnFailure) {
+ return submit(new DeleteTreeCallable(session, folderId, allVersions, unfile, continueOnFailure));
+ }
+
+ // --- ACL ---
+
+ protected static class ApplyAclCallable extends SessionCallable<Acl> {
+ private ObjectId objectId;
+ private List<Ace> addAces;
+ private List<Ace> removeAces;
+ private AclPropagation aclPropagation;
+
+ public ApplyAclCallable(Session session, ObjectId objectId, List<Ace> addAces, List<Ace> removeAces,
+ AclPropagation aclPropagation) {
+ super(session);
+ this.objectId = objectId;
+ this.addAces = addAces;
+ this.removeAces = removeAces;
+ this.aclPropagation = aclPropagation;
+ }
+
+ @Override
+ public Acl call() throws Exception {
+ return session.applyAcl(objectId, addAces, removeAces, aclPropagation);
+ }
+ }
+
+ @Override
+ public Future<Acl> applyAcl(ObjectId objectId, List<Ace> addAces, List<Ace> removeAces,
+ AclPropagation aclPropagation) {
+ return getExecutorService()
+ .submit(new ApplyAclCallable(session, objectId, addAces, removeAces, aclPropagation));
+ }
+
+ protected static class SetAclCallable extends SessionCallable<Acl> {
+ private ObjectId objectId;
+ private List<Ace> aces;
+
+ public SetAclCallable(Session session, ObjectId objectId, List<Ace> aces) {
+ super(session);
+ this.objectId = objectId;
+ this.aces = aces;
+ }
+
+ @Override
+ public Acl call() throws Exception {
+ return session.setAcl(objectId, aces);
+ }
+ }
+
+ @Override
+ public Future<Acl> setAcl(ObjectId objectId, List<Ace> aces) {
+ return submit(new SetAclCallable(session, objectId, aces));
+ }
+
+ // --- policy ---
+
+ protected static class ApplyPolicyCallable extends SessionCallable<Object> {
+ private ObjectId objectId;
+ private ObjectId[] policyIds;
+
+ public ApplyPolicyCallable(Session session, ObjectId objectId, ObjectId... policyIds) {
+ super(session);
+ this.objectId = objectId;
+ this.policyIds = policyIds;
+ }
+
+ @Override
+ public Object call() throws Exception {
+ session.applyPolicy(objectId, policyIds);
+ return null;
+ }
+ }
+
+ @Override
+ public Future<?> applyPolicy(ObjectId objectId, ObjectId... policyIds) {
+ return submit(new ApplyPolicyCallable(session, objectId, policyIds));
+ }
+
+ protected static class RemovePolicyCallable extends SessionCallable<Object> {
+ private ObjectId objectId;
+ private ObjectId[] policyIds;
+
+ public RemovePolicyCallable(Session session, ObjectId objectId, ObjectId... policyIds) {
+ super(session);
+ this.objectId = objectId;
+ this.policyIds = policyIds;
+ }
+
+ @Override
+ public Object call() throws Exception {
+ session.removePolicy(objectId, policyIds);
+ return null;
+ }
+ }
+
+ @Override
+ public Future<?> removePolicy(ObjectId objectId, ObjectId... policyIds) {
+ return submit(new RemovePolicyCallable(session, objectId, policyIds));
+ }
+
+ // --- shut down ---
+
+ /**
+ * @see ExecutorService#shutdown()
+ */
+ public void shutdown() {
+ if (getExecutorService() != null) {
+ getExecutorService().shutdown();
+ }
+ }
+
+ /**
+ * @see ExecutorService#shutdownNow()
+ */
+ public List<Runnable> shutdownNow() {
+ if (getExecutorService() != null) {
+ return getExecutorService().shutdownNow();
+ }
+
+ return Collections.emptyList();
+ }
+
+ /**
+ * @see ExecutorService#isShutdown()
+ */
+ public boolean isShutdown() {
+ if (getExecutorService() != null) {
+ return getExecutorService().isShutdown();
+ }
+
+ return true;
+ }
+
+ /**
+ * @see ExecutorService#isTerminated()
+ */
+ public boolean isTerminated() {
+ if (getExecutorService() != null) {
+ return getExecutorService().isTerminated();
+ }
+
+ return true;
+ }
+
+ /**
+ * @see ExecutorService#awaitTermination(long, TimeUnit)
+ */
+ public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
+ if (getExecutorService() != null) {
+ return getExecutorService().awaitTermination(timeout, unit);
+ }
+
+ return true;
+ }
+}
Added: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/async/AsyncSessionFactoryImpl.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/async/AsyncSessionFactoryImpl.java?rev=1681380&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/async/AsyncSessionFactoryImpl.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/async/AsyncSessionFactoryImpl.java Sat May 23 20:48:20 2015
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.runtime.async;
+
+import org.apache.chemistry.opencmis.client.api.AsyncSession;
+import org.apache.chemistry.opencmis.client.api.AsyncSessionFactory;
+import org.apache.chemistry.opencmis.client.api.Session;
+
+/**
+ * Factory for {@link AsyncSession} objects.
+ */
+public class AsyncSessionFactoryImpl implements AsyncSessionFactory {
+
+ protected AsyncSessionFactoryImpl() {
+ }
+
+ public static AsyncSessionFactoryImpl newInstance() {
+ return new AsyncSessionFactoryImpl();
+ }
+
+ @Override
+ public AsyncSession createAsyncSession(Session session) {
+ return createAsyncSession(session, 5);
+ }
+
+ @Override
+ public AsyncSession createAsyncSession(Session session, int maxParallelRequests) {
+ if (session == null) {
+ throw new IllegalArgumentException("Session must be set!");
+ }
+
+ if (maxParallelRequests < 1) {
+ throw new IllegalArgumentException("maxParallelRequests must be >0!");
+ }
+
+ return new ThreadPoolExecutorAsyncSession(session, maxParallelRequests);
+ }
+}
Added: chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/async/ThreadPoolExecutorAsyncSession.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/async/ThreadPoolExecutorAsyncSession.java?rev=1681380&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/async/ThreadPoolExecutorAsyncSession.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-client/chemistry-opencmis-client-impl/src/main/java/org/apache/chemistry/opencmis/client/runtime/async/ThreadPoolExecutorAsyncSession.java Sat May 23 20:48:20 2015
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.client.runtime.async;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.chemistry.opencmis.client.api.AsyncSession;
+import org.apache.chemistry.opencmis.client.api.Session;
+
+/**
+ * An implementation of the {@link AsyncSession} interface that uses an
+ * {@link ThreadPoolExecutor} object for running asynchronous tasks.
+ */
+public class ThreadPoolExecutorAsyncSession extends AbstractExecutorServiceAsyncSession<ThreadPoolExecutor> {
+
+ private ThreadPoolExecutor executor;
+
+ public ThreadPoolExecutorAsyncSession(Session session) {
+ this(session, 5);
+ }
+
+ public ThreadPoolExecutorAsyncSession(Session session, int maxThreads) {
+ super(session);
+ executor = new ThreadPoolExecutor(maxThreads, maxThreads, 0L, TimeUnit.MILLISECONDS,
+ new LinkedBlockingQueue<Runnable>());
+ }
+
+ @Override
+ public ThreadPoolExecutor getExecutorService() {
+ return executor;
+ }
+}
Modified: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/impl/AbstractCmisTest.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/impl/AbstractCmisTest.java?rev=1681380&r1=1681379&r2=1681380&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/impl/AbstractCmisTest.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/impl/AbstractCmisTest.java Sat May 23 20:48:20 2015
@@ -18,6 +18,7 @@
*/
package org.apache.chemistry.opencmis.tck.impl;
+import java.lang.reflect.Array;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
@@ -323,6 +324,50 @@ public abstract class AbstractCmisTest i
}
}
+ return success;
+ }
+
+ protected CmisTestResult assertEqualArray(Object expected, Object actual, CmisTestResult success,
+ CmisTestResult failure) {
+ if (expected == null && actual == null) {
+ return success;
+ }
+
+ if (expected == null) {
+ return addResultChild(failure, createResult(CmisTestResultStatus.INFO, "Expected array is null!"));
+ }
+
+ if (!expected.getClass().isArray()) {
+ return addResultChild(failure, createResult(CmisTestResultStatus.INFO, "Expected array is not an array!"));
+ }
+
+ if (actual == null) {
+ return addResultChild(failure, createResult(CmisTestResultStatus.INFO, "Actual array is null!"));
+ }
+
+ if (!actual.getClass().isArray()) {
+ return addResultChild(failure, createResult(CmisTestResultStatus.INFO, "Actual array is not an array!"));
+ }
+
+ if (Array.getLength(expected) != Array.getLength(actual)) {
+ return addResultChild(
+ failure,
+ createResult(
+ CmisTestResultStatus.INFO,
+ "Array sizes don't match! expected: " + Array.getLength(expected) + " / actual: "
+ + Array.getLength(actual)));
+ }
+
+ for (int i = 0; i < Array.getLength(expected); i++) {
+ if (!isEqual(Array.get(expected, i), Array.get(actual, i))) {
+ return addResultChild(
+ failure,
+ createResult(CmisTestResultStatus.INFO,
+ "expected array item[" + i + "]: " + formatValue(Array.get(expected, i))
+ + " / actual array item[" + i + "]: " + formatValue(Array.get(actual, i))));
+ }
+ }
+
return success;
}
Added: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/tests/crud/AsyncCreateAndDeleteDocumentTest.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/tests/crud/AsyncCreateAndDeleteDocumentTest.java?rev=1681380&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/tests/crud/AsyncCreateAndDeleteDocumentTest.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/tests/crud/AsyncCreateAndDeleteDocumentTest.java Sat May 23 20:48:20 2015
@@ -0,0 +1,228 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.tck.tests.crud;
+
+import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.FAILURE;
+import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.UNEXPECTED_EXCEPTION;
+import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.WARNING;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.Future;
+
+import org.apache.chemistry.opencmis.client.api.AsyncSession;
+import org.apache.chemistry.opencmis.client.api.CmisObject;
+import org.apache.chemistry.opencmis.client.api.Document;
+import org.apache.chemistry.opencmis.client.api.Folder;
+import org.apache.chemistry.opencmis.client.api.ItemIterable;
+import org.apache.chemistry.opencmis.client.api.ObjectId;
+import org.apache.chemistry.opencmis.client.api.Session;
+import org.apache.chemistry.opencmis.client.runtime.async.AbstractExecutorServiceAsyncSession;
+import org.apache.chemistry.opencmis.client.runtime.async.AsyncSessionFactoryImpl;
+import org.apache.chemistry.opencmis.commons.PropertyIds;
+import org.apache.chemistry.opencmis.commons.data.ContentStream;
+import org.apache.chemistry.opencmis.commons.impl.dataobjects.ContentStreamImpl;
+import org.apache.chemistry.opencmis.tck.CmisTestResult;
+import org.apache.chemistry.opencmis.tck.impl.AbstractSessionTest;
+
+/**
+ * Simple document test.
+ */
+public class AsyncCreateAndDeleteDocumentTest extends AbstractSessionTest {
+
+ @Override
+ public void init(Map<String, String> parameters) {
+ super.init(parameters);
+ setName("Asynchronous Create and Delete Document Test");
+ setDescription("Creates documents in parallel, checks the newly created documents and finally deletes the created documents in parallel.");
+ }
+
+ @Override
+ public void run(Session session) {
+ CmisTestResult f;
+
+ int numOfDocuments = 100;
+ String mimeType = "text/plain";
+
+ byte[] contentBytes = new byte[64 * 1024];
+ for (int i = 0; i < contentBytes.length; i++) {
+ contentBytes[i] = (byte) ('0' + i % 10);
+ }
+
+ // create an async session
+ AsyncSession asyncSession = AsyncSessionFactoryImpl.newInstance().createAsyncSession(session, 10);
+
+ // create a test folder
+ Folder testFolder = createTestFolder(session);
+
+ try {
+ // create documents
+ List<Future<ObjectId>> docFutures = new ArrayList<Future<ObjectId>>();
+ for (int i = 0; i < numOfDocuments; i++) {
+ String name = "asyncdoc" + i + ".txt";
+
+ Map<String, Object> properties = new HashMap<String, Object>();
+ properties.put(PropertyIds.NAME, name);
+ properties.put(PropertyIds.OBJECT_TYPE_ID, getDocumentTestTypeId());
+
+ ContentStream contentStream = new ContentStreamImpl(name, BigInteger.valueOf(contentBytes.length),
+ mimeType, new ByteArrayInputStream(contentBytes));
+
+ Future<ObjectId> newDocument = asyncSession.createDocument(properties, testFolder, contentStream, null);
+
+ docFutures.add(newDocument);
+ }
+
+ // wait for all document being created
+ List<ObjectId> docIds = new ArrayList<ObjectId>();
+ try {
+ for (Future<ObjectId> docFuture : docFutures) {
+ ObjectId id = docFuture.get();
+ docIds.add(id);
+ }
+ } catch (Exception e) {
+ addResult(createResult(UNEXPECTED_EXCEPTION,
+ "Documents could not been created! Exception: " + e.getMessage(), e, true));
+ }
+
+ // check children of the test folder
+ int count = countChildren(testFolder);
+ f = createResult(FAILURE, "Test folder should have " + numOfDocuments + " children but has " + count + "!");
+ addResult(assertEquals(count, numOfDocuments, null, f));
+
+ // simple children test
+ addResult(checkChildren(session, testFolder, "Test folder children check"));
+
+ // get documents
+ Map<String, Future<CmisObject>> getObjectFutures = new HashMap<String, Future<CmisObject>>();
+ Map<String, Future<ContentStream>> contentStreamFutures = new HashMap<String, Future<ContentStream>>();
+ Map<String, ByteArrayOutputStream> content = new HashMap<String, ByteArrayOutputStream>();
+
+ for (ObjectId docId : docIds) {
+ Future<CmisObject> getObjectFuture = asyncSession.getObject(docId, SELECT_ALL_NO_CACHE_OC);
+ getObjectFutures.put(docId.getId(), getObjectFuture);
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream(contentBytes.length);
+ content.put(docId.getId(), out);
+
+ Future<ContentStream> contentStreamFuture = asyncSession.storeContentStream(docId, out);
+ contentStreamFutures.put(docId.getId(), contentStreamFuture);
+ }
+
+ // wait for all document being fetched
+ try {
+ for (Map.Entry<String, Future<CmisObject>> getObjectFuture : getObjectFutures.entrySet()) {
+ CmisObject object = getObjectFuture.getValue().get();
+
+ f = createResult(FAILURE, "Fetching document failed!");
+ addResult(assertIsTrue(object instanceof Document, null, f));
+
+ if (object != null) {
+ f = createResult(FAILURE, "Fetched wrong document!");
+ addResult(assertEquals(getObjectFuture.getKey(), object.getId(), null, f));
+ }
+ }
+ } catch (Exception e) {
+ addResult(createResult(UNEXPECTED_EXCEPTION,
+ "Documents could not been fetched! Exception: " + e.getMessage(), e, true));
+ }
+
+ // wait for all document content being fetched
+ try {
+ for (Map.Entry<String, Future<ContentStream>> contentStreamFuture : contentStreamFutures.entrySet()) {
+ ContentStream contentStream = contentStreamFuture.getValue().get();
+
+ f = createResult(FAILURE, "Fetching document content failed!");
+ addResult(assertNotNull(contentStream, null, f));
+
+ if (contentStream != null) {
+ if (contentStream.getMimeType() == null) {
+ addResult(createResult(FAILURE, "Content MIME type is null!"));
+ } else {
+ f = createResult(WARNING, "Content MIME types don't match!");
+ addResult(assertIsTrue(contentStream.getMimeType().trim().toLowerCase(Locale.ENGLISH)
+ .startsWith(mimeType.toLowerCase(Locale.ENGLISH)), null, f));
+ }
+ }
+
+ ByteArrayOutputStream out = content.get(contentStreamFuture.getKey());
+ byte[] readBytes = out.toByteArray();
+
+ f = createResult(FAILURE, "Read content length doesn't match document content length!");
+ addResult(assertEquals(contentBytes.length, readBytes.length, null, f));
+
+ f = createResult(FAILURE, "Read content doesn't match document content!");
+ addResult(assertEqualArray(contentBytes, readBytes, null, f));
+ }
+ } catch (Exception e) {
+ addResult(createResult(UNEXPECTED_EXCEPTION,
+ "Document content could not been fetched! Exception: " + e.getMessage(), e, true));
+ }
+
+ // delete documents
+ List<Future<?>> delFutures = new ArrayList<Future<?>>();
+ for (ObjectId docId : docIds) {
+ Future<?> delFuture = asyncSession.delete(docId);
+ delFutures.add(delFuture);
+ }
+
+ // wait for all document being deleted
+ try {
+ for (Future<?> delFuture : delFutures) {
+ delFuture.get();
+ }
+ } catch (Exception e) {
+ addResult(createResult(UNEXPECTED_EXCEPTION,
+ "Documents could not been deleted! Exception: " + e.getMessage(), e, true));
+ }
+
+ // check children of the test folder
+ count = countChildren(testFolder);
+ f = createResult(FAILURE, "Test folder should be empty but has " + count + " children!");
+ addResult(assertEquals(count, 0, null, f));
+ } finally {
+ // delete the test folder
+ deleteTestFolder();
+
+ if (asyncSession instanceof AbstractExecutorServiceAsyncSession<?>) {
+ ((AbstractExecutorServiceAsyncSession<?>) asyncSession).shutdown();
+ }
+ }
+
+ addResult(createInfoResult("Tested the parallel creation and deletion of " + numOfDocuments + " documents."));
+ }
+
+ private int countChildren(Folder folder) {
+ int count = 0;
+ ItemIterable<CmisObject> children = folder.getChildren(SELECT_ALL_NO_CACHE_OC);
+ for (CmisObject child : children) {
+ if (child instanceof Document) {
+ count++;
+ }
+ }
+
+ return count;
+ }
+}
Added: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/tests/crud/AsyncCreateAndDeleteFolderTest.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/tests/crud/AsyncCreateAndDeleteFolderTest.java?rev=1681380&view=auto
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/tests/crud/AsyncCreateAndDeleteFolderTest.java (added)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/tests/crud/AsyncCreateAndDeleteFolderTest.java Sat May 23 20:48:20 2015
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.chemistry.opencmis.tck.tests.crud;
+
+import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.FAILURE;
+import static org.apache.chemistry.opencmis.tck.CmisTestResultStatus.UNEXPECTED_EXCEPTION;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Future;
+
+import org.apache.chemistry.opencmis.client.api.AsyncSession;
+import org.apache.chemistry.opencmis.client.api.CmisObject;
+import org.apache.chemistry.opencmis.client.api.Folder;
+import org.apache.chemistry.opencmis.client.api.ItemIterable;
+import org.apache.chemistry.opencmis.client.api.ObjectId;
+import org.apache.chemistry.opencmis.client.api.Session;
+import org.apache.chemistry.opencmis.client.runtime.async.AbstractExecutorServiceAsyncSession;
+import org.apache.chemistry.opencmis.client.runtime.async.AsyncSessionFactoryImpl;
+import org.apache.chemistry.opencmis.commons.PropertyIds;
+import org.apache.chemistry.opencmis.commons.enums.UnfileObject;
+import org.apache.chemistry.opencmis.tck.CmisTestResult;
+import org.apache.chemistry.opencmis.tck.impl.AbstractSessionTest;
+
+/**
+ * Simple document test.
+ */
+public class AsyncCreateAndDeleteFolderTest extends AbstractSessionTest {
+
+ @Override
+ public void init(Map<String, String> parameters) {
+ super.init(parameters);
+ setName("Asynchronous Create and Delete Folder Test");
+ setDescription("Creates folders in parallel and deletes the created folders in parallel.");
+ }
+
+ @Override
+ public void run(Session session) {
+ CmisTestResult f;
+
+ int numOfFolders = 100;
+
+ // create an async session
+ AsyncSession asyncSession = AsyncSessionFactoryImpl.newInstance().createAsyncSession(session, 10);
+
+ // create a test folder
+ Folder testFolder = createTestFolder(session);
+
+ try {
+ // create folders
+ List<Future<ObjectId>> folderFutures = new ArrayList<Future<ObjectId>>();
+ for (int i = 0; i < numOfFolders; i++) {
+ String name = "asyncfolder" + i;
+
+ Map<String, Object> properties = new HashMap<String, Object>();
+ properties.put(PropertyIds.NAME, name);
+ properties.put(PropertyIds.OBJECT_TYPE_ID, getFolderTestTypeId());
+
+ Future<ObjectId> newFolder = asyncSession.createFolder(properties, testFolder);
+
+ folderFutures.add(newFolder);
+ }
+
+ // wait for all folders being created
+ List<ObjectId> folderIds = new ArrayList<ObjectId>();
+ try {
+ for (Future<ObjectId> folderFuture : folderFutures) {
+ ObjectId id = folderFuture.get();
+ folderIds.add(id);
+ }
+ } catch (Exception e) {
+ addResult(createResult(UNEXPECTED_EXCEPTION,
+ "Folder could not been created! Exception: " + e.getMessage(), e, true));
+ }
+
+ // check children of test folder
+ int count = countChildren(testFolder);
+ f = createResult(FAILURE, "Test folder should have " + numOfFolders + " children but has " + count + "!");
+ addResult(assertEquals(count, numOfFolders, null, f));
+
+ // get folders
+ Map<String, Future<CmisObject>> getObjectFutures = new HashMap<String, Future<CmisObject>>();
+
+ for (ObjectId folderId : folderIds) {
+ Future<CmisObject> getObjectFuture = asyncSession.getObject(folderId, SELECT_ALL_NO_CACHE_OC);
+ getObjectFutures.put(folderId.getId(), getObjectFuture);
+ }
+
+ // wait for all folders being fetched
+ List<String> paths = new ArrayList<String>();
+ try {
+ for (Map.Entry<String, Future<CmisObject>> getObjectFuture : getObjectFutures.entrySet()) {
+ CmisObject object = getObjectFuture.getValue().get();
+
+ f = createResult(FAILURE, "Fetching folder failed!");
+ addResult(assertIsTrue(object instanceof Folder, null, f));
+
+ if (object != null) {
+ f = createResult(FAILURE, "Fetched wrong folder!");
+ addResult(assertEquals(getObjectFuture.getKey(), object.getId(), null, f));
+
+ paths.add(((Folder) object).getPath());
+ }
+ }
+ } catch (Exception e) {
+ addResult(createResult(UNEXPECTED_EXCEPTION,
+ "Folders could not been fetched! Exception: " + e.getMessage(), e, true));
+ }
+
+ // get folders by path
+ Map<String, Future<CmisObject>> getObjectByPathFutures = new HashMap<String, Future<CmisObject>>();
+
+ for (String path : paths) {
+ Future<CmisObject> getObjectByPathFuture = asyncSession.getObjectByPath(path, SELECT_ALL_NO_CACHE_OC);
+ getObjectByPathFutures.put(path, getObjectByPathFuture);
+ }
+
+ // wait for all folders being fetched
+ try {
+ for (Map.Entry<String, Future<CmisObject>> getObjectByPathFuture : getObjectByPathFutures.entrySet()) {
+ CmisObject object = getObjectByPathFuture.getValue().get();
+
+ f = createResult(FAILURE, "Fetching folder failed!");
+ addResult(assertIsTrue(object instanceof Folder, null, f));
+
+ if (object != null) {
+ f = createResult(FAILURE, "Fetched wrong folder!");
+ addResult(assertEquals(getObjectByPathFuture.getKey(), ((Folder) object).getPath(), null, f));
+ }
+ }
+ } catch (Exception e) {
+ addResult(createResult(UNEXPECTED_EXCEPTION,
+ "Folders could not been fetched! Exception: " + e.getMessage(), e, true));
+ }
+
+ // delete folders
+ List<Future<?>> delFutures = new ArrayList<Future<?>>();
+ for (ObjectId folderId : folderIds) {
+ Future<?> delFuture = asyncSession.deleteTree(folderId, true, UnfileObject.DELETE, true);
+ delFutures.add(delFuture);
+ }
+
+ // wait for all folders being deleted
+ try {
+ for (Future<?> delFuture : delFutures) {
+ delFuture.get();
+ }
+ } catch (Exception e) {
+ addResult(createResult(UNEXPECTED_EXCEPTION,
+ "Folder could not been deleted! Exception: " + e.getMessage(), e, true));
+ }
+
+ // check children of test folder
+ count = countChildren(testFolder);
+ f = createResult(FAILURE, "Test folder should be empty but has " + count + " children!");
+ addResult(assertEquals(count, 0, null, f));
+ } finally {
+ // delete the test folder
+ deleteTestFolder();
+
+ if (asyncSession instanceof AbstractExecutorServiceAsyncSession<?>) {
+ ((AbstractExecutorServiceAsyncSession<?>) asyncSession).shutdown();
+ }
+ }
+
+ addResult(createInfoResult("Tested the parallel creation and deletion of " + numOfFolders + " folders."));
+ }
+
+ private int countChildren(Folder folder) {
+ int count = 0;
+ ItemIterable<CmisObject> children = folder.getChildren(SELECT_ALL_NO_CACHE_OC);
+ for (CmisObject child : children) {
+ if (child instanceof Folder) {
+ count++;
+ }
+ }
+
+ return count;
+ }
+}
Modified: chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/tests/crud/CRUDTestGroup.java
URL: http://svn.apache.org/viewvc/chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/tests/crud/CRUDTestGroup.java?rev=1681380&r1=1681379&r2=1681380&view=diff
==============================================================================
--- chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/tests/crud/CRUDTestGroup.java (original)
+++ chemistry/opencmis/trunk/chemistry-opencmis-test/chemistry-opencmis-test-tck/src/main/java/org/apache/chemistry/opencmis/tck/tests/crud/CRUDTestGroup.java Sat May 23 20:48:20 2015
@@ -52,5 +52,7 @@ public class CRUDTestGroup extends Abstr
addTest(new MoveTest());
addTest(new DeleteTreeTest());
addTest(new OperationContextTest());
+ addTest(new AsyncCreateAndDeleteDocumentTest());
+ addTest(new AsyncCreateAndDeleteFolderTest());
}
}