Split SiteDataClient, along soap vs adaptor line
SiteDataClient is now a thin wrapper around the SOAP calls that performs
the necessary parsing and slightly improves the interfaces for our
usage. The rest of the methods are now in a SiteAdaptor class.
diff --git a/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java b/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
index f375629..87f1bdb 100644
--- a/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
+++ b/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
@@ -30,6 +30,9 @@
import com.google.enterprise.adaptor.Request;
import com.google.enterprise.adaptor.Response;
import com.google.enterprise.adaptor.UserPrincipal;
+import com.google.enterprise.adaptor.sharepoint.SiteDataClient.CursorPaginator;
+import com.google.enterprise.adaptor.sharepoint.SiteDataClient.Paginator;
+import com.google.enterprise.adaptor.sharepoint.SiteDataClient.XmlProcessingException;
import com.microsoft.schemas.sharepoint.soap.ContentDatabase;
import com.microsoft.schemas.sharepoint.soap.ContentDatabases;
@@ -67,14 +70,11 @@
import com.microsoft.schemas.sharepoint.soap.directory.UserGroupSoap;
import org.w3c.dom.Attr;
-import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
import java.io.*;
import java.net.*;
import java.nio.charset.Charset;
@@ -83,22 +83,10 @@
import java.util.logging.*;
import java.util.regex.Pattern;
-import javax.xml.XMLConstants;
-import javax.xml.bind.JAXBContext;
-import javax.xml.bind.JAXBException;
-import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.Source;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamSource;
-import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
import javax.xml.ws.EndpointReference;
import javax.xml.ws.Holder;
import javax.xml.ws.Service;
-import javax.xml.ws.WebServiceException;
import javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder;
/**
@@ -108,9 +96,6 @@
implements PollingIncrementalAdaptor {
/** Charset used in generated HTML responses. */
private static final Charset CHARSET = Charset.forName("UTF-8");
- /** SharePoint's namespace. */
- private static final String XMLNS
- = "http://schemas.microsoft.com/sharepoint/soap/";
private static final String XMLNS_DIRECTORY
= "http://schemas.microsoft.com/sharepoint/soap/directory/";
@@ -163,7 +148,7 @@
private static final String OWS_ATTACHMENTS_ATTRIBUTE = "ows_Attachments";
/**
* Matches a SP-encoded value that contains one or more values. See {@link
- * SiteDataClient.addMetadata}.
+ * SiteAdaptor.addMetadata}.
*/
private static final Pattern ALTERNATIVE_VALUE_PATTERN
= Pattern.compile("^\\d+;#");
@@ -190,52 +175,16 @@
= OPEN_MASK | VIEW_PAGES_MASK | VIEW_LIST_ITEMS_MASK | MANAGE_LIST_MASK;
private static final int LIST_READ_SECURITY_ENABLED = 2;
- /**
- * The JAXBContext is expensive to initialize, so we share a copy between
- * instances.
- */
- private static final JAXBContext jaxbContext;
- /**
- * XML Schema of requests and responses. Used to validate responses match
- * expectations.
- */
- private static final Schema schema;
-
- static {
- try {
- jaxbContext = JAXBContext.newInstance(
- "com.microsoft.schemas.sharepoint.soap");
- } catch (JAXBException ex) {
- throw new RuntimeException("Could not initialize JAXBContext", ex);
- }
-
- try {
- DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
- dbf.setNamespaceAware(true);
- Document doc = dbf.newDocumentBuilder()
- .parse(SiteDataSoap.class.getResourceAsStream("SiteData.wsdl"));
- String schemaNs = XMLConstants.W3C_XML_SCHEMA_NS_URI;
- Node schemaNode = doc.getElementsByTagNameNS(schemaNs, "schema").item(0);
- schema = SchemaFactory.newInstance(schemaNs).newSchema(
- new DOMSource(schemaNode));
- } catch (IOException ex) {
- throw new RuntimeException("Could not initialize Schema", ex);
- } catch (SAXException ex) {
- throw new RuntimeException("Could not initialize Schema", ex);
- } catch (ParserConfigurationException ex) {
- throw new RuntimeException("Could not initialize Schema", ex);
- }
- }
private static final Logger log
= Logger.getLogger(SharePointAdaptor.class.getName());
/**
- * Map from Site or Web URL to SiteDataClient object used to communicate with
+ * Map from Site or Web URL to SiteAdaptor object used to communicate with
* that Site/Web.
*/
- private final ConcurrentMap<String, SiteDataClient> clients
- = new ConcurrentSkipListMap<String, SiteDataClient>();
+ private final ConcurrentMap<String, SiteAdaptor> siteAdaptors
+ = new ConcurrentSkipListMap<String, SiteAdaptor>();
private final DocId virtualServerDocId = new DocId("");
private AdaptorContext context;
/**
@@ -262,7 +211,7 @@
private final ConcurrentSkipListMap<String, String> contentDatabaseChangeId
= new ConcurrentSkipListMap<String, String>();
/** Production factory for all SiteDataSoap communication objects. */
- private final SiteDataFactory siteDataFactory;
+ private final SiteDataClient.SiteDataFactory siteDataFactory;
private final UserGroupFactory userGroupFactory;
/** Client for initiating raw HTTP connections. */
private final HttpClient httpClient;
@@ -278,12 +227,12 @@
private NtlmAuthenticator ntlmAuthenticator;
public SharePointAdaptor() {
- this(new SiteDataFactoryImpl(), new UserGroupFactoryImpl(),
+ this(new SiteDataClient.SiteDataFactoryImpl(), new UserGroupFactoryImpl(),
new HttpClientImpl(), new CachedThreadPoolFactory());
}
@VisibleForTesting
- SharePointAdaptor(SiteDataFactory siteDataFactory,
+ SharePointAdaptor(SiteDataClient.SiteDataFactory siteDataFactory,
UserGroupFactory userGroupFactory, HttpClient httpClient,
Callable<ExecutorService> executorFactory) {
if (siteDataFactory == null || httpClient == null
@@ -341,7 +290,8 @@
// Test out configuration.
try {
- getSiteDataClient(virtualServer, virtualServer).getContentVirtualServer();
+ getSiteAdaptor(virtualServer, virtualServer).getSiteDataClient()
+ .getContentVirtualServer();
} catch (Exception e) {
// Don't leak the executor.
destroy();
@@ -369,20 +319,20 @@
log.entering("SharePointAdaptor", "getDocContent",
new Object[] {request, response});
DocId id = request.getDocId();
- SiteDataClient virtualServerClient
- = getSiteDataClient(virtualServer, virtualServer);
+ SiteAdaptor virtualServerSiteAdaptor
+ = getSiteAdaptor(virtualServer, virtualServer);
if (id.equals(virtualServerDocId)) {
- virtualServerClient.getVirtualServerDocContent(request, response);
+ virtualServerSiteAdaptor.getVirtualServerDocContent(request, response);
} else {
- SiteDataClient client
- = virtualServerClient.getClientForUrl(id.getUniqueId());
- if (client == null) {
+ SiteAdaptor siteAdaptor
+ = virtualServerSiteAdaptor.getAdaptorForUrl(id.getUniqueId());
+ if (siteAdaptor == null) {
log.log(Level.FINE, "responding not found");
response.respondNotFound();
log.exiting("SharePointAdaptor", "getDocContent");
return;
}
- client.getDocContent(request, response);
+ siteAdaptor.getDocContent(request, response);
}
log.exiting("SharePointAdaptor", "getDocContent");
}
@@ -398,7 +348,8 @@
public void getModifiedDocIds(DocIdPusher pusher)
throws InterruptedException, IOException {
log.entering("SharePointAdaptor", "getModifiedDocIds", pusher);
- SiteDataClient client = getSiteDataClient(virtualServer, virtualServer);
+ SiteAdaptor siteAdaptor = getSiteAdaptor(virtualServer, virtualServer);
+ SiteDataClient client = siteAdaptor.getSiteDataClient();
VirtualServer vs = null;
try {
vs = client.getContentVirtualServer();
@@ -479,7 +430,7 @@
if (changes == null) {
break;
}
- client.getModifiedDocIds(changes, pusher);
+ siteAdaptor.getModifiedDocIds(changes, pusher);
} catch (XmlProcessingException ex) {
log.log(Level.WARNING, "Error parsing changes from content "
+ "database: " + contentDatabase, ex);
@@ -500,14 +451,14 @@
log.exiting("SharePointAdaptor", "getModifiedDocIds", pusher);
}
- private SiteDataClient getSiteDataClient(String site, String web)
+ private SiteAdaptor getSiteAdaptor(String site, String web)
throws IOException {
if (web.endsWith("/")) {
// Always end without a '/' for a canonical form.
web = web.substring(0, web.length() - 1);
}
- SiteDataClient client = clients.get(web);
- if (client == null) {
+ SiteAdaptor siteAdaptor = siteAdaptors.get(web);
+ if (siteAdaptor == null) {
if (site.endsWith("/")) {
// Always end without a '/' for a canonical form.
site = site.substring(0, site.length() - 1);
@@ -520,16 +471,16 @@
UserGroupSoap userGroupSoap
= userGroupFactory.newUserGroup(endpointUserGroup);
- client = new SiteDataClient(site, web, siteDataSoap, userGroupSoap,
+ siteAdaptor = new SiteAdaptor(site, web, siteDataSoap, userGroupSoap,
new MemberIdMappingCallable(site),
new SiteUserIdMappingCallable(site));
- clients.putIfAbsent(web, client);
- client = clients.get(web);
+ siteAdaptors.putIfAbsent(web, siteAdaptor);
+ siteAdaptor = siteAdaptors.get(web);
}
- return client;
+ return siteAdaptor;
}
- private static URI spUrlToUri(String url) throws IOException {
+ static URI spUrlToUri(String url) throws IOException {
// Because SP is silly, the path of the URI is unencoded, but the rest of
// the URI is correct. Thus, we split up the path from the host, and then
// turn them into URIs separately, and then turn everything into a
@@ -552,8 +503,8 @@
}
@VisibleForTesting
- class SiteDataClient {
- private final CheckedExceptionSiteDataSoap siteData;
+ class SiteAdaptor {
+ private final SiteDataClient siteDataClient;
private final UserGroupSoap userGroup;
private final String siteUrl;
private final String webUrl;
@@ -565,11 +516,11 @@
private final Callable<MemberIdMapping> memberIdMappingCallable;
private final Callable<MemberIdMapping> siteUserIdMappingCallable;
- public SiteDataClient(String site, String web, SiteDataSoap siteDataSoap,
+ public SiteAdaptor(String site, String web, SiteDataSoap siteDataSoap,
UserGroupSoap userGroupSoap,
Callable<MemberIdMapping> memberIdMappingCallable,
Callable<MemberIdMapping> siteUserIdMappingCallable) {
- log.entering("SiteDataClient", "SiteDataClient",
+ log.entering("SiteAdaptor", "SiteAdaptor",
new Object[] {site, web, siteDataSoap});
if (site.endsWith("/")) {
throw new AssertionError();
@@ -577,17 +528,16 @@
if (web.endsWith("/")) {
throw new AssertionError();
}
- if (siteDataSoap == null || memberIdMappingCallable == null) {
+ if (memberIdMappingCallable == null) {
throw new NullPointerException();
}
this.siteUrl = site;
this.webUrl = web;
- siteDataSoap = LoggingWSHandler.create(SiteDataSoap.class, siteDataSoap);
this.userGroup = userGroupSoap;
- this.siteData = new CheckedExceptionSiteDataSoapAdapter(siteDataSoap);
+ this.siteDataClient = new SiteDataClient(siteDataSoap, xmlValidation);
this.memberIdMappingCallable = memberIdMappingCallable;
this.siteUserIdMappingCallable = siteUserIdMappingCallable;
- log.exiting("SiteDataClient", "SiteDataClient");
+ log.exiting("SiteAdaptor", "SiteAdaptor");
}
private MemberIdMapping getMemberIdMapping() throws IOException {
@@ -612,23 +562,22 @@
public void getDocContent(Request request, Response response)
throws IOException {
- log.entering("SiteDataClient", "getDocContent",
+ log.entering("SiteAdaptor", "getDocContent",
new Object[] {request, response});
String url = request.getDocId().getUniqueId();
if (getAttachmentDocContent(request, response)) {
// Success, it was an attachment.
- log.exiting("SiteDataClient", "getDocContent");
+ log.exiting("SiteAdaptor", "getDocContent");
return;
}
Holder<String> listId = new Holder<String>();
Holder<String> itemId = new Holder<String>();
- Holder<Boolean> result = new Holder<Boolean>();
// No need to retrieve webId, since it isn't populated when you contact a
// web's SiteData.asmx page instead of its parent site's.
- siteData.getURLSegments(request.getDocId().getUniqueId(), result, null,
- null, listId, itemId);
- if (!result.value) {
+ boolean result = siteDataClient.getUrlSegments(
+ request.getDocId().getUniqueId(), listId, itemId);
+ if (!result) {
// It may still be an aspx page.
if (request.getDocId().getUniqueId().toLowerCase(Locale.ENGLISH)
.endsWith(".aspx")) {
@@ -637,7 +586,7 @@
log.log(Level.FINE, "responding not found");
response.respondNotFound();
}
- log.exiting("SiteDataClient", "getDocContent");
+ log.exiting("SiteAdaptor", "getDocContent");
return;
}
if (itemId.value != null) {
@@ -648,11 +597,11 @@
// Assume it is a top-level site.
getSiteDocContent(request, response);
}
- log.exiting("SiteDataClient", "getDocContent");
+ log.exiting("SiteAdaptor", "getDocContent");
}
private DocId encodeDocId(String url) {
- log.entering("SiteDataClient", "encodeDocId", url);
+ log.entering("SiteAdaptor", "encodeDocId", url);
if (url.toLowerCase().startsWith("https://")
|| url.toLowerCase().startsWith("http://")) {
// Leave as-is.
@@ -665,7 +614,7 @@
url = parts[0] + "//" + parts[2] + url;
}
DocId docId = new DocId(url);
- log.exiting("SiteDataClient", "encodeDocId", docId);
+ log.exiting("SiteAdaptor", "encodeDocId", docId);
return docId;
}
@@ -684,9 +633,9 @@
private void getVirtualServerDocContent(Request request, Response response)
throws IOException {
- log.entering("SiteDataClient", "getVirtualServerDocContent",
+ log.entering("SiteAdaptor", "getVirtualServerDocContent",
new Object[] {request, response});
- VirtualServer vs = getContentVirtualServer();
+ VirtualServer vs = siteDataClient.getContentVirtualServer();
final long necessaryPermissionMask = LIST_ITEM_MASK;
// A PolicyUser is either a user or group, but we aren't provided with
@@ -726,7 +675,8 @@
DocIdEncoder encoder = context.getDocIdEncoder();
for (ContentDatabases.ContentDatabase cdcd
: vs.getContentDatabases().getContentDatabase()) {
- ContentDatabase cd = getContentContentDatabase(cdcd.getID(), true);
+ ContentDatabase cd
+ = siteDataClient.getContentContentDatabase(cdcd.getID(), true);
if (cd.getSites() != null) {
for (Sites.Site site : cd.getSites().getSite()) {
writer.addLink(encodeDocId(site.getURL()), null);
@@ -734,7 +684,7 @@
}
}
writer.finish();
- log.exiting("SiteDataClient", "getVirtualServerDocContent");
+ log.exiting("SiteAdaptor", "getVirtualServerDocContent");
}
/**
@@ -768,19 +718,20 @@
if (isWebSiteCollection()) {
return false;
}
- return isWebNoIndex(getClientForUrl(getWebParentUrl()).getContentWeb());
+ return isWebNoIndex(
+ getAdaptorForUrl(getWebParentUrl()).siteDataClient.getContentWeb());
}
private void getSiteDocContent(Request request, Response response)
throws IOException {
- log.entering("SiteDataClient", "getSiteDocContent",
+ log.entering("SiteAdaptor", "getSiteDocContent",
new Object[] {request, response});
- Web w = getContentWeb();
+ Web w = siteDataClient.getContentWeb();
if (isWebNoIndex(w)) {
log.fine("Document marked for NoIndex");
response.respondNotFound();
- log.exiting("SiteDataClient", "getSiteDocContent");
+ log.exiting("SiteAdaptor", "getSiteDocContent");
return;
}
@@ -793,8 +744,8 @@
// policy is additional web service call.
// TODO(ejona): Add caching for web application policy.
if (allowAnonymousAccess) {
- allowAnonymousAccess
- = !isDenyAnonymousAcessOnVirtualServer(getContentVirtualServer());
+ allowAnonymousAccess = !isDenyAnonymousAcessOnVirtualServer(
+ siteDataClient.getContentVirtualServer());
}
if (!allowAnonymousAccess) {
@@ -802,8 +753,8 @@
if (isWebSiteCollection()) {
includePermissions = true;
} else {
- SiteDataClient parentClient = getClientForUrl(getWebParentUrl());
- Web parentW = parentClient.getContentWeb();
+ SiteAdaptor parentSiteAdaptor = getAdaptorForUrl(getWebParentUrl());
+ Web parentW = parentSiteAdaptor.siteDataClient.getContentWeb();
String parentScopeId
= parentW.getMetadata().getScopeID().toLowerCase(Locale.ENGLISH);
String scopeId
@@ -868,21 +819,22 @@
}
}
writer.finish();
- log.exiting("SiteDataClient", "getSiteDocContent");
+ log.exiting("SiteAdaptor", "getSiteDocContent");
}
private void getListDocContent(Request request, Response response,
String id) throws IOException {
- log.entering("SiteDataClient", "getListDocContent",
+ log.entering("SiteAdaptor", "getListDocContent",
new Object[] {request, response, id});
- com.microsoft.schemas.sharepoint.soap.List l = getContentList(id);
- Web w = getContentWeb();
+ com.microsoft.schemas.sharepoint.soap.List l
+ = siteDataClient.getContentList(id);
+ Web w = siteDataClient.getContentWeb();
if (TrueFalseType.TRUE.equals(l.getMetadata().getNoIndex())
|| isWebNoIndex(w)) {
log.fine("Document marked for NoIndex");
response.respondNotFound();
- log.exiting("SiteDataClient", "getListDocContent");
+ log.exiting("SiteAdaptor", "getListDocContent");
return;
}
@@ -890,8 +842,8 @@
= isAllowAnonymousReadForList(l) && isAllowAnonymousPeekForWeb(w);
if (allowAnonymousAccess) {
- allowAnonymousAccess
- = !isDenyAnonymousAcessOnVirtualServer(getContentVirtualServer());
+ allowAnonymousAccess = !isDenyAnonymousAcessOnVirtualServer(
+ siteDataClient.getContentVirtualServer());
}
if (!allowAnonymousAccess) {
@@ -922,7 +874,7 @@
l.getMetadata().getTitle());
processFolder(id, "", writer);
writer.finish();
- log.exiting("SiteDataClient", "getListDocContent");
+ log.exiting("SiteAdaptor", "getListDocContent");
}
/**
@@ -931,10 +883,10 @@
*/
private void processFolder(String listGuid, String folderPath,
HtmlResponseWriter writer) throws IOException {
- log.entering("SiteDataClient", "processFolder",
+ log.entering("SiteAdaptor", "processFolder",
new Object[] {listGuid, folderPath, writer});
Paginator<ItemData> folderPaginator
- = getContentFolderChildren(listGuid, folderPath);
+ = siteDataClient.getContentFolderChildren(listGuid, folderPath);
writer.startSection(ObjectType.LIST_ITEM);
ItemData folder;
while ((folder = folderPaginator.next()) != null) {
@@ -947,7 +899,7 @@
writer.addLink(encodeDocId(rowUrl), rowTitle);
}
}
- log.exiting("SiteDataClient", "processFolder");
+ log.exiting("SiteAdaptor", "processFolder");
}
private boolean elementHasName(Element ele, QName name) {
@@ -1139,17 +1091,17 @@
private void getAspxDocContent(Request request, Response response)
throws IOException {
- log.entering("SiteDataClient", "getAspxDocContent",
+ log.entering("SiteAdaptor", "getAspxDocContent",
new Object[] {request, response});
- Web w = getContentWeb();
+ Web w = siteDataClient.getContentWeb();
boolean allowAnonymousAccess = isAllowAnonymousReadForWeb(w);
// Check if anonymous access is denied by web application policy
// only if anonymous access is enabled for web as checking web application
// policy is additional web service call.
// TODO(ejona): Add caching for web application policy.
if (allowAnonymousAccess) {
- allowAnonymousAccess
- = !isDenyAnonymousAcessOnVirtualServer(getContentVirtualServer());
+ allowAnonymousAccess = !isDenyAnonymousAcessOnVirtualServer(
+ siteDataClient.getContentVirtualServer());
}
if (!allowAnonymousAccess) {
String aspxId = request.getDocId().getUniqueId();
@@ -1159,7 +1111,7 @@
.build());
}
getFileDocContent(request, response);
- log.exiting("SiteDataClient", "getAspxDocContent");
+ log.exiting("SiteAdaptor", "getAspxDocContent");
}
/**
@@ -1171,7 +1123,7 @@
*/
private void getFileDocContent(Request request, Response response)
throws IOException {
- log.entering("SiteDataClient", "getFileDocContent",
+ log.entering("SiteAdaptor", "getFileDocContent",
new Object[] {request, response});
URI displayUrl = docIdToUri(request.getDocId());
FileInfo fi = httpClient.issueGetRequest(displayUrl.toURL());
@@ -1189,27 +1141,28 @@
} finally {
fi.getContents().close();
}
- log.exiting("SiteDataClient", "getFileDocContent");
+ log.exiting("SiteAdaptor", "getFileDocContent");
}
private void getListItemDocContent(Request request, Response response,
String listId, String itemId) throws IOException {
- log.entering("SiteDataClient", "getListItemDocContent",
+ log.entering("SiteAdaptor", "getListItemDocContent",
new Object[] {request, response, listId, itemId});
- com.microsoft.schemas.sharepoint.soap.List l = getContentList(listId);
- Web w = getContentWeb();
+ com.microsoft.schemas.sharepoint.soap.List l
+ = siteDataClient.getContentList(listId);
+ Web w = siteDataClient.getContentWeb();
if (TrueFalseType.TRUE.equals(l.getMetadata().getNoIndex())
|| isWebNoIndex(w)) {
log.fine("Document marked for NoIndex");
response.respondNotFound();
- log.exiting("SiteDataClient", "getListItemDocContent");
+ log.exiting("SiteAdaptor", "getListItemDocContent");
return;
}
boolean applyReadSecurity =
(l.getMetadata().getReadSecurity() == LIST_READ_SECURITY_ENABLED);
- ItemData i = getContentItem(listId, itemId);
+ ItemData i = siteDataClient.getContentItem(listId, itemId);
Xml xml = i.getXml();
Element data = getFirstChildWithName(xml, DATA_ELEMENT);
@@ -1235,9 +1188,19 @@
&& scopeId.equals(listScopeId)
&& isAllowAnonymousPeekForWeb(w);
+ // Check anomymous access on web only if anonymous access is applicable
+ // for list and list item.
if (allowAnonymousAccess) {
- allowAnonymousAccess
- = !isDenyAnonymousAcessOnVirtualServer(getContentVirtualServer());
+ // Even if anonymous access is enabled on list, it can be turned off
+ // on Web level by setting Anonymous access to "Nothing" on Web.
+ // Anonymous User must have minimum "Open" permission on Web
+ // for anonymous access to work on List and List Items.
+ allowAnonymousAccess = isAllowAnonymousPeekForWeb(w);
+ }
+
+ if (allowAnonymousAccess) {
+ allowAnonymousAccess = !isDenyAnonymousAcessOnVirtualServer(
+ siteDataClient.getContentVirtualServer());
}
if (!allowAnonymousAccess) {
@@ -1264,26 +1227,26 @@
if (parentIsList || scopeId.equals(listScopeId)) {
parentScopeId = listScopeId;
} else {
- // Instead of using getURLSegments and getContent(ListItem),
- // we could use just getContent(Folder).
- // However, getContent(Folder) always returns children which could
- // make the call very expensive. In addition, getContent(ListItem)
- // returns all the metadata for the folder instead of just its scope
- // so if in the future we need more metadata we will already have
- // it. GetContentEx(Folder) may provide a way to get the folder's
- // scope without its children, but it wasn't investigated.
+ // Instead of using getUrlSegments and getContent(ListItem), we could
+ // use just getContent(Folder). However, getContent(Folder) always
+ // returns children which could make the call very expensive. In
+ // addition, getContent(ListItem) returns all the metadata for the
+ // folder instead of just its scope so if in the future we need more
+ // metadata we will already have it. GetContentEx(Folder) may provide
+ // a way to get the folder's scope without its children, but it wasn't
+ // investigated.
Holder<String> folderListId = new Holder<String>();
Holder<String> folderItemId = new Holder<String>();
- Holder<Boolean> result = new Holder<Boolean>();
- siteData.getURLSegments(folderDocId.getUniqueId(), result, null,
- null, folderListId, folderItemId);
- if (!result.value) {
+ boolean result = siteDataClient.getUrlSegments(
+ folderDocId.getUniqueId(), folderListId, folderItemId);
+ if (!result) {
throw new IOException("Could not find parent folder's itemId");
}
if (!listId.equals(folderListId.value)) {
throw new AssertionError("Unexpected listId value");
}
- ItemData folderItem = getContentItem(listId, folderItemId.value);
+ ItemData folderItem
+ = siteDataClient.getContentItem(listId, folderItemId.value);
Element folderData = getFirstChildWithName(
folderItem.getXml(), DATA_ELEMENT);
Element folderRow
@@ -1399,7 +1362,7 @@
writer.start(request.getDocId(), ObjectType.FOLDER, null);
processFolder(listId, folder.substring(root.length()), writer);
writer.finish();
- log.exiting("SiteDataClient", "getListItemDocContent");
+ log.exiting("SiteAdaptor", "getListItemDocContent");
return;
}
String contentTypeId = row.getAttribute(OWS_CONTENTTYPEID_ATTRIBUTE);
@@ -1427,24 +1390,25 @@
? 0 : Integer.parseInt(strAttachments);
if (attachments > 0) {
writer.startSection(ObjectType.LIST_ITEM_ATTACHMENTS);
- Item item = getContentListItemAttachments(listId, itemId);
+ Item item
+ = siteDataClient.getContentListItemAttachments(listId, itemId);
for (Item.Attachment attachment : item.getAttachment()) {
writer.addLink(encodeDocId(attachment.getURL()), null);
}
}
writer.finish();
}
- log.exiting("SiteDataClient", "getListItemDocContent");
+ log.exiting("SiteAdaptor", "getListItemDocContent");
}
private boolean getAttachmentDocContent(Request request, Response response)
throws IOException {
- log.entering("SiteDataClient", "getAttachmentDocContent", new Object[] {
+ log.entering("SiteAdaptor", "getAttachmentDocContent", new Object[] {
request, response});
String url = request.getDocId().getUniqueId();
if (!url.contains("/Attachments/")) {
log.fine("Not an attachment: does not contain /Attachments/");
- log.exiting("SiteDataClient", "getAttachmentDocContent", false);
+ log.exiting("SiteAdaptor", "getAttachmentDocContent", false);
return false;
}
String[] parts = url.split("/Attachments/", 2);
@@ -1452,27 +1416,27 @@
parts = parts[1].split("/", 2);
if (parts.length != 2) {
log.fine("Could not separate attachment file name and list item id");
- log.exiting("SiteDataClient", "getAttachmentDocContent", false);
+ log.exiting("SiteAdaptor", "getAttachmentDocContent", false);
return false;
}
String itemId = parts[0];
log.log(Level.FINE, "Detected possible attachment: "
+ "listUrl={0}, itemId={1}", new Object[] {listUrl, itemId});
Holder<String> listIdHolder = new Holder<String>();
- Holder<Boolean> result = new Holder<Boolean>();
- siteData.getURLSegments(listUrl, result, null, null, listIdHolder, null);
- if (!result.value) {
+ boolean result
+ = siteDataClient.getUrlSegments(listUrl, listIdHolder, null);
+ if (!result) {
log.fine("Could not get list id from list url");
- log.exiting("SiteDataClient", "getAttachmentDocContent", false);
+ log.exiting("SiteAdaptor", "getAttachmentDocContent", false);
return false;
}
String listId = listIdHolder.value;
if (listId == null) {
log.fine("List URL does not point to a list");
- log.exiting("SiteDataClient", "getAttachmentDocContent", false);
+ log.exiting("SiteAdaptor", "getAttachmentDocContent", false);
return false;
}
- Item item = getContentListItemAttachments(listId, itemId);
+ Item item = siteDataClient.getContentListItemAttachments(listId, itemId);
boolean verifiedIsAttachment = false;
for (Item.Attachment attachment : item.getAttachment()) {
if (url.equals(attachment.getURL())) {
@@ -1482,21 +1446,22 @@
}
if (!verifiedIsAttachment) {
log.fine("Suspected attachment not listed in item's attachment list");
- log.exiting("SiteDataClient", "getAttachmentDocContent", false);
+ log.exiting("SiteAdaptor", "getAttachmentDocContent", false);
return false;
}
log.fine("Suspected attachment verified as being a real attachment. "
+ "Proceeding to provide content.");
- com.microsoft.schemas.sharepoint.soap.List l = getContentList(listId);
- Web w = getContentWeb();
+ com.microsoft.schemas.sharepoint.soap.List l
+ = siteDataClient.getContentList(listId);
+ Web w = siteDataClient.getContentWeb();
if (TrueFalseType.TRUE.equals(l.getMetadata().getNoIndex())
|| isWebNoIndex(w)) {
log.fine("Document marked for NoIndex");
response.respondNotFound();
- log.exiting("SiteDataClient", "getAttachmentDocContent", true);
+ log.exiting("SiteAdaptor", "getAttachmentDocContent", true);
return true;
}
- ItemData itemData = getContentItem(listId, itemId);
+ ItemData itemData = siteDataClient.getContentItem(listId, itemId);
Xml xml = itemData.getXml();
Element data = getFirstChildWithName(xml, DATA_ELEMENT);
Element row = getChildrenWithName(data, ROW_ELEMENT).get(0);
@@ -1510,8 +1475,8 @@
&& scopeId.equals(listScopeId)
&& isAllowAnonymousPeekForWeb(w);
if (allowAnonymousAccess) {
- allowAnonymousAccess
- = !isDenyAnonymousAcessOnVirtualServer(getContentVirtualServer());
+ allowAnonymousAccess = !isDenyAnonymousAcessOnVirtualServer(
+ siteDataClient.getContentVirtualServer());
}
if (!allowAnonymousAccess) {
String listItemUrl = row.getAttribute(OWS_SERVERURL_ATTRIBUTE);
@@ -1520,14 +1485,14 @@
.build());
}
getFileDocContent(request, response);
- log.exiting("SiteDataClient", "getAttachmentDocContent", true);
+ log.exiting("SiteAdaptor", "getAttachmentDocContent", true);
return true;
}
@VisibleForTesting
void getModifiedDocIds(SPContentDatabase changes, DocIdPusher pusher)
throws IOException, InterruptedException {
- log.entering("SiteDataClient", "getModifiedDocIds",
+ log.entering("SiteAdaptor", "getModifiedDocIds",
new Object[] {changes, pusher});
List<DocId> docIds = new ArrayList<DocId>();
getModifiedDocIdsContentDatabase(changes, docIds);
@@ -1540,12 +1505,12 @@
records.add(builder.setDocId(docId).build());
}
pusher.pushRecords(records);
- log.exiting("SiteDataClient", "getModifiedDocIds");
+ log.exiting("SiteAdaptor", "getModifiedDocIds");
}
private void getModifiedDocIdsContentDatabase(SPContentDatabase changes,
List<DocId> docIds) {
- log.entering("SiteDataClient", "getModifiedDocIdsContentDatabase",
+ log.entering("SiteAdaptor", "getModifiedDocIdsContentDatabase",
new Object[] {changes, docIds});
if (!"Unchanged".equals(changes.getChange())) {
docIds.add(virtualServerDocId);
@@ -1553,11 +1518,11 @@
for (SPSite site : changes.getSPSite()) {
getModifiedDocIdsSite(site, docIds);
}
- log.exiting("SiteDataClient", "getModifiedDocIdsContentDatabase");
+ log.exiting("SiteAdaptor", "getModifiedDocIdsContentDatabase");
}
private void getModifiedDocIdsSite(SPSite changes, List<DocId> docIds) {
- log.entering("SiteDataClient", "getModifiedDocIdsSite",
+ log.entering("SiteAdaptor", "getModifiedDocIdsSite",
new Object[] {changes, docIds});
if (isModified(changes.getChange())) {
docIds.add(new DocId(changes.getSite().getMetadata().getURL()));
@@ -1565,11 +1530,11 @@
for (SPWeb web : changes.getSPWeb()) {
getModifiedDocIdsWeb(web, docIds);
}
- log.exiting("SiteDataClient", "getModifiedDocIdsSite");
+ log.exiting("SiteAdaptor", "getModifiedDocIdsSite");
}
private void getModifiedDocIdsWeb(SPWeb changes, List<DocId> docIds) {
- log.entering("SiteDataClient", "getModifiedDocIdsWeb",
+ log.entering("SiteAdaptor", "getModifiedDocIdsWeb",
new Object[] {changes, docIds});
if (isModified(changes.getChange())) {
docIds.add(new DocId(changes.getWeb().getMetadata().getURL()));
@@ -1585,20 +1550,20 @@
getModifiedDocIdsFile((SPFile) choice, docIds);
}
}
- log.exiting("SiteDataClient", "getModifiedDocIdsWeb");
+ log.exiting("SiteAdaptor", "getModifiedDocIdsWeb");
}
private void getModifiedDocIdsFolder(SPFolder changes, List<DocId> docIds) {
- log.entering("SiteDataClient", "getModifiedDocIdsFolder",
+ log.entering("SiteAdaptor", "getModifiedDocIdsFolder",
new Object[] {changes, docIds});
if (isModified(changes.getChange())) {
docIds.add(encodeDocId(changes.getDisplayUrl()));
}
- log.exiting("SiteDataClient", "getModifiedDocIdsFolder");
+ log.exiting("SiteAdaptor", "getModifiedDocIdsFolder");
}
private void getModifiedDocIdsList(SPList changes, List<DocId> docIds) {
- log.entering("SiteDataClient", "getModifiedDocIdsList",
+ log.entering("SiteAdaptor", "getModifiedDocIdsList",
new Object[] {changes, docIds});
if (isModified(changes.getChange())) {
docIds.add(encodeDocId(changes.getDisplayUrl()));
@@ -1610,12 +1575,12 @@
getModifiedDocIdsListItem((SPListItem) choice, docIds);
}
}
- log.exiting("SiteDataClient", "getModifiedDocIdsList");
+ log.exiting("SiteAdaptor", "getModifiedDocIdsList");
}
private void getModifiedDocIdsListItem(SPListItem changes,
List<DocId> docIds) {
- log.entering("SiteDataClient", "getModifiedDocIdsListItem",
+ log.entering("SiteAdaptor", "getModifiedDocIdsListItem",
new Object[] {changes, docIds});
if (isModified(changes.getChange())) {
Object oData = changes.getListItem().getAny();
@@ -1633,16 +1598,16 @@
}
}
}
- log.exiting("SiteDataClient", "getModifiedDocIdsListItem");
+ log.exiting("SiteAdaptor", "getModifiedDocIdsListItem");
}
private void getModifiedDocIdsFile(SPFile changes, List<DocId> docIds) {
- log.entering("SiteDataClient", "getModifiedDocIdsFile",
+ log.entering("SiteAdaptor", "getModifiedDocIdsFile",
new Object[] {changes, docIds});
if (isModified(changes.getChange())) {
docIds.add(encodeDocId(changes.getDisplayUrl()));
}
- log.exiting("SiteDataClient", "getModifiedDocIdsFile");
+ log.exiting("SiteAdaptor", "getModifiedDocIdsFile");
}
private boolean isModified(String change) {
@@ -1650,8 +1615,8 @@
}
private MemberIdMapping retrieveMemberIdMapping() throws IOException {
- log.entering("SiteDataClient", "retrieveMemberIdMapping");
- Site site = getContentSite();
+ log.entering("SiteAdaptor", "retrieveMemberIdMapping");
+ Site site = siteDataClient.getContentSite();
Map<Integer, String> groupMap = new HashMap<Integer, String>();
for (GroupMembership.Group group : site.getGroups().getGroup()) {
GroupDescription gd = group.getGroup();
@@ -1666,13 +1631,13 @@
}
}
MemberIdMapping mapping = new MemberIdMapping(userMap, groupMap);
- log.exiting("SiteDataClient", "retrieveMemberIdMapping", mapping);
+ log.exiting("SiteAdaptor", "retrieveMemberIdMapping", mapping);
return mapping;
}
private MemberIdMapping retrieveSiteUserMapping()
throws IOException {
- log.entering("SiteDataClient", "retrieveSiteUserMapping");
+ log.entering("SiteAdaptor", "retrieveSiteUserMapping");
GetUserCollectionFromSiteResponse.GetUserCollectionFromSiteResult result
= userGroup.getUserCollectionFromSite();
Map<Integer, String> userMap = new HashMap<Integer, String>();
@@ -1680,218 +1645,37 @@
MemberIdMapping mapping;
if (result == null) {
mapping = new MemberIdMapping(userMap, groupMap);
- log.exiting("SiteDataClient", "retrieveSiteUserMapping", mapping);
+ log.exiting("SiteAdaptor", "retrieveSiteUserMapping", mapping);
return mapping;
}
GetUserCollectionFromSiteResult.GetUserCollectionFromSite siteUsers
= result.getGetUserCollectionFromSite();
if (siteUsers.getUsers() == null) {
mapping = new MemberIdMapping(userMap, groupMap);
- log.exiting("SiteDataClient", "retrieveSiteUserMapping", mapping);
+ log.exiting("SiteAdaptor", "retrieveSiteUserMapping", mapping);
return mapping;
}
for (User user : siteUsers.getUsers().getUser()) {
userMap.put((int) user.getID(), user.getLoginName());
}
mapping = new MemberIdMapping(userMap, groupMap);
- log.exiting("SiteDataClient", "retrieveSiteUserMapping", mapping);
+ log.exiting("SiteAdaptor", "retrieveSiteUserMapping", mapping);
return mapping;
}
- private VirtualServer getContentVirtualServer() throws IOException {
- log.entering("SiteDataClient", "getContentVirtualServer");
- Holder<String> result = new Holder<String>();
- siteData.getContent(ObjectType.VIRTUAL_SERVER, null, null, null, true,
- false, null, result);
- String xml = result.value;
- xml = xml.replace("<VirtualServer>",
- "<VirtualServer xmlns='" + XMLNS + "'>");
- VirtualServer vs = jaxbParse(xml, VirtualServer.class);
- log.exiting("SiteDataClient", "getContentVirtualServer", vs);
- return vs;
- }
-
- private SiteDataClient getClientForUrl(String url) throws IOException {
- log.entering("SiteDataClient", "getClientForUrl", url);
- Holder<Long> result = new Holder<Long>();
+ private SiteAdaptor getAdaptorForUrl(String url) throws IOException {
+ log.entering("SiteAdaptor", "getAdaptorForUrl", url);
Holder<String> site = new Holder<String>();
Holder<String> web = new Holder<String>();
- siteData.getSiteAndWeb(url, result, site, web);
+ long result = siteDataClient.getSiteAndWeb(url, site, web);
- if (result.value != 0) {
- log.exiting("SiteDataClient", "getClientForUrl", null);
+ if (result != 0) {
+ log.exiting("SiteAdaptor", "getAdaptorForUrl", null);
return null;
}
- SiteDataClient client = getSiteDataClient(site.value, web.value);
- log.exiting("SiteDataClient", "getClientForUrl", client);
- return client;
- }
-
- private ContentDatabase getContentContentDatabase(String id,
- boolean retrieveChildItems) throws IOException {
- log.entering("SiteDataClient", "getContentContentDatabase", id);
- Holder<String> result = new Holder<String>();
- siteData.getContent(ObjectType.CONTENT_DATABASE, id, null, null,
- retrieveChildItems, false, null, result);
- String xml = result.value;
- xml = xml.replace("<ContentDatabase>",
- "<ContentDatabase xmlns='" + XMLNS + "'>");
- ContentDatabase cd = jaxbParse(xml, ContentDatabase.class);
- log.exiting("SiteDataClient", "getContentContentDatabase", cd);
- return cd;
- }
-
- private Site getContentSite() throws IOException {
- log.entering("SiteDataClient", "getContentSite");
- Holder<String> result = new Holder<String>();
- final boolean retrieveChildItems = true;
- // When ObjectType is SITE_COLLECTION, retrieveChildItems is the only
- // input value consulted.
- siteData.getContent(ObjectType.SITE_COLLECTION, null, null, null,
- retrieveChildItems, false, null, result);
- String xml = result.value;
- xml = xml.replace("<Site>", "<Site xmlns='" + XMLNS + "'>");
- Site site = jaxbParse(xml, Site.class);
- log.exiting("SiteDataClient", "getContentSite", site);
- return site;
- }
-
- private Web getContentWeb() throws IOException {
- log.entering("SiteDataClient", "getContentWeb");
- Holder<String> result = new Holder<String>();
- siteData.getContent(ObjectType.SITE, null, null, null, true, false, null,
- result);
- String xml = result.value;
- xml = xml.replace("<Web>", "<Web xmlns='" + XMLNS + "'>");
- Web web = jaxbParse(xml, Web.class);
- log.exiting("SiteDataClient", "getContentWeb", web);
- return web;
- }
-
- private com.microsoft.schemas.sharepoint.soap.List getContentList(String id)
- throws IOException {
- log.entering("SiteDataClient", "getContentList", id);
- Holder<String> result = new Holder<String>();
- siteData.getContent(ObjectType.LIST, id, null, null, false, false, null,
- result);
- String xml = result.value;
- xml = xml.replace("<List>", "<List xmlns='" + XMLNS + "'>");
- com.microsoft.schemas.sharepoint.soap.List list = jaxbParse(xml,
- com.microsoft.schemas.sharepoint.soap.List.class);
- log.exiting("SiteDataClient", "getContentList", list);
- return list;
- }
-
- private ItemData getContentItem(String listId, String itemId)
- throws IOException {
- log.entering("SiteDataClient", "getContentItem",
- new Object[] {listId, itemId});
- Holder<String> result = new Holder<String>();
- siteData.getContent(ObjectType.LIST_ITEM, listId, "", itemId, false,
- false, null, result);
- String xml = result.value;
- xml = xml.replace("<Item>", "<ItemData xmlns='" + XMLNS + "'>");
- xml = xml.replace("</Item>", "</ItemData>");
- ItemData data = jaxbParse(xml, ItemData.class);
- log.exiting("SiteDataClient", "getContentItem", data);
- return data;
- }
-
- private Paginator<ItemData> getContentFolderChildren(final String guid,
- final String url) {
- log.entering("SiteDataClient", "getContentFolderChildren",
- new Object[] {guid, url});
- final Holder<String> lastItemIdOnPage = new Holder<String>("");
- log.exiting("SiteDataClient", "getContentFolderChildren");
- return new Paginator<ItemData>() {
- @Override
- public ItemData next() throws IOException {
- if (lastItemIdOnPage.value == null) {
- return null;
- }
- Holder<String> result = new Holder<String>();
- siteData.getContent(ObjectType.FOLDER, guid, url, null, true, false,
- lastItemIdOnPage, result);
- String xml = result.value;
- xml = xml.replace("<Folder>", "<Folder xmlns='" + XMLNS + "'>");
- return jaxbParse(xml, ItemData.class);
- }
- };
- }
-
- private Item getContentListItemAttachments(String listId, String itemId)
- throws IOException {
- log.entering("SiteDataClient", "getContentListItemAttachments",
- new Object[] {listId, itemId});
- Holder<String> result = new Holder<String>();
- siteData.getContent(ObjectType.LIST_ITEM_ATTACHMENTS, listId, "",
- itemId, true, false, null, result);
- String xml = result.value;
- xml = xml.replace("<Item ", "<Item xmlns='" + XMLNS + "' ");
- Item item = jaxbParse(xml, Item.class);
- log.exiting("SiteDataClient", "getContentListItemAttachments", item);
- return item;
- }
-
- /**
- * Get a paginator that allows looping over all the changes since {@code
- * startChangeId}. If next() throws an XmlProcessingException, it is
- * guaranteed to be after state has been updated so that a subsequent call
- * to next() will provide the next page and not repeat the erroring page.
- */
- private CursorPaginator<SPContentDatabase, String>
- getChangesContentDatabase(final String contentDatabaseGuid,
- String startChangeId, final boolean isSp2010) {
- log.entering("SiteDataClient", "getChangesContentDatabase",
- new Object[] {contentDatabaseGuid, startChangeId});
- final Holder<String> lastChangeId = new Holder<String>(startChangeId);
- final Holder<String> lastLastChangeId = new Holder<String>();
- final Holder<String> currentChangeId = new Holder<String>();
- final Holder<Boolean> moreChanges = new Holder<Boolean>(true);
- log.exiting("SiteDataClient", "getChangesContentDatabase");
- return new CursorPaginator<SPContentDatabase, String>() {
- @Override
- public SPContentDatabase next() throws IOException {
- if (!moreChanges.value) {
- return null;
- }
- lastLastChangeId.value = lastChangeId.value;
- Holder<String> result = new Holder<String>();
- // In non-SP2010, the timeout is a number of seconds. In SP2010, the
- // timeout is n * 60, where n is the number of items you want
- // returned. However, in SP2010, asking for more than 10 items seems
- // to lose results. If timeout is less than 60 in SP 2010, then it
- // causes an infinite loop.
- int timeout = isSp2010 ? 10 * 60 : 15;
- siteData.getChanges(ObjectType.CONTENT_DATABASE, contentDatabaseGuid,
- lastChangeId, currentChangeId, timeout, result, moreChanges);
- // XmlProcessingExceptions fine after this point.
- String xml = result.value;
- xml = xml.replace("<SPContentDatabase ",
- "<SPContentDatabase xmlns='" + XMLNS + "' ");
- return jaxbParse(xml, SPContentDatabase.class);
- }
-
- @Override
- public String getCursor() {
- return lastChangeId.value;
- }
- };
- }
-
- @VisibleForTesting
- <T> T jaxbParse(String xml, Class<T> klass)
- throws XmlProcessingException {
- Source source = new StreamSource(new StringReader(xml));
- try {
- Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
- if (xmlValidation) {
- unmarshaller.setSchema(schema);
- }
- return unmarshaller.unmarshal(source, klass).getValue();
- } catch (JAXBException ex) {
- throw new XmlProcessingException(ex, xml);
- }
+ SiteAdaptor siteAdaptor = getSiteAdaptor(site.value, web.value);
+ log.exiting("SiteAdaptor", "getAdaptorForUrl", siteAdaptor);
+ return siteAdaptor;
}
private HtmlResponseWriter createHtmlResponseWriter(Response response)
@@ -1902,59 +1686,12 @@
return new HtmlResponseWriter(writer, context.getDocIdEncoder(),
Locale.ENGLISH);
}
- }
- /**
- * Container exception for wrapping xml processing exceptions in IOExceptions.
- */
- private static class XmlProcessingException extends IOException {
- public XmlProcessingException(JAXBException cause, String xml) {
- super("Error when parsing xml: " + xml, cause);
+ public SiteDataClient getSiteDataClient() {
+ return siteDataClient;
}
}
- /**
- * Container exception for wrapping WebServiceExceptions in a checked
- * exception.
- */
- private static class WebServiceIOException extends IOException {
- public WebServiceIOException(WebServiceException cause) {
- super(cause);
- }
- }
-
- /**
- * An object that can be paged through.
- *
- * @param <E> element type returned by {@link #next}
- */
- private interface Paginator<E> {
- /**
- * Get the next page of the series. If an exception is thrown, the state of
- * the paginator is undefined.
- *
- * @return the next page of data, or {@code null} if no more pages available
- */
- public E next() throws IOException;
- }
-
- /**
- * An object that can be paged through, but also provide a cursor for learning
- * its current position.
- *
- * @param <E> element type returned by {@link #next}
- * @param <C> cursor type
- */
- private interface CursorPaginator<E, C> extends Paginator<E> {
- /**
- * Provides a cursor for the current position. The intent is that you could
- * get a cursor (even in the event of {@link #next} throwing an exception)
- * and use it to create a query that would continue without repeating
- * results.
- */
- public C getCursor();
- }
-
@VisibleForTesting
static class FileInfo {
/** Non-null contents. */
@@ -2081,32 +1818,6 @@
}
@VisibleForTesting
- interface SiteDataFactory {
- /**
- * The {@code endpoint} string is a SharePoint URL, meaning that spaces are
- * not encoded.
- */
- public SiteDataSoap newSiteData(String endpoint) throws IOException;
- }
-
- static class SiteDataFactoryImpl implements SiteDataFactory {
- private final Service siteDataService;
-
- public SiteDataFactoryImpl() {
- URL url = SiteDataSoap.class.getResource("SiteData.wsdl");
- QName qname = new QName(XMLNS, "SiteData");
- this.siteDataService = Service.create(url, qname);
- }
-
- @Override
- public SiteDataSoap newSiteData(String endpoint) throws IOException {
- EndpointReference endpointRef = new W3CEndpointReferenceBuilder()
- .address(spUrlToUri(endpoint).toString()).build();
- return siteDataService.getPort(endpointRef, SiteDataSoap.class);
- }
- }
-
- @VisibleForTesting
interface UserGroupFactory {
public UserGroupSoap newUserGroup(String endpoint);
}
@@ -2163,91 +1874,6 @@
}
}
- /**
- * A subset of SiteDataSoap that throws WebServiceIOExceptions instead of the
- * WebServiceException (which is a RuntimeException).
- */
- private static interface CheckedExceptionSiteDataSoap {
- public void getSiteAndWeb(String strUrl, Holder<Long> getSiteAndWebResult,
- Holder<String> strSite, Holder<String> strWeb)
- throws WebServiceIOException;
-
- public void getURLSegments(String strURL,
- Holder<Boolean> getURLSegmentsResult, Holder<String> strWebID,
- Holder<String> strBucketID, Holder<String> strListID,
- Holder<String> strItemID) throws WebServiceIOException;
-
- public void getContent(ObjectType objectType, String objectId,
- String folderUrl, String itemId, boolean retrieveChildItems,
- boolean securityOnly, Holder<String> lastItemIdOnPage,
- Holder<String> getContentResult) throws WebServiceIOException;
-
- public void getChanges(ObjectType objectType, String contentDatabaseId,
- Holder<String> lastChangeId, Holder<String> currentChangeId,
- Integer timeout, Holder<String> getChangesResult,
- Holder<Boolean> moreChanges) throws WebServiceIOException;
- }
-
- private static class CheckedExceptionSiteDataSoapAdapter
- implements CheckedExceptionSiteDataSoap {
- private final SiteDataSoap siteData;
-
- public CheckedExceptionSiteDataSoapAdapter(SiteDataSoap siteData) {
- this.siteData = siteData;
- }
-
- @Override
- public void getSiteAndWeb(String strUrl, Holder<Long> getSiteAndWebResult,
- Holder<String> strSite, Holder<String> strWeb)
- throws WebServiceIOException {
- try {
- siteData.getSiteAndWeb(strUrl, getSiteAndWebResult, strSite, strWeb);
- } catch (WebServiceException ex) {
- throw new WebServiceIOException(ex);
- }
- }
-
- @Override
- public void getURLSegments(String strURL,
- Holder<Boolean> getURLSegmentsResult, Holder<String> strWebID,
- Holder<String> strBucketID, Holder<String> strListID,
- Holder<String> strItemID) throws WebServiceIOException {
- try {
- siteData.getURLSegments(strURL, getURLSegmentsResult, strWebID,
- strBucketID, strListID, strItemID);
- } catch (WebServiceException ex) {
- throw new WebServiceIOException(ex);
- }
- }
-
- @Override
- public void getContent(ObjectType objectType, String objectId,
- String folderUrl, String itemId, boolean retrieveChildItems,
- boolean securityOnly, Holder<String> lastItemIdOnPage,
- Holder<String> getContentResult) throws WebServiceIOException {
- try {
- siteData.getContent(objectType, objectId, folderUrl, itemId,
- retrieveChildItems, securityOnly, lastItemIdOnPage,
- getContentResult);
- } catch (WebServiceException ex) {
- throw new WebServiceIOException(ex);
- }
- }
-
- @Override
- public void getChanges(ObjectType objectType, String contentDatabaseId,
- Holder<String> lastChangeId, Holder<String> currentChangeId,
- Integer timeout, Holder<String> getChangesResult,
- Holder<Boolean> moreChanges) throws WebServiceIOException {
- try {
- siteData.getChanges(objectType, contentDatabaseId, lastChangeId,
- currentChangeId, timeout, getChangesResult, moreChanges);
- } catch (WebServiceException ex) {
- throw new WebServiceIOException(ex);
- }
- }
- }
-
private class MemberIdMappingCallable implements Callable<MemberIdMapping> {
private final String siteUrl;
@@ -2312,7 +1938,7 @@
@Override
public MemberIdMapping load(String site) throws IOException {
- return getSiteDataClient(site, site).retrieveMemberIdMapping();
+ return getSiteAdaptor(site, site).retrieveMemberIdMapping();
}
}
@@ -2325,7 +1951,7 @@
@Override
public MemberIdMapping load(String site) throws IOException {
- return getSiteDataClient(site, site).retrieveSiteUserMapping();
+ return getSiteAdaptor(site, site).retrieveSiteUserMapping();
}
}
diff --git a/src/com/google/enterprise/adaptor/sharepoint/SiteDataClient.java b/src/com/google/enterprise/adaptor/sharepoint/SiteDataClient.java
new file mode 100644
index 0000000..a5bd810
--- /dev/null
+++ b/src/com/google/enterprise/adaptor/sharepoint/SiteDataClient.java
@@ -0,0 +1,471 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// 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.
+
+package com.google.enterprise.adaptor.sharepoint;
+
+import com.google.common.annotations.VisibleForTesting;
+
+import com.microsoft.schemas.sharepoint.soap.ContentDatabase;
+import com.microsoft.schemas.sharepoint.soap.Item;
+import com.microsoft.schemas.sharepoint.soap.ItemData;
+import com.microsoft.schemas.sharepoint.soap.ObjectType;
+import com.microsoft.schemas.sharepoint.soap.SPContentDatabase;
+import com.microsoft.schemas.sharepoint.soap.Site;
+import com.microsoft.schemas.sharepoint.soap.SiteDataSoap;
+import com.microsoft.schemas.sharepoint.soap.VirtualServer;
+import com.microsoft.schemas.sharepoint.soap.Web;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.logging.*;
+
+import javax.xml.XMLConstants;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Source;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import javax.xml.ws.EndpointReference;
+import javax.xml.ws.Holder;
+import javax.xml.ws.Service;
+import javax.xml.ws.WebServiceException;
+import javax.xml.ws.wsaddressing.W3CEndpointReferenceBuilder;
+
+class SiteDataClient {
+ /** SharePoint's namespace. */
+ private static final String XMLNS
+ = "http://schemas.microsoft.com/sharepoint/soap/";
+
+ private static final Logger log
+ = Logger.getLogger(SiteDataClient.class.getName());
+ /**
+ * The JAXBContext is expensive to initialize, so we share a copy between
+ * instances.
+ */
+ private static final JAXBContext jaxbContext;
+ /**
+ * XML Schema of requests and responses. Used to validate responses match
+ * expectations.
+ */
+ private static final Schema schema;
+
+ static {
+ try {
+ jaxbContext = JAXBContext.newInstance(
+ "com.microsoft.schemas.sharepoint.soap");
+ } catch (JAXBException ex) {
+ throw new RuntimeException("Could not initialize JAXBContext", ex);
+ }
+
+ try {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ Document doc = dbf.newDocumentBuilder()
+ .parse(SiteDataSoap.class.getResourceAsStream("SiteData.wsdl"));
+ String schemaNs = XMLConstants.W3C_XML_SCHEMA_NS_URI;
+ Node schemaNode = doc.getElementsByTagNameNS(schemaNs, "schema").item(0);
+ schema = SchemaFactory.newInstance(schemaNs).newSchema(
+ new DOMSource(schemaNode));
+ } catch (IOException ex) {
+ throw new RuntimeException("Could not initialize Schema", ex);
+ } catch (SAXException ex) {
+ throw new RuntimeException("Could not initialize Schema", ex);
+ } catch (ParserConfigurationException ex) {
+ throw new RuntimeException("Could not initialize Schema", ex);
+ }
+ }
+
+ private final CheckedExceptionSiteDataSoap siteData;
+ private final boolean xmlValidation;
+
+ public SiteDataClient(SiteDataSoap siteDataSoap, boolean xmlValidation) {
+ if (siteDataSoap == null) {
+ throw new NullPointerException();
+ }
+ siteDataSoap = LoggingWSHandler.create(SiteDataSoap.class, siteDataSoap);
+ this.siteData = new CheckedExceptionSiteDataSoapAdapter(siteDataSoap);
+ this.xmlValidation = xmlValidation;
+ }
+
+ public long getSiteAndWeb(String strUrl, Holder<String> strSite,
+ Holder<String> strWeb) throws IOException {
+ Holder<Long> getSiteAndWebResult = new Holder<Long>();
+ siteData.getSiteAndWeb(strUrl, getSiteAndWebResult, strSite, strWeb);
+ return getSiteAndWebResult.value;
+ }
+
+ public boolean getUrlSegments(String strURL, Holder<String> strListID,
+ Holder<String> strItemID) throws IOException {
+ Holder<Boolean> getURLSegmentsResult = new Holder<Boolean>();
+ // The returned web is not useful because we already know the web containing
+ // the URL. We don't have a use for the returned bucket.
+ siteData.getURLSegments(strURL, getURLSegmentsResult, null, null,
+ strListID, strItemID);
+ return getURLSegmentsResult.value;
+ }
+
+ public VirtualServer getContentVirtualServer() throws IOException {
+ log.entering("SiteDataClient", "getContentVirtualServer");
+ Holder<String> result = new Holder<String>();
+ siteData.getContent(ObjectType.VIRTUAL_SERVER, null, null, null, true,
+ false, null, result);
+ String xml = result.value;
+ xml = xml.replace("<VirtualServer>",
+ "<VirtualServer xmlns='" + XMLNS + "'>");
+ VirtualServer vs = jaxbParse(xml, VirtualServer.class);
+ log.exiting("SiteDataClient", "getContentVirtualServer", vs);
+ return vs;
+ }
+
+ public ContentDatabase getContentContentDatabase(String id,
+ boolean retrieveChildItems) throws IOException {
+ log.entering("SiteDataClient", "getContentContentDatabase", id);
+ Holder<String> result = new Holder<String>();
+ siteData.getContent(ObjectType.CONTENT_DATABASE, id, null, null,
+ retrieveChildItems, false, null, result);
+ String xml = result.value;
+ xml = xml.replace("<ContentDatabase>",
+ "<ContentDatabase xmlns='" + XMLNS + "'>");
+ ContentDatabase cd = jaxbParse(xml, ContentDatabase.class);
+ log.exiting("SiteDataClient", "getContentContentDatabase", cd);
+ return cd;
+ }
+
+ public Site getContentSite() throws IOException {
+ log.entering("SiteDataClient", "getContentSite");
+ Holder<String> result = new Holder<String>();
+ final boolean retrieveChildItems = true;
+ // When ObjectType is SITE_COLLECTION, retrieveChildItems is the only
+ // input value consulted.
+ siteData.getContent(ObjectType.SITE_COLLECTION, null, null, null,
+ retrieveChildItems, false, null, result);
+ String xml = result.value;
+ xml = xml.replace("<Site>", "<Site xmlns='" + XMLNS + "'>");
+ Site site = jaxbParse(xml, Site.class);
+ log.exiting("SiteDataClient", "getContentSite", site);
+ return site;
+ }
+
+ public Web getContentWeb() throws IOException {
+ log.entering("SiteDataClient", "getContentWeb");
+ Holder<String> result = new Holder<String>();
+ siteData.getContent(ObjectType.SITE, null, null, null, true, false, null,
+ result);
+ String xml = result.value;
+ xml = xml.replace("<Web>", "<Web xmlns='" + XMLNS + "'>");
+ Web web = jaxbParse(xml, Web.class);
+ log.exiting("SiteDataClient", "getContentWeb", web);
+ return web;
+ }
+
+ public com.microsoft.schemas.sharepoint.soap.List getContentList(String id)
+ throws IOException {
+ log.entering("SiteDataClient", "getContentList", id);
+ Holder<String> result = new Holder<String>();
+ siteData.getContent(ObjectType.LIST, id, null, null, false, false, null,
+ result);
+ String xml = result.value;
+ xml = xml.replace("<List>", "<List xmlns='" + XMLNS + "'>");
+ com.microsoft.schemas.sharepoint.soap.List list = jaxbParse(xml,
+ com.microsoft.schemas.sharepoint.soap.List.class);
+ log.exiting("SiteDataClient", "getContentList", list);
+ return list;
+ }
+
+ public ItemData getContentItem(String listId, String itemId)
+ throws IOException {
+ log.entering("SiteDataClient", "getContentItem",
+ new Object[] {listId, itemId});
+ Holder<String> result = new Holder<String>();
+ siteData.getContent(ObjectType.LIST_ITEM, listId, "", itemId, false,
+ false, null, result);
+ String xml = result.value;
+ xml = xml.replace("<Item>", "<ItemData xmlns='" + XMLNS + "'>");
+ xml = xml.replace("</Item>", "</ItemData>");
+ ItemData data = jaxbParse(xml, ItemData.class);
+ log.exiting("SiteDataClient", "getContentItem", data);
+ return data;
+ }
+
+ public Paginator<ItemData> getContentFolderChildren(final String guid,
+ final String url) {
+ log.entering("SiteDataClient", "getContentFolderChildren",
+ new Object[] {guid, url});
+ final Holder<String> lastItemIdOnPage = new Holder<String>("");
+ log.exiting("SiteDataClient", "getContentFolderChildren");
+ return new Paginator<ItemData>() {
+ @Override
+ public ItemData next() throws IOException {
+ if (lastItemIdOnPage.value == null) {
+ return null;
+ }
+ Holder<String> result = new Holder<String>();
+ siteData.getContent(ObjectType.FOLDER, guid, url, null, true, false,
+ lastItemIdOnPage, result);
+ String xml = result.value;
+ xml = xml.replace("<Folder>", "<Folder xmlns='" + XMLNS + "'>");
+ return jaxbParse(xml, ItemData.class);
+ }
+ };
+ }
+
+ public Item getContentListItemAttachments(String listId, String itemId)
+ throws IOException {
+ log.entering("SiteDataClient", "getContentListItemAttachments",
+ new Object[] {listId, itemId});
+ Holder<String> result = new Holder<String>();
+ siteData.getContent(ObjectType.LIST_ITEM_ATTACHMENTS, listId, "",
+ itemId, true, false, null, result);
+ String xml = result.value;
+ xml = xml.replace("<Item ", "<Item xmlns='" + XMLNS + "' ");
+ Item item = jaxbParse(xml, Item.class);
+ log.exiting("SiteDataClient", "getContentListItemAttachments", item);
+ return item;
+ }
+
+ /**
+ * Get a paginator that allows looping over all the changes since {@code
+ * startChangeId}. If next() throws an XmlProcessingException, it is
+ * guaranteed to be after state has been updated so that a subsequent call
+ * to next() will provide the next page and not repeat the erroring page.
+ */
+ public CursorPaginator<SPContentDatabase, String>
+ getChangesContentDatabase(final String contentDatabaseGuid,
+ String startChangeId, final boolean isSp2010) {
+ log.entering("SiteDataClient", "getChangesContentDatabase",
+ new Object[] {contentDatabaseGuid, startChangeId});
+ final Holder<String> lastChangeId = new Holder<String>(startChangeId);
+ final Holder<String> lastLastChangeId = new Holder<String>();
+ final Holder<String> currentChangeId = new Holder<String>();
+ final Holder<Boolean> moreChanges = new Holder<Boolean>(true);
+ log.exiting("SiteDataClient", "getChangesContentDatabase");
+ return new CursorPaginator<SPContentDatabase, String>() {
+ @Override
+ public SPContentDatabase next() throws IOException {
+ if (!moreChanges.value) {
+ return null;
+ }
+ lastLastChangeId.value = lastChangeId.value;
+ Holder<String> result = new Holder<String>();
+ // In non-SP2010, the timeout is a number of seconds. In SP2010, the
+ // timeout is n * 60, where n is the number of items you want
+ // returned. However, in SP2010, asking for more than 10 items seems
+ // to lose results. If timeout is less than 60 in SP 2010, then it
+ // causes an infinite loop.
+ int timeout = isSp2010 ? 10 * 60 : 15;
+ siteData.getChanges(ObjectType.CONTENT_DATABASE, contentDatabaseGuid,
+ lastChangeId, currentChangeId, timeout, result, moreChanges);
+ // XmlProcessingExceptions fine after this point.
+ String xml = result.value;
+ xml = xml.replace("<SPContentDatabase ",
+ "<SPContentDatabase xmlns='" + XMLNS + "' ");
+ return jaxbParse(xml, SPContentDatabase.class);
+ }
+
+ @Override
+ public String getCursor() {
+ return lastChangeId.value;
+ }
+ };
+ }
+
+ @VisibleForTesting
+ <T> T jaxbParse(String xml, Class<T> klass)
+ throws XmlProcessingException {
+ Source source = new StreamSource(new StringReader(xml));
+ try {
+ Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
+ if (xmlValidation) {
+ unmarshaller.setSchema(schema);
+ }
+ return unmarshaller.unmarshal(source, klass).getValue();
+ } catch (JAXBException ex) {
+ throw new XmlProcessingException(ex, xml);
+ }
+ }
+
+ /**
+ * Container exception for wrapping xml processing exceptions in IOExceptions.
+ */
+ public static class XmlProcessingException extends IOException {
+ public XmlProcessingException(JAXBException cause, String xml) {
+ super("Error when parsing xml: " + xml, cause);
+ }
+ }
+
+ /**
+ * Container exception for wrapping WebServiceExceptions in a checked
+ * exception.
+ */
+ public static class WebServiceIOException extends IOException {
+ public WebServiceIOException(WebServiceException cause) {
+ super(cause);
+ }
+ }
+
+ /**
+ * An object that can be paged through.
+ *
+ * @param <E> element type returned by {@link #next}
+ */
+ public interface Paginator<E> {
+ /**
+ * Get the next page of the series. If an exception is thrown, the state of
+ * the paginator is undefined.
+ *
+ * @return the next page of data, or {@code null} if no more pages available
+ */
+ public E next() throws IOException;
+ }
+
+ /**
+ * An object that can be paged through, but also provide a cursor for learning
+ * its current position.
+ *
+ * @param <E> element type returned by {@link #next}
+ * @param <C> cursor type
+ */
+ public interface CursorPaginator<E, C> extends Paginator<E> {
+ /**
+ * Provides a cursor for the current position. The intent is that you could
+ * get a cursor (even in the event of {@link #next} throwing an exception)
+ * and use it to create a query that would continue without repeating
+ * results.
+ */
+ public C getCursor();
+ }
+
+ @VisibleForTesting
+ interface SiteDataFactory {
+ /**
+ * The {@code endpoint} string is a SharePoint URL, meaning that spaces are
+ * not encoded.
+ */
+ public SiteDataSoap newSiteData(String endpoint) throws IOException;
+ }
+
+ static class SiteDataFactoryImpl implements SiteDataFactory {
+ private final Service siteDataService;
+
+ public SiteDataFactoryImpl() {
+ URL url = SiteDataSoap.class.getResource("SiteData.wsdl");
+ QName qname = new QName(XMLNS, "SiteData");
+ this.siteDataService = Service.create(url, qname);
+ }
+
+ @Override
+ public SiteDataSoap newSiteData(String endpoint) throws IOException {
+ EndpointReference endpointRef = new W3CEndpointReferenceBuilder()
+ .address(SharePointAdaptor.spUrlToUri(endpoint).toString()).build();
+ return siteDataService.getPort(endpointRef, SiteDataSoap.class);
+ }
+ }
+
+ /**
+ * A subset of SiteDataSoap that throws WebServiceIOExceptions instead of the
+ * WebServiceException (which is a RuntimeException).
+ */
+ private static interface CheckedExceptionSiteDataSoap {
+ public void getSiteAndWeb(String strUrl, Holder<Long> getSiteAndWebResult,
+ Holder<String> strSite, Holder<String> strWeb)
+ throws WebServiceIOException;
+
+ public void getURLSegments(String strURL,
+ Holder<Boolean> getURLSegmentsResult, Holder<String> strWebID,
+ Holder<String> strBucketID, Holder<String> strListID,
+ Holder<String> strItemID) throws WebServiceIOException;
+
+ public void getContent(ObjectType objectType, String objectId,
+ String folderUrl, String itemId, boolean retrieveChildItems,
+ boolean securityOnly, Holder<String> lastItemIdOnPage,
+ Holder<String> getContentResult) throws WebServiceIOException;
+
+ public void getChanges(ObjectType objectType, String contentDatabaseId,
+ Holder<String> lastChangeId, Holder<String> currentChangeId,
+ Integer timeout, Holder<String> getChangesResult,
+ Holder<Boolean> moreChanges) throws WebServiceIOException;
+ }
+
+ private static class CheckedExceptionSiteDataSoapAdapter
+ implements CheckedExceptionSiteDataSoap {
+ private final SiteDataSoap siteData;
+
+ public CheckedExceptionSiteDataSoapAdapter(SiteDataSoap siteData) {
+ this.siteData = siteData;
+ }
+
+ @Override
+ public void getSiteAndWeb(String strUrl, Holder<Long> getSiteAndWebResult,
+ Holder<String> strSite, Holder<String> strWeb)
+ throws WebServiceIOException {
+ try {
+ siteData.getSiteAndWeb(strUrl, getSiteAndWebResult, strSite, strWeb);
+ } catch (WebServiceException ex) {
+ throw new WebServiceIOException(ex);
+ }
+ }
+
+ @Override
+ public void getURLSegments(String strURL,
+ Holder<Boolean> getURLSegmentsResult, Holder<String> strWebID,
+ Holder<String> strBucketID, Holder<String> strListID,
+ Holder<String> strItemID) throws WebServiceIOException {
+ try {
+ siteData.getURLSegments(strURL, getURLSegmentsResult, strWebID,
+ strBucketID, strListID, strItemID);
+ } catch (WebServiceException ex) {
+ throw new WebServiceIOException(ex);
+ }
+ }
+
+ @Override
+ public void getContent(ObjectType objectType, String objectId,
+ String folderUrl, String itemId, boolean retrieveChildItems,
+ boolean securityOnly, Holder<String> lastItemIdOnPage,
+ Holder<String> getContentResult) throws WebServiceIOException {
+ try {
+ siteData.getContent(objectType, objectId, folderUrl, itemId,
+ retrieveChildItems, securityOnly, lastItemIdOnPage,
+ getContentResult);
+ } catch (WebServiceException ex) {
+ throw new WebServiceIOException(ex);
+ }
+ }
+
+ @Override
+ public void getChanges(ObjectType objectType, String contentDatabaseId,
+ Holder<String> lastChangeId, Holder<String> currentChangeId,
+ Integer timeout, Holder<String> getChangesResult,
+ Holder<Boolean> moreChanges) throws WebServiceIOException {
+ try {
+ siteData.getChanges(objectType, contentDatabaseId, lastChangeId,
+ currentChangeId, timeout, getChangesResult, moreChanges);
+ } catch (WebServiceException ex) {
+ throw new WebServiceIOException(ex);
+ }
+ }
+ }
+}
diff --git a/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java b/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
index 78bbb20..74b2b16 100644
--- a/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
+++ b/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
@@ -16,7 +16,7 @@
import static com.google.enterprise.adaptor.sharepoint.SharePointAdaptor.FileInfo;
import static com.google.enterprise.adaptor.sharepoint.SharePointAdaptor.HttpClient;
-import static com.google.enterprise.adaptor.sharepoint.SharePointAdaptor.SiteDataFactory;
+import static com.google.enterprise.adaptor.sharepoint.SiteDataClient.SiteDataFactory;
import static org.junit.Assert.*;
import com.google.common.base.Objects;
@@ -255,8 +255,8 @@
@Test
public void testSiteDataFactoryImpl() throws IOException {
- SharePointAdaptor.SiteDataFactoryImpl sdfi
- = new SharePointAdaptor.SiteDataFactoryImpl();
+ SiteDataClient.SiteDataFactoryImpl sdfi
+ = new SiteDataClient.SiteDataFactoryImpl();
assertNotNull(
sdfi.newSiteData("http://localhost:1/_vti_bin/SiteData.asmx"));
// Test a site with a space.
@@ -522,7 +522,7 @@
new DocId("http://localhost:1/sites/SiteCollection/Lists/Custom List/"
+ "AllItems.aspx"));
GetContentsResponse response = new GetContentsResponse(baos);
- adaptor.new SiteDataClient("http://localhost:1/sites/SiteCollection",
+ adaptor.new SiteAdaptor("http://localhost:1/sites/SiteCollection",
"http://localhost:1/sites/SiteCollection", siteData,
new UnsupportedUserGroupSoap(), Callables.returning(memberIdMapping),
new UnsupportedCallable<MemberIdMapping>())
@@ -566,7 +566,7 @@
new DocId("http://localhost:1/sites/SiteCollection/Lists/Custom List/"
+ "AllItems.aspx"));
GetContentsResponse response = new GetContentsResponse(baos);
- adaptor.new SiteDataClient("http://localhost:1/sites/SiteCollection",
+ adaptor.new SiteAdaptor("http://localhost:1/sites/SiteCollection",
"http://localhost:1/sites/SiteCollection", siteData,
new UnsupportedUserGroupSoap(),
new UnsupportedCallable<MemberIdMapping>(),
@@ -609,7 +609,7 @@
GetContentsRequest request = new GetContentsRequest(
new DocId(attachmentId));
GetContentsResponse response = new GetContentsResponse(baos);
- adaptor.new SiteDataClient("http://localhost:1/sites/SiteCollection",
+ adaptor.new SiteAdaptor("http://localhost:1/sites/SiteCollection",
"http://localhost:1/sites/SiteCollection", siteData,
new UnsupportedUserGroupSoap(),
new UnsupportedCallable<MemberIdMapping>(),
@@ -660,7 +660,7 @@
new DocId("http://localhost:1/sites/SiteCollection/Lists/Custom List/"
+ "Test Folder/2_.000"));
GetContentsResponse response = new GetContentsResponse(baos);
- adaptor.new SiteDataClient("http://localhost:1/sites/SiteCollection",
+ adaptor.new SiteAdaptor("http://localhost:1/sites/SiteCollection",
"http://localhost:1/sites/SiteCollection", siteData,
new UnsupportedUserGroupSoap(), Callables.returning(memberIdMapping),
new UnsupportedCallable<MemberIdMapping>())
@@ -775,7 +775,7 @@
new DocId("http://localhost:1/sites/SiteCollection/Lists/Custom List/"
+ "Test Folder/2_.000"));
GetContentsResponse response = new GetContentsResponse(baos);
- adaptor.new SiteDataClient("http://localhost:1/sites/SiteCollection",
+ adaptor.new SiteAdaptor("http://localhost:1/sites/SiteCollection",
"http://localhost:1/sites/SiteCollection", siteData,
new UnsupportedUserGroupSoap(), Callables.returning(memberIdMapping),
new UnsupportedCallable<MemberIdMapping>())
@@ -833,7 +833,7 @@
new DocId("http://localhost:1/sites/SiteCollection/Lists/Custom List/"
+ "Test Folder/2_.000"));
GetContentsResponse response = new GetContentsResponse(baos);
- adaptor.new SiteDataClient("http://localhost:1/sites/SiteCollection",
+ adaptor.new SiteAdaptor("http://localhost:1/sites/SiteCollection",
"http://localhost:1/sites/SiteCollection", siteData,
mockUserGroupFactory.newUserGroup(
"http://localhost:1/sites/SiteCollection"),
@@ -900,7 +900,7 @@
new DocId("http://localhost:1/sites/SiteCollection/Lists/Custom List/"
+ "Test Folder/2_.000"));
GetContentsResponse response = new GetContentsResponse(baos);
- adaptor.new SiteDataClient("http://localhost:1/sites/SiteCollection",
+ adaptor.new SiteAdaptor("http://localhost:1/sites/SiteCollection",
"http://localhost:1/sites/SiteCollection",
siteData, new UnsupportedUserGroupSoap(),
Callables.returning(memberIdMapping),
@@ -944,7 +944,7 @@
new DocId("http://localhost:1/sites/SiteCollection/Lists/Custom List/"
+ "Test Folder"));
GetContentsResponse response = new GetContentsResponse(baos);
- adaptor.new SiteDataClient("http://localhost:1/sites/SiteCollection",
+ adaptor.new SiteAdaptor("http://localhost:1/sites/SiteCollection",
"http://localhost:1/sites/SiteCollection",
siteData, new UnsupportedUserGroupSoap(),
Callables.returning(memberIdMapping),
@@ -1221,17 +1221,14 @@
executorFactory);
AccumulatingDocIdPusher pusher = new AccumulatingDocIdPusher();
adaptor.init(new MockAdaptorContext(config, pusher));
- SharePointAdaptor.SiteDataClient client = adaptor.new SiteDataClient(
+ SPContentDatabase result = parseChanges(getChangesContentDatabase);
+ adaptor.new SiteAdaptor(
"http://localhost:1/sites/SiteCollection",
"http://localhost:1/sites/SiteCollection", new UnsupportedSiteData(),
new UnsupportedUserGroupSoap(),
new UnsupportedCallable<MemberIdMapping>(),
- new UnsupportedCallable<MemberIdMapping>());
-
- SPContentDatabase result
- = parseChanges(client, getChangesContentDatabase);
-
- client.getModifiedDocIds(result, pusher);
+ new UnsupportedCallable<MemberIdMapping>())
+ .getModifiedDocIds(result, pusher);
assertEquals(1, pusher.getRecords().size());
assertEquals(new DocIdPusher.Record.Builder(new DocId(
"http://localhost:1/Lists/Announcements/2_.000"))
@@ -1240,15 +1237,8 @@
@Test
public void testParseError() throws Exception {
- adaptor = new SharePointAdaptor(initableSiteDataFactory,
- new UnsupportedUserGroupFactory(), new UnsupportedHttpClient(),
- executorFactory);
- adaptor.init(new MockAdaptorContext(config, null));
- SharePointAdaptor.SiteDataClient client = adaptor.new SiteDataClient(
- "http://localhost:1", "http://localhost:1",
- new UnsupportedSiteData(), new UnsupportedUserGroupSoap(),
- new UnsupportedCallable<MemberIdMapping>(),
- new UnsupportedCallable<MemberIdMapping>());
+ SiteDataClient client = new SiteDataClient(
+ new UnsupportedSiteData(), false);
String xml = "<broken";
thrown.expect(IOException.class);
client.jaxbParse(xml, SPContentDatabase.class);
@@ -1256,16 +1246,8 @@
@Test
public void testValidationError() throws Exception {
- config.overrideKey("sharepoint.xmlValidation", "true");
- adaptor = new SharePointAdaptor(initableSiteDataFactory,
- new UnsupportedUserGroupFactory(),
- new UnsupportedHttpClient(), executorFactory);
- adaptor.init(new MockAdaptorContext(config, null));
- SharePointAdaptor.SiteDataClient client = adaptor.new SiteDataClient(
- "http://localhost:1", "http://localhost:1",
- new UnsupportedSiteData(), new UnsupportedUserGroupSoap(),
- new UnsupportedCallable<MemberIdMapping>(),
- new UnsupportedCallable<MemberIdMapping>());
+ SiteDataClient client = new SiteDataClient(
+ new UnsupportedSiteData(), true);
// Lacks required child element.
String xml = "<SPContentDatabase"
+ " xmlns='http://schemas.microsoft.com/sharepoint/soap/'/>";
@@ -1275,16 +1257,8 @@
@Test
public void testDisabledValidation() throws Exception {
- adaptor = new SharePointAdaptor(initableSiteDataFactory,
- new UnsupportedUserGroupFactory(),
- new UnsupportedHttpClient(), executorFactory);
- config.overrideKey("sharepoint.xmlValidation", "false");
- adaptor.init(new MockAdaptorContext(config, null));
- SharePointAdaptor.SiteDataClient client = adaptor.new SiteDataClient(
- "http://localhost:1", "http://localhost:1",
- new UnsupportedSiteData(), new UnsupportedUserGroupSoap(),
- new UnsupportedCallable<MemberIdMapping>(),
- new UnsupportedCallable<MemberIdMapping>());
+ SiteDataClient client = new SiteDataClient(
+ new UnsupportedSiteData(), false);
// Lacks required child element.
String xml = "<SPContentDatabase"
+ " xmlns='http://schemas.microsoft.com/sharepoint/soap/'/>";
@@ -1294,16 +1268,8 @@
@Test
public void testParseUnknownXml() throws Exception {
- config.overrideKey("sharepoint.xmlValidation", "true");
- adaptor = new SharePointAdaptor(initableSiteDataFactory,
- new UnsupportedUserGroupFactory(),
- new UnsupportedHttpClient(), executorFactory);
- adaptor.init(new MockAdaptorContext(config, null));
- SharePointAdaptor.SiteDataClient client = adaptor.new SiteDataClient(
- "http://localhost:1", "http://localhost:1",
- new UnsupportedSiteData(), new UnsupportedUserGroupSoap(),
- new UnsupportedCallable<MemberIdMapping>(),
- new UnsupportedCallable<MemberIdMapping>());
+ SiteDataClient client = new SiteDataClient(
+ new UnsupportedSiteData(), true);
// Valid XML, but not any class that we know about.
String xml = "<html/>";
thrown.expect(IOException.class);
@@ -1346,8 +1312,8 @@
}
}
- private SPContentDatabase parseChanges(
- SharePointAdaptor.SiteDataClient client, String xml) throws IOException {
+ private SPContentDatabase parseChanges(String xml) throws IOException {
+ SiteDataClient client = new SiteDataClient(new UnsupportedSiteData(), true);
String xmlns = "http://schemas.microsoft.com/sharepoint/soap/";
xml = xml.replace("<SPContentDatabase ",
"<SPContentDatabase xmlns='" + xmlns + "' ");