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 interface HttpConstants {
|
||||||
public static final String CONTENT_LENGTH = "Content-Length";
|
public static final String CONTENT_LENGTH = "Content-Length";
|
||||||
public static final String CONTENT_TYPE = "Content-Type";
|
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 HOST = "Host";
|
||||||
public static final String DATE = "Date";
|
public static final String DATE = "Date";
|
||||||
public static final String BINARY = "application/octet-stream";
|
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() {
|
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.List;
|
||||||
import java.util.concurrent.Future;
|
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.S3Bucket;
|
||||||
import org.jclouds.aws.s3.domain.S3Object;
|
import org.jclouds.aws.s3.domain.S3Object;
|
||||||
|
|
||||||
|
@ -100,10 +100,10 @@ public interface S3Connection {
|
||||||
* @param options
|
* @param options
|
||||||
* for creating your bucket
|
* for creating your bucket
|
||||||
* @return true, if the bucket was created
|
* @return true, if the bucket was created
|
||||||
* @see CreateBucketOptions
|
* @see PutBucketOptions
|
||||||
*/
|
*/
|
||||||
Future<Boolean> createBucketIfNotExists(String name,
|
Future<Boolean> createBucketIfNotExists(String name,
|
||||||
CreateBucketOptions options);
|
PutBucketOptions options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the bucket, if it is empty.
|
* Deletes the bucket, if it is empty.
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
package org.jclouds.aws.s3.commands;
|
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 org.jclouds.http.commands.callables.ReturnTrueIf200;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
@ -34,6 +35,7 @@ public class BucketExists extends S3FutureCommand<Boolean> {
|
||||||
@Inject
|
@Inject
|
||||||
public BucketExists(@Named("jclouds.http.address") String amazonHost,
|
public BucketExists(@Named("jclouds.http.address") String amazonHost,
|
||||||
ReturnTrueIf200 callable, @Assisted String s3Bucket) {
|
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;
|
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.domain.S3Object;
|
||||||
import org.jclouds.aws.s3.xml.S3ParserFactory;
|
import org.jclouds.aws.s3.xml.S3ParserFactory;
|
||||||
|
|
||||||
|
@ -89,10 +89,10 @@ public class S3CommandFactory {
|
||||||
private PutBucketFactoryOptions putBucketFactoryOptions;
|
private PutBucketFactoryOptions putBucketFactoryOptions;
|
||||||
|
|
||||||
public static interface 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);
|
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.
|
* Contains options supported in the REST API for the PUT bucket operation.
|
||||||
* <p/>
|
* <h2>Usage</h2>
|
||||||
* Example usage:
|
* 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/>
|
* <p/>
|
||||||
* <code>
|
* <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 static org.jclouds.aws.s3.domain.S3Bucket.MetaData.LocationConstraint.*;
|
||||||
* import org.jclouds.aws.s3.S3Connection;
|
* 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));
|
* Future<Boolean> createdInEu = connection.createBucketIfNotExists("bucketName",locationConstraint(EU));
|
||||||
* <code>
|
* <code>
|
||||||
*
|
*
|
||||||
|
* Description of parameters taken from {@link http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html?RESTBucketPUT.html}
|
||||||
|
*
|
||||||
* @author Adrian Cole
|
* @author Adrian Cole
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class CreateBucketOptions {
|
public class PutBucketOptions {
|
||||||
private LocationConstraint constraint;
|
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");
|
this.constraint = checkNotNull(constraint, "constraint");
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see PutBucketOptions#locationConstraint(LocationConstraint)
|
||||||
|
*/
|
||||||
public LocationConstraint getLocationConstraint() {
|
public LocationConstraint getLocationConstraint() {
|
||||||
return constraint;
|
return constraint;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder {
|
public static class Builder {
|
||||||
public static CreateBucketOptions locationConstraint(
|
/**
|
||||||
|
* @see PutBucketOptions#locationConstraint(LocationConstraint)
|
||||||
|
*/
|
||||||
|
public static PutBucketOptions locationConstraint(
|
||||||
LocationConstraint constraint) {
|
LocationConstraint constraint) {
|
||||||
CreateBucketOptions options = new CreateBucketOptions();
|
PutBucketOptions options = new PutBucketOptions();
|
||||||
return options.locationConstraint(constraint);
|
return options.locationConstraint(constraint);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -43,7 +43,8 @@ import com.google.inject.name.Named;
|
||||||
|
|
||||||
public class RequestAuthorizeSignature implements HttpRequestFilter {
|
public class RequestAuthorizeSignature implements HttpRequestFilter {
|
||||||
private static final String[] firstHeadersToSign = new String[] {
|
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 accessKey;
|
||||||
private final String secretKey;
|
private final String secretKey;
|
||||||
|
@ -110,20 +111,57 @@ public class RequestAuthorizeSignature implements HttpRequestFilter {
|
||||||
|
|
||||||
public void filter(HttpRequest request) throws HttpException {
|
public void filter(HttpRequest request) throws HttpException {
|
||||||
// re-sign the request
|
// re-sign the request
|
||||||
request.getHeaders().removeAll(S3Constants.AUTH);
|
removeOldHeaders(request);
|
||||||
request.getHeaders().removeAll(HttpConstants.CONTENT_TYPE);
|
|
||||||
|
addContentTypeHeader(request);
|
||||||
|
addDateHeader(request);
|
||||||
|
|
||||||
StringBuilder toSign = new StringBuilder();
|
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) {
|
if (request.getContent() != null && request.getContentType() != null) {
|
||||||
request.getHeaders().put(HttpConstants.CONTENT_TYPE,
|
request.getHeaders().put(HttpConstants.CONTENT_TYPE,
|
||||||
request.getContentType());
|
request.getContentType());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void appendMethod(HttpRequest request, StringBuilder toSign) {
|
||||||
toSign.append(request.getMethod()).append("\n");
|
toSign.append(request.getMethod()).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDateHeader(HttpRequest request) {
|
||||||
request.getHeaders().put(HttpConstants.DATE,
|
request.getHeaders().put(HttpConstants.DATE,
|
||||||
dateService.timestampAsHeaderString());
|
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()) {
|
for (String header : request.getHeaders().keySet()) {
|
||||||
if (header.startsWith("x-amz-")) {
|
if (header.startsWith("x-amz-")) {
|
||||||
toSign.append(header).append(":");
|
toSign.append(header).append(":");
|
||||||
|
@ -133,21 +171,28 @@ public class RequestAuthorizeSignature implements HttpRequestFilter {
|
||||||
toSign.append("\n");
|
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)
|
String hostHeader = request.getHeaders().get(HttpConstants.HOST)
|
||||||
.iterator().next();
|
.iterator().next();
|
||||||
if (hostHeader.endsWith(".s3.amazonaws.com"))
|
if (hostHeader.endsWith(".s3.amazonaws.com"))
|
||||||
toSign.append("/").append(
|
toSign.append("/").append(
|
||||||
hostHeader.substring(0, hostHeader.length() - 17));
|
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) {
|
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.PutBucket;
|
||||||
import org.jclouds.aws.s3.commands.PutObject;
|
import org.jclouds.aws.s3.commands.PutObject;
|
||||||
import org.jclouds.aws.s3.commands.S3CommandFactory;
|
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.S3Bucket;
|
||||||
import org.jclouds.aws.s3.domain.S3Object;
|
import org.jclouds.aws.s3.domain.S3Object;
|
||||||
import org.jclouds.aws.s3.domain.S3Bucket.MetaData;
|
import org.jclouds.aws.s3.domain.S3Bucket.MetaData;
|
||||||
|
@ -130,7 +130,7 @@ public class LiveS3Connection implements S3Connection {
|
||||||
* @see PutBucket
|
* @see PutBucket
|
||||||
*/
|
*/
|
||||||
public Future<Boolean> createBucketIfNotExists(String s3Bucket,
|
public Future<Boolean> createBucketIfNotExists(String s3Bucket,
|
||||||
CreateBucketOptions options) {
|
PutBucketOptions options) {
|
||||||
PutBucket putBucket = factory.createPutBucket(s3Bucket, options);
|
PutBucket putBucket = factory.createPutBucket(s3Bucket, options);
|
||||||
client.submit(putBucket);
|
client.submit(putBucket);
|
||||||
return putBucket;
|
return putBucket;
|
||||||
|
|
|
@ -141,15 +141,19 @@ public class AmazonS3Test extends S3IntegrationTest {
|
||||||
TimeUnit.SECONDS);
|
TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
Boolean bucketExists() throws Exception {
|
@Test
|
||||||
String s3Bucket = bucketPrefix + "adrianjbosstest";
|
void bucketExists() throws Exception {
|
||||||
return client.bucketExists(s3Bucket).get(10, TimeUnit.SECONDS);
|
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 {
|
Boolean deleteBucket() throws Exception {
|
||||||
String s3Bucket = bucketPrefix + "adrianjbosstest";
|
String s3Bucket = bucketPrefix + "adrianjbosstest";
|
||||||
return client.deleteBucketIfEmpty(s3Bucket)
|
return client.deleteBucketIfEmpty(s3Bucket).get(10, TimeUnit.SECONDS);
|
||||||
.get(10, TimeUnit.SECONDS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Boolean deleteObject() throws Exception {
|
Boolean deleteObject() throws Exception {
|
||||||
|
|
|
@ -34,7 +34,7 @@ import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
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.S3Bucket;
|
||||||
import org.jclouds.aws.s3.domain.S3Object;
|
import org.jclouds.aws.s3.domain.S3Object;
|
||||||
import org.jclouds.aws.s3.domain.S3Bucket.MetaData;
|
import org.jclouds.aws.s3.domain.S3Bucket.MetaData;
|
||||||
|
@ -214,7 +214,7 @@ public class StubS3Connection implements S3Connection {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Future<Boolean> createBucketIfNotExists(String name,
|
public Future<Boolean> createBucketIfNotExists(String name,
|
||||||
CreateBucketOptions options) {
|
PutBucketOptions options) {
|
||||||
throw new UnsupportedOperationException("todo");
|
throw new UnsupportedOperationException("todo");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ import static org.easymock.classextension.EasyMock.createMock;
|
||||||
import static org.easymock.classextension.EasyMock.replay;
|
import static org.easymock.classextension.EasyMock.replay;
|
||||||
|
|
||||||
import org.jclouds.aws.s3.commands.config.S3CommandsModule;
|
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.S3Object;
|
||||||
import org.jclouds.aws.s3.domain.S3Bucket.MetaData.LocationConstraint;
|
import org.jclouds.aws.s3.domain.S3Bucket.MetaData.LocationConstraint;
|
||||||
import org.testng.annotations.AfterMethod;
|
import org.testng.annotations.AfterMethod;
|
||||||
|
@ -98,8 +98,7 @@ public class S3CommandFactoryTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testCreatePutBucketOptions() {
|
void testCreatePutBucketOptions() {
|
||||||
assert commandFactory.createPutBucket("test",
|
assert commandFactory.createPutBucket("test", PutBucketOptions.Builder
|
||||||
CreateBucketOptions.Builder
|
|
||||||
.locationConstraint(LocationConstraint.EU)) != null;
|
.locationConstraint(LocationConstraint.EU)) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
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.assertEquals;
|
||||||
import static org.testng.Assert.assertNull;
|
import static org.testng.Assert.assertNull;
|
||||||
|
|
||||||
import org.jclouds.aws.s3.domain.S3Bucket.MetaData.LocationConstraint;
|
import org.jclouds.aws.s3.domain.S3Bucket.MetaData.LocationConstraint;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
public class CreateBucketOptionsTest {
|
/**
|
||||||
|
* Tests possible uses of GetBucketOptions and GetBucketOptions.Builder.*
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
public class PutBucketOptionsTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationConstraint() {
|
public void testLocationConstraint() {
|
||||||
CreateBucketOptions options = new CreateBucketOptions();
|
PutBucketOptions options = new PutBucketOptions();
|
||||||
options.locationConstraint(LocationConstraint.EU);
|
options.locationConstraint(LocationConstraint.EU);
|
||||||
assertEquals(options.getLocationConstraint(), LocationConstraint.EU);
|
assertEquals(options.getLocationConstraint(), LocationConstraint.EU);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNullLocationConstraint() {
|
public void testNullLocationConstraint() {
|
||||||
CreateBucketOptions options = new CreateBucketOptions();
|
PutBucketOptions options = new PutBucketOptions();
|
||||||
assertNull(options.getLocationConstraint());
|
assertNull(options.getLocationConstraint());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLocationConstraintStatic() {
|
public void testLocationConstraintStatic() {
|
||||||
CreateBucketOptions options = locationConstraint(LocationConstraint.EU);
|
PutBucketOptions options = locationConstraint(LocationConstraint.EU);
|
||||||
assertEquals(options.getLocationConstraint(), LocationConstraint.EU);
|
assertEquals(options.getLocationConstraint(), LocationConstraint.EU);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue