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()); } }
