Specify socket timeout and read time out for SharePoint web services call to avoid hanged threads from unstable SharePoint env.
https://codereview.appspot.com/99080044/
diff --git a/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java b/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
index 01de037..06e03fb 100644
--- a/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
+++ b/src/com/google/enterprise/adaptor/sharepoint/SharePointAdaptor.java
@@ -266,6 +266,9 @@
private static final String SITE_COLLECTION_ADMIN_FRAGMENT = "admin";
+ private int socketTimeoutMillis;
+ private int readTimeOutMillis;
+
/**
* Mapping of mime-types used by SharePoint to ones that the GSA comprehends.
*/
@@ -488,6 +491,10 @@
String stsrealm = config.getValue("sharepoint.sts.realm");
boolean useLiveAuthentication = Boolean.parseBoolean(
config.getValue("sharepoint.useLiveAuthentication"));
+ socketTimeoutMillis = Integer.parseInt(
+ config.getValue("adaptor.docHeaderTimeoutSecs")) * 1000;
+ readTimeOutMillis = Integer.parseInt(
+ config.getValue("adaptor.docContentTimeoutSecs")) * 1000;
log.log(Level.CONFIG, "VirtualServer: {0}", virtualServer);
log.log(Level.CONFIG, "Username: {0}", username);
@@ -521,6 +528,7 @@
} else {
AuthenticationSoap authenticationSoap = authenticationClientFactory
.newSharePointFormsAuthentication(virtualServer, username, password);
+ addSocketTimeoutConfiguration((BindingProvider) authenticationSoap);
authenticationHandler = new SharePointFormsAuthenticationHandler
.Builder(username, password, scheduledExecutor, authenticationSoap)
.build();
@@ -968,13 +976,15 @@
String endpointPeople = spUrlToUri(site + "/_vti_bin/People.asmx")
.toString();
PeopleSoap peopleSoap = soapFactory.newPeople(endpointPeople);
- // JAX-WS RT 2.1.4 doesn't handle headers correctly and always assumes the
- // list contains precisely one entry, so we work around it here.
- if (authenticationHandler.isFormsAuthentication()) {
- addFormsAuthenticationCookies((BindingProvider) siteDataSoap);
- addFormsAuthenticationCookies((BindingProvider) userGroupSoap);
- addFormsAuthenticationCookies((BindingProvider) peopleSoap);
- }
+
+ addFormsAuthenticationCookies((BindingProvider) siteDataSoap);
+ addFormsAuthenticationCookies((BindingProvider) userGroupSoap);
+ addFormsAuthenticationCookies((BindingProvider) peopleSoap);
+
+ addSocketTimeoutConfiguration((BindingProvider) siteDataSoap);
+ addSocketTimeoutConfiguration((BindingProvider) userGroupSoap);
+ addSocketTimeoutConfiguration((BindingProvider) peopleSoap);
+
siteAdaptor = new SiteAdaptor(site, web, siteDataSoap, userGroupSoap,
peopleSoap, new MemberIdMappingCallable(site),
new SiteUserIdMappingCallable(site));
@@ -996,6 +1006,17 @@
authenticationHandler.getAuthenticationCookies()));
}
+ private void addSocketTimeoutConfiguration(BindingProvider port) {
+ port.getRequestContext().put("com.sun.xml.internal.ws.connect.timeout",
+ socketTimeoutMillis);
+ port.getRequestContext().put("com.sun.xml.internal.ws.request.timeout",
+ readTimeOutMillis);
+ port.getRequestContext().put("com.sun.xml.ws.connect.timeout",
+ socketTimeoutMillis);
+ port.getRequestContext().put("com.sun.xml.ws.request.timeout",
+ readTimeOutMillis);
+ }
+
private void disableFormsAuthentication(BindingProvider port) {
port.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS,
Collections.singletonMap("X-FORMS_BASED_AUTH_ACCEPTED",
diff --git a/src/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptor.java b/src/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptor.java
index 6e91ec1..db23326 100644
--- a/src/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptor.java
+++ b/src/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptor.java
@@ -123,6 +123,9 @@
public static final String GSA_PROPNAME_COLLEAGUES =
"google_social_user_colleagues";
+ private static int socketTimeoutMillis;
+ private static int readTimeOutMillis;
+
// Mapping for SharePoint user profile properties to
// GSA Expert Search properties
static {
@@ -232,6 +235,11 @@
boolean useLiveAuthentication = Boolean.parseBoolean(
config.getValue("sharepoint.useLiveAuthentication"));
+ socketTimeoutMillis = Integer.parseInt(
+ config.getValue("adaptor.docHeaderTimeoutSecs")) * 1000;
+ readTimeOutMillis = Integer.parseInt(
+ config.getValue("adaptor.docContentTimeoutSecs")) * 1000;
+
log.log(Level.CONFIG, "virtualServer: {0}", virtualServer);
log.log(Level.CONFIG, "Username: {0}", username);
log.log(Level.CONFIG, "setAcl: {0}", setAcl);
@@ -272,6 +280,7 @@
} else {
AuthenticationSoap authenticationSoap = authenticationClientFactory
.newSharePointFormsAuthentication(virtualServer, username, password);
+ addSocketTimeoutConfiguration((BindingProvider) authenticationSoap);
authenticationHandler = new SharePointFormsAuthenticationHandler
.Builder(username, password, scheduledExecutor, authenticationSoap)
.build();
@@ -321,6 +330,17 @@
userProfileChangeToken);
}
+ private static void addSocketTimeoutConfiguration(BindingProvider port) {
+ port.getRequestContext().put("com.sun.xml.internal.ws.connect.timeout",
+ socketTimeoutMillis);
+ port.getRequestContext().put("com.sun.xml.internal.ws.request.timeout",
+ readTimeOutMillis);
+ port.getRequestContext().put("com.sun.xml.ws.connect.timeout",
+ socketTimeoutMillis);
+ port.getRequestContext().put("com.sun.xml.ws.request.timeout",
+ readTimeOutMillis);
+ }
+
private static class NtlmAuthenticator extends Authenticator {
private final String username;
private final char[] password;
@@ -375,14 +395,15 @@
UserProfileChangeServiceSoap inUserProfileChangeServiceSoap
= userProfileChangeServiceSoap.getPort(
endpointChangeRef, UserProfileChangeServiceSoap.class);
- // JAX-WS RT 2.1.4 doesn't handle headers correctly and always assumes the
- // list contains precisely one entry, so we work around it here.
- if (!cookies.isEmpty()) {
- addFormsAuthenticationCookies(
- (BindingProvider) inUserProfileServiceSoap, cookies);
- addFormsAuthenticationCookies(
- (BindingProvider) inUserProfileChangeServiceSoap, cookies);
- }
+
+ addFormsAuthenticationCookies(
+ (BindingProvider) inUserProfileServiceSoap, cookies);
+ addFormsAuthenticationCookies(
+ (BindingProvider) inUserProfileChangeServiceSoap, cookies);
+ addSocketTimeoutConfiguration((BindingProvider) inUserProfileServiceSoap);
+ addSocketTimeoutConfiguration(
+ (BindingProvider) inUserProfileChangeServiceSoap);
+
return new SharePointUserProfileServiceWS(inUserProfileServiceSoap,
inUserProfileChangeServiceSoap);
}
diff --git a/test/com/google/enterprise/adaptor/sharepoint/DelegatingSiteData.java b/test/com/google/enterprise/adaptor/sharepoint/DelegatingSiteData.java
index 75043f0..3e67ac3 100644
--- a/test/com/google/enterprise/adaptor/sharepoint/DelegatingSiteData.java
+++ b/test/com/google/enterprise/adaptor/sharepoint/DelegatingSiteData.java
@@ -25,10 +25,14 @@
import com.microsoft.schemas.sharepoint.soap.SSiteMetadata;
import com.microsoft.schemas.sharepoint.soap.SWebMetadata;
import com.microsoft.schemas.sharepoint.soap.SiteDataSoap;
+import java.util.Map;
+import javax.xml.ws.Binding;
+import javax.xml.ws.BindingProvider;
+import javax.xml.ws.EndpointReference;
import javax.xml.ws.Holder;
-abstract class DelegatingSiteData implements SiteDataSoap {
+abstract class DelegatingSiteData implements SiteDataSoap, BindingProvider {
protected abstract SiteDataSoap delegate();
@Override
@@ -127,6 +131,31 @@
public String getChangesEx(int version, String xmlInput) {
return delegate().getChangesEx(version, xmlInput);
}
+
+ @Override
+ public Map<String, Object> getRequestContext() {
+ return ((BindingProvider) delegate()).getRequestContext();
+ }
+
+ @Override
+ public Map<String, Object> getResponseContext() {
+ return ((BindingProvider) delegate()).getResponseContext();
+ }
+
+ @Override
+ public Binding getBinding() {
+ return ((BindingProvider) delegate()).getBinding();
+ }
+
+ @Override
+ public EndpointReference getEndpointReference() {
+ return ((BindingProvider) delegate()).getEndpointReference();
+ }
+
+ @Override
+ public <T extends EndpointReference> T getEndpointReference(Class<T> clazz) {
+ return ((BindingProvider) delegate()).getEndpointReference(clazz);
+ }
}
diff --git a/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java b/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
index 4162017..d5cd8e3 100644
--- a/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
+++ b/test/com/google/enterprise/adaptor/sharepoint/SharePointAdaptorTest.java
@@ -123,6 +123,7 @@
import javax.xml.ws.Holder;
import javax.xml.ws.WebServiceException;
+import javax.xml.ws.handler.MessageContext;
/**
* Test cases for {@link SharePointAdaptor}.
@@ -348,6 +349,57 @@
}
@Test
+ public void testAdaptorWithSocketTimeoutConfiguration() throws Exception {
+ Map<String, Object> goldenRequestContext;
+ Map<String, Object> goldenRequestContextAuth;
+ {
+ Map<String, Object> tmp = new HashMap<String, Object>();
+ tmp.put("com.sun.xml.internal.ws.connect.timeout", 20000);
+ tmp.put("com.sun.xml.internal.ws.request.timeout", 180000);
+ tmp.put("com.sun.xml.ws.connect.timeout", 20000);
+ tmp.put("com.sun.xml.ws.request.timeout", 180000);
+ goldenRequestContextAuth
+ = Collections.unmodifiableMap(new HashMap<String, Object>(tmp));
+ // Disabling forms authentication
+ tmp.put(MessageContext.HTTP_REQUEST_HEADERS,
+ Collections.singletonMap("X-FORMS_BASED_AUTH_ACCEPTED",
+ Collections.singletonList("f")));
+ goldenRequestContext = Collections.unmodifiableMap(tmp);
+ }
+
+ MockSiteData siteDataSoap = new MockSiteData()
+ .register(VS_CONTENT_EXCHANGE).register(CD_CONTENT_EXCHANGE);
+ MockPeopleSoap peopleSoap = new MockPeopleSoap();
+ MockUserGroupSoap userGroupSoap = new MockUserGroupSoap(null);
+ final MockAuthenticationSoap authenticationSoap
+ = new MockAuthenticationSoap();
+ SoapFactory siteDataFactory = MockSoapFactory.blank()
+ .endpoint(VS_ENDPOINT, siteDataSoap)
+ .endpoint("http://localhost:1/_vti_bin/People.asmx", peopleSoap)
+ .endpoint("http://localhost:1/_vti_bin/UserGroup.asmx", userGroupSoap);
+
+ adaptor = new SharePointAdaptor(siteDataFactory,
+ new UnsupportedHttpClient(), executorFactory,
+ new MockAuthenticationClientFactoryForms() {
+ @Override
+ public AuthenticationSoap newSharePointFormsAuthentication(
+ String virtualServer, String username, String password)
+ throws IOException {
+ return authenticationSoap;
+ }
+ });
+ config.overrideKey("adaptor.docHeaderTimeoutSecs", "20");
+ adaptor.init(new MockAdaptorContext(config, pusher));
+ assertEquals(goldenRequestContext, siteDataSoap.getRequestContext());
+ assertEquals(goldenRequestContext, peopleSoap.getRequestContext());
+ assertEquals(goldenRequestContext, userGroupSoap.getRequestContext());
+ assertEquals(goldenRequestContextAuth,
+ authenticationSoap.getRequestContext());
+ adaptor.destroy();
+ adaptor = null;
+ }
+
+ @Test
public void testAdaptorInitWithAdfs() throws Exception {
SoapFactory siteDataFactory = MockSoapFactory.blank()
.endpoint(VS_ENDPOINT, MockSiteData.blank()
@@ -2050,7 +2102,9 @@
private static class UnsupportedPeopleSoap extends DelegatingPeopleSoap
implements BindingProvider {
- private final String endpoint;
+ private final String endpoint;
+ private final Map<String, Object> requestContext
+ = new HashMap<String, Object>();
public UnsupportedPeopleSoap() {
this(null);
@@ -2071,7 +2125,7 @@
@Override
public Map<String, Object> getRequestContext() {
- throw new UnsupportedOperationException();
+ return requestContext;
}
@Override
@@ -2156,7 +2210,9 @@
private static class UnsupportedUserGroupSoap
extends DelegatingUserGroupSoap implements BindingProvider {
- private final String endpoint;
+ private final String endpoint;
+ private final Map<String, Object> requestContext
+ = new HashMap<String, Object>();
public UnsupportedUserGroupSoap() {
this(null);
@@ -2177,7 +2233,7 @@
@Override
public Map<String, Object> getRequestContext() {
- throw new UnsupportedOperationException();
+ return requestContext;
}
@Override
@@ -2461,6 +2517,8 @@
private static class MockAuthenticationSoap extends
UnsupportedAuthenticationSoap {
+ private final Map<String, Object> requestContext
+ = new HashMap<String, Object>();
@Override
public LoginResult login(String string, String string1) {
throw new UnsupportedOperationException();
@@ -2470,6 +2528,11 @@
public AuthenticationMode mode() {
return AuthenticationMode.WINDOWS;
}
+
+ @Override
+ public Map<String, Object> getRequestContext() {
+ return requestContext;
+ }
}
private static class UnsupportedAuthenticationSoap
@@ -2492,11 +2555,37 @@
throw new UnsupportedOperationException("Endpoint: " + endpoint);
}
}
+
+ @Override
+ public Map<String, Object> getRequestContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<String, Object> getResponseContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Binding getBinding() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public EndpointReference getEndpointReference() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T extends EndpointReference> T getEndpointReference(
+ Class<T> clazz) {
+ throw new UnsupportedOperationException();
+ }
}
private abstract static class DelegatingAuthenticationSoap
- implements AuthenticationSoap {
+ implements AuthenticationSoap, BindingProvider {
protected abstract AuthenticationSoap delegate();
@Override
@@ -2508,13 +2597,41 @@
public AuthenticationMode mode() {
return delegate().mode();
}
+
+ @Override
+ public Map<String, Object> getRequestContext() {
+ return ((BindingProvider) delegate()).getRequestContext();
+ }
+
+ @Override
+ public Map<String, Object> getResponseContext() {
+ return ((BindingProvider) delegate()).getResponseContext();
+ }
+
+ @Override
+ public Binding getBinding() {
+ return ((BindingProvider) delegate()).getBinding();
+ }
+
+ @Override
+ public EndpointReference getEndpointReference() {
+ return ((BindingProvider) delegate()).getEndpointReference();
+ }
+
+ @Override
+ public <T extends EndpointReference> T getEndpointReference(
+ Class<T> clazz) {
+ return ((BindingProvider) delegate()).getEndpointReference(clazz);
+ }
}
/**
* Throw UnsupportedOperationException for all calls.
*/
private static class UnsupportedSiteData extends DelegatingSiteData
- implements BindingProvider{
+ implements BindingProvider {
+ private final Map<String, Object> requestContext
+ = new HashMap<String, Object>();
@Override
protected SiteDataSoap delegate() {
throw new UnsupportedOperationException();
@@ -2522,7 +2639,7 @@
@Override
public Map<String, Object> getRequestContext() {
- throw new UnsupportedOperationException();
+ return requestContext;
}
@Override
@@ -2650,7 +2767,6 @@
private final List<ContentExchange> contentList;
private final List<ChangesExchange> changesList;
private final List<SiteAndWebExchange> siteAndWebList;
- private Map<String, Object> requestContext = new HashMap<String, Object>();
private MockSiteData() {
this.urlSegmentsList = Collections.emptyList();
@@ -2746,11 +2862,6 @@
}
fail("Could not find " + strUrl);
}
-
- @Override
- public Map<String, Object> getRequestContext() {
- return requestContext;
- }
public static MockSiteData blank() {
return new MockSiteData();
diff --git a/test/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptorTest.java b/test/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptorTest.java
index 7b2bd1d..5df3fc0 100644
--- a/test/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptorTest.java
+++ b/test/com/google/enterprise/adaptor/sharepoint/SharePointUserProfileAdaptorTest.java
@@ -68,6 +68,9 @@
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.ws.Binding;
+import javax.xml.ws.BindingProvider;
+import javax.xml.ws.EndpointReference;
import javax.xml.ws.WebServiceException;
@@ -666,7 +669,10 @@
}
}
- private static class MockAuthenticationSoap implements AuthenticationSoap {
+ private static class MockAuthenticationSoap
+ implements AuthenticationSoap, BindingProvider {
+ private final Map<String, Object> requestContext
+ = new HashMap<String, Object>();
@Override
public LoginResult login(String string, String string1) {
throw new UnsupportedOperationException();
@@ -676,6 +682,32 @@
public AuthenticationMode mode() {
return AuthenticationMode.WINDOWS;
}
+
+ @Override
+ public Map<String, Object> getRequestContext() {
+ return requestContext;
+ }
+
+ @Override
+ public Map<String, Object> getResponseContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Binding getBinding() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public EndpointReference getEndpointReference() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T extends EndpointReference> T getEndpointReference(
+ Class<T> clazz) {
+ throw new UnsupportedOperationException();
+ }
}
private static class UnsupportedAuthenticationClientFactory