Skip to content

Commit

Permalink
Merge pull request #154 from christav/dev
Browse files Browse the repository at this point in the history
Adding support for setting timeout in configuration
  • Loading branch information
Chris Tavares committed Sep 27, 2012
2 parents be59df0 + be72040 commit 89f971c
Show file tree
Hide file tree
Showing 9 changed files with 307 additions and 62 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
* Copyright 2011 Microsoft Corporation
*
* 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
* 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.
* 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.microsoft.windowsazure.services.core;

Expand All @@ -23,10 +23,18 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.sun.jersey.api.client.config.ClientConfig;

public class Configuration {

/**
* Property name for socket connection timeout used by services created with this configuration.
*/
public static final String PROPERTY_CONNECT_TIMEOUT = "com.microsoft.windowsazure.services.core.Configuration.connectTimeout";

/**
* Property name for socket read timeout used by services created with this configuration.
*/
public static final String PROPERTY_READ_TIMEOUT = "com.microsoft.windowsazure.services.core.Configuration.readTimeout";

private static Configuration instance;
Map<String, Object> properties;
Builder builder;
Expand All @@ -36,17 +44,11 @@ public class Configuration {
public Configuration() {
this.properties = new HashMap<String, Object>();
this.builder = DefaultBuilder.create();
init();
}

public Configuration(Builder builder) {
this.properties = new HashMap<String, Object>();
this.builder = builder;
init();
}

private void init() {
setProperty("ClientConfig", builder.build("", ClientConfig.class, properties));
}

public static Configuration getInstance() {
Expand Down Expand Up @@ -102,4 +104,7 @@ public void setProperty(String name, Object value) {
properties.put(name, value);
}

public Map<String, Object> getProperties() {
return properties;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* Copyright 2012 Microsoft Corporation
*
* 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.microsoft.windowsazure.services.core;

/**
* Exception indicating a service operation has timed out.
*/
public class ServiceTimeoutException extends ServiceException {

private static final long serialVersionUID = 6612846403178749361L;

/**
* Construct a ServiceTimeoutException instance with default parameters.
*/
public ServiceTimeoutException() {
}

/**
* Construct a ServiceTimeoutException instance with the specified message.
*
* @param message
* Exception message
*/
public ServiceTimeoutException(String message) {
super(message);
}

/**
* Construct a ServiceTimeoutException instance with specified
* message and cause
*
* @param message
* Exception message
* @param cause
* Exception that caused this exception to occur
*/
public ServiceTimeoutException(String message, Throwable cause) {
super(message, cause);
}

/**
* Construct a ServiceTimeoutException instance with the specified cause.
*
* @param cause
* Exception that caused this exception to occur
*/
public ServiceTimeoutException(Throwable cause) {
super(cause);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,22 @@
* Copyright 2011 Microsoft Corporation
*
* 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
* 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.
* 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.microsoft.windowsazure.services.core.utils;

import java.net.SocketTimeoutException;

import com.microsoft.windowsazure.services.core.ServiceException;
import com.microsoft.windowsazure.services.core.ServiceTimeoutException;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.ClientResponse.Status;
import com.sun.jersey.api.client.UniformInterfaceException;
Expand All @@ -25,12 +28,16 @@ public static ServiceException process(String serviceName, ServiceException exce
Throwable cause = exception.getCause();

for (Throwable scan = cause; scan != null; scan = scan.getCause()) {
if (ServiceException.class.isAssignableFrom(scan.getClass())) {
Class scanClass = scan.getClass();
if (ServiceException.class.isAssignableFrom(scanClass)) {
return populate(exception, serviceName, (ServiceException) scan);
}
else if (UniformInterfaceException.class.isAssignableFrom(scan.getClass())) {
else if (UniformInterfaceException.class.isAssignableFrom(scanClass)) {
return populate(exception, serviceName, (UniformInterfaceException) scan);
}
else if (SocketTimeoutException.class.isAssignableFrom(scanClass)) {
return populate(exception, serviceName, (SocketTimeoutException) scan);
}
}

exception.setServiceName(serviceName);
Expand Down Expand Up @@ -83,4 +90,9 @@ static ServiceException populate(ServiceException exception, String serviceName,
return exception;
}

static ServiceException populate(ServiceException exception, String serviceName, SocketTimeoutException cause) {
ServiceTimeoutException newException = new ServiceTimeoutException(cause.getMessage(), cause);
newException.setServiceName(serviceName);
return newException;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import com.microsoft.windowsazure.services.core.Builder;
import com.microsoft.windowsazure.services.core.Builder.Registry;
import com.microsoft.windowsazure.services.core.Configuration;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
Expand All @@ -31,8 +32,37 @@ public void register(Registry registry) {
@Override
public ClientConfig create(String profile, Builder builder, Map<String, Object> properties) {
ClientConfig clientConfig = new DefaultClientConfig();
profile = normalizeProfile(profile);

// Lower levels of the stack assume timeouts are set.
// Set default timeout on clientConfig in case user
// hasn't set it yet in their configuration

clientConfig.getProperties().put(ClientConfig.PROPERTY_CONNECT_TIMEOUT, new Integer(90 * 1000));
clientConfig.getProperties().put(ClientConfig.PROPERTY_READ_TIMEOUT, new Integer(90 * 1000));

for (Entry<String, Object> entry : properties.entrySet()) {
clientConfig.getProperties().put(entry.getKey(), entry.getValue());
Object propertyValue = entry.getValue();
String propertyKey = entry.getKey();

if (propertyKey.equals(profile + Configuration.PROPERTY_CONNECT_TIMEOUT)) {
propertyKey = ClientConfig.PROPERTY_CONNECT_TIMEOUT;
}
if (propertyKey.equals(profile + Configuration.PROPERTY_READ_TIMEOUT)) {
propertyKey = ClientConfig.PROPERTY_READ_TIMEOUT;
}

// ClientConfig requires instance of Integer to properly set
// timeouts, but config file will deliver strings. Special
// case these timeout properties and convert them to Integer
// if necessary.
if (propertyKey.equals(ClientConfig.PROPERTY_CONNECT_TIMEOUT)
|| propertyKey.equals(ClientConfig.PROPERTY_READ_TIMEOUT)) {
if (propertyValue instanceof String) {
propertyValue = Integer.valueOf((String) propertyValue);
}
}
clientConfig.getProperties().put(propertyKey, propertyValue);
}
return clientConfig;
}
Expand All @@ -41,7 +71,7 @@ public ClientConfig create(String profile, Builder builder, Map<String, Object>
registry.add(new Builder.Factory<Client>() {
@Override
public Client create(String profile, Builder builder, Map<String, Object> properties) {
ClientConfig clientConfig = (ClientConfig) properties.get("ClientConfig");
ClientConfig clientConfig = builder.build(profile, ClientConfig.class, properties);
Client client = Client.create(clientConfig);
return client;
}
Expand All @@ -50,11 +80,23 @@ public Client create(String profile, Builder builder, Map<String, Object> proper
registry.add(new Builder.Factory<HttpURLConnectionClient>() {
@Override
public HttpURLConnectionClient create(String profile, Builder builder, Map<String, Object> properties) {
ClientConfig clientConfig = (ClientConfig) properties.get("ClientConfig");
ClientConfig clientConfig = builder.build(profile, ClientConfig.class, properties);
HttpURLConnectionClient client = HttpURLConnectionClient.create(clientConfig);
//client.addFilter(new LoggingFilter());
return client;
}
});
}

private static String normalizeProfile(String profile) {
if (profile == null) {
return "";
}

if (profile.endsWith(".")) {
return profile;
}

return profile + ".";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
* Copyright 2011 Microsoft Corporation
*
* 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
* 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.
* 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.microsoft.windowsazure.services.core.utils.pipeline;

Expand All @@ -26,7 +26,7 @@ public HttpURLConnectionClient(HttpURLConnectionClientHandler handler, ClientCon
}

public static HttpURLConnectionClient create(ClientConfig config) {
return new HttpURLConnectionClient(new HttpURLConnectionClientHandler(), config);
return new HttpURLConnectionClient(new HttpURLConnectionClientHandler(config), config);
}

public HttpURLConnectionClientHandler getRootHandler() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
* Copyright 2011 Microsoft Corporation
*
* 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
* 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.
* 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.microsoft.windowsazure.services.core.utils.pipeline;

Expand All @@ -37,10 +37,28 @@
import com.sun.jersey.core.header.InBoundHeaders;

public class HttpURLConnectionClientHandler extends TerminatingClientHandler {

private final int connectionTimeoutMillis;
private final int readTimeoutMillis;

public HttpURLConnectionClientHandler(ClientConfig clientConfig) {
connectionTimeoutMillis = readTimeoutFromConfig(clientConfig, ClientConfig.PROPERTY_CONNECT_TIMEOUT);
readTimeoutMillis = readTimeoutFromConfig(clientConfig, ClientConfig.PROPERTY_READ_TIMEOUT);
}

private static int readTimeoutFromConfig(ClientConfig config, String propertyName) {
Integer property = (Integer) config.getProperty(propertyName);
if (property != null) {
return property.intValue();
}
throw new IllegalArgumentException(propertyName);
}

/**
* Empty "no-op" listener if none registered
*/
private static final EntityStreamingListener EMPTY_STREAMING_LISTENER = new EntityStreamingListener() {
@Override
public void onBeforeStreamingEntity(ClientRequest clientRequest) {
}
};
Expand Down Expand Up @@ -164,6 +182,7 @@ public String toString() {
}
}

@Override
public ClientResponse handle(final ClientRequest ro) throws ClientHandlerException {
try {
return doHandle(ro);
Expand All @@ -176,6 +195,9 @@ public ClientResponse handle(final ClientRequest ro) throws ClientHandlerExcepti
private ClientResponse doHandle(final ClientRequest clientRequest) throws IOException, MalformedURLException,
ProtocolException {
final HttpURLConnection urlConnection = (HttpURLConnection) clientRequest.getURI().toURL().openConnection();
urlConnection.setReadTimeout(readTimeoutMillis);
urlConnection.setConnectTimeout(connectionTimeoutMillis);

final EntityStreamingListener entityStreamingListener = getEntityStreamingListener(clientRequest);

urlConnection.setRequestMethod(clientRequest.getMethod());
Expand All @@ -202,6 +224,7 @@ private ClientResponse doHandle(final ClientRequest clientRequest) throws IOExce
writeRequestEntity(clientRequest, new RequestEntityWriterListener() {
private boolean inStreamingMode;

@Override
public void onRequestEntitySize(long size) {
if (size != -1 && size < Integer.MAX_VALUE) {
inStreamingMode = true;
Expand All @@ -222,6 +245,7 @@ public void onRequestEntitySize(long size) {
}
}

@Override
public OutputStream onGetOutputStream() throws IOException {
if (inStreamingMode)
return new StreamingOutputStream(urlConnection, clientRequest);
Expand Down
Loading

0 comments on commit 89f971c

Please sign in to comment.