mirror of https://github.com/apache/jclouds.git
Issue 18: added Options for commands that support it
git-svn-id: http://jclouds.googlecode.com/svn/trunk@479 3d8758e0-26b5-11de-8745-db77d3ebf521
This commit is contained in:
parent
412fb3a816
commit
aeba634379
|
@ -31,6 +31,7 @@ package org.jclouds.http;
|
|||
public interface HttpConstants {
|
||||
public static final String CONTENT_LENGTH = "Content-Length";
|
||||
public static final String CONTENT_TYPE = "Content-Type";
|
||||
public static final String CONTENT_MD5 = "Content-MD5";
|
||||
public static final String HOST = "Host";
|
||||
public static final String DATE = "Date";
|
||||
public static final String BINARY = "application/octet-stream";
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.amazon.s3;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import org.jclouds.aws.PerformanceTest;
|
||||
import org.jclouds.aws.s3.DateService;
|
||||
import org.joda.time.DateTime;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.SimpleTimeZone;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletionService;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorCompletionService;
|
||||
|
||||
@Test(sequential = true, timeOut = 2 * 60 * 1000, testName = "s3.DateTest", groups = "performance")
|
||||
public class DateServiceTest extends PerformanceTest {
|
||||
Injector i = Guice.createInjector();
|
||||
|
||||
DateService utils = i.getInstance(DateService.class);
|
||||
SimpleDateFormat dateParser;
|
||||
|
||||
public DateServiceTest() {
|
||||
this.dateParser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
|
||||
this.dateParser.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
||||
}
|
||||
|
||||
Date amazonDateFromString(String toParse) throws ParseException {
|
||||
return this.dateParser.parse(toParse);
|
||||
}
|
||||
|
||||
private static String toParse = "2009-03-12T02:00:07.000Z";
|
||||
|
||||
@Test
|
||||
public void testParseDateSameAsAmazon() throws ParseException,
|
||||
ExecutionException, InterruptedException {
|
||||
Date java = dateParser.parse(toParse);
|
||||
DateTime joda = utils.dateTimeFromXMLFormat(toParse);
|
||||
assert java.equals(joda.toDate());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeStampDateSameAsAmazon() throws ExecutionException,
|
||||
InterruptedException {
|
||||
String java = AWSAuthConnection.httpDate();
|
||||
String joda = utils.timestampAsHeaderString();
|
||||
assert java.equals(joda);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToHeaderString() throws ExecutionException,
|
||||
InterruptedException {
|
||||
String joda1 = utils.toHeaderString(new DateTime());
|
||||
String joda = utils.timestampAsHeaderString();
|
||||
assert joda1.equals(joda);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTimeStampSerialResponseTime() throws ExecutionException,
|
||||
InterruptedException {
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
utils.timestampAsHeaderString();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonTimeStampSerialResponseTime() {
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
AWSAuthConnection.httpDate();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTimeStampParallelResponseTime() throws InterruptedException,
|
||||
ExecutionException {
|
||||
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(
|
||||
exec);
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
completer.submit(new Callable<Boolean>() {
|
||||
public Boolean call() throws ExecutionException,
|
||||
InterruptedException {
|
||||
utils.timestampAsHeaderString();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
assert completer.take().get();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonTimeStampParallelResponseTime() throws InterruptedException,
|
||||
ExecutionException {
|
||||
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(
|
||||
exec);
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
completer.submit(new Callable<Boolean>() {
|
||||
public Boolean call() {
|
||||
AWSAuthConnection.httpDate();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
assert completer.take().get();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParseDateSerialResponseTime() throws ExecutionException,
|
||||
InterruptedException {
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
utils.dateTimeFromXMLFormat(toParse);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonParseDateSerialResponseTime() {
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
AWSAuthConnection.httpDate();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParseDateParallelResponseTime() throws InterruptedException,
|
||||
ExecutionException {
|
||||
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(
|
||||
exec);
|
||||
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
completer.submit(new Callable<Boolean>() {
|
||||
public Boolean call() throws ExecutionException,
|
||||
InterruptedException {
|
||||
utils.dateTimeFromXMLFormat(toParse);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
assert completer.take().get();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonParseDateParallelResponseTime() throws InterruptedException,
|
||||
ExecutionException {
|
||||
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(
|
||||
exec);
|
||||
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
completer.submit(new Callable<Boolean>() {
|
||||
public Boolean call() {
|
||||
AWSAuthConnection.httpDate();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
assert completer.take().get();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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.amazon.s3;
|
||||
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
import org.jclouds.aws.PerformanceTest;
|
||||
import org.jclouds.aws.s3.DateService;
|
||||
import org.joda.time.DateTime;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.SimpleTimeZone;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CompletionService;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorCompletionService;
|
||||
|
||||
@Test(sequential = true, timeOut = 2 * 60 * 1000, testName = "s3.DateTest", groups = "performance")
|
||||
public class DateTest extends PerformanceTest {
|
||||
Injector i = Guice.createInjector();
|
||||
|
||||
DateService utils = i.getInstance(DateService.class);
|
||||
SimpleDateFormat dateParser;
|
||||
|
||||
|
||||
public DateTest() {
|
||||
this.dateParser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
|
||||
this.dateParser.setTimeZone(new SimpleTimeZone(0, "GMT"));
|
||||
}
|
||||
|
||||
Date amazonDateFromString(String toParse) throws ParseException {
|
||||
return this.dateParser.parse(toParse);
|
||||
}
|
||||
|
||||
private static String toParse = "2009-03-12T02:00:07.000Z";
|
||||
|
||||
@Test
|
||||
public void testParseDateSameAsAmazon() throws ParseException, ExecutionException, InterruptedException {
|
||||
Date java = dateParser.parse(toParse);
|
||||
DateTime joda = utils.dateTimeFromXMLFormat(toParse);
|
||||
assert java.equals(joda.toDate());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testTimeStampDateSameAsAmazon() throws ExecutionException, InterruptedException {
|
||||
String java = AWSAuthConnection.httpDate();
|
||||
String joda = utils.timestampAsHeaderString();
|
||||
assert java.equals(joda);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTimeStampSerialResponseTime() throws ExecutionException, InterruptedException {
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
utils.timestampAsHeaderString();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonTimeStampSerialResponseTime() {
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
AWSAuthConnection.httpDate();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testTimeStampParallelResponseTime() throws InterruptedException, ExecutionException {
|
||||
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(exec);
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
completer.submit(new Callable<Boolean>() {
|
||||
public Boolean call() throws ExecutionException, InterruptedException {
|
||||
utils.timestampAsHeaderString();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < LOOP_COUNT; i++) assert completer.take().get();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonTimeStampParallelResponseTime() throws InterruptedException, ExecutionException {
|
||||
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(exec);
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
completer.submit(new Callable<Boolean>() {
|
||||
public Boolean call() {
|
||||
AWSAuthConnection.httpDate();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < LOOP_COUNT; i++) assert completer.take().get();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void testParseDateSerialResponseTime() throws ExecutionException, InterruptedException {
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
utils.dateTimeFromXMLFormat(toParse);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonParseDateSerialResponseTime() {
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
AWSAuthConnection.httpDate();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testParseDateParallelResponseTime() throws InterruptedException, ExecutionException {
|
||||
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(exec);
|
||||
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
completer.submit(new Callable<Boolean>() {
|
||||
public Boolean call() throws ExecutionException, InterruptedException {
|
||||
utils.dateTimeFromXMLFormat(toParse);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < LOOP_COUNT; i++) assert completer.take().get();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAmazonParseDateParallelResponseTime() throws InterruptedException, ExecutionException {
|
||||
CompletionService<Boolean> completer = new ExecutorCompletionService<Boolean>(exec);
|
||||
|
||||
for (int i = 0; i < LOOP_COUNT; i++)
|
||||
completer.submit(new Callable<Boolean>() {
|
||||
public Boolean call() {
|
||||
AWSAuthConnection.httpDate();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (int i = 0; i < LOOP_COUNT; i++) assert completer.take().get();
|
||||
}
|
||||
|
||||
}
|
|
@ -42,7 +42,10 @@ public class DateService {
|
|||
}
|
||||
|
||||
public String timestampAsHeaderString() {
|
||||
return headerDateFormat.print(new DateTime(DateTimeZone.UTC));
|
||||
return toHeaderString(new DateTime());
|
||||
}
|
||||
|
||||
public String toHeaderString(DateTime date) {
|
||||
return headerDateFormat.print(date.withZone(DateTimeZone.UTC));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ package org.jclouds.aws.s3;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
import org.jclouds.aws.s3.commands.options.CreateBucketOptions;
|
||||
import org.jclouds.aws.s3.commands.options.PutBucketOptions;
|
||||
import org.jclouds.aws.s3.domain.S3Bucket;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
|
||||
|
@ -100,10 +100,10 @@ public interface S3Connection {
|
|||
* @param options
|
||||
* for creating your bucket
|
||||
* @return true, if the bucket was created
|
||||
* @see CreateBucketOptions
|
||||
* @see PutBucketOptions
|
||||
*/
|
||||
Future<Boolean> createBucketIfNotExists(String name,
|
||||
CreateBucketOptions options);
|
||||
PutBucketOptions options);
|
||||
|
||||
/**
|
||||
* Deletes the bucket, if it is empty.
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
package org.jclouds.aws.s3.commands;
|
||||
|
||||
import static org.jclouds.aws.s3.commands.options.GetBucketOptions.Builder.maxKeys;
|
||||
import org.jclouds.http.commands.callables.ReturnTrueIf200;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
|
@ -34,6 +35,7 @@ public class BucketExists extends S3FutureCommand<Boolean> {
|
|||
@Inject
|
||||
public BucketExists(@Named("jclouds.http.address") String amazonHost,
|
||||
ReturnTrueIf200 callable, @Assisted String s3Bucket) {
|
||||
super("HEAD", "/", callable, amazonHost, s3Bucket);
|
||||
super("HEAD", "/" + maxKeys(0).toQueryString(), callable, amazonHost,
|
||||
s3Bucket);
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@
|
|||
*/
|
||||
package org.jclouds.aws.s3.commands;
|
||||
|
||||
import org.jclouds.aws.s3.commands.options.CreateBucketOptions;
|
||||
import org.jclouds.aws.s3.commands.options.PutBucketOptions;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.aws.s3.xml.S3ParserFactory;
|
||||
|
||||
|
@ -89,10 +89,10 @@ public class S3CommandFactory {
|
|||
private PutBucketFactoryOptions putBucketFactoryOptions;
|
||||
|
||||
public static interface PutBucketFactoryOptions {
|
||||
PutBucket create(String bucket, CreateBucketOptions options);
|
||||
PutBucket create(String bucket, PutBucketOptions options);
|
||||
}
|
||||
|
||||
public PutBucket createPutBucket(String bucket, CreateBucketOptions options) {
|
||||
public PutBucket createPutBucket(String bucket, PutBucketOptions options) {
|
||||
return putBucketFactoryOptions.create(bucket, options);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,293 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 org.jclouds.aws.s3.commands.options;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.jclouds.aws.s3.DateService;
|
||||
import org.jclouds.aws.s3.S3Utils;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
* Contains options supported in the REST API for the COPY object operation.
|
||||
* <p/>
|
||||
* <h2>Usage</h2> The recommended way to instantiate a CopyObjectOptions object
|
||||
* is to statically import CopyObjectOptions.Builder.* and invoke a static
|
||||
* creation method followed by an instance mutator (if needed):
|
||||
* <p/>
|
||||
* <code>
|
||||
* import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.*
|
||||
*
|
||||
* S3Connection connection = // get connection
|
||||
*
|
||||
* Multimap<String,String> metadata = HashMultimap.create();
|
||||
* metadata.put("x-amz-meta-adrian", "foo");
|
||||
*
|
||||
* // this will copy the object, provided it wasn't modified since yesterday.
|
||||
* // it will not use metadata from the source, and instead use what we pass in.
|
||||
* Future<S3Object.MetaData> object = connection.copyObject("sourceBucket", "objectName",
|
||||
* "destinationBucket", "destinationName",
|
||||
* overrideMetadataWith(meta).
|
||||
* ifUnmodifiedSince(new DateTime().minusDays(1))
|
||||
* );
|
||||
* <code>
|
||||
*
|
||||
* Description of parameters taken from {@link http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTObjectCOPY.html}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class CopyObjectOptions {
|
||||
private final static DateService dateService = new DateService();
|
||||
|
||||
private String ifModifiedSince;
|
||||
private String ifUnmodifiedSince;
|
||||
private String ifMatch;
|
||||
private String ifNoneMatch;
|
||||
private Multimap<String, String> metadata;
|
||||
|
||||
/**
|
||||
* For use in the header x-amz-copy-source-if-unmodified-since
|
||||
* <p />
|
||||
* Copies the object if it hasn't been modified since the specified time;
|
||||
* otherwise returns a 412 (precondition failed).
|
||||
* <p />
|
||||
* This header can be used with x-amz-copy-source-if-match, but cannot be
|
||||
* used with other conditional copy headers.
|
||||
*
|
||||
* @return valid HTTP date (go to http://rfc.net/rfc2616.html#s3.3).
|
||||
* @see CopyObjectOptions#ifSourceModifiedSince(DateTime)
|
||||
*/
|
||||
public String getIfModifiedSince() {
|
||||
return ifModifiedSince;
|
||||
}
|
||||
|
||||
/**
|
||||
* For use in the header x-amz-copy-source-if-modified-since
|
||||
* <p />
|
||||
* Copies the object if it has been modified since the specified time;
|
||||
* otherwise returns a 412 (failed condition).
|
||||
* <p/>
|
||||
* This header can be used with x-amz-copy-source-if-none-match, but cannot
|
||||
* be used with other conditional copy headers.
|
||||
*
|
||||
* @return valid HTTP date (go to http://rfc.net/rfc2616.html#s3.3).
|
||||
*
|
||||
* @see CopyObjectOptions#ifSourceUnmodifiedSince(DateTime)
|
||||
*/
|
||||
public String getIfUnmodifiedSince() {
|
||||
return ifUnmodifiedSince;
|
||||
}
|
||||
|
||||
/**
|
||||
* For use in the request header: x-amz-copy-source-if-match
|
||||
* <p />
|
||||
* Copies the object if its entity tag (ETag) matches the specified tag;
|
||||
* otherwise return a 412 (precondition failed).
|
||||
* <p/>
|
||||
* This header can be used with x-amz-copy-source-if-unmodified-since, but
|
||||
* cannot be used with other conditional copy headers.
|
||||
*
|
||||
* @see CopyObjectOptions#ifSourceMd5Matches(String)
|
||||
*/
|
||||
public String getIfMatch() {
|
||||
return ifMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* For use in the request header: x-amz-copy-source-if-none-match
|
||||
* <p />
|
||||
* Copies the object if its entity tag (ETag) is different than the
|
||||
* specified Etag; otherwise returns a 412 (failed condition).
|
||||
* <p/>
|
||||
* This header can be used with x-amz-copy-source-if-modified-since, but
|
||||
* cannot be used with other conditional copy headers.
|
||||
*
|
||||
* @see CopyObjectOptions#ifSourceMd5DoesntMatch(String)
|
||||
*/
|
||||
public String getIfNoneMatch() {
|
||||
return ifNoneMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* When not null, contains the header
|
||||
* [x-amz-copy-source-if-unmodified-since] -> [REPLACE] and metadata headers
|
||||
* passed in from the users.
|
||||
*
|
||||
* @see #overrideMetadataWith(Multimap)
|
||||
*/
|
||||
public Multimap<String, String> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only return the object if it has changed since this time.
|
||||
* <p />
|
||||
* Not compatible with {@link #ifSourceMd5Matches(byte[])} or
|
||||
* {@link #ifSourceUnmodifiedSince(DateTime)}
|
||||
*/
|
||||
public CopyObjectOptions ifSourceModifiedSince(DateTime ifModifiedSince) {
|
||||
checkState(ifMatch == null,
|
||||
"ifMd5Matches() is not compatible with ifModifiedSince()");
|
||||
checkState(ifUnmodifiedSince == null,
|
||||
"ifUnmodifiedSince() is not compatible with ifModifiedSince()");
|
||||
this.ifModifiedSince = dateService.toHeaderString(checkNotNull(
|
||||
ifModifiedSince, "ifModifiedSince"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only return the object if it hasn't changed since this time.
|
||||
* <p />
|
||||
* Not compatible with {@link #ifSourceMd5DoesntMatch(byte[])} or
|
||||
* {@link #ifSourceModifiedSince(DateTime)}
|
||||
*/
|
||||
public CopyObjectOptions ifSourceUnmodifiedSince(DateTime ifUnmodifiedSince) {
|
||||
checkState(ifNoneMatch == null,
|
||||
"ifMd5DoesntMatch() is not compatible with ifUnmodifiedSince()");
|
||||
checkState(ifModifiedSince == null,
|
||||
"ifModifiedSince() is not compatible with ifUnmodifiedSince()");
|
||||
this.ifUnmodifiedSince = dateService.toHeaderString(checkNotNull(
|
||||
ifUnmodifiedSince, "ifUnmodifiedSince"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The object's md5 hash should match the parameter <code>md5</code>.
|
||||
*
|
||||
* <p />
|
||||
* Not compatible with {@link #ifSourceMd5DoesntMatch(byte[])} or
|
||||
* {@link #ifSourceModifiedSince(DateTime)}
|
||||
*
|
||||
* @param md5
|
||||
* hash representing the entity
|
||||
* @throws UnsupportedEncodingException
|
||||
* if there was a problem converting this into an S3 eTag string
|
||||
*/
|
||||
public CopyObjectOptions ifSourceMd5Matches(byte[] md5)
|
||||
throws UnsupportedEncodingException {
|
||||
checkState(ifNoneMatch == null,
|
||||
"ifMd5DoesntMatch() is not compatible with ifMd5Matches()");
|
||||
checkState(ifModifiedSince == null,
|
||||
"ifModifiedSince() is not compatible with ifMd5Matches()");
|
||||
this.ifMatch = String.format("\"%1s\"", S3Utils
|
||||
.toHexString(checkNotNull(md5, "md5")));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* The object should not have a md5 hash corresponding with the parameter
|
||||
* <code>md5</code>.
|
||||
* <p />
|
||||
* Not compatible with {@link #ifSourceMd5Matches(byte[])} or
|
||||
* {@link #ifSourceUnmodifiedSince(DateTime)}
|
||||
*
|
||||
* @param md5
|
||||
* hash representing the entity
|
||||
* @throws UnsupportedEncodingException
|
||||
* if there was a problem converting this into an S3 eTag string
|
||||
*/
|
||||
public CopyObjectOptions ifSourceMd5DoesntMatch(byte[] md5)
|
||||
throws UnsupportedEncodingException {
|
||||
checkState(ifMatch == null,
|
||||
"ifMd5Matches() is not compatible with ifMd5DoesntMatch()");
|
||||
Preconditions
|
||||
.checkState(ifUnmodifiedSince == null,
|
||||
"ifUnmodifiedSince() is not compatible with ifMd5DoesntMatch()");
|
||||
this.ifNoneMatch = String.format("\"%1s\"", S3Utils
|
||||
.toHexString(checkNotNull(md5, "ifMd5DoesntMatch")));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the provided metadata instead of what is on the source object.
|
||||
*/
|
||||
public CopyObjectOptions overrideMetadataWith(
|
||||
Multimap<String, String> metadata) {
|
||||
checkNotNull(metadata, "metadata");
|
||||
for (String header : metadata.keySet()) {
|
||||
checkArgument(header.startsWith("x-amz-meta-"),
|
||||
"Metadata keys must start with x-amz-meta-");
|
||||
}
|
||||
metadata.put("x-amz-copy-source-if-unmodified-since", "REPLACE");
|
||||
this.metadata = metadata;
|
||||
return this;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
/**
|
||||
* @see CopyObjectOptions#getIfModifiedSince()
|
||||
*/
|
||||
public static CopyObjectOptions ifSourceModifiedSince(
|
||||
DateTime ifModifiedSince) {
|
||||
CopyObjectOptions options = new CopyObjectOptions();
|
||||
return options.ifSourceModifiedSince(ifModifiedSince);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CopyObjectOptions#ifSourceUnmodifiedSince(DateTime)
|
||||
*/
|
||||
public static CopyObjectOptions ifSourceUnmodifiedSince(
|
||||
DateTime ifUnmodifiedSince) {
|
||||
CopyObjectOptions options = new CopyObjectOptions();
|
||||
return options.ifSourceUnmodifiedSince(ifUnmodifiedSince);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CopyObjectOptions#ifSourceMd5Matches(byte[])
|
||||
*/
|
||||
public static CopyObjectOptions ifSourceMd5Matches(byte[] md5)
|
||||
throws UnsupportedEncodingException {
|
||||
CopyObjectOptions options = new CopyObjectOptions();
|
||||
return options.ifSourceMd5Matches(md5);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CopyObjectOptions#ifSourceMd5DoesntMatch(byte[])
|
||||
*/
|
||||
public static CopyObjectOptions ifSourceMd5DoesntMatch(byte[] md5)
|
||||
throws UnsupportedEncodingException {
|
||||
CopyObjectOptions options = new CopyObjectOptions();
|
||||
return options.ifSourceMd5DoesntMatch(md5);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #overrideMetadataWith(Multimap)
|
||||
*/
|
||||
public static CopyObjectOptions overrideMetadataWith(
|
||||
Multimap<String, String> metadata) {
|
||||
CopyObjectOptions options = new CopyObjectOptions();
|
||||
return options.overrideMetadataWith(metadata);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 org.jclouds.aws.s3.commands.options;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
/**
|
||||
* Contains options supported in the REST API for the GET bucket operation. <h2>
|
||||
* Usage</h2> The recommended way to instantiate a GetBucketOptions object is to
|
||||
* statically import GetBucketOptions.Builder.* and invoke a static creation
|
||||
* method followed by an instance mutator (if needed):
|
||||
* <p/>
|
||||
* <code>
|
||||
* import static org.jclouds.aws.s3.commands.options.GetBucketOptions.Builder.*
|
||||
*
|
||||
* S3Connection connection = // get connection
|
||||
* Future<S3Bucket> bucket = connection.getBucket("bucketName",prefix("/home/users").maxKeys(1000));
|
||||
* <code>
|
||||
*
|
||||
* Description of parameters taken from {@link http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketGET.html}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class GetBucketOptions {
|
||||
private Map<String, String> options = new HashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Builds a query string, ex. ?marker=toast
|
||||
*
|
||||
* @return an http query string representing these options, or empty string
|
||||
* if none are present.
|
||||
*/
|
||||
public String toQueryString() {
|
||||
StringBuilder builder = new StringBuilder("");
|
||||
if (options.size() > 0) {
|
||||
builder.append("?");
|
||||
for (Iterator<Entry<String, String>> i = options.entrySet()
|
||||
.iterator(); i.hasNext();) {
|
||||
Entry<String, String> entry = i.next();
|
||||
builder.append(entry.getKey()).append("=").append(
|
||||
entry.getValue());
|
||||
if (i.hasNext())
|
||||
builder.append("&");
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Limits the response to keys which begin with the indicated prefix. You
|
||||
* can use prefixes to separate a bucket into different sets of keys in a
|
||||
* way similar to how a file system uses folders.
|
||||
*/
|
||||
public GetBucketOptions prefix(String prefix) {
|
||||
options.put("prefix", checkNotNull(prefix, "prefix"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GetBucketOptions#prefix(String)
|
||||
*/
|
||||
public String getPrefix() {
|
||||
return options.get("prefix");
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates where in the bucket to begin listing. The list will only
|
||||
* include keys that occur lexicographically after marker. This is
|
||||
* convenient for pagination: To get the next page of results use the last
|
||||
* key of the current page as the marker.
|
||||
*/
|
||||
public GetBucketOptions marker(String marker) {
|
||||
options.put("marker", checkNotNull(marker, "marker"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GetBucketOptions#marker(String)
|
||||
*/
|
||||
public String getMarker() {
|
||||
return options.get("marker");
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum number of keys you'd like to see in the response body. The
|
||||
* server might return fewer than this many keys, but will not return more.
|
||||
*/
|
||||
public GetBucketOptions maxKeys(long maxKeys) {
|
||||
checkState(maxKeys >= 0, "maxKeys must be >= 0");
|
||||
options.put("max-keys", Long.toString(maxKeys));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GetBucketOptions#maxKeys(String)
|
||||
*/
|
||||
public String getMaxKeys() {
|
||||
return options.get("max-keys");
|
||||
}
|
||||
|
||||
/**
|
||||
* Causes keys that contain the same string between the prefix and the first
|
||||
* occurrence of the delimiter to be rolled up into a single result element
|
||||
* in the CommonPrefixes collection. These rolled-up keys are not returned
|
||||
* elsewhere in the response.
|
||||
*/
|
||||
public GetBucketOptions delimiter(String delimiter) {
|
||||
options.put("delimiter", checkNotNull(delimiter, "delimiter"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GetBucketOptions#delimiter(String)
|
||||
*/
|
||||
public String getDelimiter() {
|
||||
return options.get("delimiter");
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
/**
|
||||
* @see GetBucketOptions#prefix
|
||||
*/
|
||||
public static GetBucketOptions prefix(String prefix) {
|
||||
GetBucketOptions options = new GetBucketOptions();
|
||||
return options.prefix(prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GetBucketOptions#marker
|
||||
*/
|
||||
public static GetBucketOptions marker(String marker) {
|
||||
GetBucketOptions options = new GetBucketOptions();
|
||||
return options.marker(marker);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GetBucketOptions#maxKeys
|
||||
*/
|
||||
public static GetBucketOptions maxKeys(long maxKeys) {
|
||||
GetBucketOptions options = new GetBucketOptions();
|
||||
return options.maxKeys(maxKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GetBucketOptions#delimiter
|
||||
*/
|
||||
public static GetBucketOptions delimiter(String delimiter) {
|
||||
GetBucketOptions options = new GetBucketOptions();
|
||||
return options.delimiter(delimiter);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,257 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 org.jclouds.aws.s3.commands.options;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.jclouds.aws.s3.DateService;
|
||||
import org.jclouds.aws.s3.S3Utils;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Contains options supported in the REST API for the GET object operation. <h2>
|
||||
* Usage</h2> The recommended way to instantiate a GetObjectOptions object is to
|
||||
* statically import GetObjectOptions.Builder.* and invoke a static creation
|
||||
* method followed by an instance mutator (if needed):
|
||||
* <p/>
|
||||
* <code>
|
||||
* import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.*
|
||||
*
|
||||
* S3Connection connection = // get connection
|
||||
*
|
||||
* // this will get the first megabyte of an object, provided it wasn't modified since yesterday
|
||||
* Future<S3Object> object = connection.getObject("bucket","objectName",range(0,1024).ifUnmodifiedSince(new DateTime().minusDays(1)));
|
||||
* <code>
|
||||
*
|
||||
* Description of parameters taken from {@link http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTObjectGET.html}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class GetObjectOptions {
|
||||
private final static DateService dateService = new DateService();
|
||||
|
||||
private String range;
|
||||
private String ifModifiedSince;
|
||||
private String ifUnmodifiedSince;
|
||||
private String ifMatch;
|
||||
private String ifNoneMatch;
|
||||
|
||||
/**
|
||||
* Only download the specified range of the object.
|
||||
*/
|
||||
public GetObjectOptions range(long start, long end) {
|
||||
checkState(start >= 0, "start must be >= 0");
|
||||
checkState(end >= 0, "end must be >= 0");
|
||||
this.range = String.format("bytes=%1d-%2d", start, end);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* For use in the header Range
|
||||
* <p />
|
||||
*
|
||||
* @see GetObjectOptions#range(long, long)
|
||||
*/
|
||||
public String getRange() {
|
||||
return range;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only return the object if it has changed since this time.
|
||||
* <p />
|
||||
* Not compatible with {@link #ifMd5Matches(byte[])} or
|
||||
* {@link #ifUnmodifiedSince(DateTime)}
|
||||
*/
|
||||
public GetObjectOptions ifModifiedSince(DateTime ifModifiedSince) {
|
||||
checkState(ifMatch == null,
|
||||
"ifMd5Matches() is not compatible with ifModifiedSince()");
|
||||
checkState(ifUnmodifiedSince == null,
|
||||
"ifUnmodifiedSince() is not compatible with ifModifiedSince()");
|
||||
this.ifModifiedSince = dateService.toHeaderString(checkNotNull(
|
||||
ifModifiedSince, "ifModifiedSince"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* For use in the header If-Modified-Since
|
||||
* <p />
|
||||
* Return the object only if it has been modified since the specified time,
|
||||
* otherwise return a 304 (not modified).
|
||||
*
|
||||
* @see GetObjectOptions#ifModifiedSince(DateTime)
|
||||
*/
|
||||
public String getIfModifiedSince() {
|
||||
return ifModifiedSince;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only return the object if it hasn't changed since this time.
|
||||
* <p />
|
||||
* Not compatible with {@link #ifMd5DoesntMatch(byte[])} or
|
||||
* {@link #ifModifiedSince(DateTime)}
|
||||
*/
|
||||
public GetObjectOptions ifUnmodifiedSince(DateTime ifUnmodifiedSince) {
|
||||
checkState(ifNoneMatch == null,
|
||||
"ifMd5DoesntMatch() is not compatible with ifUnmodifiedSince()");
|
||||
checkState(ifModifiedSince == null,
|
||||
"ifModifiedSince() is not compatible with ifUnmodifiedSince()");
|
||||
this.ifUnmodifiedSince = dateService.toHeaderString(checkNotNull(
|
||||
ifUnmodifiedSince, "ifUnmodifiedSince"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* For use in the header If-Unmodified-Since
|
||||
* <p />
|
||||
* Return the object only if it has not been modified since the specified
|
||||
* time, otherwise return a 412 (precondition failed).
|
||||
*
|
||||
* @see GetObjectOptions#ifUnmodifiedSince(DateTime)
|
||||
*/
|
||||
public String getIfUnmodifiedSince() {
|
||||
return ifUnmodifiedSince;
|
||||
}
|
||||
|
||||
/**
|
||||
* The object's md5 hash should match the parameter <code>md5</code>.
|
||||
*
|
||||
* <p />
|
||||
* Not compatible with {@link #ifMd5DoesntMatch(byte[])} or
|
||||
* {@link #ifModifiedSince(DateTime)}
|
||||
*
|
||||
* @param md5
|
||||
* hash representing the entity
|
||||
* @throws UnsupportedEncodingException
|
||||
* if there was a problem converting this into an S3 eTag string
|
||||
*/
|
||||
public GetObjectOptions ifMd5Matches(byte[] md5)
|
||||
throws UnsupportedEncodingException {
|
||||
checkState(ifNoneMatch == null,
|
||||
"ifMd5DoesntMatch() is not compatible with ifMd5Matches()");
|
||||
checkState(ifModifiedSince == null,
|
||||
"ifModifiedSince() is not compatible with ifMd5Matches()");
|
||||
this.ifMatch = String.format("\"%1s\"", S3Utils
|
||||
.toHexString(checkNotNull(md5, "md5")));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* For use in the request header: If-Match
|
||||
* <p />
|
||||
* Return the object only if its entity tag (ETag) is the same as the md5
|
||||
* specified, otherwise return a 412 (precondition failed).
|
||||
*
|
||||
* @see GetObjectOptions#ifMd5Matches(String)
|
||||
*/
|
||||
public String getIfMatch() {
|
||||
return ifMatch;
|
||||
}
|
||||
|
||||
/**
|
||||
* The object should not have a md5 hash corresponding with the parameter
|
||||
* <code>md5</code>.
|
||||
* <p />
|
||||
* Not compatible with {@link #ifMd5Matches(byte[])} or
|
||||
* {@link #ifUnmodifiedSince(DateTime)}
|
||||
*
|
||||
* @param md5
|
||||
* hash representing the entity
|
||||
* @throws UnsupportedEncodingException
|
||||
* if there was a problem converting this into an S3 eTag string
|
||||
*/
|
||||
public GetObjectOptions ifMd5DoesntMatch(byte[] md5)
|
||||
throws UnsupportedEncodingException {
|
||||
checkState(ifMatch == null,
|
||||
"ifMd5Matches() is not compatible with ifMd5DoesntMatch()");
|
||||
checkState(ifUnmodifiedSince == null,
|
||||
"ifUnmodifiedSince() is not compatible with ifMd5DoesntMatch()");
|
||||
this.ifNoneMatch = String.format("\"%1s\"", S3Utils
|
||||
.toHexString(checkNotNull(md5, "ifMd5DoesntMatch")));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* For use in the request header: If-None-Match
|
||||
* <p />
|
||||
* Return the object only if its entity tag (ETag) is different from the one
|
||||
* specified, otherwise return a 304 (not modified).
|
||||
*
|
||||
* @see GetObjectOptions#ifMd5DoesntMatch(String)
|
||||
*/
|
||||
public String getIfNoneMatch() {
|
||||
return ifNoneMatch;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
|
||||
/**
|
||||
* @see GetObjectOptions#range(long, long)
|
||||
*/
|
||||
public static GetObjectOptions range(long start, long end) {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
return options.range(start, end);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GetObjectOptions#getIfModifiedSince()
|
||||
*/
|
||||
public static GetObjectOptions ifModifiedSince(DateTime ifModifiedSince) {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
return options.ifModifiedSince(ifModifiedSince);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GetObjectOptions#ifUnmodifiedSince(DateTime)
|
||||
*/
|
||||
public static GetObjectOptions ifUnmodifiedSince(
|
||||
DateTime ifUnmodifiedSince) {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
return options.ifUnmodifiedSince(ifUnmodifiedSince);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GetObjectOptions#ifMd5Matches(byte[])
|
||||
*/
|
||||
public static GetObjectOptions ifMd5Matches(byte[] md5)
|
||||
throws UnsupportedEncodingException {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
return options.ifMd5Matches(md5);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see GetObjectOptions#ifMd5DoesntMatch(byte[])
|
||||
*/
|
||||
public static GetObjectOptions ifMd5DoesntMatch(byte[] md5)
|
||||
throws UnsupportedEncodingException {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
return options.ifMd5DoesntMatch(md5);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -29,11 +29,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
|
||||
/**
|
||||
* Contains options supported in the REST API for the PUT bucket operation.
|
||||
* <p/>
|
||||
* Example usage:
|
||||
* <h2>Usage</h2>
|
||||
* The recommended way to instantiate a PutBucketOptions object is to statically import PutBucketOptions.Builder.* and invoke a static creation method followed by an instance mutator (if needed):
|
||||
* <p/>
|
||||
* <code>
|
||||
* import static org.jclouds.aws.s3.commands.options.CreateBucketOptions.Builder.*
|
||||
* import static org.jclouds.aws.s3.commands.options.PutBucketOptions.Builder.*
|
||||
* import static org.jclouds.aws.s3.domain.S3Bucket.MetaData.LocationConstraint.*;
|
||||
* import org.jclouds.aws.s3.S3Connection;
|
||||
*
|
||||
|
@ -41,25 +41,38 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
|||
* Future<Boolean> createdInEu = connection.createBucketIfNotExists("bucketName",locationConstraint(EU));
|
||||
* <code>
|
||||
*
|
||||
* Description of parameters taken from {@link http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketPUT.html}
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*
|
||||
*/
|
||||
public class CreateBucketOptions {
|
||||
public class PutBucketOptions {
|
||||
private LocationConstraint constraint;
|
||||
|
||||
public CreateBucketOptions locationConstraint(LocationConstraint constraint) {
|
||||
/**
|
||||
* Depending on your latency and legal requirements, you can specify a
|
||||
* location constraint that will affect where your data physically resides.
|
||||
* You can currently specify a Europe (EU) location constraint.
|
||||
*/
|
||||
public PutBucketOptions locationConstraint(LocationConstraint constraint) {
|
||||
this.constraint = checkNotNull(constraint, "constraint");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PutBucketOptions#locationConstraint(LocationConstraint)
|
||||
*/
|
||||
public LocationConstraint getLocationConstraint() {
|
||||
return constraint;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
public static CreateBucketOptions locationConstraint(
|
||||
/**
|
||||
* @see PutBucketOptions#locationConstraint(LocationConstraint)
|
||||
*/
|
||||
public static PutBucketOptions locationConstraint(
|
||||
LocationConstraint constraint) {
|
||||
CreateBucketOptions options = new CreateBucketOptions();
|
||||
PutBucketOptions options = new PutBucketOptions();
|
||||
return options.locationConstraint(constraint);
|
||||
}
|
||||
}
|
|
@ -43,7 +43,8 @@ import com.google.inject.name.Named;
|
|||
|
||||
public class RequestAuthorizeSignature implements HttpRequestFilter {
|
||||
private static final String[] firstHeadersToSign = new String[] {
|
||||
"Content-MD5", "Content-Type", "Date" };
|
||||
HttpConstants.CONTENT_MD5, HttpConstants.CONTENT_TYPE,
|
||||
HttpConstants.DATE };
|
||||
|
||||
private final String accessKey;
|
||||
private final String secretKey;
|
||||
|
@ -110,20 +111,57 @@ public class RequestAuthorizeSignature implements HttpRequestFilter {
|
|||
|
||||
public void filter(HttpRequest request) throws HttpException {
|
||||
// re-sign the request
|
||||
request.getHeaders().removeAll(S3Constants.AUTH);
|
||||
request.getHeaders().removeAll(HttpConstants.CONTENT_TYPE);
|
||||
removeOldHeaders(request);
|
||||
|
||||
addContentTypeHeader(request);
|
||||
addDateHeader(request);
|
||||
|
||||
StringBuilder toSign = new StringBuilder();
|
||||
appendMethod(request, toSign);
|
||||
appendHttpHeaders(request, toSign);
|
||||
appendAmzHeaders(request, toSign);
|
||||
appendBucketName(request, toSign);
|
||||
appendUriPath(request, toSign);
|
||||
|
||||
addAuthHeader(request, toSign);
|
||||
}
|
||||
|
||||
private void removeOldHeaders(HttpRequest request) {
|
||||
request.getHeaders().removeAll(S3Constants.AUTH);
|
||||
request.getHeaders().removeAll(HttpConstants.CONTENT_TYPE);
|
||||
request.getHeaders().removeAll(HttpConstants.DATE);
|
||||
}
|
||||
|
||||
private void addAuthHeader(HttpRequest request, StringBuilder toSign)
|
||||
throws HttpException {
|
||||
String signature;
|
||||
try {
|
||||
signature = S3Utils.hmacSha1Base64(toSign.toString(), secretKey
|
||||
.getBytes());
|
||||
} catch (Exception e) {
|
||||
throw new HttpException("error signing request", e);
|
||||
}
|
||||
request.getHeaders().put(S3Constants.AUTH,
|
||||
"AWS " + accessKey + ":" + signature);
|
||||
}
|
||||
|
||||
private void addContentTypeHeader(HttpRequest request) {
|
||||
if (request.getContent() != null && request.getContentType() != null) {
|
||||
request.getHeaders().put(HttpConstants.CONTENT_TYPE,
|
||||
request.getContentType());
|
||||
}
|
||||
}
|
||||
|
||||
private void appendMethod(HttpRequest request, StringBuilder toSign) {
|
||||
toSign.append(request.getMethod()).append("\n");
|
||||
}
|
||||
|
||||
private void addDateHeader(HttpRequest request) {
|
||||
request.getHeaders().put(HttpConstants.DATE,
|
||||
dateService.timestampAsHeaderString());
|
||||
for (String header : firstHeadersToSign)
|
||||
toSign.append(
|
||||
valueOrEmpty(request.getHeaders().get(header))).append("\n");
|
||||
}
|
||||
|
||||
private void appendAmzHeaders(HttpRequest request, StringBuilder toSign) {
|
||||
for (String header : request.getHeaders().keySet()) {
|
||||
if (header.startsWith("x-amz-")) {
|
||||
toSign.append(header).append(":");
|
||||
|
@ -133,21 +171,28 @@ public class RequestAuthorizeSignature implements HttpRequestFilter {
|
|||
toSign.append("\n");
|
||||
}
|
||||
}
|
||||
// to do amazon headers
|
||||
}
|
||||
|
||||
private void appendHttpHeaders(HttpRequest request, StringBuilder toSign) {
|
||||
for (String header : firstHeadersToSign)
|
||||
toSign.append(valueOrEmpty(request.getHeaders().get(header)))
|
||||
.append("\n");
|
||||
}
|
||||
|
||||
private void appendBucketName(HttpRequest request, StringBuilder toSign) {
|
||||
String hostHeader = request.getHeaders().get(HttpConstants.HOST)
|
||||
.iterator().next();
|
||||
if (hostHeader.endsWith(".s3.amazonaws.com"))
|
||||
toSign.append("/").append(
|
||||
hostHeader.substring(0, hostHeader.length() - 17));
|
||||
toSign.append(request.getUri());
|
||||
String signature;
|
||||
try {
|
||||
signature = S3Utils.hmacSha1Base64(toSign.toString(), secretKey.getBytes());
|
||||
} catch (Exception e) {
|
||||
throw new HttpException("error signing request", e);
|
||||
}
|
||||
request.getHeaders().put("Authorization",
|
||||
"AWS " + accessKey + ":" + signature);
|
||||
}
|
||||
|
||||
private void appendUriPath(HttpRequest request, StringBuilder toSign) {
|
||||
int queryIndex = request.getUri().indexOf('?');
|
||||
if (queryIndex >= 0)
|
||||
toSign.append(request.getUri().substring(0, queryIndex));
|
||||
else
|
||||
toSign.append(request.getUri());
|
||||
}
|
||||
|
||||
private String valueOrEmpty(Collection<String> collection) {
|
||||
|
|
|
@ -38,7 +38,7 @@ import org.jclouds.aws.s3.commands.HeadMetaData;
|
|||
import org.jclouds.aws.s3.commands.PutBucket;
|
||||
import org.jclouds.aws.s3.commands.PutObject;
|
||||
import org.jclouds.aws.s3.commands.S3CommandFactory;
|
||||
import org.jclouds.aws.s3.commands.options.CreateBucketOptions;
|
||||
import org.jclouds.aws.s3.commands.options.PutBucketOptions;
|
||||
import org.jclouds.aws.s3.domain.S3Bucket;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.aws.s3.domain.S3Bucket.MetaData;
|
||||
|
@ -130,7 +130,7 @@ public class LiveS3Connection implements S3Connection {
|
|||
* @see PutBucket
|
||||
*/
|
||||
public Future<Boolean> createBucketIfNotExists(String s3Bucket,
|
||||
CreateBucketOptions options) {
|
||||
PutBucketOptions options) {
|
||||
PutBucket putBucket = factory.createPutBucket(s3Bucket, options);
|
||||
client.submit(putBucket);
|
||||
return putBucket;
|
||||
|
|
|
@ -141,15 +141,19 @@ public class AmazonS3Test extends S3IntegrationTest {
|
|||
TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
Boolean bucketExists() throws Exception {
|
||||
String s3Bucket = bucketPrefix + "adrianjbosstest";
|
||||
return client.bucketExists(s3Bucket).get(10, TimeUnit.SECONDS);
|
||||
@Test
|
||||
void bucketExists() throws Exception {
|
||||
String s3Bucket = bucketPrefix + "needstoexist";
|
||||
assert !client.bucketExists(s3Bucket).get(10, TimeUnit.SECONDS);
|
||||
assert client.createBucketIfNotExists(s3Bucket).get(10,
|
||||
TimeUnit.SECONDS);
|
||||
assert client.bucketExists(s3Bucket).get(10, TimeUnit.SECONDS);
|
||||
|
||||
}
|
||||
|
||||
Boolean deleteBucket() throws Exception {
|
||||
String s3Bucket = bucketPrefix + "adrianjbosstest";
|
||||
return client.deleteBucketIfEmpty(s3Bucket)
|
||||
.get(10, TimeUnit.SECONDS);
|
||||
return client.deleteBucketIfEmpty(s3Bucket).get(10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
Boolean deleteObject() throws Exception {
|
||||
|
|
|
@ -34,7 +34,7 @@ import java.util.concurrent.Future;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jclouds.aws.s3.commands.options.CreateBucketOptions;
|
||||
import org.jclouds.aws.s3.commands.options.PutBucketOptions;
|
||||
import org.jclouds.aws.s3.domain.S3Bucket;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.aws.s3.domain.S3Bucket.MetaData;
|
||||
|
@ -214,7 +214,7 @@ public class StubS3Connection implements S3Connection {
|
|||
}
|
||||
|
||||
public Future<Boolean> createBucketIfNotExists(String name,
|
||||
CreateBucketOptions options) {
|
||||
PutBucketOptions options) {
|
||||
throw new UnsupportedOperationException("todo");
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ import static org.easymock.classextension.EasyMock.createMock;
|
|||
import static org.easymock.classextension.EasyMock.replay;
|
||||
|
||||
import org.jclouds.aws.s3.commands.config.S3CommandsModule;
|
||||
import org.jclouds.aws.s3.commands.options.CreateBucketOptions;
|
||||
import org.jclouds.aws.s3.commands.options.PutBucketOptions;
|
||||
import org.jclouds.aws.s3.domain.S3Object;
|
||||
import org.jclouds.aws.s3.domain.S3Bucket.MetaData.LocationConstraint;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
|
@ -98,9 +98,8 @@ public class S3CommandFactoryTest {
|
|||
|
||||
@Test
|
||||
void testCreatePutBucketOptions() {
|
||||
assert commandFactory.createPutBucket("test",
|
||||
CreateBucketOptions.Builder
|
||||
.locationConstraint(LocationConstraint.EU)) != null;
|
||||
assert commandFactory.createPutBucket("test", PutBucketOptions.Builder
|
||||
.locationConstraint(LocationConstraint.EU)) != null;
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -0,0 +1,288 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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
|
||||
* specifSourceic language governing permissions and limitations
|
||||
* under the License.
|
||||
* ====================================================================
|
||||
*/
|
||||
package org.jclouds.aws.s3.commands.options;
|
||||
|
||||
import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceMd5DoesntMatch;
|
||||
import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceMd5Matches;
|
||||
import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceModifiedSince;
|
||||
import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.ifSourceUnmodifiedSince;
|
||||
import static org.jclouds.aws.s3.commands.options.CopyObjectOptions.Builder.overrideMetadataWith;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNull;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.jclouds.aws.s3.DateService;
|
||||
import org.jclouds.aws.s3.S3Utils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.HashMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
||||
/**
|
||||
* Tests possible uses of CopyObjectOptions and CopyObjectOptions.Builder.*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class CopyObjectOptionsTest {
|
||||
|
||||
private byte[] testBytes;
|
||||
private DateTime now;
|
||||
private String nowExpected;
|
||||
private Multimap<String, String> goodMeta;
|
||||
private Multimap<String, String> badMeta;
|
||||
|
||||
@BeforeMethod
|
||||
void setUp() {
|
||||
goodMeta = HashMultimap.create();
|
||||
goodMeta.put("x-amz-meta-adrian", "foo");
|
||||
badMeta = HashMultimap.create();
|
||||
badMeta.put("x-google-meta-adrian", "foo");
|
||||
|
||||
now = new DateTime();
|
||||
nowExpected = new DateService().toHeaderString(now);
|
||||
testBytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGoodMetaStatic() {
|
||||
CopyObjectOptions options = overrideMetadataWith(goodMeta);
|
||||
assertGoodMeta(options);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testMetaNPE() {
|
||||
overrideMetadataWith(null);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testBadMeta() {
|
||||
overrideMetadataWith(badMeta);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalArgumentException.class)
|
||||
public void testBadMetaStatic() {
|
||||
overrideMetadataWith(badMeta);
|
||||
}
|
||||
|
||||
private void assertGoodMeta(CopyObjectOptions options) {
|
||||
assert options != null;
|
||||
assert options.getMetadata() != null;
|
||||
assertEquals(options.getMetadata().size(), 2);
|
||||
assertEquals(options.getMetadata().get(
|
||||
"x-amz-copy-source-if-unmodified-since").iterator().next(),
|
||||
"REPLACE");
|
||||
assertEquals(options.getMetadata().get("x-amz-meta-adrian").iterator()
|
||||
.next(), "foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGoodMeta() {
|
||||
CopyObjectOptions options = new CopyObjectOptions();
|
||||
options.overrideMetadataWith(goodMeta);
|
||||
assertGoodMeta(options);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfModifiedSince() {
|
||||
CopyObjectOptions options = new CopyObjectOptions();
|
||||
options.ifSourceModifiedSince(now);
|
||||
assertEquals(options.getIfModifiedSince(), nowExpected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullIfModifiedSince() {
|
||||
CopyObjectOptions options = new CopyObjectOptions();
|
||||
assertNull(options.getIfModifiedSince());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfModifiedSinceStatic() {
|
||||
CopyObjectOptions options = ifSourceModifiedSince(now);
|
||||
assertEquals(options.getIfModifiedSince(), nowExpected);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testIfModifiedSinceNPE() {
|
||||
ifSourceModifiedSince(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfUnmodifiedSince() {
|
||||
CopyObjectOptions options = new CopyObjectOptions();
|
||||
options.ifSourceUnmodifiedSince(now);
|
||||
isNowExpected(options);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullIfUnmodifiedSince() {
|
||||
CopyObjectOptions options = new CopyObjectOptions();
|
||||
assertNull(options.getIfUnmodifiedSince());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfUnmodifiedSinceStatic() {
|
||||
CopyObjectOptions options = ifSourceUnmodifiedSince(now);
|
||||
isNowExpected(options);
|
||||
}
|
||||
|
||||
private void isNowExpected(CopyObjectOptions options) {
|
||||
assertEquals(options.getIfUnmodifiedSince(), nowExpected);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testIfUnmodifiedSinceNPE() {
|
||||
ifSourceUnmodifiedSince(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfMd5Matches() throws UnsupportedEncodingException {
|
||||
CopyObjectOptions options = new CopyObjectOptions();
|
||||
options.ifSourceMd5Matches(testBytes);
|
||||
matchesHex(options.getIfMatch());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullIfMd5Matches() {
|
||||
CopyObjectOptions options = new CopyObjectOptions();
|
||||
assertNull(options.getIfMatch());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfMd5MatchesStatic() throws UnsupportedEncodingException {
|
||||
CopyObjectOptions options = ifSourceMd5Matches(testBytes);
|
||||
matchesHex(options.getIfMatch());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testIfMd5MatchesNPE() throws UnsupportedEncodingException {
|
||||
ifSourceMd5Matches(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfMd5DoesntMatch() throws UnsupportedEncodingException {
|
||||
CopyObjectOptions options = new CopyObjectOptions();
|
||||
options.ifSourceMd5DoesntMatch(testBytes);
|
||||
matchesHex(options.getIfNoneMatch());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullIfMd5DoesntMatch() {
|
||||
CopyObjectOptions options = new CopyObjectOptions();
|
||||
assertNull(options.getIfNoneMatch());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfMd5DoesntMatchStatic()
|
||||
throws UnsupportedEncodingException {
|
||||
CopyObjectOptions options = ifSourceMd5DoesntMatch(testBytes);
|
||||
matchesHex(options.getIfNoneMatch());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testIfMd5DoesntMatchNPE() throws UnsupportedEncodingException {
|
||||
ifSourceMd5DoesntMatch(null);
|
||||
}
|
||||
|
||||
private void matchesHex(String match) throws UnsupportedEncodingException {
|
||||
String expected = "\"" + S3Utils.toHexString(testBytes) + "\"";
|
||||
assertEquals(match, expected);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testIfUnmodifiedAfterModified() {
|
||||
ifSourceModifiedSince(now).ifSourceUnmodifiedSince(now);
|
||||
|
||||
}
|
||||
|
||||
public void testIfUnmodifiedAfterMd5Matches()
|
||||
throws UnsupportedEncodingException {
|
||||
ifSourceMd5Matches(testBytes).ifSourceUnmodifiedSince(now);
|
||||
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testIfUnmodifiedAfterMd5DoesntMatch()
|
||||
throws UnsupportedEncodingException {
|
||||
ifSourceMd5DoesntMatch(testBytes).ifSourceUnmodifiedSince(now);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testIfModifiedAfterUnmodified() {
|
||||
ifSourceUnmodifiedSince(now).ifSourceModifiedSince(now);
|
||||
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testIfModifiedAfterMd5Matches()
|
||||
throws UnsupportedEncodingException {
|
||||
ifSourceMd5Matches(testBytes).ifSourceModifiedSince(now);
|
||||
|
||||
}
|
||||
|
||||
public void testIfModifiedAfterMd5DoesntMatch()
|
||||
throws UnsupportedEncodingException {
|
||||
ifSourceMd5DoesntMatch(testBytes).ifSourceModifiedSince(now);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testMd5MatchesAfterIfModified()
|
||||
throws UnsupportedEncodingException {
|
||||
ifSourceModifiedSince(now).ifSourceMd5Matches(testBytes);
|
||||
|
||||
}
|
||||
|
||||
public void testMd5MatchesAfterIfUnmodified()
|
||||
throws UnsupportedEncodingException {
|
||||
ifSourceUnmodifiedSince(now).ifSourceMd5Matches(testBytes);
|
||||
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testMd5MatchesAfterMd5DoesntMatch()
|
||||
throws UnsupportedEncodingException {
|
||||
ifSourceMd5DoesntMatch(testBytes).ifSourceMd5Matches(testBytes);
|
||||
}
|
||||
|
||||
public void testMd5DoesntMatchAfterIfModified()
|
||||
throws UnsupportedEncodingException {
|
||||
ifSourceModifiedSince(now).ifSourceMd5DoesntMatch(testBytes);
|
||||
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testMd5DoesntMatchAfterIfUnmodified()
|
||||
throws UnsupportedEncodingException {
|
||||
ifSourceUnmodifiedSince(now).ifSourceMd5DoesntMatch(testBytes);
|
||||
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testMd5DoesntMatchAfterMd5Matches()
|
||||
throws UnsupportedEncodingException {
|
||||
ifSourceMd5Matches(testBytes).ifSourceMd5DoesntMatch(testBytes);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 org.jclouds.aws.s3.commands.options;
|
||||
|
||||
import static org.jclouds.aws.s3.commands.options.GetBucketOptions.Builder.delimiter;
|
||||
import static org.jclouds.aws.s3.commands.options.GetBucketOptions.Builder.marker;
|
||||
import static org.jclouds.aws.s3.commands.options.GetBucketOptions.Builder.maxKeys;
|
||||
import static org.jclouds.aws.s3.commands.options.GetBucketOptions.Builder.prefix;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNull;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests possible uses of GetBucketOptions and GetBucketOptions.Builder.*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class GetBucketOptionsTest {
|
||||
|
||||
@Test
|
||||
public void testPrefix() {
|
||||
GetBucketOptions options = new GetBucketOptions();
|
||||
options.prefix("test");
|
||||
assertEquals(options.getPrefix(), "test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoOptionsQueryString() {
|
||||
GetBucketOptions options = new GetBucketOptions();
|
||||
assertEquals(options.toQueryString(), "");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneOptionQueryString() {
|
||||
GetBucketOptions options = new GetBucketOptions();
|
||||
options.prefix("test");
|
||||
assertEquals(options.toQueryString(), "?prefix=test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTwoOptionQueryString() {
|
||||
GetBucketOptions options = new GetBucketOptions();
|
||||
options.prefix("test").maxKeys(1);
|
||||
try {
|
||||
assertEquals(options.toQueryString(), "?prefix=test&max-keys=1");
|
||||
} catch (AssertionError e) {
|
||||
assertEquals(options.toQueryString(), "?max-keys=1&prefix=test");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullPrefix() {
|
||||
GetBucketOptions options = new GetBucketOptions();
|
||||
assertNull(options.getPrefix());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrefixStatic() {
|
||||
GetBucketOptions options = prefix("test");
|
||||
assertEquals(options.getPrefix(), "test");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testPrefixNPE() {
|
||||
prefix(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMarker() {
|
||||
GetBucketOptions options = new GetBucketOptions();
|
||||
options.marker("test");
|
||||
assertEquals(options.getMarker(), "test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullMarker() {
|
||||
GetBucketOptions options = new GetBucketOptions();
|
||||
assertNull(options.getMarker());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMarkerStatic() {
|
||||
GetBucketOptions options = marker("test");
|
||||
assertEquals(options.getMarker(), "test");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testMarkerNPE() {
|
||||
marker(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaxKeys() {
|
||||
GetBucketOptions options = new GetBucketOptions();
|
||||
options.maxKeys(1000);
|
||||
assertEquals(options.getMaxKeys(), "1000");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullMaxKeys() {
|
||||
GetBucketOptions options = new GetBucketOptions();
|
||||
assertNull(options.getMaxKeys());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaxKeysStatic() {
|
||||
GetBucketOptions options = maxKeys(1000);
|
||||
assertEquals(options.getMaxKeys(), "1000");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testMaxKeysNegative() {
|
||||
maxKeys(-1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelimiter() {
|
||||
GetBucketOptions options = new GetBucketOptions();
|
||||
options.delimiter("test");
|
||||
assertEquals(options.getDelimiter(), "test");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullDelimiter() {
|
||||
GetBucketOptions options = new GetBucketOptions();
|
||||
assertNull(options.getDelimiter());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelimiterStatic() {
|
||||
GetBucketOptions options = delimiter("test");
|
||||
assertEquals(options.getDelimiter(), "test");
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testDelimiterNPE() {
|
||||
delimiter(null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,286 @@
|
|||
/**
|
||||
*
|
||||
* Copyright (C) 2009 Adrian Cole <adrian@jclouds.org>
|
||||
*
|
||||
* ====================================================================
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you 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 org.jclouds.aws.s3.commands.options;
|
||||
|
||||
import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.ifMd5DoesntMatch;
|
||||
import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.ifMd5Matches;
|
||||
import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.ifModifiedSince;
|
||||
import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.ifUnmodifiedSince;
|
||||
import static org.jclouds.aws.s3.commands.options.GetObjectOptions.Builder.range;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNull;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.jclouds.aws.s3.DateService;
|
||||
import org.jclouds.aws.s3.S3Utils;
|
||||
import org.joda.time.DateTime;
|
||||
import org.testng.annotations.BeforeTest;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
/**
|
||||
* Tests possible uses of GetObjectOptions and GetObjectOptions.Builder.*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class GetObjectOptionsTest {
|
||||
|
||||
private byte[] testBytes;
|
||||
private DateTime now;
|
||||
private String nowExpected;
|
||||
|
||||
@BeforeTest
|
||||
void setUp() {
|
||||
now = new DateTime();
|
||||
nowExpected = new DateService().toHeaderString(now);
|
||||
testBytes = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7 };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfModifiedSince() {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
options.ifModifiedSince(now);
|
||||
assertEquals(options.getIfModifiedSince(), nowExpected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullIfModifiedSince() {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
assertNull(options.getIfModifiedSince());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfModifiedSinceStatic() {
|
||||
GetObjectOptions options = ifModifiedSince(now);
|
||||
assertEquals(options.getIfModifiedSince(), nowExpected);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testIfModifiedSinceNPE() {
|
||||
ifModifiedSince(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfUnmodifiedSince() {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
options.ifUnmodifiedSince(now);
|
||||
isNowExpected(options);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullIfUnmodifiedSince() {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
assertNull(options.getIfUnmodifiedSince());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfUnmodifiedSinceStatic() {
|
||||
GetObjectOptions options = ifUnmodifiedSince(now);
|
||||
isNowExpected(options);
|
||||
}
|
||||
|
||||
private void isNowExpected(GetObjectOptions options) {
|
||||
assertEquals(options.getIfUnmodifiedSince(), nowExpected);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testIfUnmodifiedSinceNPE() {
|
||||
ifUnmodifiedSince(null);
|
||||
}
|
||||
|
||||
public void testModifiedSinceAndRange() {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
options.ifModifiedSince(now);
|
||||
options.range(0, 1024);
|
||||
isNowExpected(options);
|
||||
bytes1to1024(options);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRange() {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
options.range(0, 1024);
|
||||
bytes1to1024(options);
|
||||
}
|
||||
|
||||
private void bytes1to1024(GetObjectOptions options) {
|
||||
assertEquals(options.getRange(), "bytes=0-1024");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullRange() {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
assertNull(options.getRange());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeStatic() {
|
||||
GetObjectOptions options = range(0, 1024);
|
||||
bytes1to1024(options);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testRangeNegative1() {
|
||||
range(-1, 0);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testRangeNegative2() {
|
||||
range(0, -1);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testRangeNegative() {
|
||||
range(-1, -1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfMd5Matches() throws UnsupportedEncodingException {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
options.ifMd5Matches(testBytes);
|
||||
matchesHex(options.getIfMatch());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullIfMd5Matches() {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
assertNull(options.getIfMatch());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfMd5MatchesStatic() throws UnsupportedEncodingException {
|
||||
GetObjectOptions options = ifMd5Matches(testBytes);
|
||||
matchesHex(options.getIfMatch());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testIfMd5MatchesNPE() throws UnsupportedEncodingException {
|
||||
ifMd5Matches(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfMd5DoesntMatch() throws UnsupportedEncodingException {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
options.ifMd5DoesntMatch(testBytes);
|
||||
matchesHex(options.getIfNoneMatch());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullIfMd5DoesntMatch() {
|
||||
GetObjectOptions options = new GetObjectOptions();
|
||||
assertNull(options.getIfNoneMatch());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIfMd5DoesntMatchStatic()
|
||||
throws UnsupportedEncodingException {
|
||||
GetObjectOptions options = ifMd5DoesntMatch(testBytes);
|
||||
matchesHex(options.getIfNoneMatch());
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = NullPointerException.class)
|
||||
public void testIfMd5DoesntMatchNPE() throws UnsupportedEncodingException {
|
||||
ifMd5DoesntMatch(null);
|
||||
}
|
||||
|
||||
private void matchesHex(String match) throws UnsupportedEncodingException {
|
||||
String expected = "\"" + S3Utils.toHexString(testBytes) + "\"";
|
||||
assertEquals(match, expected);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testIfUnmodifiedAfterModified() {
|
||||
ifModifiedSince(now).ifUnmodifiedSince(now);
|
||||
|
||||
}
|
||||
|
||||
public void testIfUnmodifiedAfterMd5Matches()
|
||||
throws UnsupportedEncodingException {
|
||||
ifMd5Matches(testBytes).ifUnmodifiedSince(now);
|
||||
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testIfUnmodifiedAfterMd5DoesntMatch()
|
||||
throws UnsupportedEncodingException {
|
||||
ifMd5DoesntMatch(testBytes).ifUnmodifiedSince(now);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testIfModifiedAfterUnmodified() {
|
||||
ifUnmodifiedSince(now).ifModifiedSince(now);
|
||||
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testIfModifiedAfterMd5Matches()
|
||||
throws UnsupportedEncodingException {
|
||||
ifMd5Matches(testBytes).ifModifiedSince(now);
|
||||
|
||||
}
|
||||
|
||||
public void testIfModifiedAfterMd5DoesntMatch()
|
||||
throws UnsupportedEncodingException {
|
||||
ifMd5DoesntMatch(testBytes).ifModifiedSince(now);
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testMd5MatchesAfterIfModified()
|
||||
throws UnsupportedEncodingException {
|
||||
ifModifiedSince(now).ifMd5Matches(testBytes);
|
||||
|
||||
}
|
||||
|
||||
public void testMd5MatchesAfterIfUnmodified()
|
||||
throws UnsupportedEncodingException {
|
||||
ifUnmodifiedSince(now).ifMd5Matches(testBytes);
|
||||
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testMd5MatchesAfterMd5DoesntMatch()
|
||||
throws UnsupportedEncodingException {
|
||||
ifMd5DoesntMatch(testBytes).ifMd5Matches(testBytes);
|
||||
}
|
||||
|
||||
public void testMd5DoesntMatchAfterIfModified()
|
||||
throws UnsupportedEncodingException {
|
||||
ifModifiedSince(now).ifMd5DoesntMatch(testBytes);
|
||||
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testMd5DoesntMatchAfterIfUnmodified()
|
||||
throws UnsupportedEncodingException {
|
||||
ifUnmodifiedSince(now).ifMd5DoesntMatch(testBytes);
|
||||
|
||||
}
|
||||
|
||||
@Test(expectedExceptions = IllegalStateException.class)
|
||||
public void testMd5DoesntMatchAfterMd5Matches()
|
||||
throws UnsupportedEncodingException {
|
||||
ifMd5Matches(testBytes).ifMd5DoesntMatch(testBytes);
|
||||
}
|
||||
|
||||
}
|
|
@ -23,31 +23,36 @@
|
|||
*/
|
||||
package org.jclouds.aws.s3.commands.options;
|
||||
|
||||
import static org.jclouds.aws.s3.commands.options.CreateBucketOptions.Builder.locationConstraint;
|
||||
import static org.jclouds.aws.s3.commands.options.PutBucketOptions.Builder.locationConstraint;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNull;
|
||||
|
||||
import org.jclouds.aws.s3.domain.S3Bucket.MetaData.LocationConstraint;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
public class CreateBucketOptionsTest {
|
||||
/**
|
||||
* Tests possible uses of GetBucketOptions and GetBucketOptions.Builder.*
|
||||
*
|
||||
* @author Adrian Cole
|
||||
*/
|
||||
public class PutBucketOptionsTest {
|
||||
|
||||
@Test
|
||||
public void testLocationConstraint() {
|
||||
CreateBucketOptions options = new CreateBucketOptions();
|
||||
PutBucketOptions options = new PutBucketOptions();
|
||||
options.locationConstraint(LocationConstraint.EU);
|
||||
assertEquals(options.getLocationConstraint(), LocationConstraint.EU);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullLocationConstraint() {
|
||||
CreateBucketOptions options = new CreateBucketOptions();
|
||||
PutBucketOptions options = new PutBucketOptions();
|
||||
assertNull(options.getLocationConstraint());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocationConstraintStatic() {
|
||||
CreateBucketOptions options = locationConstraint(LocationConstraint.EU);
|
||||
PutBucketOptions options = locationConstraint(LocationConstraint.EU);
|
||||
assertEquals(options.getLocationConstraint(), LocationConstraint.EU);
|
||||
}
|
||||
|
Loading…
Reference in New Issue