Skip to content
This repository has been archived by the owner on Apr 14, 2022. It is now read-only.

Commit

Permalink
CMIS-30: implement navigation services for AtomPub and Simple client
Browse files Browse the repository at this point in the history
git-svn-id: https://svn.apache.org/repos/asf/incubator/chemistry/trunk@794388 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
Florent Guillaume committed Jul 15, 2009
1 parent 9ed0603 commit 3d3491a
Show file tree
Hide file tree
Showing 12 changed files with 305 additions and 39 deletions.
Expand Up @@ -72,7 +72,7 @@ public interface SPI {
* Returns the descendant objects contained at one or more levels in the
* tree rooted at the specified folder. The ordering and tree walk algorithm
* is repository-specific, but should be consistent. A depth of 1 means
* returning only the direct children (same as {@link #getChildren}
* returning only the direct children (same as {@link #getChildren}).
* <p>
* Only the filter-selected properties associated with each object are
* returned. The content stream is not returned.
Expand Down
Expand Up @@ -25,6 +25,7 @@
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

Expand Down Expand Up @@ -58,6 +59,8 @@
*/
public class APPConnection implements Connection, SPI {

public static final int DEFAULT_MAX_CHILDREN = 20;

protected APPFolder root;

protected Connector connector;
Expand Down Expand Up @@ -167,33 +170,132 @@ public ObjectId newObjectId(String id) {
* ----- Navigation Services -----
*/

/**
* Accumulates the descendants into a list recursively.
*/
protected void accumulateDescendants(ObjectId folder, BaseType type,
int depth, String filter, boolean includeAllowableActions,
boolean includeRelationships, String orderBy, List<ObjectEntry> list) {
// TODO deal with paging properly
List<ObjectEntry> children = getChildren(folder, type, filter,
includeAllowableActions, includeRelationships,
Integer.MAX_VALUE, 0, orderBy, new boolean[1]);
for (ObjectEntry child : children) {
BaseType childType = repository.getType(child.getTypeId()).getBaseType();
if (type == null || childType.equals(type)) {
list.add(child);
}
if (depth > 1 && childType == BaseType.FOLDER) {
accumulateDescendants(child, type, depth - 1, filter,
includeAllowableActions, includeRelationships, orderBy,
list);
}
}
}

public List<ObjectEntry> getDescendants(ObjectId folder, BaseType type,
int depth, String filter, boolean includeAllowableActions,
boolean includeRelationships, String orderBy) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException();
// TODO includeRelationship, includeAllowableActions, orderBy
List<ObjectEntry> list = new ArrayList<ObjectEntry>();
accumulateDescendants(folder, type, depth, filter,
includeAllowableActions, includeRelationships, orderBy, list);
return list;
}

public List<ObjectEntry> getChildren(ObjectId folder, BaseType type,
String filter, boolean includeAllowableActions,
boolean includeRelationships, int maxItems, int skipCount,
String orderBy, boolean[] hasMoreItems) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException();
// TODO filter, includeRelationship, includeAllowableActions, orderBy
if (maxItems <= 0) {
maxItems = DEFAULT_MAX_CHILDREN;
}
if (skipCount < 0) {
skipCount = 0;
}

String href = getObjectEntry(folder).getLink(CMIS.LINK_CHILDREN);
Response resp = connector.get(new Request(href));
if (!resp.isOk()) {
throw new ContentManagerException(
"Remote server returned error code: "
+ resp.getStatusCode());
}
List<ObjectEntry> feed = resp.getObjectFeed(new ReadContext(this));

List<ObjectEntry> result = new LinkedList<ObjectEntry>();
hasMoreItems[0] = false;
boolean done = false;
for (ObjectEntry entry : feed) {
// type filtering
if (type != null
&& !repository.getType(entry.getTypeId()).getBaseType().equals(
type)) {
continue;
}
// skip
if (skipCount > 0) {
skipCount--;
continue;
}
// entry is ok
if (done) {
hasMoreItems[0] = true;
break;
}
result.add(entry);
if (result.size() >= maxItems) {
done = true;
// don't break now, we still have to find out if there are more
// non-filtered entries to fill in hasMoreItems
}
}
return result;
}

public List<ObjectEntry> getFolderParent(ObjectId folder, String filter,
boolean includeAllowableActions, boolean includeRelationships,
boolean returnToRoot) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException();
// TODO filter, includeRelationship, includeAllowableActions
List<ObjectEntry> result = new LinkedList<ObjectEntry>();
APPObjectEntry current = getObjectEntry(folder);
Type type = repository.getType(current.getTypeId());
if (!type.getBaseType().equals(BaseType.FOLDER)) {
throw new IllegalArgumentException("Not a folder: " + folder);
}
String rootId = current.connection.getRootFolder().getId();
ReadContext ctx = new ReadContext(this);
do {
if (current.getId().equals(rootId)) {
break;
}
String href = current.getLink(CMIS.LINK_PARENTS);
Response resp = connector.get(new Request(href));
if (!resp.isOk()) {
throw new ContentManagerException(
"Remote server returned error code: "
+ resp.getStatusCode());
}
current = (APPObjectEntry) resp.getObject(ctx);
result.add(current);
} while (returnToRoot);
return result;
}

public Collection<ObjectEntry> getObjectParents(ObjectId object,
String filter, boolean includeAllowableActions,
boolean includeRelationships) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException();
// TODO filter, includeRelationship, includeAllowableActions
APPObjectEntry current = getObjectEntry(object);
String href = current.getLink(CMIS.LINK_PARENTS);
Response resp = connector.get(new Request(href));
if (!resp.isOk()) {
throw new ContentManagerException(
"Remote server returned error code: "
+ resp.getStatusCode());
}
return resp.getObjectFeed(new ReadContext(this));
}

public Collection<ObjectEntry> getCheckedoutDocuments(ObjectId folder,
Expand All @@ -208,32 +310,40 @@ public Collection<ObjectEntry> getCheckedoutDocuments(ObjectId folder,
* ----- Object Services -----
*/

/**
* TODO temporary implementation to have something working until search is
* implemented Versions not yet supported
/*
* TODO hardcoded Chemistry URL pattern here...
*
* Will use URI templates (or, failing that, search) in future versions.
*/
public CMISObject getObject(ObjectId object, ReturnVersion returnVersion) {
String objectId = object.getId();
if (returnVersion == null) {
returnVersion = ReturnVersion.THIS;
protected APPObjectEntry getObjectEntry(ObjectId objectId) {
if (objectId instanceof APPObjectEntry) {
return ((APPObjectEntry) objectId);
}
// TODO hardcoded URL pattern here...
String href = repository.getCollectionHref(CMIS.COL_ROOT_CHILDREN);
if (!href.matches(".*/children/[0-9a-f-]{36}")) {
throw new AssertionError(href);
if (href.matches(".*/children/[0-9a-f-]{36}")) {
href = href.substring(0, href.length() - "/children/".length() - 36);
} else {
if (href.matches(".*/children$")) {
href = href.substring(0, href.length() - "/children".length());
} else {
throw new AssertionError(href);
}
}
href = href.substring(0, href.length() - "/children/".length() - 36);
href += "/object/" + objectId;
Request req = new Request(href);
Response resp = connector.get(req);
href += "/object/" + objectId.getId();
Response resp = connector.get(new Request(href));
if (!resp.isOk()) {
throw new ContentManagerException(
"Remote server returned error code: "
+ resp.getStatusCode());
}
return (APPObjectEntry) resp.getObject(new ReadContext(this));
}

APPObjectEntry entry = (APPObjectEntry) resp.getObject(new ReadContext(
this));
public CMISObject getObject(ObjectId object, ReturnVersion returnVersion) {
if (returnVersion == null) {
returnVersion = ReturnVersion.THIS;
}
APPObjectEntry entry = getObjectEntry(object);
Type type = getRepository().getType(entry.getTypeId());
switch (type.getBaseType()) {
case DOCUMENT:
Expand Down
Expand Up @@ -63,7 +63,6 @@ public List<Folder> getAncestors() {
}

public List<CMISObject> getChildren(BaseType type) {
// TODO type
String href = entry.getLink(CMIS.LINK_CHILDREN);
Response resp = entry.connection.getConnector().get(new Request(href));
if (!resp.isOk()) {
Expand All @@ -74,8 +73,14 @@ public List<CMISObject> getChildren(BaseType type) {
List<ObjectEntry> feed = resp.getObjectFeed(new ReadContext(
entry.connection));
List<CMISObject> children = new ArrayList<CMISObject>(feed.size());
for (ObjectEntry e : feed) {
children.add(APPObject.construct((APPObjectEntry) e));
APPRepository repository = entry.connection.repository;
for (ObjectEntry child : feed) {
if (type != null
&& !repository.getType(child.getTypeId()).getBaseType().equals(
type)) {
continue;
}
children.add(APPObject.construct((APPObjectEntry) child));
}
return children;
}
Expand Down
Expand Up @@ -31,6 +31,9 @@ public class Request {
protected List<String> params;

public Request(String url) {
if (url == null) {
throw new NullPointerException("Null url");
}
this.url = url;
}

Expand Down
Expand Up @@ -143,13 +143,13 @@ protected String addEntryDetails(RequestContext request, Entry entry,
// CMIS links
entry.addLink(getRepositoryLink(request), CMIS.LINK_REPOSITORY);
entry.addLink(getTypeLink(object.getTypeId(), request), CMIS.LINK_TYPE);
String oid = object.getId();
entry.addLink(getParentsLink(oid, request), CMIS.LINK_PARENTS);
Type objectType = repository.getType(object.getTypeId());
if (objectType.getBaseType() == BaseType.FOLDER) {
String oid = object.getId();
entry.addLink(getChildrenLink(oid, request), CMIS.LINK_CHILDREN);
entry.addLink(getDescendantsLink(oid, request),
CMIS.LINK_DESCENDANTS);
entry.addLink(getParentsLink(oid, request), CMIS.LINK_PARENTS);
}
// entry.addLink("XXX", CMIS.LINK_ALLOWABLE_ACTIONS);
// entry.addLink("XXX", CMIS.LINK_RELATIONSHIPS);
Expand Down
Expand Up @@ -25,6 +25,7 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
Expand Down Expand Up @@ -244,11 +245,37 @@ protected void saveObject(SimpleObject object) {
* ----- Navigation Services -----
*/

/**
* Accumulates the descendants into a list recursively.
*/
protected void accumulateDescendants(ObjectId folder, BaseType type,
int depth, String filter, boolean includeAllowableActions,
boolean includeRelationships, String orderBy, List<ObjectEntry> list) {
// TODO deal with paging properly
List<ObjectEntry> children = getChildren(folder, type, filter,
includeAllowableActions, includeRelationships,
Integer.MAX_VALUE, 0, orderBy, new boolean[1]);
for (ObjectEntry child : children) {
BaseType childType = repository.getType(child.getTypeId()).getBaseType();
if (type == null || childType.equals(type)) {
list.add(child);
}
if (depth > 1 && childType == BaseType.FOLDER) {
accumulateDescendants(child, type, depth - 1, filter,
includeAllowableActions, includeRelationships, orderBy,
list);
}
}
}

public List<ObjectEntry> getDescendants(ObjectId folder, BaseType type,
int depth, String filter, boolean includeAllowableActions,
boolean includeRelationships, String orderBy) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException();
// TODO includeRelationship, includeAllowableActions, orderBy
List<ObjectEntry> list = new ArrayList<ObjectEntry>();
accumulateDescendants(folder, type, depth, filter,
includeAllowableActions, includeRelationships, orderBy, list);
return list;
}

public List<ObjectEntry> getChildren(ObjectId folder, BaseType type,
Expand Down Expand Up @@ -294,8 +321,32 @@ protected static List<ObjectEntry> subList(List<ObjectEntry> all,
public List<ObjectEntry> getFolderParent(ObjectId folder, String filter,
boolean includeAllowableActions, boolean includeRelationships,
boolean returnToRoot) {
// TODO Auto-generated method stub
throw new UnsupportedOperationException();
// TODO filter, includeRelationship, includeAllowableActions
List<ObjectEntry> result = new LinkedList<ObjectEntry>();
SimpleData data = repository.datas.get(folder.getId());
if (data == null) {
throw new RuntimeException("No such folder: " + folder);
}
String typeId = (String) data.get(Property.TYPE_ID);
Type type = repository.getType(typeId);
if (!type.getBaseType().equals(BaseType.FOLDER)) {
throw new IllegalArgumentException("Not a folder: " + folder);
}
String currentId = (String) data.get(Property.ID);
do {
Set<String> parents = repository.parents.get(currentId);
if (parents == null || parents.isEmpty()) {
break;
}
if (parents.size() > 1) {
throw new AssertionError(currentId + " has " + parents.size()
+ " parents");
}
currentId = parents.iterator().next();
data = repository.datas.get(currentId);
result.add(new SimpleObjectEntry(data, this));
} while (returnToRoot);
return result;
}

public Collection<ObjectEntry> getObjectParents(ObjectId object,
Expand Down
Expand Up @@ -26,6 +26,7 @@
import org.apache.chemistry.Document;
import org.apache.chemistry.Folder;
import org.apache.chemistry.ObjectId;
import org.apache.chemistry.Property;
import org.apache.chemistry.Unfiling;

public class SimpleFolder extends SimpleObject implements Folder {
Expand Down Expand Up @@ -54,11 +55,16 @@ public List<Folder> getAncestors() {
}

public List<CMISObject> getChildren(BaseType type) {
// TODO type
Set<String> ids = entry.connection.repository.children.get(getId());
SimpleRepository repository = entry.connection.repository;
Set<String> ids = repository.children.get(getId());
List<CMISObject> children = new ArrayList<CMISObject>(ids.size());
for (String id : ids) {
SimpleData d = entry.connection.repository.datas.get(id);
SimpleData d = repository.datas.get(id);
if (type != null
&& !repository.getType((String) d.get(Property.TYPE_ID)).getBaseType().equals(
type)) {
continue;
}
children.add(SimpleObject.construct(new SimpleObjectEntry(d,
entry.connection)));
}
Expand Down
Expand Up @@ -144,4 +144,10 @@ public void save() {
}
}

@Override
public String toString() {
return getClass().getSimpleName() + '(' + getTypeId() + ',' + getId()
+ ')';
}

}

0 comments on commit 3d3491a

Please sign in to comment.