Improve folder support and File vs ListItem
Folders now return their all their children, independent of if the List
is a DocumentLibrary or some other list type.
Generic list items are now differentiated from files, so we can provide
the binary contents of files and generate HTML for list items.
diff --git a/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java b/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
index b9b9d26..d49ebdb 100644
--- a/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
+++ b/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
@@ -14,6 +14,7 @@
package com.google.enterprise.adaptor.sharepoint;
+import com.google.common.collect.Lists;
import com.google.enterprise.adaptor.AbstractAdaptor;
import com.google.enterprise.adaptor.AdaptorContext;
import com.google.enterprise.adaptor.Config;
@@ -24,8 +25,12 @@
import com.google.enterprise.adaptor.Request;
import com.google.enterprise.adaptor.Response;
+import org.apache.axiom.om.OMContainer;
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.OMNode;
import org.apache.axis2.AxisFault;
import org.apache.axis2.client.Options;
+import org.apache.axis2.databinding.types.UnsignedInt;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.transport.http.HttpTransportProperties;
import org.apache.commons.httpclient.HttpClient;
@@ -39,9 +44,10 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
-import java.util.Arrays;
+import java.util.*;
import java.util.concurrent.*;
+import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;
@@ -50,6 +56,16 @@
*/
public class SharePointAdaptor extends AbstractAdaptor {
private static final Charset CHARSET = Charset.forName("UTF-8");
+ private static final QName DATA_ELEMENT
+ = new QName("urn:schemas-microsoft-com:rowset", "data");
+ private static final QName ROW_ELEMENT = new QName("#RowsetSchema", "row");
+ private static final QName OWS_FSOBJTYPE_ATTRIBUTE
+ = new QName("ows_FSObjType");
+ private static final QName OWS_TITLE_ATTRIBUTE = new QName("ows_Title");
+ private static final QName OWS_SERVERURL_ATTRIBUTE
+ = new QName("ows_ServerUrl");
+ private static final QName OWS_CONTENTTYPE_ATTRIBUTE
+ = new QName("ows_ContentType");
private final ConcurrentMap<String, SiteDataClient> clients
= new ConcurrentSkipListMap<String, SiteDataClient>();
@@ -159,6 +175,15 @@
urlRequest.setStrURL(request.getDocId().getUniqueId());
SiteDataStub.GetURLSegmentsResponse urlResponse
= stub.getURLSegments(urlRequest);
+ if (DEBUG) {
+ System.out.println("getURLSegmentsResponse");
+ System.out.println("Result: "
+ + urlResponse.getGetURLSegmentsResult());
+ System.out.println("webid: " + urlResponse.getStrWebID());
+ System.out.println("itemid: " + urlResponse.getStrItemID());
+ System.out.println("listid: " + urlResponse.getStrListID());
+ System.out.println("bucketid: " + urlResponse.getStrBucketID());
+ }
if (!urlResponse.getGetURLSegmentsResult()) {
response.respondNotFound();
return;
@@ -194,7 +219,7 @@
System.out.println(response.getGetChangesResult());
}
- private String encodeUrl(String url) {
+ private DocId encodeDocId(String url) {
if (url.toLowerCase().startsWith("https://")
|| url.toLowerCase().startsWith("http://")) {
// Leave as-is.
@@ -206,7 +231,11 @@
String[] parts = siteUrl.split("/", 4);
url = parts[0] + "//" + parts[2] + url;
}
- URI uri = context.getDocIdEncoder().encodeDocId(new DocId(url));
+ return new DocId(url);
+ }
+
+ private String encodeUrl(String url) {
+ URI uri = context.getDocIdEncoder().encodeDocId(encodeDocId(url));
return uri.toASCIIString();
}
@@ -276,7 +305,29 @@
writer.write("</ul>");
}
if (w.getFPFolder() != null) {
- getFolderDataDocContent(writer, w.getFPFolder());
+ SiteDataStub.FolderData f = w.getFPFolder();
+ if (f.getFolders() != null) {
+ writer.write("<p>Folders</p><ul>");
+ for (SiteDataStub.Folders folders : f.getFolders()) {
+ if (folders.getFolder() != null) {
+ for (SiteDataStub.Folder_type0 folder : folders.getFolder()) {
+ writer.write(liUrl(folder.getURL()));
+ }
+ }
+ }
+ writer.write("</ul>");
+ }
+ if (f.getFiles() != null) {
+ writer.write("<p>Files</p><ul>");
+ for (SiteDataStub.Files files : f.getFiles()) {
+ if (files.getFile() != null) {
+ for (SiteDataStub.File_type0 file : files.getFile()) {
+ writer.write(liUrl(file.getURL()));
+ }
+ }
+ }
+ writer.write("</ul>");
+ }
}
writer.write("</body></html>");
writer.flush();
@@ -285,77 +336,105 @@
private void getListDocContent(Request request, Response response,
String id) throws Exception {
SiteDataStub.List l = getContentList(id);
+ processFolder(id, "", response);
+ }
+
+ private void processFolder(String listGuid, String folderPath,
+ Response response) throws Exception {
response.setContentType("text/html");
Writer writer
= new OutputStreamWriter(response.getOutputStream(), CHARSET);
writer.write("<!DOCTYPE html>\n"
+ "<html><head>"
- + "<title>List " + l.getMetadata().getTitle() + "</title>"
+ + "<title>Folder " + folderPath + "</title>"
+ "</head>"
+ "<body>"
- + "<h1>List " + l.getMetadata().getTitle() + "</h1>");
- if ("DocumentLibrary".equals(l.getMetadata().getBaseType().getValue())) {
- SiteDataStub.FPFolder f
- = getContentFolder(l.getMetadata().getRootFolder());
- getFolderDataDocContent(writer, f.getFPFolder());
- } else {
- writer.write("<p>List Items</p><ul>");
- for (int i = 0; i < l.getMetadata().getItemCount(); i++) {
- // TODO: determine URLs to provide.
- }
- writer.write("</ul>");
+ + "<h1>Folder " + folderPath + "</h1>");
+ SiteDataStub.Folder folder = getContentFolder(listGuid, folderPath);
+ SiteDataStub.Xml xml = folder.getFolder().getXml();
+
+ OMElement data = getFirstChildWithName(xml, DATA_ELEMENT);
+ writer.write("<p>List items</p><ul>");
+ for (OMElement row : getChildrenWithName(data, ROW_ELEMENT)) {
+ String rowUrl = row.getAttributeValue(OWS_SERVERURL_ATTRIBUTE);
+ String rowTitle = row.getAttributeValue(OWS_TITLE_ATTRIBUTE);
+ // TODO(ejona): Fix raw string concatenation.
+ writer.write("<li><a href=\"" + encodeUrl(rowUrl) + "\">" + rowTitle
+ + "</a></li>");
}
+ writer.write("</ul>");
+
writer.write("</body></html>");
writer.flush();
}
- private void getFolderDataDocContent(Writer writer,
- SiteDataStub.FolderData f) throws IOException {
- if (f.getFolders() != null) {
- writer.write("<p>Folders</p><ul>");
- for (SiteDataStub.Folders folders : f.getFolders()) {
- if (folders.getFolder() != null) {
- for (SiteDataStub.Folder_type0 folder : folders.getFolder()) {
- writer.write(liUrl(folder.getURL()));
- }
- }
+ private OMElement getFirstChildWithName(SiteDataStub.Xml xml, QName name) {
+ for (OMElement child : xml.getExtraElement()) {
+ if (child.getQName().equals(name)) {
+ return child;
}
- writer.write("</ul>");
}
- if (f.getFiles() != null) {
- writer.write("<p>Files</p><ul>");
- for (SiteDataStub.Files files : f.getFiles()) {
- if (files.getFile() != null) {
- for (SiteDataStub.File_type0 file : files.getFile()) {
- writer.write(liUrl(file.getURL()));
- }
- }
- }
- writer.write("</ul>");
- }
+ return null;
}
- private void recurseFile(String id, String url, String prefix)
- throws Exception {
- System.out.println(prefix + "File: " + url);
- prefix += " ";
- System.out.println(prefix + "ID=" + id);
+ private List<OMElement> getChildrenWithName(OMElement ele, QName name) {
+ @SuppressWarnings("unchecked")
+ Iterator<OMElement> children = ele.getChildrenWithName(ROW_ELEMENT);
+ return Lists.newArrayList(children);
}
private void getListItemDocContent(Request request, Response response,
String listId, String itemId) throws Exception {
- //SiteDataStub.ItemData i = getContentItem(listId, itemId);
- String url = request.getDocId().getUniqueId();
- String[] parts = url.split("/", 4);
- url = parts[0] + "/" + parts[1] + "/" + parts[2] + "/" +
- new URI(null, null, parts[3], null).toASCIIString();
- GetMethod method = new GetMethod(url);
- int statusCode = httpClient.executeMethod(method);
- if (statusCode != HttpStatus.SC_OK) {
- throw new RuntimeException("Got status code: " + statusCode);
+ SiteDataStub.ItemData i = getContentItem(listId, itemId);
+ SiteDataStub.Xml xml = i.getXml();
+
+ OMElement data = getFirstChildWithName(xml, DATA_ELEMENT);
+ OMElement row = getChildrenWithName(data, ROW_ELEMENT).get(0);
+ // This should be in the form of "1234;#0". We want to extract the 0.
+ String type =
+ row.getAttributeValue(OWS_FSOBJTYPE_ATTRIBUTE).split(";#", 2)[1];
+ boolean isFolder = "1".equals(type);
+ String title = row.getAttributeValue(OWS_TITLE_ATTRIBUTE);
+ if (title == null) {
+ title = "Unknown title";
}
- InputStream is = method.getResponseBodyAsStream();
- IOHelper.copyStream(is, response.getOutputStream());
+ String serverUrl = row.getAttributeValue(OWS_SERVERURL_ATTRIBUTE);
+
+ if (isFolder) {
+ SiteDataStub.List l = getContentList(listId);
+ String root
+ = encodeDocId(l.getMetadata().getRootFolder()).getUniqueId();
+ System.out.println("serverUrl: " + serverUrl);
+ String folder = encodeDocId(serverUrl).getUniqueId();
+ if (!folder.startsWith(root)) {
+ throw new AssertionError();
+ }
+ System.out.println("folder: " + folder);
+ processFolder(listId, folder.substring(root.length()), response);
+ return;
+ }
+ String contentType = row.getAttributeValue(OWS_CONTENTTYPE_ATTRIBUTE);
+ // TODO(ejona): This is likely unreliable. Investigate a better way.
+ if ("Document".equals(contentType)) {
+ // This is a file, so display its contents.
+ String url = request.getDocId().getUniqueId();
+ String[] parts = url.split("/", 4);
+ url = parts[0] + "/" + parts[1] + "/" + parts[2] + "/" +
+ new URI(null, null, parts[3], null).toASCIIString();
+ GetMethod method = new GetMethod(url);
+ int statusCode = httpClient.executeMethod(method);
+ if (statusCode != HttpStatus.SC_OK) {
+ throw new RuntimeException("Got status code: " + statusCode);
+ }
+ InputStream is = method.getResponseBodyAsStream();
+ IOHelper.copyStream(is, response.getOutputStream());
+ } else {
+ // Some list item.
+ Writer writer
+ = new OutputStreamWriter(response.getOutputStream(), CHARSET);
+ // TODO(ejona): Handle this case.
+ writer.write("TODO: ListItem");
+ }
}
private SiteDataStub.VirtualServer getContentVirtualServer()
@@ -439,7 +518,7 @@
private SiteDataStub.List getContentList(String id) throws Exception {
SiteDataStub.GetContent request = new SiteDataStub.GetContent();
request.setObjectType(SiteDataStub.ObjectType.List);
- request.setRetrieveChildItems(true);
+ request.setRetrieveChildItems(false);
request.setSecurityOnly(false);
request.setObjectId(id);
SiteDataStub.GetContentResponse response = stub.getContent(request);
@@ -478,13 +557,15 @@
return SiteDataStub.ItemData.Factory.parse(reader);
}
- private SiteDataStub.FPFolder getContentFolder(String url)
+ private SiteDataStub.Folder getContentFolder(String guid, String url)
throws Exception {
SiteDataStub.GetContent request = new SiteDataStub.GetContent();
request.setObjectType(SiteDataStub.ObjectType.Folder);
request.setRetrieveChildItems(true);
request.setSecurityOnly(false);
request.setFolderUrl(url);
+ request.setObjectId(guid);
+ request.setLastItemIdOnPage("");
SiteDataStub.GetContentResponse response = stub.getContent(request);
if (DEBUG) {
System.out.println(" Folder (Specific)");
@@ -492,10 +573,10 @@
System.out.println(response.getGetContentResult());
}
String xml = response.getGetContentResult();
- xml = xml.replace("<FPFolder>", "<FPFolder xmlns='" + XMLNS + "'>");
+ xml = xml.replace("<Folder>", "<Folder xmlns='" + XMLNS + "'>");
XMLStreamReader reader = xmlInputFactory.createXMLStreamReader(
new StringReader(xml));
- return SiteDataStub.FPFolder.Factory.parse(reader);
+ return SiteDataStub.Folder.Factory.parse(reader);
}
}
}