Issue 647: DateCodec impl delegates to DateService

This commit is contained in:
Aled Sage 2012-05-17 10:03:49 +01:00
parent cd9c830c5a
commit 2637a4b6e9
14 changed files with 164 additions and 76 deletions

View File

@ -95,6 +95,7 @@ import org.jclouds.http.HttpResponseException;
import org.jclouds.http.HttpUtils;
import org.jclouds.http.options.HttpRequestOptions;
import org.jclouds.io.ContentMetadata;
import org.jclouds.io.ContentMetadataCodec;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import org.jclouds.io.payloads.BaseMutableContentMetadata;
@ -124,6 +125,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
protected final DateService dateService;
protected final Crypto crypto;
protected final HttpGetOptionsListToGetOptions httpGetOptionsConverter;
protected final ContentMetadataCodec contentMetadataCodec;
protected final IfDirectoryReturnNameStrategy ifDirectoryReturnName;
protected final Factory blobFactory;
protected final FilesystemStorageStrategy storageStrategy;
@ -132,6 +134,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
protected FilesystemAsyncBlobStore(BlobStoreContext context,
DateService dateService, Crypto crypto,
HttpGetOptionsListToGetOptions httpGetOptionsConverter,
ContentMetadataCodec contentMetadataCodec,
IfDirectoryReturnNameStrategy ifDirectoryReturnName,
BlobUtils blobUtils,
@Named(Constants.PROPERTY_USER_THREADS) ExecutorService service,
@ -143,6 +146,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
this.dateService = dateService;
this.crypto = crypto;
this.httpGetOptionsConverter = httpGetOptionsConverter;
this.contentMetadataCodec = contentMetadataCodec;
this.ifDirectoryReturnName = ifDirectoryReturnName;
this.storageStrategy = checkNotNull(storageStrategy, "Storage strategy");
}
@ -475,7 +479,7 @@ public class FilesystemAsyncBlobStore extends BaseAsyncBlobStore {
}
private void copyPayloadHeadersToBlob(Payload payload, Blob blob) {
blob.getAllHeaders().putAll(HttpUtils.getContentHeadersFromMetadata(payload.getContentMetadata()));
blob.getAllHeaders().putAll(contentMetadataCodec.toHeaders(payload.getContentMetadata()));
}
/**

View File

@ -114,6 +114,21 @@ public class NovaEC2ParserModule extends AbstractModule {
if (Objects.equal("-", toParse)) return null;
return delegate.iso8601SecondsDateParse(toParse);
}
@Override
public String rfc1123DateFormat(Date date) {
return delegate.rfc1123DateFormat(date);
}
@Override
public String rfc1123DateFormat() {
return delegate.rfc1123DateFormat();
}
@Override
public Date rfc1123DateParse(String toParse) {
return delegate.rfc1123DateParse(toParse);
}
}
}

View File

@ -0,0 +1,17 @@
package org.jclouds.date;
import org.jclouds.date.internal.SimpleDateCodecFactory;
import com.google.inject.ImplementedBy;
/**
* Codecs for converting from Date->String and vice versa.
*
* @author aled
*/
@ImplementedBy(SimpleDateCodecFactory.class)
public interface DateCodecFactory {
public DateCodec rfc1123();
}

View File

@ -1,47 +0,0 @@
package org.jclouds.date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class DateCodecs {
// See http://stackoverflow.com/questions/10584647/simpledateformat-parse-is-one-hour-out-using-rfc-1123-gmt-in-summer
// for why not using "zzz"
public final static String RFC1123_DATE_PATTERN = "EEE, dd MMM yyyyy HH:mm:ss Z";
/*
* Use default Java Date/SimpleDateFormat classes for date manipulation, but be *very* careful to
* guard against the lack of thread safety.
*/
// @GuardedBy("this")
private static final SimpleDateFormat rfc1123SimpleDateFormat = new SimpleDateFormat(RFC1123_DATE_PATTERN, Locale.US);
public static DateCodec rfc1123() {
return new SimpleDateCodec(rfc1123SimpleDateFormat);
}
private static class SimpleDateCodec implements DateCodec {
private final SimpleDateFormat dateFormat;
SimpleDateCodec(SimpleDateFormat dateFormat) {
this.dateFormat = dateFormat;
}
@Override
public Date toDate(String date) throws ParseException {
synchronized (dateFormat) {
return dateFormat.parse(date);
}
}
@Override
public String toString(Date date) {
synchronized (dateFormat) {
return dateFormat.format(date);
}
}
}
}

View File

@ -60,4 +60,10 @@ public interface DateService {
Date iso8601SecondsDateParse(String toParse);
String rfc1123DateFormat(Date date);
String rfc1123DateFormat();
Date rfc1123DateParse(String toParse);
}

View File

@ -0,0 +1,41 @@
package org.jclouds.date.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import java.text.ParseException;
import java.util.Date;
import org.jclouds.date.DateCodec;
import org.jclouds.date.DateCodecFactory;
import org.jclouds.date.DateService;
import com.google.inject.Inject;
public class SimpleDateCodecFactory implements DateCodecFactory {
private final DateService dateService;
private volatile DateCodec rfc1123Codec;
@Inject
public SimpleDateCodecFactory(final DateService dateService) {
this.dateService = checkNotNull(dateService, "dateService");
}
public DateCodec rfc1123() {
if (rfc1123Codec == null) {
rfc1123Codec = new DateCodec() {
@Override
public Date toDate(String date) throws ParseException {
return dateService.rfc1123DateParse(date);
}
@Override
public String toString(Date date) {
return dateService.rfc1123DateFormat(date);
}
};
}
return rfc1123Codec;
}
}

View File

@ -51,6 +51,11 @@ public class SimpleDateFormatDateService implements DateService {
// @GuardedBy("this")
private static final SimpleDateFormat rfc822SimpleDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
// See http://stackoverflow.com/questions/10584647/simpledateformat-parse-is-one-hour-out-using-rfc-1123-gmt-in-summer
// for why not using "zzz"
// @GuardedBy("this")
private static final SimpleDateFormat rfc1123SimpleDateFormat = new SimpleDateFormat("EEE, dd MMM yyyyy HH:mm:ss Z", Locale.US);
// @GuardedBy("this")
private static final SimpleDateFormat cSimpleDateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", Locale.US);
@ -180,4 +185,26 @@ public class SimpleDateFormatDateService implements DateService {
}
}
}
@Override
public final String rfc1123DateFormat(Date date) {
synchronized (rfc1123SimpleDateFormat) {
return rfc1123SimpleDateFormat.format(date);
}
}
@Override
public final String rfc1123DateFormat() {
return rfc1123DateFormat(new Date());
}
@Override
public final Date rfc1123DateParse(String toParse) {
synchronized (rfc1123SimpleDateFormat) {
try {
return rfc1123SimpleDateFormat.parse(toParse);
} catch (ParseException pe) {
throw new RuntimeException("Error parsing data at " + pe.getErrorOffset(), pe);
}
}
}
}

View File

@ -14,7 +14,7 @@ import javax.ws.rs.core.HttpHeaders;
import org.jclouds.crypto.CryptoStreams;
import org.jclouds.date.DateCodec;
import org.jclouds.date.DateCodecs;
import org.jclouds.date.DateCodecFactory;
import org.jclouds.io.ContentMetadataCodec.DefaultContentMetadataCodec;
import org.jclouds.logging.Logger;
@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMultimap.Builder;
import com.google.common.collect.Multimap;
import com.google.inject.ImplementedBy;
import com.google.inject.Inject;
@ImplementedBy(DefaultContentMetadataCodec.class)
public interface ContentMetadataCodec {
@ -53,8 +54,13 @@ public interface ContentMetadataCodec {
@Resource
protected Logger logger = Logger.NULL;
private final DateCodec httpExpiresDateCodec = DateCodecs.rfc1123();
private final DateCodec httpExpiresDateCodec;
@Inject
public DefaultContentMetadataCodec(DateCodecFactory dateCodecs) {
httpExpiresDateCodec = dateCodecs.rfc1123();
}
protected DateCodec getExpiresDateCodec() {
return httpExpiresDateCodec;
}

View File

@ -34,6 +34,8 @@ import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.date.internal.SimpleDateCodecFactory;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.BaseJettyTest;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpResponse;
@ -113,7 +115,8 @@ public class BackoffLimitedRetryHandlerTest {
ExecutorService execService = Executors.newCachedThreadPool();
BackoffLimitedRetryHandler backoff = new BackoffLimitedRetryHandler();
HttpUtils utils = new HttpUtils(0, 500, 1, 1);
ContentMetadataCodec contentMetadataCodec = new DefaultContentMetadataCodec();
ContentMetadataCodec contentMetadataCodec = new DefaultContentMetadataCodec(
new SimpleDateCodecFactory(new SimpleDateFormatDateService()));
RedirectionRetryHandler retry = new RedirectionRetryHandler(uriBuilderProvider, backoff);
JavaUrlHttpCommandExecutorService httpService = new JavaUrlHttpCommandExecutorService(utils,
contentMetadataCodec, execService,

View File

@ -49,6 +49,8 @@ import org.jclouds.apis.ApiMetadata;
import org.jclouds.concurrent.MoreExecutors;
import org.jclouds.concurrent.SingleThreaded;
import org.jclouds.concurrent.config.ConfiguresExecutorService;
import org.jclouds.date.internal.SimpleDateCodecFactory;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.http.HttpCommandExecutorService;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse;
@ -60,10 +62,10 @@ import org.jclouds.http.handlers.DelegatingRetryHandler;
import org.jclouds.http.internal.BaseHttpCommandExecutorService;
import org.jclouds.http.internal.HttpWire;
import org.jclouds.io.ContentMetadataCodec;
import org.jclouds.io.ContentMetadataCodec.DefaultContentMetadataCodec;
import org.jclouds.io.CopyInputStreamInputSupplierMap;
import org.jclouds.io.Payload;
import org.jclouds.io.Payloads;
import org.jclouds.io.ContentMetadataCodec.DefaultContentMetadataCodec;
import org.jclouds.logging.config.NullLoggingModule;
import org.jclouds.providers.ProviderMetadata;
import org.jclouds.rest.RestApiMetadata;
@ -120,7 +122,8 @@ public abstract class BaseRestClientExpectTest<S> {
protected String provider = "mock";
protected ContentMetadataCodec contentMetadataCodec = new DefaultContentMetadataCodec();
protected ContentMetadataCodec contentMetadataCodec = new DefaultContentMetadataCodec(
new SimpleDateCodecFactory(new SimpleDateFormatDateService()));
/**
* Override this to supply alternative bindings for use in the test. This is commonly used to

View File

@ -32,6 +32,8 @@ import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.crypto.Crypto;
import org.jclouds.date.internal.SimpleDateCodecFactory;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.encryption.internal.JCECrypto;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpUtils;
@ -72,7 +74,9 @@ public class ConvertToGaeRequestTest {
@BeforeTest
void setupClient() throws MalformedURLException {
endPoint = URI.create("http://localhost:80/foo");
req = new ConvertToGaeRequest(new HttpUtils(0, 0, 0, 0), new DefaultContentMetadataCodec());
req = new ConvertToGaeRequest(new HttpUtils(0, 0, 0, 0), new DefaultContentMetadataCodec(
new SimpleDateCodecFactory(new SimpleDateFormatDateService())));
}
@Test

View File

@ -34,6 +34,8 @@ import java.util.List;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.crypto.Crypto;
import org.jclouds.date.internal.SimpleDateCodecFactory;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.encryption.internal.JCECrypto;
import org.jclouds.http.HttpResponse;
import org.jclouds.io.ContentMetadataCodec.DefaultContentMetadataCodec;
@ -68,7 +70,8 @@ public class ConvertToJcloudsResponseTest {
@BeforeTest
void setupClient() throws MalformedURLException {
endPoint = URI.create("http://localhost:80/foo");
req = new ConvertToJcloudsResponse(new DefaultContentMetadataCodec());
req = new ConvertToJcloudsResponse(new DefaultContentMetadataCodec(
new SimpleDateCodecFactory(new SimpleDateFormatDateService())));
}
@Test

View File

@ -53,6 +53,9 @@ public class JodaDateService implements DateService {
private static final DateTimeFormatter iso8601DateFormatter = DateTimeFormat.forPattern(
"yyyy-MM-dd'T'HH:mm:ss.SSSZ").withLocale(Locale.US).withZone(DateTimeZone.forID("GMT"));
private static final DateTimeFormatter rfc1123DateFormat = DateTimeFormat.forPattern(
"EEE, dd MMM yyyyy HH:mm:ss Z").withLocale(Locale.US).withZone(DateTimeZone.forID("GMT"));
public final Date fromSeconds(long seconds) {
return new Date(seconds * 1000);
}
@ -124,4 +127,19 @@ public class JodaDateService implements DateService {
toParse += tz;
return iso8601SecondsDateFormatter.parseDateTime(toParse).toDate();
}
@Override
public final String rfc1123DateFormat(Date dateTime) {
return rfc1123DateFormat.print(new DateTime(dateTime));
}
@Override
public final String rfc1123DateFormat() {
return rfc1123DateFormat(new Date());
}
@Override
public final Date rfc1123DateParse(String toParse) {
return rfc1123DateFormat.parseDateTime(toParse).toDate();
}
}

View File

@ -23,27 +23,18 @@ import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.net.MalformedURLException;
import java.text.ParseException;
import java.util.Date;
import java.util.NoSuchElementException;
import java.util.Set;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.domain.Location;
import java.io.IOException;
import java.net.MalformedURLException;
import java.text.ParseException;
import java.util.Date;
import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.date.DateCodec;
import org.jclouds.date.DateCodecs;
import org.jclouds.http.HttpCommandExecutorService;
import org.jclouds.http.TransformingHttpCommandExecutorService;
import org.jclouds.http.TransformingHttpCommandExecutorServiceImpl;
import org.jclouds.http.config.SSLModule;
import org.jclouds.http.internal.JavaUrlHttpCommandExecutorService;
import org.jclouds.date.internal.SimpleDateCodecFactory;
import org.jclouds.date.internal.SimpleDateFormatDateService;
import org.jclouds.domain.Location;
import org.jclouds.io.ContentMetadataCodec;
import org.jclouds.io.ContentMetadataCodec.DefaultContentMetadataCodec;
import org.jclouds.s3.blobstore.integration.S3ContainerLiveTest;
@ -51,13 +42,10 @@ import org.jclouds.util.Strings2;
import org.testng.annotations.Test;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.inject.AbstractModule;
import com.google.inject.Module;
import com.google.inject.Scopes;
/**
* @author Adrian Cole
@ -89,12 +77,12 @@ public class AWSS3ContainerLiveTest extends S3ContainerLiveTest {
@Test(groups = { "live" })
public void testCreateBlobWithMalformedExpiry() throws InterruptedException, MalformedURLException, IOException {
// Create a blob that has a malformed Expires value; requires overriding the ContentMetadataCodec in Guice...
final ContentMetadataCodec contentMetadataCodec = new DefaultContentMetadataCodec() {
final ContentMetadataCodec contentMetadataCodec = new DefaultContentMetadataCodec(new SimpleDateCodecFactory(new SimpleDateFormatDateService())) {
@Override
protected DateCodec getExpiresDateCodec() {
return new DateCodec() {
@Override public Date toDate(String date) throws ParseException {
return DateCodecs.rfc1123().toDate(date);
return new Date();
}
@Override public String toString(Date date) {
return "wrong";