You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by dc...@apache.org on 2010/02/11 12:44:29 UTC

svn commit: r908938 - in /incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry: abdera/ext/ tck/atompub/client/ tck/atompub/fixture/ tck/atompub/test/ tck/atompub/test/spec/

Author: dcaruana
Date: Thu Feb 11 11:44:23 2010
New Revision: 908938

URL: http://svn.apache.org/viewvc?rev=908938&view=rev
Log:
CMIS-115: Add Change Log tests to TCK
- update TCK Abdera extension to allow for query of change log related information

Added:
    incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISChangeEventInfo.java   (with props)
    incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/AssertChangeTypeInChangeLogVisitor.java   (with props)
    incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/ManageAccessControlListVisitor.java   (with props)
    incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/UpdateDocumentsVisitor.java   (with props)
    incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/spec/ChangeLogTest.java   (with props)
Modified:
    incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISAccessControlList.java
    incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISCapabilities.java
    incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISConstants.java
    incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISExtensionFactory.java
    incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISObject.java
    incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISRepositoryInfo.java
    incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISTypeDefinition.java
    incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/client/CMISClient.java
    incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/TCKTestSuite.java
    incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/spec/AccessControlListTest.java

Modified: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISAccessControlList.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISAccessControlList.java?rev=908938&r1=908937&r2=908938&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISAccessControlList.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISAccessControlList.java Thu Feb 11 11:44:23 2010
@@ -17,7 +17,9 @@
 package org.apache.chemistry.abdera.ext;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import org.apache.abdera.factory.Factory;
 import org.apache.abdera.model.Element;
@@ -63,4 +65,31 @@
         }
         return entries;
     }
+
+    /**
+     * Flattens an access control list into a structure that is easy to compare:
+     * a set of triples containing the principal ID, the direct flag and the
+     * permission name.
+     * 
+     * @param accessControlList
+     *            the access control list
+     * 
+     * @return the set of triples
+     */
+    public Set<List<Object>> getHashedEntries() {
+        List<CMISAccessControlEntry> entries = getEntries();
+        Set<List<Object>> hashSet = new HashSet<List<Object>>(entries.size() * 2);
+        for (CMISAccessControlEntry accessControlEntry : entries) {
+            String principalId = accessControlEntry.getPrincipalId();
+            Boolean direct = accessControlEntry.isDirect();
+            for (String permission : accessControlEntry.getPermissions()) {
+                List<Object> comparable = new ArrayList<Object>(3);
+                comparable.add(principalId);
+                comparable.add(direct);
+                comparable.add(permission);
+                hashSet.add(comparable);
+            }
+        }
+        return hashSet;
+    }
 }

Modified: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISCapabilities.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISCapabilities.java?rev=908938&r1=908937&r2=908938&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISCapabilities.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISCapabilities.java Thu Feb 11 11:44:23 2010
@@ -87,4 +87,9 @@
         Element child = getFirstChild(CMISConstants.CAPABILITY_ACL);
         return child.getText();
     }
+
+    public String getChanges() {
+        Element child = getFirstChild(CMISConstants.CAPABILITY_CHANGES);
+        return child.getText();
+    }
 }

Added: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISChangeEventInfo.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISChangeEventInfo.java?rev=908938&view=auto
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISChangeEventInfo.java (added)
+++ incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISChangeEventInfo.java Thu Feb 11 11:44:23 2010
@@ -0,0 +1,39 @@
+/*
+ * Licensed 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.
+ *
+ * Authors:
+ *     David Ward, Alfresco
+ */
+package org.apache.chemistry.abdera.ext;
+
+import org.apache.abdera.factory.Factory;
+import org.apache.abdera.model.Element;
+import org.apache.abdera.model.ExtensibleElementWrapper;
+
+/**
+ * CMIS Change Event Info for the Abdera ATOM library.
+ */
+public class CMISChangeEventInfo extends ExtensibleElementWrapper {
+
+    public CMISChangeEventInfo(Element internal) {
+        super(internal);
+    }
+
+    public CMISChangeEventInfo(Factory factory) {
+        super(factory, CMISConstants.CHANGE_EVENT_INFO);
+    }
+
+    public String getChangeType() {
+        return getFirstChild(CMISConstants.CHANGE_TYPE).getText();
+    }
+}

Propchange: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISChangeEventInfo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISConstants.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISConstants.java?rev=908938&r1=908937&r2=908938&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISConstants.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISConstants.java Thu Feb 11 11:44:23 2010
@@ -62,6 +62,8 @@
     public static final QName VERSION_SUPPORTED = new QName(CMIS_NS, "cmisVersionSupported");
     public static final QName PRINCIPAL_ANONYMOUS = new QName(CMIS_NS, "principalAnonymous");
     public static final QName PRINCIPAL_ANYONE = new QName(CMIS_NS, "principalAnyone");
+    public static final QName LATEST_CHANGE_LOG_TOKEN = new QName(CMIS_NS, "latestChangeLogToken");
+    public static final QName CHANGES_ON_TYPE = new QName(CMIS_NS, "changesOnType");
 
     // CMIS URI Templates
     public static final QName URI_TEMPLATE = new QName(CMISRA_NS, "uritemplate");
@@ -86,6 +88,7 @@
     public static final QName CAPABILITY_JOIN = new QName(CMIS_NS, "capabilityJoin");
     public static final QName CAPABILITY_RENDITIONS = new QName(CMIS_NS, "capabilityRenditions");
     public static final QName CAPABILITY_ACL = new QName(CMIS_NS, "capabilityACL");
+    public static final QName CAPABILITY_CHANGES = new QName(CMIS_NS, "capabilityChanges");
 
     // ACL Capabilities
     public static final QName ACL_CAPABILITY = new QName(CMIS_NS, "aclCapability");
@@ -179,6 +182,7 @@
     public static final String REL_SERVICE = "service";
     public static final String REL_UP = "up";
     public static final String REL_DOWN = "down";
+    public static final String REL_NEXT = "next";
     public static final String REL_DESCRIBED_BY = "describedby";
     public static final String REL_VERSION_HISTORY = "version-history";
     public static final String REL_CURRENT_VERSION = "current-version";
@@ -191,6 +195,7 @@
     public static final String REL_POLICIES = CMISLINK_NS + "policies";
     public static final String REL_RELATIONSHIPS = CMISLINK_NS + "relationships";
     public static final String REL_ACL = CMISLINK_NS + "acl";
+    public static final String REL_CHANGES = CMISLINK_NS + "changes";
     public static final String REL_ASSOC_SOURCE = CMISLINK_NS + "source";
     public static final String REL_ASSOC_TARGET = CMISLINK_NS + "target";
 
@@ -246,6 +251,16 @@
     public static final QName PERMISSION = new QName(CMIS_NS, "permission");
     public static final QName DIRECT = new QName(CMIS_NS, "direct");
 
+    // CMIS Change Event Info
+    public static final QName CHANGE_EVENT_INFO = new QName(CMIS_NS, "changeEventInfo");
+    public static final QName CHANGE_TYPE = new QName(CMIS_NS, "changeType");
+
+    // CMIS Change Types
+    public static final String CHANGE_TYPE_CREATED = "created";
+    public static final String CHANGE_TYPE_UPDATED = "updated";
+    public static final String CHANGE_TYPE_DELETED = "deleted";
+    public static final String CHANGE_TYPE_SECURITY = "security";
+    
     // CMIS Type Names
     public static final String TYPE_DOCUMENT = "cmis:document";
     public static final String TYPE_FOLDER = "cmis:folder";

Modified: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISExtensionFactory.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISExtensionFactory.java?rev=908938&r1=908937&r2=908938&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISExtensionFactory.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISExtensionFactory.java Thu Feb 11 11:44:23 2010
@@ -60,6 +60,7 @@
         addImpl(HTML_PROPERTY, CMISPropertyHtml.class);
         addImpl(PROPERTY_VALUE, CMISValue.class);
         addImpl(ALLOWABLE_ACTIONS, CMISAllowableActions.class);
+        addImpl(CHANGE_EVENT_INFO, CMISChangeEventInfo.class);
         addImpl(ACCESS_CONTROL_LIST, CMISAccessControlList.class);
         addImpl(PERMISSION, CMISAccessControlEntry.class);
         addImpl(TYPE_DEFINITION, CMISTypeDefinition.class);

Modified: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISObject.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISObject.java?rev=908938&r1=908937&r2=908938&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISObject.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISObject.java Thu Feb 11 11:44:23 2010
@@ -67,6 +67,28 @@
     }
 
     /**
+     * Gets the change event information for this CMIS Object if it is in a
+     * change log.
+     * 
+     * @return change event information for this CMIS Object
+     */
+    public CMISChangeEventInfo getChangeEventInfo() {
+        Element child = getFirstChild(CMISConstants.CHANGE_EVENT_INFO);
+        return (CMISChangeEventInfo) child;
+    }
+
+    /**
+     * Gets the access control list for this CMIS Object if it is in a change
+     * log.
+     * 
+     * @return access control list for this CMIS Object
+     */
+    public CMISAccessControlList getAccessControlList() {
+        Element child = getFirstChild(CMISConstants.ACCESS_CONTROL_LIST);
+        return (CMISAccessControlList) child;
+    }
+
+    /**
      * Gets name
      * 
      * @return name property

Modified: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISRepositoryInfo.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISRepositoryInfo.java?rev=908938&r1=908937&r2=908938&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISRepositoryInfo.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISRepositoryInfo.java Thu Feb 11 11:44:23 2010
@@ -16,6 +16,9 @@
  */
 package org.apache.chemistry.abdera.ext;
 
+import java.util.HashSet;
+import java.util.Set;
+
 import org.apache.abdera.factory.Factory;
 import org.apache.abdera.model.Element;
 import org.apache.abdera.model.ElementWrapper;
@@ -140,4 +143,21 @@
         }
         return null;
     }
+
+    public String getLatestChangeLogToken() {
+        Element child = getFirstChild(CMISConstants.LATEST_CHANGE_LOG_TOKEN);
+        if (child != null) {
+            return child.getText();
+        }
+        return null;
+    }
+
+    public Set<String> getChangesOnType() {
+        Set<String> changesOnType = new HashSet<String>(5);
+        for (Element type = getFirstChild(CMISConstants.CHANGES_ON_TYPE); type != null; type = type
+                .getNextSibling(CMISConstants.CHANGES_ON_TYPE)) {
+            changesOnType.add(type.getText());
+        }
+        return changesOnType;
+    }
 }

Modified: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISTypeDefinition.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISTypeDefinition.java?rev=908938&r1=908937&r2=908938&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISTypeDefinition.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/abdera/ext/CMISTypeDefinition.java Thu Feb 11 11:44:23 2010
@@ -54,6 +54,17 @@
     }
 
     /**
+     * Gets a value that indicates whether the base type for this Object-Type is
+     * the Document, Folder, Relationship, or Policy base type.
+     * 
+     * @return "cmis:document", "cmis:folder", "cmis:relationship" or
+     *         "cmis:policy"
+     */
+    public String getBaseId() {
+        return getFirstChild(CMISConstants.TYPE_BASE_ID).getText();
+    }
+
+    /**
      * Gets all Property Definitions for this CMIS Type
      * 
      * @return property definitions

Modified: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/client/CMISClient.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/client/CMISClient.java?rev=908938&r1=908937&r2=908938&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/client/CMISClient.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/client/CMISClient.java Thu Feb 11 11:44:23 2010
@@ -21,6 +21,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.StringReader;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -39,6 +40,7 @@
 import org.apache.abdera.model.Link;
 import org.apache.abdera.model.Service;
 import org.apache.abdera.model.Workspace;
+import org.apache.abdera.util.Constants;
 import org.apache.chemistry.abdera.ext.CMISACLCapability;
 import org.apache.chemistry.abdera.ext.CMISCapabilities;
 import org.apache.chemistry.abdera.ext.CMISConstants;
@@ -109,7 +111,11 @@
     }
 
     public Service getRepository() throws Exception {
-        if (cmisService == null) {
+        return getRepository(false);
+    }
+
+    public Service getRepository(boolean refresh) throws Exception {
+        if (refresh || cmisService == null) {
             Request req = new GetRequest(serviceUrl);
             Response res = executeRequest(req, 200);
             String xml = res.getContentAsString();
@@ -121,10 +127,14 @@
         return cmisService;
     }
 
+
     public CMISRepositoryInfo getRepositoryInfo() throws Exception {
-        if (cmisRepositoryInfo == null) {
-            // TODO: latestChangeLogToken can't be cached
-            Service repo = getRepository();
+        return getRepositoryInfo(false);
+    }
+
+    public CMISRepositoryInfo getRepositoryInfo(boolean refresh) throws Exception {
+        if (refresh || cmisRepositoryInfo == null) {
+            Service repo = getRepository(refresh);
             Workspace workspace = getWorkspace(repo);
             cmisRepositoryInfo = workspace.getExtension(CMISConstants.REPOSITORY_INFO);
             Assert.assertNotNull(cmisRepositoryInfo);
@@ -141,7 +151,7 @@
     }
 
     public Workspace getWorkspace() throws Exception {
-        return getRepository().getWorkspaces().get(0);
+        return getRepository(false).getWorkspaces().get(0);
     }
 
     public Workspace getWorkspace(Service service) {
@@ -217,9 +227,22 @@
     public CMISUriTemplate getTypeByIdUriTemplate(Workspace workspace) {
         return getUriTemplate(workspace, CMISConstants.URI_TYPE_BY_ID);
     }
+    
+    public Link getLink(Workspace workspace, String rel, String... matchesMimetypes)
+    {
+        List<Link> links = workspace.getExtensions(Constants.LINK);
+        List<Link> filteredLinks = new ArrayList<Link>(links.size());
+        for (Link link : links)
+        {
+            if (link.getRel().equals(rel))
+            {
+                filteredLinks.add(link);
+            }
+        }
+        return getLink(filteredLinks, matchesMimetypes);
+    }
 
-    public Link getLink(Entry entry, String rel, String... matchesMimetypes) {
-        List<Link> links = entry.getLinks(rel);
+    private Link getLink(List<Link> links, String... matchesMimetypes) {
         if (links != null) {
             for (Link link : links) {
                 MimeType mimetype = link.getMimeType();
@@ -257,6 +280,10 @@
         }
         return null;
     }
+    
+    public Link getLink(Entry entry, String rel, String... matchesMimetypes) {
+        return getLink(entry.getLinks(rel), matchesMimetypes);
+    }
 
     public Link getChildrenLink(Entry entry) {
         return getLink(entry, CMISConstants.REL_DOWN, CMISConstants.MIMETYPE_FEED);
@@ -281,6 +308,10 @@
     public List<Link> getRenditionLinks(Entry entry) {
         return entry.getLinks(CMISConstants.REL_ALTERNATE);
     }
+    
+    public Link getChangesLink(Workspace workspace) {
+        return getLink(workspace, CMISConstants.REL_CHANGES, CMISConstants.MIMETYPE_FEED);
+    }    
 
     public Entry getEntry(IRI href) throws Exception {
         return getEntry(href, null);

Added: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/AssertChangeTypeInChangeLogVisitor.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/AssertChangeTypeInChangeLogVisitor.java?rev=908938&view=auto
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/AssertChangeTypeInChangeLogVisitor.java (added)
+++ incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/AssertChangeTypeInChangeLogVisitor.java Thu Feb 11 11:44:23 2010
@@ -0,0 +1,147 @@
+/*
+ * Licensed 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.
+ *
+ * Authors:
+ *     David Ward, Alfresco
+ */
+package org.apache.chemistry.tck.atompub.fixture;
+
+import java.io.StringReader;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.abdera.model.Element;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Feed;
+import org.apache.abdera.model.Link;
+import org.apache.chemistry.abdera.ext.CMISAccessControlList;
+import org.apache.chemistry.abdera.ext.CMISChangeEventInfo;
+import org.apache.chemistry.abdera.ext.CMISConstants;
+import org.apache.chemistry.abdera.ext.CMISObject;
+import org.apache.chemistry.tck.atompub.client.CMISAppModel;
+import org.apache.chemistry.tck.atompub.client.CMISClient;
+import org.apache.chemistry.tck.atompub.fixture.EntryTree.TreeVisitor;
+import org.apache.chemistry.tck.atompub.http.GetRequest;
+import org.apache.chemistry.tck.atompub.http.Request;
+import org.apache.chemistry.tck.atompub.http.Response;
+import org.junit.Assert;
+
+/**
+ * Visitor that asserts that an entry of the given type exists for the given
+ * object types in the change log feed after the given change log token.
+ * Optionally follows paging links and checks included ACLs and properties.
+ */
+public class AssertChangeTypeInChangeLogVisitor implements TreeVisitor {
+
+    private String changeType;
+    private Set<String> changesOnType;
+    private Map<String, Entry> entriesByObjectId;
+
+    public AssertChangeTypeInChangeLogVisitor(CMISClient client, CMISAppModel model, String changeLogToken,
+            Integer maxItems, boolean includeACL, boolean includeProperties, String changeType,
+            Set<String> changesOnType) throws Exception {
+        this.changeType = changeType;
+        this.changesOnType = changesOnType;
+        Feed feed = getChangeLog(client, changeLogToken, maxItems, includeACL, includeProperties);
+        List<Entry> entries = feed.getEntries();
+        this.entriesByObjectId = new HashMap<String, Entry>(entries.size() * 2);
+        // Keep looping until we have no more "next" links
+        for (;;) {
+            if (maxItems != null) {
+                Assert.assertFalse("maxItems exceeded", entries.size() > maxItems);
+            }
+            for (Entry entry : entries) {
+                CMISObject object = entry.getExtension(CMISConstants.OBJECT);
+                Assert.assertNotNull(object);
+                String objectId = object.getObjectId().getStringValue();
+                Assert.assertNotNull(objectId);
+                CMISChangeEventInfo changeEventInfo = object.getChangeEventInfo();
+                Assert.assertNotNull(changeEventInfo);
+                if (changeEventInfo.getChangeType().equals(changeType)) {
+                    entriesByObjectId.put(objectId, entry);
+
+                    // Ensure the change log entry contains the expected ACL
+                    if (includeACL) {
+                        CMISAccessControlList accessControlList = object.getAccessControlList();
+                        Assert.assertNotNull("Expected ACL", accessControlList);
+                        Link accessControlListLink = entry.getLink(CMISConstants.REL_ACL);
+                        Assert.assertNotNull("Expected ACL Link", accessControlListLink);
+                        Request req = new GetRequest(accessControlListLink.getHref().toString());
+                        Response accessControlListRes = client.executeRequest(req, 200);
+                        Assert.assertNotNull(accessControlListRes);
+                        Element fetchedAccessControlList = model.parse(new StringReader(accessControlListRes
+                                .getContentAsString()), null);
+                        Assert.assertNotNull(fetchedAccessControlList);
+                        Assert.assertTrue(fetchedAccessControlList instanceof CMISAccessControlList);
+                        Assert.assertEquals(accessControlList.getHashedEntries(),
+                                ((CMISAccessControlList) fetchedAccessControlList).getHashedEntries());
+                    }
+
+                    // Ensure we have the expected properties
+                    Set<String> properties = new HashSet<String>(object.getProperties().getIds());
+                    Assert.assertTrue(properties.contains(CMISConstants.PROP_OBJECT_ID));
+
+                    // Object ID MUST be the only property if we didn't include
+                    // properties
+                    if (!includeProperties) {
+                        Assert.assertTrue("Unexpected properties in change log", properties.size() == 1);
+                    }
+                }
+            }
+            // Keep looping while we have a next page link
+            Link nextPageLink = feed.getLink(CMISConstants.REL_NEXT);
+            if (nextPageLink == null) {
+                break;
+            }
+            feed = client.getFeed(nextPageLink.getHref());
+            entries = feed.getEntries();
+        }
+    }
+
+    public void visit(EntryTree entry) throws Exception {
+        if (this.changesOnType.contains(entry.type)) {
+            CMISObject object = entry.entry.getExtension(CMISConstants.OBJECT);
+            Assert.assertNotNull(object);
+            String objectId = object.getObjectId().getStringValue();
+            Assert.assertNotNull(objectId);
+            Assert.assertTrue(this.changeType + " change log entry should exist for " + objectId, entriesByObjectId
+                    .containsKey(objectId));
+        }
+    }
+
+    private Feed getChangeLog(CMISClient client, String changeLogToken, Integer maxItems, boolean includeACL,
+            boolean includeProperties) throws Exception {
+        Link changesLink = client.getChangesLink(client.getWorkspace());
+        Assert.assertNotNull(changesLink);
+        Map<String, String> args = new HashMap<String, String>(5);
+        if (changeLogToken != null) {
+            args.put("changeLogToken", changeLogToken);
+        }
+        if (maxItems != null) {
+            args.put("maxItems", maxItems.toString());
+        }
+        if (includeACL) {
+            args.put("includeACL", "true");
+        }
+        if (includeProperties) {
+            args.put("includeProperties", "true");
+            args.put("filter", "*");
+        }
+        Feed changes = client.getFeed(changesLink.getHref(), args);
+        Assert.assertNotNull(changes);
+        return changes;
+    }
+}

Propchange: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/AssertChangeTypeInChangeLogVisitor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/ManageAccessControlListVisitor.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/ManageAccessControlListVisitor.java?rev=908938&view=auto
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/ManageAccessControlListVisitor.java (added)
+++ incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/ManageAccessControlListVisitor.java Thu Feb 11 11:44:23 2010
@@ -0,0 +1,259 @@
+/*
+ * Licensed 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.
+ *
+ * Authors:
+ *     David Ward, Alfresco
+ */
+package org.apache.chemistry.tck.atompub.fixture;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.abdera.model.Element;
+import org.apache.abdera.model.Entry;
+import org.apache.abdera.model.Link;
+import org.apache.chemistry.abdera.ext.CMISACLCapability;
+import org.apache.chemistry.abdera.ext.CMISAccessControlList;
+import org.apache.chemistry.abdera.ext.CMISAllowableActions;
+import org.apache.chemistry.abdera.ext.CMISConstants;
+import org.apache.chemistry.abdera.ext.CMISObject;
+import org.apache.chemistry.abdera.ext.CMISRepositoryInfo;
+import org.apache.chemistry.abdera.ext.CMISTypeDefinition;
+import org.apache.chemistry.tck.atompub.client.CMISAppModel;
+import org.apache.chemistry.tck.atompub.client.CMISClient;
+import org.apache.chemistry.tck.atompub.fixture.EntryTree.TreeVisitor;
+import org.apache.chemistry.tck.atompub.http.GetRequest;
+import org.apache.chemistry.tck.atompub.http.PutRequest;
+import org.apache.chemistry.tck.atompub.http.Request;
+import org.apache.chemistry.tck.atompub.http.Response;
+import org.junit.Assert;
+
+/**
+ * Visitor that manages ACLs on all objects in a tree.
+ */
+public class ManageAccessControlListVisitor implements TreeVisitor {
+
+    private CMISClient client;
+    private CMISAppModel model;
+    private Set<String> rejectedTypes = new HashSet<String>(5);
+
+    public ManageAccessControlListVisitor(CMISClient client, CMISAppModel model) {
+        this.client = client;
+        this.model = model;
+    }
+
+    public void visit(EntryTree entry) throws Exception {
+        Link accessControlListLink = entry.entry.getLink(CMISConstants.REL_ACL);
+        Request req = new GetRequest(accessControlListLink.getHref().toString());
+        Response accessControlListRes = client.executeRequest(req, 200);
+        Assert.assertNotNull(accessControlListRes);
+        Element accessControlList = model.parse(new StringReader(accessControlListRes.getContentAsString()), null);
+        Assert.assertNotNull(accessControlList);
+        Assert.assertTrue(accessControlList instanceof CMISAccessControlList);
+        CMISObject childObject = entry.entry.getExtension(CMISConstants.OBJECT);
+        Assert.assertNotNull(childObject);
+        String objectId = childObject.getObjectId().getStringValue();
+        Assert.assertNotNull(objectId);
+
+        // Check whether apply ACL is an allowable action
+        CMISAllowableActions objectAllowableActions = childObject.getExtension(CMISConstants.ALLOWABLE_ACTIONS);
+        Assert.assertNotNull(objectAllowableActions);
+        boolean canApplyACL = objectAllowableActions.isAllowed("canApplyACL");
+
+        // Check whether the typedef allows ACL management
+        Link typeLink = entry.entry.getLink(CMISConstants.REL_DESCRIBED_BY);
+        Assert.assertNotNull(typeLink);
+        Entry type = client.getEntry(typeLink.getHref());
+        Assert.assertNotNull(type);
+        CMISTypeDefinition docType = type.getExtension(CMISConstants.TYPE_DEFINITION);
+        Assert.assertNotNull(docType);
+        boolean controllableACL = docType.getControllableACL();
+        if (!controllableACL) {
+            Assert.assertFalse(canApplyACL);
+        }
+        // If we are not allowed to apply the ACL, we should expect an error
+        // status code
+        int expectedStatusMin = 200, expectedStatusMax = 200;
+        if (!canApplyACL) {
+            expectedStatusMin = 400;
+            expectedStatusMax = 499;
+            // Remember the set of rejected types to help with change log
+            // validation
+            rejectedTypes.add(docType.getBaseId());
+        }
+
+        // Convert the ACL to an easy to use form
+        Set<List<Object>> hashedACL = ((CMISAccessControlList) accessControlList).getHashedEntries();
+
+        // Take a back up for future reference
+        Set<List<Object>> originalACL = new HashSet<List<Object>>(hashedACL);
+
+        // Choose some permissions to add in to the ACL
+        CMISACLCapability aclCapability = client.getACLCapability();
+        Assert.assertNotNull(aclCapability);
+        Set<String> repositoryPermissions = new HashSet<String>(aclCapability.getRepositoryPermissions());
+        String supportedPermissions = aclCapability.getSupportedPermissions();
+        CMISRepositoryInfo info = client.getRepositoryInfo();
+
+        // Add some ACES with repository permissions if supported
+        if (!supportedPermissions.equals("basic")) {
+            chooseRepositoryPermission(repositoryPermissions, client.getUserId(), hashedACL);
+            chooseRepositoryPermission(repositoryPermissions, info.getPrincipalAnonymous(), hashedACL);
+            chooseRepositoryPermission(repositoryPermissions, info.getPrincipalAnyone(), hashedACL);
+        }
+
+        // Add some ACES with CMIS permissions if supported
+        if (!supportedPermissions.equals("repository")) {
+            addAce(client.getUserId(), hashedACL, "cmis:write");
+            addAce(info.getPrincipalAnonymous(), hashedACL, "cmis:read");
+            addAce(info.getPrincipalAnyone(), hashedACL, "cmis:read");
+        }
+
+        // Apply the ACL with the additions
+        accessControlList = applyACL(accessControlListLink, hashedACL, expectedStatusMin, expectedStatusMax);
+
+        // If change logging supported + changesOnType includes document, ensure
+        // an entry shows up in the change log and ensure ACL is identical when
+        // includeACL=true
+
+        // If we expected success, try removing the ACEs we added and restoring
+        // the ACL to its original state
+        if (accessControlList != null) {
+            applyACL(accessControlListLink, originalACL, expectedStatusMin, expectedStatusMax);
+        }
+    }
+
+    /**
+     * Gets the set of base types that we have not been able to handle, and thus
+     * do not expect to show in the change log.
+     * 
+     * @return the rejected types
+     */
+    public Set<String> getRejectedTypes() {
+        return rejectedTypes;
+    }
+
+    /**
+     * Chooses a repository permission to add to an ACL for a given principal.
+     * Tries to find one that would result in a new entry.
+     * 
+     * @param repositoryPermissions
+     *            the repository permissions. Permissions are removed as they
+     *            are used
+     * @param principalId
+     *            the principal id. If <code>null</code> the method returns
+     *            immediately.
+     * @param hashedACL
+     *            the current state of the ACL. Tries to avoid creating an ACE
+     *            that is already present. The ace with the chosen permission is
+     *            added to this set
+     * 
+     * @return an ACE with the chosen permission or <code>null</code> if it was
+     *         not possible to choose one< object>
+     */
+    private static List<Object> chooseRepositoryPermission(Set<String> repositoryPermissions, String principalId,
+            Set<List<Object>> hashedACL) {
+        if (principalId == null) {
+            return null;
+        }
+        List<Object> potential = new ArrayList<Object>(3);
+        potential.add(principalId);
+        potential.add(Boolean.TRUE);
+        for (String permission : repositoryPermissions) {
+            potential.add(permission);
+            if (hashedACL.add(potential)) {
+                repositoryPermissions.remove(permission);
+                return potential;
+            }
+            potential.remove(2);
+        }
+        return null;
+    }
+
+    /**
+     * Adds an ACE for the given principal and permission to the given ACL if it
+     * does not already exist.
+     * 
+     * @param principalId
+     *            the principal id. If <code>null</code> the method returns
+     *            immediately.
+     * @param hashedACL
+     *            the current state of the ACL. The ace with the chosen given is
+     *            added to this set
+     * @param permission
+     *            the permission
+     * 
+     * @return an ACE with the permission if it did not already exist in the ACL
+     *         or <code>null</code> otherwise
+     */
+    private static List<Object> addAce(String principalId, Set<List<Object>> hashedACL, String permission) {
+        if (principalId == null) {
+            return null;
+        }
+        List<Object> potential = new ArrayList<Object>(3);
+        potential.add(principalId);
+        potential.add(Boolean.TRUE);
+        potential.add(permission);
+        if (hashedACL.add(potential)) {
+            return potential;
+        }
+        return null;
+    }
+
+    /**
+     * Applies the given ACL using the CMIS API.
+     * 
+     * @param accessControlListLink
+     *            the access control list link
+     * @param hashedACL
+     *            the hashed ACL
+     * @param expectedStatusMin
+     *            Minimum expected result status code
+     * @param expectedStatusMax
+     *            Maximum expected result status code
+     * 
+     * @return the resulting access control list
+     * 
+     * @throws Exception
+     *             on error
+     */
+    private CMISAccessControlList applyACL(Link accessControlListLink, Set<List<Object>> hashedACL,
+            int expectedStatusMin, int expectedStatusMax) throws Exception {
+        StringBuilder buff = new StringBuilder(1024);
+        buff.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>").append(
+                "<cmis:acl xmlns:cmis=\"http://docs.oasis-open.org/ns/cmis/core/200908/\">");
+        for (List<Object> ace : hashedACL) {
+            buff.append("<cmis:permission><cmis:principal><cmis:principalId>").append(ace.get(0)).append(
+                    "</cmis:principalId></cmis:principal><cmis:permission>").append(ace.get(2)).append(
+                    "</cmis:permission><cmis:direct>").append(ace.get(1)).append("</cmis:direct></cmis:permission>");
+        }
+        buff.append("</cmis:acl>");
+        String req = buff.toString();
+        client.getAppValidator().validate(new StreamSource(new StringReader(req)));
+        Request putReq = new PutRequest(accessControlListLink.getHref().toString(), req, CMISConstants.MIMETYPE_CMISACL);
+        Response aclRes = client.executeRequest(putReq, expectedStatusMin, expectedStatusMax);
+        Assert.assertNotNull(aclRes);
+        if (aclRes.getStatus() == 200) {
+            Element accessControlList = model.parse(new StringReader(aclRes.getContentAsString()), null);
+            Assert.assertNotNull(accessControlList);
+            Assert.assertTrue(accessControlList instanceof CMISAccessControlList);
+            return (CMISAccessControlList) accessControlList;
+        }
+        return null;
+    }
+}

Propchange: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/ManageAccessControlListVisitor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/UpdateDocumentsVisitor.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/UpdateDocumentsVisitor.java?rev=908938&view=auto
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/UpdateDocumentsVisitor.java (added)
+++ incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/UpdateDocumentsVisitor.java Thu Feb 11 11:44:23 2010
@@ -0,0 +1,53 @@
+/*
+ * Licensed 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.
+ *
+ * Authors:
+ *     David Ward, Alfresco
+ */
+package org.apache.chemistry.tck.atompub.fixture;
+
+import org.apache.chemistry.abdera.ext.CMISConstants;
+import org.apache.chemistry.tck.atompub.client.CMISClient;
+import org.apache.chemistry.tck.atompub.fixture.EntryTree.TreeVisitor;
+import org.apache.chemistry.tck.atompub.http.PutRequest;
+import org.apache.chemistry.tck.atompub.http.Request;
+import org.apache.chemistry.tck.atompub.utils.ResourceLoader;
+import org.apache.commons.codec.binary.Base64;
+
+/**
+ * Visitor that updates all documents in a tree.
+ */
+public class UpdateDocumentsVisitor implements TreeVisitor {
+
+    private CMISClient client;
+    private ResourceLoader templates;
+
+    public UpdateDocumentsVisitor(CMISClient client, ResourceLoader templates) {
+        this.client = client;
+        this.templates = templates;
+    }
+
+    public void visit(EntryTree entry) throws Exception {
+        if (entry.type.equals(CMISConstants.TYPE_DOCUMENT)) {
+            String updateFile = templates.load("updatedocument.cmisatomentry.xml");
+            updateFile = updateFile.replace("${ID}", entry.entry.getId().toString());
+            String guid = String.valueOf(System.currentTimeMillis());
+            updateFile = updateFile.replace("${NAME}", guid);
+            updateFile = updateFile.replace("${CMISCONTENT}", new String(Base64
+                    .encodeBase64(("updated content " + guid).getBytes())));
+            Request putReq = new PutRequest(entry.entry.getSelfLink().getHref().toString(), updateFile,
+                    CMISConstants.MIMETYPE_ENTRY);
+            client.executeRequest(putReq, 200);
+        }
+    }
+}

Propchange: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/fixture/UpdateDocumentsVisitor.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/TCKTestSuite.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/TCKTestSuite.java?rev=908938&r1=908937&r2=908938&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/TCKTestSuite.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/TCKTestSuite.java Thu Feb 11 11:44:23 2010
@@ -22,6 +22,7 @@
 
 import org.apache.chemistry.tck.atompub.test.spec.AccessControlListTest;
 import org.apache.chemistry.tck.atompub.test.spec.AllowableActionsTest;
+import org.apache.chemistry.tck.atompub.test.spec.ChangeLogTest;
 import org.apache.chemistry.tck.atompub.test.spec.ContentStreamTest;
 import org.apache.chemistry.tck.atompub.test.spec.CreateTest;
 import org.apache.chemistry.tck.atompub.test.spec.DeleteTest;
@@ -61,6 +62,7 @@
         suite.addTestSuite(AllowableActionsTest.class);
         suite.addTestSuite(VersionsTest.class);
         suite.addTestSuite(AccessControlListTest.class);
+        suite.addTestSuite(ChangeLogTest.class);
         
         // custom type tests
         // TODO: when mechanism for registering custom types is done

Modified: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/spec/AccessControlListTest.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/spec/AccessControlListTest.java?rev=908938&r1=908937&r2=908938&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/spec/AccessControlListTest.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/spec/AccessControlListTest.java Thu Feb 11 11:44:23 2010
@@ -17,32 +17,22 @@
 package org.apache.chemistry.tck.atompub.test.spec;
 
 import java.io.StringReader;
-import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
-import java.util.Set;
-
-import javax.xml.transform.stream.StreamSource;
 
 import org.apache.abdera.i18n.iri.IRI;
 import org.apache.abdera.model.Element;
 import org.apache.abdera.model.Entry;
 import org.apache.abdera.model.Link;
-import org.apache.chemistry.abdera.ext.CMISACLCapability;
-import org.apache.chemistry.abdera.ext.CMISAccessControlEntry;
 import org.apache.chemistry.abdera.ext.CMISAccessControlList;
-import org.apache.chemistry.abdera.ext.CMISAllowableActions;
 import org.apache.chemistry.abdera.ext.CMISConstants;
 import org.apache.chemistry.abdera.ext.CMISObject;
-import org.apache.chemistry.abdera.ext.CMISRepositoryInfo;
-import org.apache.chemistry.abdera.ext.CMISTypeDefinition;
 import org.apache.chemistry.abdera.ext.CMISUriTemplate;
 import org.apache.chemistry.tck.atompub.TCKSkipCapabilityException;
 import org.apache.chemistry.tck.atompub.TCKTest;
+import org.apache.chemistry.tck.atompub.fixture.EntryTree;
+import org.apache.chemistry.tck.atompub.fixture.ManageAccessControlListVisitor;
 import org.apache.chemistry.tck.atompub.http.GetRequest;
-import org.apache.chemistry.tck.atompub.http.PutRequest;
 import org.apache.chemistry.tck.atompub.http.Request;
 import org.apache.chemistry.tck.atompub.http.Response;
 import org.junit.Assert;
@@ -87,8 +77,8 @@
         Assert.assertNotNull(childObject);
         CMISAccessControlList objectAccessControlList = childObject.getExtension(CMISConstants.ACCESS_CONTROL_LIST);
         Assert.assertNotNull(objectAccessControlList);
-        Assert.assertEquals(hashAccessControlList((CMISAccessControlList) accessControlList),
-                hashAccessControlList(objectAccessControlList));
+        Assert.assertEquals(((CMISAccessControlList) accessControlList).getHashedEntries(), objectAccessControlList
+                .getHashedEntries());
     }
 
     /**
@@ -126,90 +116,20 @@
         Assert.assertNotNull(childObject);
         CMISAccessControlList objectAccessControlList = childObject.getExtension(CMISConstants.ACCESS_CONTROL_LIST);
         Assert.assertNotNull(objectAccessControlList);
-        Assert.assertEquals(hashAccessControlList((CMISAccessControlList) accessControlList),
-                hashAccessControlList(objectAccessControlList));
+        Assert.assertEquals(((CMISAccessControlList) accessControlList).getHashedEntries(), objectAccessControlList
+                .getHashedEntries());
     }
 
     /**
-     * Test manage access control list.
+     * Tests managing the access control lists of a folder and a document
      * 
      * @throws Exception
      *             on error
      */
     public void testManageAccessControlList() throws Exception {
         checkACLCapability(true);
-        Entry document = fixture.createTestDocument("testManageAccessControlList");
-
-        Link accessControlListLink = document.getLink(CMISConstants.REL_ACL);
-        Request req = new GetRequest(accessControlListLink.getHref().toString());
-        Response accessControlListRes = client.executeRequest(req, 200);
-        Assert.assertNotNull(accessControlListRes);
-        Element accessControlList = model.parse(new StringReader(accessControlListRes.getContentAsString()), null);
-        Assert.assertNotNull(accessControlList);
-        Assert.assertTrue(accessControlList instanceof CMISAccessControlList);
-        CMISObject childObject = document.getExtension(CMISConstants.OBJECT);
-        Assert.assertNotNull(childObject);
-        String objectId = childObject.getObjectId().getStringValue();
-        Assert.assertNotNull(objectId);
-
-        // Check whether apply ACL is an allowable action
-        CMISAllowableActions objectAllowableActions = childObject.getExtension(CMISConstants.ALLOWABLE_ACTIONS);
-        Assert.assertNotNull(objectAllowableActions);
-        boolean canApplyACL = objectAllowableActions.isAllowed("canApplyACL");
-
-        // Check whether the typedef allows ACL management
-        Link typeLink = document.getLink(CMISConstants.REL_DESCRIBED_BY);
-        Assert.assertNotNull(typeLink);
-        Entry type = client.getEntry(typeLink.getHref());
-        Assert.assertNotNull(type);
-        CMISTypeDefinition docType = type.getExtension(CMISConstants.TYPE_DEFINITION);
-        Assert.assertNotNull(docType);
-        boolean controllableACL = docType.getControllableACL();
-        if (!controllableACL) {
-            Assert.assertFalse(canApplyACL);
-        }
-        // If we are not allowed to apply the ACL, we should expect an error
-        // status code
-        int expectedStatusMin = 200, expectedStatusMax = 200;
-        if (!canApplyACL) {
-            expectedStatusMin = 400;
-            expectedStatusMax = 499;
-        }
-
-        // Convert the ACL to an easy to use form
-        Set<List<Object>> hashedACL = hashAccessControlList((CMISAccessControlList) accessControlList);
-
-        // Take a back up for future reference
-        Set<List<Object>> originalACL = new HashSet<List<Object>>(hashedACL);
-
-        // Choose some permissions to add in to the ACL
-        CMISACLCapability aclCapability = client.getACLCapability();
-        Assert.assertNotNull(aclCapability);
-        Set<String> repositoryPermissions = new HashSet<String>(aclCapability.getRepositoryPermissions());
-        String supportedPermissions = aclCapability.getSupportedPermissions();
-        CMISRepositoryInfo info = client.getRepositoryInfo();
-
-        // Add some ACES with repository permissions if supported
-        if (!supportedPermissions.equals("basic")) {
-            chooseRepositoryPermission(repositoryPermissions, client.getUserId(), hashedACL);
-            chooseRepositoryPermission(repositoryPermissions, info.getPrincipalAnonymous(), hashedACL);
-            chooseRepositoryPermission(repositoryPermissions, info.getPrincipalAnyone(), hashedACL);
-        }
-
-        // Add some ACES with CMIS permissions if supported
-        if (!supportedPermissions.equals("repository")) {
-            addAce(client.getUserId(), hashedACL, "cmis:write");
-            addAce(info.getPrincipalAnonymous(), hashedACL, "cmis:read");
-            addAce(info.getPrincipalAnyone(), hashedACL, "cmis:read");
-        }
-
-        // Apply the ACL with the additions
-        accessControlList = applyACL(accessControlListLink, hashedACL, expectedStatusMin, expectedStatusMax);
-
-        // If we expected success, try removing the ACEs we added and restoring the ACL to its original state
-        if (accessControlList != null) {
-            applyACL(accessControlListLink, originalACL, expectedStatusMin, expectedStatusMax);
-        }
+        EntryTree folderTree = fixture.createTestTree("testManageAccessControlList", 1, 1, null, null);
+        folderTree.walkTree(new ManageAccessControlListVisitor(client, model));
     }
 
     /**
@@ -238,140 +158,4 @@
         // Ensure the ACL capability info has been supplied as required
         assertNotNull(client.getACLCapability());
     }
-
-    /**
-     * Flattens an access control list into a structure that is easy to compare:
-     * a set of triples containing the principal ID, the direct flag and the
-     * permission name.
-     * 
-     * @param accessControlList
-     *            the access control list
-     * 
-     * @return the set of triples
-     */
-    private static Set<List<Object>> hashAccessControlList(CMISAccessControlList accessControlList) {
-        List<CMISAccessControlEntry> entries = accessControlList.getEntries();
-        Set<List<Object>> hashSet = new HashSet<List<Object>>(entries.size() * 2);
-        for (CMISAccessControlEntry accessControlEntry : entries) {
-            String principalId = accessControlEntry.getPrincipalId();
-            Boolean direct = accessControlEntry.isDirect();
-            for (String permission : accessControlEntry.getPermissions()) {
-                List<Object> comparable = new ArrayList<Object>(3);
-                comparable.add(principalId);
-                comparable.add(direct);
-                comparable.add(permission);
-                hashSet.add(comparable);
-            }
-        }
-        return hashSet;
-    }
-
-    /**
-     * Chooses a repository permission to add to an ACL for a given principal.
-     * Tries to find one that would result in a new entry.
-     * 
-     * @param repositoryPermissions
-     *            the repository permissions. Permissions are removed as they
-     *            are used
-     * @param principalId
-     *            the principal id. If <code>null</code> the method returns
-     *            immediately.
-     * @param hashedACL
-     *            the current state of the ACL. Tries to avoid creating an ACE
-     *            that is already present. The ace with the chosen permission is
-     *            added to this set
-     * 
-     * @return an ACE with the chosen permission or <code>null</code> if it was
-     *         not possible to choose one< object>
-     */
-    private static List<Object> chooseRepositoryPermission(Set<String> repositoryPermissions, String principalId,
-            Set<List<Object>> hashedACL) {
-        if (principalId == null) {
-            return null;
-        }
-        List<Object> potential = new ArrayList<Object>(3);
-        potential.add(principalId);
-        potential.add(Boolean.TRUE);
-        for (String permission : repositoryPermissions) {
-            potential.add(permission);
-            if (hashedACL.add(potential)) {
-                repositoryPermissions.remove(permission);
-                return potential;
-            }
-            potential.remove(2);
-        }
-        return null;
-    }
-
-    /**
-     * Adds an ACE for the given principal and permission to the given ACL if it
-     * does not already exist.
-     * 
-     * @param principalId
-     *            the principal id. If <code>null</code> the method returns
-     *            immediately.
-     * @param hashedACL
-     *            the current state of the ACL. The ace with the chosen given is
-     *            added to this set
-     * @param permission
-     *            the permission
-     * 
-     * @return an ACE with the permission if it did not already exist in the ACL
-     *         or <code>null</code> otherwise
-     */
-    private static List<Object> addAce(String principalId, Set<List<Object>> hashedACL, String permission) {
-        if (principalId == null) {
-            return null;
-        }
-        List<Object> potential = new ArrayList<Object>(3);
-        potential.add(principalId);
-        potential.add(Boolean.TRUE);
-        potential.add(permission);
-        if (hashedACL.add(potential)) {
-            return potential;
-        }
-        return null;
-    }
-
-    /**
-     * Applies the given ACL using the CMIS API.
-     * 
-     * @param accessControlListLink
-     *            the access control list link
-     * @param hashedACL
-     *            the hashed ACL
-     * @param expectedStatusMin
-     *            Minimum expected result status code
-     * @param expectedStatusMax
-     *            Maximum expected result status code
-     * 
-     * @return the resulting access control list
-     * 
-     * @throws Exception
-     *             on error
-     */
-    private CMISAccessControlList applyACL(Link accessControlListLink, Set<List<Object>> hashedACL,
-            int expectedStatusMin, int expectedStatusMax) throws Exception {
-        StringBuilder buff = new StringBuilder(1024);
-        buff.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>").append(
-                "<cmis:acl xmlns:cmis=\"http://docs.oasis-open.org/ns/cmis/core/200908/\">");
-        for (List<Object> ace : hashedACL) {
-            buff.append("<cmis:permission><cmis:principal><cmis:principalId>").append(ace.get(0)).append(
-                    "</cmis:principalId></cmis:principal><cmis:permission>").append(ace.get(2)).append(
-                    "</cmis:permission><cmis:direct>").append(ace.get(1)).append("</cmis:direct></cmis:permission>");
-        }
-        buff.append("</cmis:acl>");
-        String req = buff.toString();
-        client.getAppValidator().validate(new StreamSource(new StringReader(req)));
-        Request putReq = new PutRequest(accessControlListLink.getHref().toString(), req, CMISConstants.MIMETYPE_CMISACL);
-        Response aclRes = client.executeRequest(putReq, expectedStatusMin, expectedStatusMax);
-        Assert.assertNotNull(aclRes);
-        if (aclRes.getStatus() == 200) {
-            Element accessControlList = model.parse(new StringReader(aclRes.getContentAsString()), null);
-            Assert.assertNotNull(accessControlList);
-            Assert.assertTrue(accessControlList instanceof CMISAccessControlList);
-            return (CMISAccessControlList) accessControlList;
-        }
-        return null;
-    }
 }

Added: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/spec/ChangeLogTest.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/spec/ChangeLogTest.java?rev=908938&view=auto
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/spec/ChangeLogTest.java (added)
+++ incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/spec/ChangeLogTest.java Thu Feb 11 11:44:23 2010
@@ -0,0 +1,165 @@
+/*
+ * Licensed 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.
+ *
+ * Authors:
+ *     David Ward, Alfresco
+ */
+package org.apache.chemistry.tck.atompub.test.spec;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.chemistry.abdera.ext.CMISConstants;
+import org.apache.chemistry.tck.atompub.TCKSkipCapabilityException;
+import org.apache.chemistry.tck.atompub.TCKTest;
+import org.apache.chemistry.tck.atompub.fixture.AssertChangeTypeInChangeLogVisitor;
+import org.apache.chemistry.tck.atompub.fixture.EntryTree;
+import org.apache.chemistry.tck.atompub.fixture.ManageAccessControlListVisitor;
+import org.apache.chemistry.tck.atompub.fixture.UpdateDocumentsVisitor;
+import org.junit.Assert;
+
+/**
+ * CMIS Change Log Tests.
+ */
+public class ChangeLogTest extends TCKTest {
+
+    /**
+     * Tests all change types on documents and folders.
+     * 
+     * @throws Exception
+     *             on error
+     */
+    public void testDocumentsAndFolders() throws Exception {
+        testDocumentsAndFolders(null);
+    }
+
+    /**
+     * Run the same tests, but with paged change logs.
+     * 
+     * @throws Exception
+     *             on error
+     */
+    public void testPaging() throws Exception {
+        testDocumentsAndFolders(1);
+    }
+
+    /**
+     * Tests all change types on documents and folders.
+     * 
+     * @param maxItems
+     *            the maximum number of items per page or <code>null</code> if
+     *            unlimited
+     * 
+     * @throws Exception
+     *             on error
+     */
+    private void testDocumentsAndFolders(Integer maxItems) throws Exception {
+        // Validate the capability
+        checkChangeLogCapability(false);
+
+        // Get the change log token
+        String changeLogToken = client.getRepositoryInfo(true).getLatestChangeLogToken();
+
+        // Create a folder tree
+        EntryTree folderTree = fixture.createTestTree("changeLog", 4, 3, null, null);
+
+        // Fetch changesOnType
+        Set<String> changesOnType = client.getRepositoryInfo().getChangesOnType();
+        assertTrue(changesOnType.size() > 0);
+
+        // Check created entries exist for the objects of applicable types
+        folderTree.walkTree(new AssertChangeTypeInChangeLogVisitor(client, model, changeLogToken, maxItems, false,
+                false, CMISConstants.CHANGE_TYPE_CREATED, changesOnType));
+
+        // Get the new change log token
+        changeLogToken = client.getRepositoryInfo(true).getLatestChangeLogToken();
+        assertNotNull(changeLogToken);
+
+        // Walk the tree and update all the documents
+
+        // TODO: Work out a reliable way of updating folders!
+        // 2.1.11.1: "A Repository MAY record events such as
+        // filing/unfiling/moving of Documents as change events on the
+        // Documents, their parent Folder(s), or both the Documents and the
+        // parent Folders."
+        if (changesOnType.contains(CMISConstants.TYPE_DOCUMENT)) {
+            folderTree.walkTree(new UpdateDocumentsVisitor(client, templates));
+
+            // Check updated entries exist for the document objects
+            folderTree.walkTree(new AssertChangeTypeInChangeLogVisitor(client, model, changeLogToken, maxItems, false,
+                    true, CMISConstants.CHANGE_TYPE_UPDATED, Collections.singleton(CMISConstants.TYPE_DOCUMENT)));
+
+            // Get the new change log token
+            changeLogToken = client.getRepositoryInfo(true).getLatestChangeLogToken();
+            assertNotNull(changeLogToken);
+        }
+
+        // Skip security tests if we don't have ACL manage capability
+        String aclCapability = client.getCapabilities().getACL();
+        if (aclCapability.equals("manage")) {
+            // Walk the tree and update all ACLs
+            ManageAccessControlListVisitor visitor = new ManageAccessControlListVisitor(client, model); 
+            folderTree.walkTree(visitor);
+
+            // Create a filtered set of change types that we know we should be
+            // able to manage
+            Set<String> filteredChangesOnType = new HashSet<String>(changesOnType);
+            filteredChangesOnType.removeAll(visitor.getRejectedTypes());
+
+            // Check security entries exist for the objects of applicable types
+            // and include the ACL
+            folderTree.walkTree(new AssertChangeTypeInChangeLogVisitor(client, model, changeLogToken, maxItems, true,
+                    true, CMISConstants.CHANGE_TYPE_SECURITY, changesOnType));
+
+            // Get the new change log token
+            changeLogToken = client.getRepositoryInfo(true).getLatestChangeLogToken();
+            assertNotNull(changeLogToken);
+        }
+
+        // Delete the tree
+        fixture.delete();
+
+        // Check deleted entries exist for the objects of applicable types
+        folderTree.walkTree(new AssertChangeTypeInChangeLogVisitor(client, model, changeLogToken, maxItems, false,
+                false, CMISConstants.CHANGE_TYPE_DELETED, changesOnType));
+    }
+
+    /**
+     * Check whether we have sufficient capability to read change logs and
+     * optionally their properties.
+     * 
+     * @param properties
+     *            <code>true</code> if we require properties capability or
+     *            <code>false</code> if objectidsonly capability is sufficient.
+     * 
+     * @throws TCKSkipCapabilityException
+     *             if we don't have sufficient capability
+     * @throws Exception
+     *             on error
+     */
+    private void checkChangeLogCapability(boolean properties) throws TCKSkipCapabilityException, Exception {
+        String changesCapability = client.getCapabilities().getChanges();
+        if (properties) {
+            if (!changesCapability.equals("properties") && !changesCapability.equals("all")) {
+                throw new TCKSkipCapabilityException("Changes", "properties", changesCapability);
+            }
+        } else {
+            if (changesCapability.equals("none")) {
+                throw new TCKSkipCapabilityException("Changes", "objectidsonly", changesCapability);
+            }
+        }
+        // Ensure we have some types that will show up in the change log!
+        Assert.assertFalse(client.getRepositoryInfo().getChangesOnType().isEmpty());
+    }
+}

Propchange: incubator/chemistry/trunk/chemistry/chemistry-tck-atompub/src/main/java/org/apache/chemistry/tck/atompub/test/spec/ChangeLogTest.java
------------------------------------------------------------------------------
    svn:eol-style = native