Issue 27: got eucalyptus and walrus working, after refactoring error handling

This commit is contained in:
Adrian Cole 2010-07-11 01:26:56 -07:00
parent f5f031685d
commit 41e3ec6709
74 changed files with 1018 additions and 601 deletions

View File

@ -23,8 +23,8 @@ import static org.jclouds.util.Utils.propagateOrNull;
import java.net.URI; import java.net.URI;
import org.jclouds.blobstore.KeyAlreadyExistsException; import org.jclouds.blobstore.KeyAlreadyExistsException;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -43,8 +43,10 @@ public class ReturnEndpointIfAlreadyExists implements Function<Exception, URI>,
return URI.class.cast(propagateOrNull(from)); return URI.class.cast(propagateOrNull(from));
} }
public void setContext(GeneratedHttpRequest<?> request) { @Override
public ReturnEndpointIfAlreadyExists setContext(HttpRequest request) {
this.endpoint = request == null ? null : request.getEndpoint(); this.endpoint = request == null ? null : request.getEndpoint();
return this;
} }
} }

View File

@ -22,6 +22,8 @@ import static org.jclouds.Constants.PROPERTY_API_VERSION;
import static org.jclouds.Constants.PROPERTY_ENDPOINT; import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.jclouds.aws.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS; import static org.jclouds.aws.ec2.reference.EC2Constants.PROPERTY_EC2_AMI_OWNERS;
import static org.jclouds.aws.ec2.reference.EC2Constants.PROPERTY_ELB_ENDPOINT; import static org.jclouds.aws.ec2.reference.EC2Constants.PROPERTY_ELB_ENDPOINT;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
import java.util.Properties; import java.util.Properties;
@ -36,6 +38,8 @@ public class EC2PropertiesBuilder extends PropertiesBuilder {
@Override @Override
protected Properties defaultProperties() { protected Properties defaultProperties() {
Properties properties = super.defaultProperties(); Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
properties.setProperty(PROPERTY_HEADER_TAG, "amz");
properties.setProperty(PROPERTY_ENDPOINT, "https://ec2.us-east-1.amazonaws.com"); properties.setProperty(PROPERTY_ENDPOINT, "https://ec2.us-east-1.amazonaws.com");
properties.setProperty(PROPERTY_API_VERSION, EC2AsyncClient.VERSION); properties.setProperty(PROPERTY_API_VERSION, EC2AsyncClient.VERSION);
properties.setProperty(PROPERTY_ELB_ENDPOINT, properties.setProperty(PROPERTY_ELB_ENDPOINT,

View File

@ -34,7 +34,7 @@ public class EucalyptusPropertiesBuilder extends EC2PropertiesBuilder {
protected Properties defaultProperties() { protected Properties defaultProperties() {
Properties properties = super.defaultProperties(); Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_ENDPOINT, properties.setProperty(PROPERTY_ENDPOINT,
"http://ecc.eucalyptus.com:8773/services/Eucalyptus"); "http://173.205.188.130:8773/services/Eucalyptus");
// TODO // TODO
// properties.setProperty(PROPERTY_ELB_ENDPOINT, // properties.setProperty(PROPERTY_ELB_ENDPOINT,
// "https://elasticloadbalancing.us-east-1.amazonaws.com"); // "https://elasticloadbalancing.us-east-1.amazonaws.com");

View File

@ -29,12 +29,13 @@ import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.internal.GeneratedHttpRequest;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class AttachmentHandler extends ParseSax.HandlerWithResult<Attachment> { public class AttachmentHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Attachment> {
private StringBuilder currentText = new StringBuilder(); private StringBuilder currentText = new StringBuilder();
@Resource @Resource
@ -51,7 +52,7 @@ public class AttachmentHandler extends ParseSax.HandlerWithResult<Attachment> {
private Date attachTime; private Date attachTime;
public Attachment getResult() { public Attachment getResult() {
String region = EC2Utils.findRegionInArgsOrNull(request); String region = EC2Utils.findRegionInArgsOrNull((GeneratedHttpRequest<?>) request);
if (region == null) if (region == null)
region = defaultRegion; region = defaultRegion;
return new Attachment(region, volumeId, instanceId, device, attachmentStatus, attachTime); return new Attachment(region, volumeId, instanceId, device, attachmentStatus, attachTime);

View File

@ -34,8 +34,9 @@ import org.jclouds.aws.ec2.domain.RootDeviceType;
import org.jclouds.aws.ec2.domain.RunningInstance; import org.jclouds.aws.ec2.domain.RunningInstance;
import org.jclouds.aws.ec2.util.EC2Utils; import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.http.functions.ParseSax.HandlerWithResult; import org.jclouds.http.functions.ParseSax.HandlerForGeneratedRequestWithResult;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@ -45,15 +46,14 @@ import com.google.common.collect.Sets;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public abstract class BaseReservationHandler<T> extends HandlerWithResult<T> { public abstract class BaseReservationHandler<T> extends HandlerForGeneratedRequestWithResult<T> {
protected final DateService dateService; protected final DateService dateService;
protected final String defaultRegion; protected final String defaultRegion;
@Inject @Inject
public BaseReservationHandler(DateService dateService, public BaseReservationHandler(DateService dateService, @Region String defaultRegion) {
@Region String defaultRegion) {
this.dateService = dateService; this.dateService = dateService;
this.defaultRegion = defaultRegion; this.defaultRegion = defaultRegion;
} }
@ -90,8 +90,7 @@ public abstract class BaseReservationHandler<T> extends HandlerWithResult<T> {
protected boolean inProductCodes; protected boolean inProductCodes;
protected boolean inGroups; protected boolean inGroups;
private boolean inBlockDeviceMapping; private boolean inBlockDeviceMapping;
private Map<String, RunningInstance.EbsBlockDevice> ebsBlockDevices = Maps private Map<String, RunningInstance.EbsBlockDevice> ebsBlockDevices = Maps.newHashMap();
.newHashMap();
private String volumeId; private String volumeId;
private Attachment.Status attachmentStatus; private Attachment.Status attachmentStatus;
@ -101,8 +100,7 @@ public abstract class BaseReservationHandler<T> extends HandlerWithResult<T> {
private String deviceName; private String deviceName;
private String rootDeviceName; private String rootDeviceName;
public void startElement(String uri, String name, String qName, public void startElement(String uri, String name, String qName, Attributes attrs) {
Attributes attrs) {
if (qName.equals("instancesSet")) { if (qName.equals("instancesSet")) {
inInstances = true; inInstances = true;
} else if (qName.equals("productCodesSet")) { } else if (qName.equals("productCodesSet")) {
@ -194,14 +192,11 @@ public abstract class BaseReservationHandler<T> extends HandlerWithResult<T> {
} else if (qName.equals("volumeId")) { } else if (qName.equals("volumeId")) {
volumeId = currentOrNull(); volumeId = currentOrNull();
} else if (qName.equals("status")) { } else if (qName.equals("status")) {
attachmentStatus = Attachment.Status.fromValue(currentText.toString() attachmentStatus = Attachment.Status.fromValue(currentText.toString().trim());
.trim());
} else if (qName.equals("attachTime")) { } else if (qName.equals("attachTime")) {
attachTime = dateService.iso8601DateParse(currentText.toString() attachTime = dateService.iso8601DateParse(currentText.toString().trim());
.trim());
} else if (qName.equals("deleteOnTermination")) { } else if (qName.equals("deleteOnTermination")) {
deleteOnTermination = Boolean.parseBoolean(currentText.toString() deleteOnTermination = Boolean.parseBoolean(currentText.toString().trim());
.trim());
} else if (qName.equals("rootDeviceName")) { } else if (qName.equals("rootDeviceName")) {
rootDeviceName = currentOrNull(); rootDeviceName = currentOrNull();
} else if (qName.equals("item")) { } else if (qName.equals("item")) {
@ -212,36 +207,34 @@ public abstract class BaseReservationHandler<T> extends HandlerWithResult<T> {
protected void inItem() { protected void inItem() {
if (inBlockDeviceMapping) { if (inBlockDeviceMapping) {
ebsBlockDevices.put(deviceName, new RunningInstance.EbsBlockDevice( ebsBlockDevices.put(deviceName, new RunningInstance.EbsBlockDevice(volumeId,
volumeId, attachmentStatus, attachTime, deleteOnTermination)); attachmentStatus, attachTime, deleteOnTermination));
this.deviceName = null; this.deviceName = null;
this.volumeId = null; this.volumeId = null;
this.attachmentStatus = null; this.attachmentStatus = null;
this.attachTime = null; this.attachTime = null;
this.deleteOnTermination = true; this.deleteOnTermination = true;
} else if (inInstances && !inProductCodes && !inBlockDeviceMapping) { } else if (inInstances && !inProductCodes && !inBlockDeviceMapping) {
String region = EC2Utils.findRegionInArgsOrNull(request); String region = EC2Utils.findRegionInArgsOrNull((GeneratedHttpRequest<?>) request);
// Eucalyptus // Eucalyptus
if (ipAddress == null && dnsName != null if (ipAddress == null && dnsName != null && dnsName.matches(".*[0-9]$")) {
&& dnsName.matches(".*[0-9]$")) {
ipAddress = dnsName; ipAddress = dnsName;
dnsName = null; dnsName = null;
} }
if (privateIpAddress == null && privateDnsName != null if (privateIpAddress == null && privateDnsName != null
&& privateDnsName.matches(".*[0-9]$")) { && privateDnsName.matches(".*[0-9]$")) {
privateIpAddress = privateDnsName; privateIpAddress = privateDnsName;
privateDnsName = null; privateDnsName = null;
} }
if (region == null) if (region == null)
region = defaultRegion; region = defaultRegion;
instances.add(new RunningInstance(region, groupIds, amiLaunchIndex, instances.add(new RunningInstance(region, groupIds, amiLaunchIndex, dnsName, imageId,
dnsName, imageId, instanceId, instanceState, instanceType, instanceId, instanceState, instanceType, ipAddress, kernelId, keyName,
ipAddress, kernelId, keyName, launchTime, monitoring, launchTime, monitoring, availabilityZone, platform, privateDnsName,
availabilityZone, platform, privateDnsName, privateIpAddress, privateIpAddress, productCodes, ramdiskId, reason, subnetId, vpcId,
productCodes, ramdiskId, reason, subnetId, vpcId, rootDeviceType, rootDeviceName, ebsBlockDevices));
rootDeviceType, rootDeviceName, ebsBlockDevices));
this.amiLaunchIndex = null; this.amiLaunchIndex = null;
this.dnsName = null; this.dnsName = null;
this.imageId = null; this.imageId = null;
@ -273,11 +266,11 @@ public abstract class BaseReservationHandler<T> extends HandlerWithResult<T> {
} }
protected Reservation newReservation() { protected Reservation newReservation() {
String region = EC2Utils.findRegionInArgsOrNull(request); String region = EC2Utils.findRegionInArgsOrNull((GeneratedHttpRequest<?>) request);
if (region == null) if (region == null)
region = defaultRegion; region = defaultRegion;
Reservation info = new Reservation(region, groupIds, instances, ownerId, Reservation info = new Reservation(region, groupIds, instances, ownerId, requesterId,
requesterId, reservationId); reservationId);
this.groupIds = Sets.newTreeSet(); this.groupIds = Sets.newTreeSet();
this.instances = Sets.newTreeSet(); this.instances = Sets.newTreeSet();
this.ownerId = null; this.ownerId = null;

View File

@ -32,6 +32,7 @@ import org.jclouds.aws.ec2.domain.Attachment;
import org.jclouds.aws.ec2.domain.Volume; import org.jclouds.aws.ec2.domain.Volume;
import org.jclouds.aws.ec2.util.EC2Utils; import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
@ -43,7 +44,8 @@ import com.google.common.collect.Sets;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class CreateVolumeResponseHandler extends ParseSax.HandlerWithResult<Volume> { public class CreateVolumeResponseHandler extends
ParseSax.HandlerForGeneratedRequestWithResult<Volume> {
private StringBuilder currentText = new StringBuilder(); private StringBuilder currentText = new StringBuilder();
@Resource @Resource
@ -154,11 +156,11 @@ public class CreateVolumeResponseHandler extends ParseSax.HandlerWithResult<Volu
} }
@Override @Override
public void setContext(GeneratedHttpRequest<?> request) { public CreateVolumeResponseHandler setContext(HttpRequest request) {
super.setContext(request); super.setContext(request);
region = EC2Utils.findRegionInArgsOrNull(request); region = EC2Utils.findRegionInArgsOrNull((GeneratedHttpRequest<?>) request);
if (region == null) { if (region == null) {
String zone = EC2Utils.findAvailabilityZoneInArgsOrNull(request); String zone = EC2Utils.findAvailabilityZoneInArgsOrNull((GeneratedHttpRequest<?>) request);
if (zone != null) { if (zone != null) {
region = checkNotNull(availabilityZoneToRegion.get(zone), String.format( region = checkNotNull(availabilityZoneToRegion.get(zone), String.format(
"zone %s not in %s", zone, availabilityZoneToRegion)); "zone %s not in %s", zone, availabilityZoneToRegion));
@ -166,5 +168,6 @@ public class CreateVolumeResponseHandler extends ParseSax.HandlerWithResult<Volu
region = defaultRegion; region = defaultRegion;
} }
} }
return this;
} }
} }

View File

@ -26,8 +26,9 @@ import javax.inject.Inject;
import org.jclouds.aws.Region; import org.jclouds.aws.Region;
import org.jclouds.aws.ec2.domain.PublicIpInstanceIdPair; import org.jclouds.aws.ec2.domain.PublicIpInstanceIdPair;
import org.jclouds.aws.ec2.util.EC2Utils; import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.http.functions.ParseSax.HandlerWithResult; import org.jclouds.http.functions.ParseSax.HandlerForGeneratedRequestWithResult;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
@ -36,7 +37,7 @@ import com.google.common.collect.Sets;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class DescribeAddressesResponseHandler extends public class DescribeAddressesResponseHandler extends
HandlerWithResult<Set<PublicIpInstanceIdPair>> { HandlerForGeneratedRequestWithResult<Set<PublicIpInstanceIdPair>> {
@Resource @Resource
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
@ -59,7 +60,7 @@ public class DescribeAddressesResponseHandler extends
} else if (qName.equals("instanceId")) { } else if (qName.equals("instanceId")) {
instanceId = currentOrNull(); instanceId = currentOrNull();
} else if (qName.equals("item")) { } else if (qName.equals("item")) {
String region = EC2Utils.findRegionInArgsOrNull(request); String region = EC2Utils.findRegionInArgsOrNull((GeneratedHttpRequest<?>) request);
if (region == null) if (region == null)
region = defaultRegion; region = defaultRegion;
pairs.add(new PublicIpInstanceIdPair(region, ipAddress, instanceId)); pairs.add(new PublicIpInstanceIdPair(region, ipAddress, instanceId));

View File

@ -34,6 +34,7 @@ import org.jclouds.aws.ec2.domain.Image.ImageType;
import org.jclouds.aws.ec2.util.EC2Utils; import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@ -48,7 +49,8 @@ import com.google.common.collect.Sets;
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeImages.html" * @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-query-DescribeImages.html"
* /> * />
*/ */
public class DescribeImagesResponseHandler extends ParseSax.HandlerWithResult<Set<Image>> { public class DescribeImagesResponseHandler extends
ParseSax.HandlerForGeneratedRequestWithResult<Set<Image>> {
@Inject @Inject
public DescribeImagesResponseHandler(@Region String defaultRegion) { public DescribeImagesResponseHandler(@Region String defaultRegion) {
@ -151,7 +153,7 @@ public class DescribeImagesResponseHandler extends ParseSax.HandlerWithResult<Se
this.deleteOnTermination = true; this.deleteOnTermination = true;
} else if (!inProductCodes) { } else if (!inProductCodes) {
try { try {
String region = EC2Utils.findRegionInArgsOrNull(request); String region = EC2Utils.findRegionInArgsOrNull((GeneratedHttpRequest<?>) request);
if (region == null) if (region == null)
region = defaultRegion; region = defaultRegion;
contents.add(new Image(region, architecture, this.name, description, imageId, contents.add(new Image(region, architecture, this.name, description, imageId,

View File

@ -26,6 +26,7 @@ import org.jclouds.aws.Region;
import org.jclouds.aws.ec2.domain.KeyPair; import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.aws.ec2.util.EC2Utils; import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
@ -36,7 +37,8 @@ import com.google.common.collect.Sets;
* /> * />
* @author Adrian Cole * @author Adrian Cole
*/ */
public class DescribeKeyPairsResponseHandler extends ParseSax.HandlerWithResult<Set<KeyPair>> { public class DescribeKeyPairsResponseHandler extends
ParseSax.HandlerForGeneratedRequestWithResult<Set<KeyPair>> {
@Inject @Inject
@Region @Region
String defaultRegion; String defaultRegion;
@ -55,7 +57,7 @@ public class DescribeKeyPairsResponseHandler extends ParseSax.HandlerWithResult<
if (qName.equals("keyFingerprint")) { if (qName.equals("keyFingerprint")) {
this.keyFingerprint = currentText.toString().trim(); this.keyFingerprint = currentText.toString().trim();
} else if (qName.equals("item")) { } else if (qName.equals("item")) {
String region = EC2Utils.findRegionInArgsOrNull(request); String region = EC2Utils.findRegionInArgsOrNull((GeneratedHttpRequest<?>) request);
if (region == null) if (region == null)
region = defaultRegion; region = defaultRegion;
keyPairs.add(new KeyPair(region, keyName, keyFingerprint, null)); keyPairs.add(new KeyPair(region, keyName, keyFingerprint, null));

View File

@ -29,6 +29,7 @@ import org.jclouds.aws.ec2.domain.SecurityGroup;
import org.jclouds.aws.ec2.domain.UserIdGroupPair; import org.jclouds.aws.ec2.domain.UserIdGroupPair;
import org.jclouds.aws.ec2.util.EC2Utils; import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
@ -41,7 +42,7 @@ import com.google.common.collect.Sets;
* @author Adrian Cole * @author Adrian Cole
*/ */
public class DescribeSecurityGroupsResponseHandler extends public class DescribeSecurityGroupsResponseHandler extends
ParseSax.HandlerWithResult<SortedSet<SecurityGroup>> { ParseSax.HandlerForGeneratedRequestWithResult<SortedSet<SecurityGroup>> {
@Inject @Inject
@Region @Region
String defaultRegion; String defaultRegion;
@ -117,7 +118,7 @@ public class DescribeSecurityGroupsResponseHandler extends
this.userId = null; this.userId = null;
this.userIdGroupName = null; this.userIdGroupName = null;
} else if (!inIpPermissions && !inIpRanges && !inGroups) { } else if (!inIpPermissions && !inIpRanges && !inGroups) {
String region = EC2Utils.findRegionInArgsOrNull(request); String region = EC2Utils.findRegionInArgsOrNull((GeneratedHttpRequest<?>) request);
if (region == null) if (region == null)
region = defaultRegion; region = defaultRegion;
securtyGroups.add(new SecurityGroup(region, groupName, ownerId, groupDescription, securtyGroups.add(new SecurityGroup(region, groupName, ownerId, groupDescription,

View File

@ -23,8 +23,8 @@ import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
import org.jclouds.aws.ec2.domain.Snapshot; import org.jclouds.aws.ec2.domain.Snapshot;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
@ -66,8 +66,9 @@ public class DescribeSnapshotsResponseHandler extends ParseSax.HandlerWithResult
} }
@Override @Override
public void setContext(GeneratedHttpRequest<?> request) { public DescribeSnapshotsResponseHandler setContext(HttpRequest request) {
snapshotHandler.setContext(request); snapshotHandler.setContext(request);
super.setContext(request); super.setContext(request);
return this;
} }
} }

View File

@ -23,8 +23,8 @@ import java.util.Set;
import javax.inject.Inject; import javax.inject.Inject;
import org.jclouds.aws.ec2.domain.Volume; import org.jclouds.aws.ec2.domain.Volume;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
@ -73,8 +73,9 @@ public class DescribeVolumesResponseHandler extends ParseSax.HandlerWithResult<S
} }
@Override @Override
public void setContext(GeneratedHttpRequest<?> request) { public DescribeVolumesResponseHandler setContext(HttpRequest request) {
volumeHandler.setContext(request); volumeHandler.setContext(request);
super.setContext(request); super.setContext(request);
return this;
} }
} }

View File

@ -26,7 +26,8 @@ import org.jclouds.aws.Region;
import org.jclouds.aws.ec2.domain.InstanceState; import org.jclouds.aws.ec2.domain.InstanceState;
import org.jclouds.aws.ec2.domain.InstanceStateChange; import org.jclouds.aws.ec2.domain.InstanceStateChange;
import org.jclouds.aws.ec2.util.EC2Utils; import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.http.functions.ParseSax.HandlerWithResult; import org.jclouds.http.functions.ParseSax.HandlerForGeneratedRequestWithResult;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
@ -46,7 +47,8 @@ import com.google.common.collect.Sets;
* @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-StopInstancesResponseInfoType.html" * @see <a href="http://docs.amazonwebservices.com/AWSEC2/latest/APIReference/ApiReference-ItemType-StopInstancesResponseInfoType.html"
* /> * />
*/ */
public class InstanceStateChangeHandler extends HandlerWithResult<SortedSet<InstanceStateChange>> { public class InstanceStateChangeHandler extends
HandlerForGeneratedRequestWithResult<SortedSet<InstanceStateChange>> {
private StringBuilder currentText = new StringBuilder(); private StringBuilder currentText = new StringBuilder();
@Inject @Inject
@Region @Region
@ -89,7 +91,7 @@ public class InstanceStateChangeHandler extends HandlerWithResult<SortedSet<Inst
previousState = InstanceState.fromValue(currentOrNull()); previousState = InstanceState.fromValue(currentOrNull());
} }
} else if (qName.equals("item")) { } else if (qName.equals("item")) {
String region = EC2Utils.findRegionInArgsOrNull(request); String region = EC2Utils.findRegionInArgsOrNull((GeneratedHttpRequest<?>) request);
if (region == null) if (region == null)
region = defaultRegion; region = defaultRegion;
instances.add(new InstanceStateChange(region, instanceId, shutdownState, previousState)); instances.add(new InstanceStateChange(region, instanceId, shutdownState, previousState));

View File

@ -24,6 +24,7 @@ import org.jclouds.aws.Region;
import org.jclouds.aws.ec2.domain.KeyPair; import org.jclouds.aws.ec2.domain.KeyPair;
import org.jclouds.aws.ec2.util.EC2Utils; import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
/** /**
* *
@ -32,7 +33,7 @@ import org.jclouds.http.functions.ParseSax;
* /> * />
* @author Adrian Cole * @author Adrian Cole
*/ */
public class KeyPairResponseHandler extends ParseSax.HandlerWithResult<KeyPair> { public class KeyPairResponseHandler extends ParseSax.HandlerForGeneratedRequestWithResult<KeyPair> {
@Inject @Inject
@Region @Region
String defaultRegion; String defaultRegion;
@ -42,7 +43,7 @@ public class KeyPairResponseHandler extends ParseSax.HandlerWithResult<KeyPair>
private String keyName; private String keyName;
public KeyPair getResult() { public KeyPair getResult() {
String region = EC2Utils.findRegionInArgsOrNull(request); String region = EC2Utils.findRegionInArgsOrNull((GeneratedHttpRequest<?>) request);
if (region == null) if (region == null)
region = defaultRegion; region = defaultRegion;
return new KeyPair(region, keyName, keyFingerprint, keyMaterial); return new KeyPair(region, keyName, keyFingerprint, keyMaterial);

View File

@ -28,12 +28,13 @@ import org.jclouds.aws.ec2.domain.Snapshot.Status;
import org.jclouds.aws.ec2.util.EC2Utils; import org.jclouds.aws.ec2.util.EC2Utils;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.rest.internal.GeneratedHttpRequest;
/** /**
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class SnapshotHandler extends ParseSax.HandlerWithResult<Snapshot> { public class SnapshotHandler extends ParseSax.HandlerForGeneratedRequestWithResult<Snapshot> {
private StringBuilder currentText = new StringBuilder(); private StringBuilder currentText = new StringBuilder();
protected final DateService dateService; protected final DateService dateService;
@ -56,7 +57,7 @@ public class SnapshotHandler extends ParseSax.HandlerWithResult<Snapshot> {
} }
public Snapshot getResult() { public Snapshot getResult() {
String region = EC2Utils.findRegionInArgsOrNull(request); String region = EC2Utils.findRegionInArgsOrNull((GeneratedHttpRequest<?>) request);
if (region == null) if (region == null)
region = defaultRegion; region = defaultRegion;
Snapshot snapshot = new Snapshot(region, id, volumeId, volumeSize, status, startTime, Snapshot snapshot = new Snapshot(region, id, volumeId, volumeSize, status, startTime,

View File

@ -20,6 +20,8 @@ package org.jclouds.aws.elb;
import static org.jclouds.Constants.PROPERTY_API_VERSION; import static org.jclouds.Constants.PROPERTY_API_VERSION;
import static org.jclouds.Constants.PROPERTY_ENDPOINT; import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_REGIONS; import static org.jclouds.aws.reference.AWSConstants.PROPERTY_REGIONS;
import java.util.Properties; import java.util.Properties;
@ -38,6 +40,8 @@ public class ELBPropertiesBuilder extends PropertiesBuilder {
@Override @Override
protected Properties defaultProperties() { protected Properties defaultProperties() {
Properties properties = super.defaultProperties(); Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
properties.setProperty(PROPERTY_HEADER_TAG, "amz");
properties.setProperty(PROPERTY_API_VERSION, ELBAsyncClient.VERSION); properties.setProperty(PROPERTY_API_VERSION, ELBAsyncClient.VERSION);
properties.setProperty(PROPERTY_REGIONS, Joiner.on(',').join(Region.US_EAST_1, properties.setProperty(PROPERTY_REGIONS, Joiner.on(',').join(Region.US_EAST_1,
Region.US_WEST_1, Region.EU_WEST_1, Region.AP_SOUTHEAST_1)); Region.US_WEST_1, Region.EU_WEST_1, Region.AP_SOUTHEAST_1));

View File

@ -30,6 +30,7 @@ import org.jclouds.aws.elb.domain.LoadBalancer.AppCookieStickinessPolicy;
import org.jclouds.aws.elb.domain.LoadBalancer.LBCookieStickinessPolicy; import org.jclouds.aws.elb.domain.LoadBalancer.LBCookieStickinessPolicy;
import org.jclouds.aws.elb.domain.LoadBalancer.LoadBalancerListener; import org.jclouds.aws.elb.domain.LoadBalancer.LoadBalancerListener;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
@ -42,7 +43,7 @@ import com.google.common.collect.Sets;
* @author Lili Nadar * @author Lili Nadar
*/ */
public class DescribeLoadBalancersResponseHandler extends public class DescribeLoadBalancersResponseHandler extends
ParseSax.HandlerWithResult<Set<LoadBalancer>> { ParseSax.HandlerForGeneratedRequestWithResult<Set<LoadBalancer>> {
@Inject @Inject
public DescribeLoadBalancersResponseHandler(@Region String defaultRegion) { public DescribeLoadBalancersResponseHandler(@Region String defaultRegion) {
this.defaultRegion = defaultRegion; this.defaultRegion = defaultRegion;
@ -129,7 +130,7 @@ public class DescribeLoadBalancersResponseHandler extends
} else if (!(inListenerDescriptions || inAppCookieStickinessPolicies || inInstances } else if (!(inListenerDescriptions || inAppCookieStickinessPolicies || inInstances
|| inLBCookieStickinessPolicies || inAvailabilityZones)) { || inLBCookieStickinessPolicies || inAvailabilityZones)) {
try { try {
String region = EC2Utils.findRegionInArgsOrNull(request); String region = EC2Utils.findRegionInArgsOrNull((GeneratedHttpRequest<?>) request);
if (region == null) if (region == null)
region = defaultRegion; region = defaultRegion;
@ -158,9 +159,10 @@ public class DescribeLoadBalancersResponseHandler extends
} }
@Override @Override
public void setContext(GeneratedHttpRequest<?> request) { public DescribeLoadBalancersResponseHandler setContext(HttpRequest request) {
listenerHandler.setContext(request); listenerHandler.setContext(request);
super.setContext(request); super.setContext(request);
return this;
} }
public class LoadBalancerListenerHandler extends public class LoadBalancerListenerHandler extends

View File

@ -18,6 +18,8 @@
*/ */
package org.jclouds.aws.handlers; package org.jclouds.aws.handlers;
import static org.jclouds.http.HttpUtils.closeClientButKeepContentStream;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Named; import javax.inject.Named;
@ -25,10 +27,8 @@ import org.jclouds.Constants;
import org.jclouds.aws.domain.AWSError; import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.util.AWSUtils; import org.jclouds.aws.util.AWSUtils;
import org.jclouds.http.HttpCommand; import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpRetryHandler; import org.jclouds.http.HttpRetryHandler;
import org.jclouds.http.HttpUtils;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import com.google.inject.Inject; import com.google.inject.Inject;
@ -59,20 +59,16 @@ public class AWSClientErrorRetryHandler implements HttpRetryHandler {
return false; return false;
if (response.getStatusCode() == 400 || response.getStatusCode() == 403 if (response.getStatusCode() == 400 || response.getStatusCode() == 403
|| response.getStatusCode() == 409) { || response.getStatusCode() == 409) {
byte[] content = HttpUtils.closeClientButKeepContentStream(response);
command.incrementFailureCount(); command.incrementFailureCount();
// Content can be null in the case of HEAD requests // Content can be null in the case of HEAD requests
if (content != null) { if (response.getPayload() != null) {
try { closeClientButKeepContentStream(response);
AWSError error = utils.parseAWSErrorFromContent(command.getRequest(), response, AWSError error = utils.parseAWSErrorFromContent(command.getRequest(), response);
new String(content)); if (error != null
if ("RequestTimeout".equals(error.getCode()) && ("RequestTimeout".equals(error.getCode())
|| "OperationAborted".equals(error.getCode()) || "OperationAborted".equals(error.getCode()) || "SignatureDoesNotMatch"
|| "SignatureDoesNotMatch".equals(error.getCode())) { .equals(error.getCode()))) {
return true; return true;
}
} catch (HttpException e) {
logger.warn(e, "error parsing response: %s", new String(content));
} }
} }
} }

View File

@ -32,7 +32,6 @@ import javax.ws.rs.core.UriBuilder;
import org.jclouds.aws.domain.AWSError; import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.util.AWSUtils; import org.jclouds.aws.util.AWSUtils;
import org.jclouds.http.HttpCommand; import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.http.handlers.BackoffLimitedRetryHandler; import org.jclouds.http.handlers.BackoffLimitedRetryHandler;
import org.jclouds.http.handlers.RedirectionRetryHandler; import org.jclouds.http.handlers.RedirectionRetryHandler;
@ -57,33 +56,26 @@ public class AWSRedirectionRetryHandler extends RedirectionRetryHandler {
public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) { public boolean shouldRetryRequest(HttpCommand command, HttpResponse response) {
if (response.getFirstHeaderOrNull(HttpHeaders.LOCATION) == null if (response.getFirstHeaderOrNull(HttpHeaders.LOCATION) == null
&& (response.getStatusCode() == 301 || response.getStatusCode() == 307)) { && (response.getStatusCode() == 301 || response.getStatusCode() == 307)) {
byte[] content = closeClientButKeepContentStream(response);
if (command.getRequest().getMethod() == HttpMethod.HEAD) { if (command.getRequest().getMethod() == HttpMethod.HEAD) {
changeToGETRequest(command.getRequest()); changeToGETRequest(command.getRequest());
return true; return true;
} else { } else {
command.incrementRedirectCount(); command.incrementRedirectCount();
try { closeClientButKeepContentStream(response);
AWSError error = utils.parseAWSErrorFromContent(command.getRequest(), response, AWSError error = utils.parseAWSErrorFromContent(command.getRequest(), response);
new String(content)); String host = error.getDetails().get("Endpoint");
String host = error.getDetails().get("Endpoint"); if (host != null) {
if (host != null) { if (host.equals(command.getRequest().getEndpoint().getHost())) {
if (host.equals(command.getRequest().getEndpoint().getHost())) { // must be an amazon error related to
// must be an amazon error related to // http://developer.amazonwebservices.com/connect/thread.jspa?messageID=72287&#72287
// http://developer.amazonwebservices.com/connect/thread.jspa?messageID=72287&#72287 return backoffHandler.shouldRetryRequest(command, response);
return backoffHandler.shouldRetryRequest(command, response);
} else {
changeSchemeHostAndPortTo(command.getRequest(), command.getRequest()
.getEndpoint().getScheme(), host, command.getRequest().getEndpoint()
.getPort(), uriBuilderProvider.get());
}
return true;
} else { } else {
return false; changeSchemeHostAndPortTo(command.getRequest(), command.getRequest()
.getEndpoint().getScheme(), host, command.getRequest().getEndpoint()
.getPort(), uriBuilderProvider.get());
} }
} catch (HttpException e) { return true;
logger.error(e, "error on redirect for command %s; response %s; retrying...", } else {
command, response);
return false; return false;
} }
} }

View File

@ -20,8 +20,6 @@ package org.jclouds.aws.handlers;
import static org.jclouds.http.HttpUtils.releasePayload; import static org.jclouds.http.HttpUtils.releasePayload;
import java.io.IOException;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@ -39,7 +37,6 @@ import org.jclouds.http.HttpResponseException;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.AuthorizationException; import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.ResourceNotFoundException; import org.jclouds.rest.ResourceNotFoundException;
import org.jclouds.util.Utils;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
@ -67,7 +64,7 @@ public class ParseAWSErrorFromXmlContent implements HttpErrorHandler {
HttpRequest request = command.getRequest(); HttpRequest request = command.getRequest();
Exception exception = new HttpResponseException(command, response); Exception exception = new HttpResponseException(command, response);
try { try {
AWSError error = parseErrorFromContentOrNull(request, response); AWSError error = utils.parseAWSErrorFromContent(request, response);
exception = error != null ? new AWSResponseException(command, response, error) : exception; exception = error != null ? new AWSResponseException(command, response, error) : exception;
switch (response.getStatusCode()) { switch (response.getStatusCode()) {
case 400: case 400:
@ -103,16 +100,4 @@ public class ParseAWSErrorFromXmlContent implements HttpErrorHandler {
} }
} }
AWSError parseErrorFromContentOrNull(HttpRequest request, HttpResponse response) {
if (response.getPayload() != null) {
try {
String content = Utils.toStringAndClose(response.getPayload().getInput());
if (content != null && content.indexOf('<') >= 0)
return utils.parseAWSErrorFromContent(request, response, content);
} catch (IOException e) {
logger.warn(e, "exception reading error from response", response);
}
}
return null;
}
} }

View File

@ -26,5 +26,6 @@ package org.jclouds.aws.reference;
public interface AWSConstants { public interface AWSConstants {
public static final String PROPERTY_REGIONS = "jclouds.aws.regions"; public static final String PROPERTY_REGIONS = "jclouds.aws.regions";
public static final String PROPERTY_DEFAULT_REGIONS = "jclouds.aws.default_regions"; public static final String PROPERTY_DEFAULT_REGIONS = "jclouds.aws.default_regions";
public static final String PROPERTY_AUTH_TAG = "jclouds.aws.auth.tag";
public static final String PROPERTY_HEADER_TAG = "jclouds.aws.header.tag";
} }

View File

@ -16,34 +16,18 @@
* limitations under the License. * limitations under the License.
* ==================================================================== * ====================================================================
*/ */
package org.jclouds.rest.annotations; package org.jclouds.aws.s3;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* Prefixes the hostname of the endpoint with the contents of a method parameter, * Annotates the parameter that this is a bucket.
*
* @author Adrian Cole
*/ */
@Target(ElementType.PARAMETER) @Target(PARAMETER)
@Retention(RetentionPolicy.RUNTIME) @Retention(RUNTIME)
public @interface HostPrefixParam { public @interface Bucket {
/**
* Defines the characters that will be inserted in-between the value of the annotated method
* argument and the existing hostname.
*
* <p />
* <ul>
* <li>hostname was {@code mydomain.com}</li>
* <li>method argument is {@code myhost}</li>
* <li>if {@code joinOn} is not set, result is {@code myhostmydomain.com}</li>
* <li>if {@code joinOn} is set to {@code .}, result is {@code myhost.mydomain.com}</li>
* </ul>
*
*/
String value() default ".";
} }

View File

@ -1,16 +1,33 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.jclouds.aws.s3; package org.jclouds.aws.s3;
import static org.jclouds.Constants.PROPERTY_ENDPOINT; import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_DEFAULT_REGIONS; import static org.jclouds.aws.reference.AWSConstants.PROPERTY_DEFAULT_REGIONS;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_REGIONS; import static org.jclouds.aws.reference.AWSConstants.PROPERTY_REGIONS;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_AUTH_TAG;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_HEADER_TAG;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_SERVICE_EXPR;
import java.util.Properties; import java.util.Properties;
/** /**
* Builds properties used in Walrus Clients * Builds properties used in Google Storage
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@ -18,9 +35,8 @@ public class GoogleStoragePropertiesBuilder extends S3PropertiesBuilder {
@Override @Override
protected Properties defaultProperties() { protected Properties defaultProperties() {
Properties properties = super.defaultProperties(); Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_S3_AUTH_TAG, "GOOG1"); properties.setProperty(PROPERTY_AUTH_TAG, "GOOG1");
properties.setProperty(PROPERTY_S3_HEADER_TAG, "goog"); properties.setProperty(PROPERTY_HEADER_TAG, "goog");
properties.setProperty(PROPERTY_S3_SERVICE_EXPR, "\\.commondatastorage\\.googleapis\\.com");
return properties; return properties;
} }

View File

@ -30,8 +30,11 @@ import javax.ws.rs.HEAD;
import javax.ws.rs.PUT; import javax.ws.rs.PUT;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.jclouds.aws.s3.binders.BindACLToXMLPayload; import org.jclouds.aws.s3.binders.BindACLToXMLPayload;
import org.jclouds.aws.s3.binders.BindAsHostPrefixIfConfigured;
import org.jclouds.aws.s3.binders.BindBucketLoggingToXmlPayload; import org.jclouds.aws.s3.binders.BindBucketLoggingToXmlPayload;
import org.jclouds.aws.s3.binders.BindNoBucketLoggingToXmlPayload; import org.jclouds.aws.s3.binders.BindNoBucketLoggingToXmlPayload;
import org.jclouds.aws.s3.binders.BindPayerToXmlPayload; import org.jclouds.aws.s3.binders.BindPayerToXmlPayload;
@ -73,7 +76,6 @@ import org.jclouds.http.options.GetOptions;
import org.jclouds.rest.annotations.BinderParam; import org.jclouds.rest.annotations.BinderParam;
import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.Headers; import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.HostPrefixParam;
import org.jclouds.rest.annotations.ParamParser; import org.jclouds.rest.annotations.ParamParser;
import org.jclouds.rest.annotations.ParamValidators; import org.jclouds.rest.annotations.ParamValidators;
import org.jclouds.rest.annotations.QueryParams; import org.jclouds.rest.annotations.QueryParams;
@ -98,7 +100,6 @@ import com.google.common.util.concurrent.ListenableFuture;
* @see S3Client * @see S3Client
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAPI.html" /> * @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAPI.html" />
*/ */
@VirtualHost
@SkipEncoding('/') @SkipEncoding('/')
@RequestFilters(RequestAuthorizeSignature.class) @RequestFilters(RequestAuthorizeSignature.class)
@BlobScope(CONTAINER) @BlobScope(CONTAINER)
@ -118,7 +119,7 @@ public interface S3AsyncClient {
@ExceptionParser(ReturnNullOnKeyNotFound.class) @ExceptionParser(ReturnNullOnKeyNotFound.class)
@ResponseParser(ParseObjectFromHeadersAndHttpContent.class) @ResponseParser(ParseObjectFromHeadersAndHttpContent.class)
ListenableFuture<S3Object> getObject( ListenableFuture<S3Object> getObject(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName, @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName,
@PathParam("key") String key, GetOptions... options); @PathParam("key") String key, GetOptions... options);
/** /**
@ -129,7 +130,7 @@ public interface S3AsyncClient {
@ExceptionParser(ReturnNullOnKeyNotFound.class) @ExceptionParser(ReturnNullOnKeyNotFound.class)
@ResponseParser(ParseObjectMetadataFromHeaders.class) @ResponseParser(ParseObjectMetadataFromHeaders.class)
ListenableFuture<ObjectMetadata> headObject( ListenableFuture<ObjectMetadata> headObject(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName, @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName,
@PathParam("key") String key); @PathParam("key") String key);
/** /**
@ -139,7 +140,7 @@ public interface S3AsyncClient {
@Path("{key}") @Path("{key}")
@ExceptionParser(ReturnFalseOnKeyNotFound.class) @ExceptionParser(ReturnFalseOnKeyNotFound.class)
ListenableFuture<Boolean> objectExists( ListenableFuture<Boolean> objectExists(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName, @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName,
@PathParam("key") String key); @PathParam("key") String key);
/** /**
@ -149,7 +150,7 @@ public interface S3AsyncClient {
@Path("{key}") @Path("{key}")
@ExceptionParser(ReturnVoidOnNotFoundOr404.class) @ExceptionParser(ReturnVoidOnNotFoundOr404.class)
ListenableFuture<Void> deleteObject( ListenableFuture<Void> deleteObject(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName, @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName,
@PathParam("key") String key); @PathParam("key") String key);
/** /**
@ -159,7 +160,7 @@ public interface S3AsyncClient {
@Path("{key}") @Path("{key}")
@ResponseParser(ParseETagHeader.class) @ResponseParser(ParseETagHeader.class)
ListenableFuture<String> putObject( ListenableFuture<String> putObject(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName, @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName,
@PathParam("key") @ParamParser(ObjectKey.class) @BinderParam(BindS3ObjectToPayload.class) S3Object object, @PathParam("key") @ParamParser(ObjectKey.class) @BinderParam(BindS3ObjectToPayload.class) S3Object object,
PutObjectOptions... options); PutObjectOptions... options);
@ -172,7 +173,7 @@ public interface S3AsyncClient {
ListenableFuture<Boolean> putBucketInRegion( ListenableFuture<Boolean> putBucketInRegion(
// TODO endpoint based on region // TODO endpoint based on region
@BinderParam(BindRegionToXmlPayload.class) @Nullable String region, @BinderParam(BindRegionToXmlPayload.class) @Nullable String region,
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName, @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName,
PutBucketOptions... options); PutBucketOptions... options);
/** /**
@ -182,7 +183,7 @@ public interface S3AsyncClient {
@Path("/") @Path("/")
@ExceptionParser(ReturnTrueOn404OrNotFoundFalseIfNotEmpty.class) @ExceptionParser(ReturnTrueOn404OrNotFoundFalseIfNotEmpty.class)
ListenableFuture<Boolean> deleteBucketIfEmpty( ListenableFuture<Boolean> deleteBucketIfEmpty(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName); @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName);
/** /**
* @see S3Client#bucketExists * @see S3Client#bucketExists
@ -192,7 +193,7 @@ public interface S3AsyncClient {
@QueryParams(keys = "max-keys", values = "0") @QueryParams(keys = "max-keys", values = "0")
@ExceptionParser(ReturnFalseOnContainerNotFound.class) @ExceptionParser(ReturnFalseOnContainerNotFound.class)
ListenableFuture<Boolean> bucketExists( ListenableFuture<Boolean> bucketExists(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName); @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName);
/** /**
* @see S3Client#getBucketLocation * @see S3Client#getBucketLocation
@ -202,7 +203,7 @@ public interface S3AsyncClient {
@Path("/") @Path("/")
@XMLResponseParser(LocationConstraintHandler.class) @XMLResponseParser(LocationConstraintHandler.class)
ListenableFuture<String> getBucketLocation( ListenableFuture<String> getBucketLocation(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName); @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName);
/** /**
* @see S3Client#getBucketPayer * @see S3Client#getBucketPayer
@ -212,7 +213,7 @@ public interface S3AsyncClient {
@Path("/") @Path("/")
@XMLResponseParser(PayerHandler.class) @XMLResponseParser(PayerHandler.class)
ListenableFuture<Payer> getBucketPayer( ListenableFuture<Payer> getBucketPayer(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName); @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName);
/** /**
* @see S3Client#setBucketPayer * @see S3Client#setBucketPayer
@ -221,7 +222,7 @@ public interface S3AsyncClient {
@QueryParams(keys = "requestPayment") @QueryParams(keys = "requestPayment")
@Path("/") @Path("/")
ListenableFuture<Void> setBucketPayer( ListenableFuture<Void> setBucketPayer(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName, @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName,
@BinderParam(BindPayerToXmlPayload.class) Payer payer); @BinderParam(BindPayerToXmlPayload.class) Payer payer);
/** /**
@ -231,7 +232,7 @@ public interface S3AsyncClient {
@Path("/") @Path("/")
@XMLResponseParser(ListBucketHandler.class) @XMLResponseParser(ListBucketHandler.class)
ListenableFuture<ListBucketResponse> listBucket( ListenableFuture<ListBucketResponse> listBucket(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName, @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName,
ListBucketOptions... options); ListBucketOptions... options);
/** /**
@ -240,6 +241,7 @@ public interface S3AsyncClient {
@GET @GET
@XMLResponseParser(ListAllMyBucketsHandler.class) @XMLResponseParser(ListAllMyBucketsHandler.class)
@Path("/") @Path("/")
@VirtualHost
ListenableFuture<? extends SortedSet<BucketMetadata>> listOwnedBuckets(); ListenableFuture<? extends SortedSet<BucketMetadata>> listOwnedBuckets();
/** /**
@ -252,7 +254,7 @@ public interface S3AsyncClient {
ListenableFuture<ObjectMetadata> copyObject( ListenableFuture<ObjectMetadata> copyObject(
@PathParam("sourceBucket") String sourceBucket, @PathParam("sourceBucket") String sourceBucket,
@PathParam("sourceObject") String sourceObject, @PathParam("sourceObject") String sourceObject,
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String destinationBucket, @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String destinationBucket,
@PathParam("destinationObject") String destinationObject, CopyObjectOptions... options); @PathParam("destinationObject") String destinationObject, CopyObjectOptions... options);
/** /**
@ -264,7 +266,7 @@ public interface S3AsyncClient {
@ExceptionParser(ThrowContainerNotFoundOn404.class) @ExceptionParser(ThrowContainerNotFoundOn404.class)
@Path("/") @Path("/")
ListenableFuture<AccessControlList> getBucketACL( ListenableFuture<AccessControlList> getBucketACL(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName); @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName);
/** /**
* @see S3Client#putBucketACL * @see S3Client#putBucketACL
@ -273,7 +275,7 @@ public interface S3AsyncClient {
@Path("/") @Path("/")
@QueryParams(keys = "acl") @QueryParams(keys = "acl")
ListenableFuture<Boolean> putBucketACL( ListenableFuture<Boolean> putBucketACL(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName, @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName,
@BinderParam(BindACLToXMLPayload.class) AccessControlList acl); @BinderParam(BindACLToXMLPayload.class) AccessControlList acl);
/** /**
@ -285,7 +287,7 @@ public interface S3AsyncClient {
@XMLResponseParser(AccessControlListHandler.class) @XMLResponseParser(AccessControlListHandler.class)
@ExceptionParser(ThrowKeyNotFoundOn404.class) @ExceptionParser(ThrowKeyNotFoundOn404.class)
ListenableFuture<AccessControlList> getObjectACL( ListenableFuture<AccessControlList> getObjectACL(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName, @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName,
@PathParam("key") String key); @PathParam("key") String key);
/** /**
@ -295,7 +297,7 @@ public interface S3AsyncClient {
@QueryParams(keys = "acl") @QueryParams(keys = "acl")
@Path("{key}") @Path("{key}")
ListenableFuture<Boolean> putObjectACL( ListenableFuture<Boolean> putObjectACL(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName, @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName,
@PathParam("key") String key, @PathParam("key") String key,
@BinderParam(BindACLToXMLPayload.class) AccessControlList acl); @BinderParam(BindACLToXMLPayload.class) AccessControlList acl);
@ -308,7 +310,7 @@ public interface S3AsyncClient {
@ExceptionParser(ThrowContainerNotFoundOn404.class) @ExceptionParser(ThrowContainerNotFoundOn404.class)
@Path("/") @Path("/")
ListenableFuture<BucketLogging> getBucketLogging( ListenableFuture<BucketLogging> getBucketLogging(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName); @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName);
/** /**
* @see S3Client#enableBucketLogging * @see S3Client#enableBucketLogging
@ -317,7 +319,7 @@ public interface S3AsyncClient {
@Path("/") @Path("/")
@QueryParams(keys = "logging") @QueryParams(keys = "logging")
ListenableFuture<Void> enableBucketLogging( ListenableFuture<Void> enableBucketLogging(
@HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName, @Bucket @BinderParam(BindAsHostPrefixIfConfigured.class) @ParamValidators( { BucketNameValidator.class }) String bucketName,
@BinderParam(BindBucketLoggingToXmlPayload.class) BucketLogging logging); @BinderParam(BindBucketLoggingToXmlPayload.class) BucketLogging logging);
/** /**
@ -326,7 +328,8 @@ public interface S3AsyncClient {
@PUT @PUT
@Path("/") @Path("/")
@QueryParams(keys = "logging") @QueryParams(keys = "logging")
@Produces(MediaType.TEXT_XML)
ListenableFuture<Void> disableBucketLogging( ListenableFuture<Void> disableBucketLogging(
@BinderParam(BindNoBucketLoggingToXmlPayload.class) @HostPrefixParam @ParamValidators( { BucketNameValidator.class }) String bucketName); @Bucket @BinderParam(BindNoBucketLoggingToXmlPayload.class) @ParamValidators( { BucketNameValidator.class }) String bucketName);
} }

View File

@ -21,11 +21,12 @@ package org.jclouds.aws.s3;
import static org.jclouds.Constants.PROPERTY_API_VERSION; import static org.jclouds.Constants.PROPERTY_API_VERSION;
import static org.jclouds.Constants.PROPERTY_ENDPOINT; import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.jclouds.Constants.PROPERTY_RELAX_HOSTNAME; import static org.jclouds.Constants.PROPERTY_RELAX_HOSTNAME;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_DEFAULT_REGIONS; import static org.jclouds.aws.reference.AWSConstants.PROPERTY_DEFAULT_REGIONS;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_REGIONS; import static org.jclouds.aws.reference.AWSConstants.PROPERTY_REGIONS;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_AUTH_TAG; import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_SERVICE_PATH;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_HEADER_TAG; import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_VIRTUAL_HOST_BUCKETS;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_SERVICE_EXPR;
import static org.jclouds.blobstore.reference.BlobStoreConstants.DIRECTORY_SUFFIX_FOLDER; import static org.jclouds.blobstore.reference.BlobStoreConstants.DIRECTORY_SUFFIX_FOLDER;
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_BLOBSTORE_DIRECTORY_SUFFIX; import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_BLOBSTORE_DIRECTORY_SUFFIX;
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX; import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
@ -47,9 +48,10 @@ public class S3PropertiesBuilder extends PropertiesBuilder {
protected Properties defaultProperties() { protected Properties defaultProperties() {
Properties properties = super.defaultProperties(); Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_API_VERSION, S3AsyncClient.VERSION); properties.setProperty(PROPERTY_API_VERSION, S3AsyncClient.VERSION);
properties.setProperty(PROPERTY_S3_AUTH_TAG, "AWS"); properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
properties.setProperty(PROPERTY_S3_HEADER_TAG, "amz"); properties.setProperty(PROPERTY_HEADER_TAG, "amz");
properties.setProperty(PROPERTY_S3_SERVICE_EXPR, "\\.s3[^.]*\\.amazonaws\\.com"); properties.setProperty(PROPERTY_S3_SERVICE_PATH, "/");
properties.setProperty(PROPERTY_S3_VIRTUAL_HOST_BUCKETS, "true");
properties.setProperty(PROPERTY_RELAX_HOSTNAME, "true"); properties.setProperty(PROPERTY_RELAX_HOSTNAME, "true");
addEndpoints(properties); addEndpoints(properties);
properties.setProperty(PROPERTY_BLOBSTORE_DIRECTORY_SUFFIX, DIRECTORY_SUFFIX_FOLDER); properties.setProperty(PROPERTY_BLOBSTORE_DIRECTORY_SUFFIX, DIRECTORY_SUFFIX_FOLDER);
@ -90,7 +92,7 @@ public class S3PropertiesBuilder extends PropertiesBuilder {
protected void setMetaPrefix() { protected void setMetaPrefix() {
if (properties.getProperty(PROPERTY_USER_METADATA_PREFIX) == null) { if (properties.getProperty(PROPERTY_USER_METADATA_PREFIX) == null) {
properties.setProperty(PROPERTY_USER_METADATA_PREFIX, String.format("x-%s-meta-", properties.setProperty(PROPERTY_USER_METADATA_PREFIX, String.format("x-%s-meta-",
properties.getProperty(PROPERTY_S3_HEADER_TAG))); properties.getProperty(PROPERTY_HEADER_TAG)));
} }
} }

View File

@ -1,8 +1,29 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.jclouds.aws.s3; package org.jclouds.aws.s3;
import static org.jclouds.Constants.PROPERTY_API_VERSION;
import static org.jclouds.Constants.PROPERTY_ENDPOINT; import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_DEFAULT_REGIONS; import static org.jclouds.aws.reference.AWSConstants.PROPERTY_DEFAULT_REGIONS;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_REGIONS; import static org.jclouds.aws.reference.AWSConstants.PROPERTY_REGIONS;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_SERVICE_PATH;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_VIRTUAL_HOST_BUCKETS;
import java.util.Properties; import java.util.Properties;
@ -16,9 +37,12 @@ public class WalrusPropertiesBuilder extends S3PropertiesBuilder {
protected Properties addEndpoints(Properties properties) { protected Properties addEndpoints(Properties properties) {
properties.setProperty(PROPERTY_REGIONS, "Walrus"); properties.setProperty(PROPERTY_REGIONS, "Walrus");
properties.setProperty(PROPERTY_DEFAULT_REGIONS, "Walrus"); properties.setProperty(PROPERTY_DEFAULT_REGIONS, "Walrus");
properties.setProperty(PROPERTY_API_VERSION, "Walrus-1.6");
properties.setProperty(PROPERTY_ENDPOINT, "http://ecc.eucalyptus.com:8773/services/Walrus"); properties.setProperty(PROPERTY_ENDPOINT, "http://ecc.eucalyptus.com:8773/services/Walrus");
properties.setProperty(PROPERTY_ENDPOINT + ".Walrus", properties.setProperty(PROPERTY_ENDPOINT + ".Walrus",
"http://ecc.eucalyptus.com:8773/services/Walrus"); "http://ecc.eucalyptus.com:8773/services/Walrus");
properties.setProperty(PROPERTY_S3_SERVICE_PATH, "/services/Walrus");
properties.setProperty(PROPERTY_S3_VIRTUAL_HOST_BUCKETS, "false");
return properties; return properties;
} }

View File

@ -0,0 +1,81 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.jclouds.aws.s3.binders;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_SERVICE_PATH;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_VIRTUAL_HOST_BUCKETS;
import static org.jclouds.http.HttpUtils.urlEncode;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.aws.s3.S3AsyncClient;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.Binder;
import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.binders.BindAsHostPrefix;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
/**
*
* @author Adrian Cole
*/
@Singleton
public class BindAsHostPrefixIfConfigured implements Binder {
private final Provider<UriBuilder> uriBuilderProvider;
private final BindAsHostPrefix bindAsHostPrefix;
private final boolean isVhostStyle;
private final String servicePath;
@Inject
public BindAsHostPrefixIfConfigured(BindAsHostPrefix bindAsHostPrefix,
@Named(PROPERTY_S3_VIRTUAL_HOST_BUCKETS) boolean isVhostStyle,
@Named(PROPERTY_S3_SERVICE_PATH) String servicePath,
Provider<UriBuilder> uriBuilderProvider) {
this.bindAsHostPrefix = bindAsHostPrefix;
this.isVhostStyle = isVhostStyle;
this.servicePath = servicePath;
this.uriBuilderProvider = uriBuilderProvider;
}
public void bindToRequest(HttpRequest request, Object payload) {
if (isVhostStyle) {
bindAsHostPrefix.bindToRequest(request, payload);
request.getHeaders().replaceValues(HttpHeaders.HOST,
ImmutableSet.of(request.getEndpoint().getHost()));
} else {
UriBuilder builder = uriBuilderProvider.get().uri(request.getEndpoint());
StringBuilder path = new StringBuilder(urlEncode(request.getEndpoint().getPath(),
S3AsyncClient.class.getAnnotation(SkipEncoding.class).value()));
int indexToInsert = path.indexOf(servicePath);
indexToInsert = indexToInsert == -1 ? 0 : indexToInsert;
indexToInsert += servicePath.length();
path.insert(indexToInsert, "/" + payload.toString());
builder.replacePath(path.toString());
request.setEndpoint(builder.buildFromEncodedMap(Maps.<String, Object> newHashMap()));
}
}
}

View File

@ -18,8 +18,8 @@
*/ */
package org.jclouds.aws.s3.binders; package org.jclouds.aws.s3.binders;
import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import javax.ws.rs.core.MediaType;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.rest.Binder; import org.jclouds.rest.Binder;
@ -30,11 +30,17 @@ import org.jclouds.rest.Binder;
*/ */
@Singleton @Singleton
public class BindNoBucketLoggingToXmlPayload implements Binder { public class BindNoBucketLoggingToXmlPayload implements Binder {
private final BindAsHostPrefixIfConfigured bindAsHostPrefixIfConfigured;
@Inject
BindNoBucketLoggingToXmlPayload(BindAsHostPrefixIfConfigured bindAsHostPrefixIfConfigured) {
this.bindAsHostPrefixIfConfigured = bindAsHostPrefixIfConfigured;
}
public void bindToRequest(HttpRequest request, Object payload) { public void bindToRequest(HttpRequest request, Object payload) {
bindAsHostPrefixIfConfigured.bindToRequest(request, payload);
String stringPayload = "<BucketLoggingStatus xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"/>"; String stringPayload = "<BucketLoggingStatus xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"/>";
request.setPayload(stringPayload); request.setPayload(stringPayload);
request.getPayload().setContentType(MediaType.TEXT_XML);
} }
} }

View File

@ -69,7 +69,7 @@ public class S3RestClientModule extends AWSRestClientModule<S3Client, S3AsyncCli
@Provides @Provides
@Singleton @Singleton
RequestSigner provideRequestSigner(RequestAuthorizeSignature in) { protected RequestSigner provideRequestSigner(RequestAuthorizeSignature in) {
return in; return in;
} }
@ -79,7 +79,7 @@ public class S3RestClientModule extends AWSRestClientModule<S3Client, S3AsyncCli
@Provides @Provides
@TimeStamp @TimeStamp
@Singleton @Singleton
Supplier<String> provideTimeStampCache(@Named(Constants.PROPERTY_SESSION_INTERVAL) long seconds, protected Supplier<String> provideTimeStampCache(@Named(Constants.PROPERTY_SESSION_INTERVAL) long seconds,
final DateService dateService) { final DateService dateService) {
return new ExpirableSupplier<String>(new Supplier<String>() { return new ExpirableSupplier<String>(new Supplier<String>() {
public String get() { public String get() {

View File

@ -18,9 +18,17 @@
*/ */
package org.jclouds.aws.s3.filters; package org.jclouds.aws.s3.filters;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkArgument;
import static org.jclouds.Constants.PROPERTY_CREDENTIAL;
import static org.jclouds.Constants.PROPERTY_IDENTITY;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_SERVICE_PATH;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_VIRTUAL_HOST_BUCKETS;
import static org.jclouds.util.Patterns.NEWLINE_PATTERN; import static org.jclouds.util.Patterns.NEWLINE_PATTERN;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
@ -34,7 +42,7 @@ import javax.inject.Singleton;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import org.jclouds.Constants; import org.jclouds.Constants;
import org.jclouds.aws.s3.reference.S3Constants; import org.jclouds.aws.s3.Bucket;
import org.jclouds.date.TimeStamp; import org.jclouds.date.TimeStamp;
import org.jclouds.encryption.EncryptionService; import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
@ -44,10 +52,13 @@ import org.jclouds.http.HttpUtils;
import org.jclouds.http.internal.SignatureWire; import org.jclouds.http.internal.SignatureWire;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.RequestSigner; import org.jclouds.rest.RequestSigner;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.util.Utils; import org.jclouds.util.Utils;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/** /**
* Signs the S3 request. * Signs the S3 request.
@ -75,18 +86,21 @@ public class RequestAuthorizeSignature implements HttpRequestFilter, RequestSign
private final String authTag; private final String authTag;
private final String headerTag; private final String headerTag;
private final String srvExpr; private final String servicePath;
private final boolean isVhostStyle;
@Inject @Inject
public RequestAuthorizeSignature(SignatureWire signatureWire, public RequestAuthorizeSignature(SignatureWire signatureWire,
@Named(S3Constants.PROPERTY_S3_AUTH_TAG) String authTag, @Named(PROPERTY_AUTH_TAG) String authTag,
@Named(S3Constants.PROPERTY_S3_SERVICE_EXPR) String srvExpr, @Named(PROPERTY_S3_VIRTUAL_HOST_BUCKETS) boolean isVhostStyle,
@Named(S3Constants.PROPERTY_S3_HEADER_TAG) String headerTag, @Named(PROPERTY_S3_SERVICE_PATH) String servicePath,
@Named(Constants.PROPERTY_IDENTITY) String accessKey, @Named(PROPERTY_HEADER_TAG) String headerTag,
@Named(Constants.PROPERTY_CREDENTIAL) String secretKey, @Named(PROPERTY_IDENTITY) String accessKey,
@Named(PROPERTY_CREDENTIAL) String secretKey,
@TimeStamp Provider<String> timeStampProvider, EncryptionService encryptionService, @TimeStamp Provider<String> timeStampProvider, EncryptionService encryptionService,
HttpUtils utils) { HttpUtils utils) {
this.srvExpr = srvExpr; this.isVhostStyle = isVhostStyle;
this.servicePath = servicePath;
this.headerTag = headerTag; this.headerTag = headerTag;
this.authTag = authTag; this.authTag = authTag;
this.signatureWire = signatureWire; this.signatureWire = signatureWire;
@ -112,15 +126,15 @@ public class RequestAuthorizeSignature implements HttpRequestFilter, RequestSign
appendPayloadMetadata(request, buffer); appendPayloadMetadata(request, buffer);
appendHttpHeaders(request, buffer); appendHttpHeaders(request, buffer);
appendAmzHeaders(request, buffer); appendAmzHeaders(request, buffer);
appendBucketName(request, buffer); if (isVhostStyle)
appendBucketName(request, buffer);
appendUriPath(request, buffer); appendUriPath(request, buffer);
if (signatureWire.enabled()) if (signatureWire.enabled())
signatureWire.output(buffer.toString()); signatureWire.output(buffer.toString());
return buffer.toString(); return buffer.toString();
} }
private void calculateAndReplaceAuthHeader(HttpRequest request, String toSign) void calculateAndReplaceAuthHeader(HttpRequest request, String toSign) throws HttpException {
throws HttpException {
String signature = sign(toSign); String signature = sign(toSign);
if (signatureWire.enabled()) if (signatureWire.enabled())
signatureWire.input(Utils.toInputStream(signature)); signatureWire.input(Utils.toInputStream(signature));
@ -139,16 +153,16 @@ public class RequestAuthorizeSignature implements HttpRequestFilter, RequestSign
return signature; return signature;
} }
private void appendMethod(HttpRequest request, StringBuilder toSign) { void appendMethod(HttpRequest request, StringBuilder toSign) {
toSign.append(request.getMethod()).append("\n"); toSign.append(request.getMethod()).append("\n");
} }
private void replaceDateHeader(HttpRequest request) { void replaceDateHeader(HttpRequest request) {
request.getHeaders().replaceValues(HttpHeaders.DATE, request.getHeaders().replaceValues(HttpHeaders.DATE,
Collections.singletonList(timeStampProvider.get())); Collections.singletonList(timeStampProvider.get()));
} }
private void appendAmzHeaders(HttpRequest request, StringBuilder toSign) { void appendAmzHeaders(HttpRequest request, StringBuilder toSign) {
Set<String> headers = new TreeSet<String>(request.getHeaders().keySet()); Set<String> headers = new TreeSet<String>(request.getHeaders().keySet());
for (String header : headers) { for (String header : headers) {
if (header.startsWith("x-" + headerTag + "-")) { if (header.startsWith("x-" + headerTag + "-")) {
@ -162,7 +176,7 @@ public class RequestAuthorizeSignature implements HttpRequestFilter, RequestSign
} }
} }
private void appendPayloadMetadata(HttpRequest request, StringBuilder buffer) { void appendPayloadMetadata(HttpRequest request, StringBuilder buffer) {
buffer.append( buffer.append(
utils.valueOrEmpty(request.getPayload() == null ? null : request.getPayload() utils.valueOrEmpty(request.getPayload() == null ? null : request.getPayload()
.getContentMD5())).append("\n"); .getContentMD5())).append("\n");
@ -171,19 +185,33 @@ public class RequestAuthorizeSignature implements HttpRequestFilter, RequestSign
.getContentType())).append("\n"); .getContentType())).append("\n");
} }
private void appendHttpHeaders(HttpRequest request, StringBuilder toSign) { void appendHttpHeaders(HttpRequest request, StringBuilder toSign) {
for (String header : firstHeadersToSign) for (String header : firstHeadersToSign)
toSign.append(valueOrEmpty(request.getHeaders().get(header))).append("\n"); toSign.append(valueOrEmpty(request.getHeaders().get(header))).append("\n");
} }
@VisibleForTesting @VisibleForTesting
void appendBucketName(HttpRequest request, StringBuilder toSign) { void appendBucketName(HttpRequest req, StringBuilder toSign) {
String hostHeader = request.getFirstHeaderOrNull(HttpHeaders.HOST); checkArgument(req instanceof GeneratedHttpRequest<?>,
if (hostHeader == null) "this should be a generated http request");
hostHeader = checkNotNull(request.getEndpoint().getHost(), GeneratedHttpRequest<?> request = GeneratedHttpRequest.class.cast(req);
"request.getEndPoint().getHost()");
if (hostHeader.matches(".*" + srvExpr)) String bucketName = null;
toSign.append("/").append(hostHeader.replaceAll(srvExpr, ""));
for (int i = 0; i < request.getJavaMethod().getParameterAnnotations().length; i++) {
if (Iterables.any(Arrays.asList(request.getJavaMethod().getParameterAnnotations()[i]),
new Predicate<Annotation>() {
public boolean apply(Annotation input) {
return input.annotationType().equals(Bucket.class);
}
})) {
bucketName = (String) request.getArgs()[i];
break;
}
}
if (bucketName != null)
toSign.append(servicePath).append(bucketName);
} }
@VisibleForTesting @VisibleForTesting

View File

@ -22,9 +22,9 @@ import javax.inject.Inject;
import org.jclouds.aws.s3.domain.MutableObjectMetadata; import org.jclouds.aws.s3.domain.MutableObjectMetadata;
import org.jclouds.aws.s3.domain.S3Object; import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -57,8 +57,10 @@ public class ParseObjectFromHeadersAndHttpContent implements Function<HttpRespon
return object; return object;
} }
public void setContext(GeneratedHttpRequest<?> request) { @Override
public ParseObjectFromHeadersAndHttpContent setContext(HttpRequest request) {
metadataParser.setContext(request); metadataParser.setContext(request);
return this;
} }
} }

View File

@ -18,20 +18,21 @@
*/ */
package org.jclouds.aws.s3.functions; package org.jclouds.aws.s3.functions;
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
import static org.jclouds.http.HttpUtils.attemptToParseSizeAndRangeFromHeaders; import static org.jclouds.http.HttpUtils.attemptToParseSizeAndRangeFromHeaders;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import org.jclouds.aws.s3.blobstore.functions.BlobToObjectMetadata; import org.jclouds.aws.s3.blobstore.functions.BlobToObjectMetadata;
import org.jclouds.aws.s3.domain.MutableObjectMetadata; import org.jclouds.aws.s3.domain.MutableObjectMetadata;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.blobstore.domain.BlobMetadata; import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.functions.ParseSystemAndUserMetadataFromHeaders; import org.jclouds.blobstore.functions.ParseSystemAndUserMetadataFromHeaders;
import org.jclouds.encryption.EncryptionService; import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.util.Utils; import org.jclouds.util.Utils;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
@ -49,13 +50,16 @@ public class ParseObjectMetadataFromHeaders implements
private final ParseSystemAndUserMetadataFromHeaders blobMetadataParser; private final ParseSystemAndUserMetadataFromHeaders blobMetadataParser;
private final BlobToObjectMetadata blobToObjectMetadata; private final BlobToObjectMetadata blobToObjectMetadata;
private final EncryptionService encryptionService; private final EncryptionService encryptionService;
private final String userMdPrefix;
@Inject @Inject
public ParseObjectMetadataFromHeaders(ParseSystemAndUserMetadataFromHeaders blobMetadataParser, public ParseObjectMetadataFromHeaders(ParseSystemAndUserMetadataFromHeaders blobMetadataParser,
BlobToObjectMetadata blobToObjectMetadata, EncryptionService encryptionService) { BlobToObjectMetadata blobToObjectMetadata, EncryptionService encryptionService,
@Named(PROPERTY_USER_METADATA_PREFIX) String userMdPrefix) {
this.blobMetadataParser = blobMetadataParser; this.blobMetadataParser = blobMetadataParser;
this.blobToObjectMetadata = blobToObjectMetadata; this.blobToObjectMetadata = blobToObjectMetadata;
this.encryptionService = encryptionService; this.encryptionService = encryptionService;
this.userMdPrefix = userMdPrefix;
} }
/** /**
@ -80,15 +84,17 @@ public class ParseObjectMetadataFromHeaders implements
@VisibleForTesting @VisibleForTesting
protected void addETagTo(HttpResponse from, MutableObjectMetadata metadata) { protected void addETagTo(HttpResponse from, MutableObjectMetadata metadata) {
if (metadata.getETag() == null) { if (metadata.getETag() == null) {
String eTagHeader = from.getFirstHeaderOrNull(S3Headers.AMZ_MD5); String eTagHeader = from.getFirstHeaderOrNull(userMdPrefix + "object-eTag");
if (eTagHeader != null) { if (eTagHeader != null) {
metadata.setETag(eTagHeader); metadata.setETag(eTagHeader);
} }
} }
} }
public void setContext(GeneratedHttpRequest<?> request) { @Override
public ParseObjectMetadataFromHeaders setContext(HttpRequest request) {
blobMetadataParser.setContext(request); blobMetadataParser.setContext(request);
return this;
} }
} }

View File

@ -20,11 +20,13 @@ package org.jclouds.aws.s3.options;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX; import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
@ -70,11 +72,8 @@ import com.google.common.collect.Multimap;
*/ */
public class CopyObjectOptions extends BaseHttpRequestOptions { public class CopyObjectOptions extends BaseHttpRequestOptions {
private final static DateService dateService = new SimpleDateFormatDateService(); private final static DateService dateService = new SimpleDateFormatDateService();
public static final CopyObjectOptions NONE = new CopyObjectOptions(); public static final CopyObjectOptions NONE = new CopyObjectOptions();
private Map<String, String> metadata; private Map<String, String> metadata;
private CannedAccessPolicy acl = CannedAccessPolicy.PRIVATE; private CannedAccessPolicy acl = CannedAccessPolicy.PRIVATE;
private String metadataPrefix; private String metadataPrefix;
@ -84,6 +83,13 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
this.metadataPrefix = metadataPrefix; this.metadataPrefix = metadataPrefix;
} }
private String headerTag;
@Inject
public void setHeaderTag(@Named(PROPERTY_HEADER_TAG) String headerTag) {
this.headerTag = headerTag;
}
/** /**
* Override the default ACL (private) with the specified one. * Override the default ACL (private) with the specified one.
* *
@ -251,15 +257,18 @@ public class CopyObjectOptions extends BaseHttpRequestOptions {
@Override @Override
public Multimap<String, String> buildRequestHeaders() { public Multimap<String, String> buildRequestHeaders() {
checkState(headerTag != null, "headerTag should have been injected!");
checkState(metadataPrefix != null, "metadataPrefix should have been injected!"); checkState(metadataPrefix != null, "metadataPrefix should have been injected!");
Multimap<String, String> returnVal = LinkedHashMultimap.create(); Multimap<String, String> returnVal = LinkedHashMultimap.create();
returnVal.putAll(headers); for (Entry<String, String> entry : headers.entries()) {
returnVal.put(entry.getKey().replace("aws", headerTag), entry.getValue());
}
if (metadata != null) { if (metadata != null) {
for (String key : metadata.keySet()) { for (String key : metadata.keySet()) {
returnVal.put(key.startsWith(metadataPrefix) ? key : metadataPrefix + key, metadata returnVal.put(key.startsWith(metadataPrefix) ? key : metadataPrefix + key, metadata
.get(key)); .get(key));
} }
returnVal.put("x-amz-metadata-directive", "REPLACE"); returnVal.put("x-" + headerTag + "-metadata-directive", "REPLACE");
} }
return returnVal; return returnVal;
} }

View File

@ -19,11 +19,21 @@
package org.jclouds.aws.s3.options; package org.jclouds.aws.s3.options;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
import java.util.Map.Entry;
import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.aws.s3.domain.CannedAccessPolicy; import org.jclouds.aws.s3.domain.CannedAccessPolicy;
import org.jclouds.aws.s3.reference.S3Headers; import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.http.options.BaseHttpRequestOptions; import org.jclouds.http.options.BaseHttpRequestOptions;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
/** /**
* Contains options supported in the REST API for the PUT bucket operation. <h2> * Contains options supported in the REST API for the PUT bucket operation. <h2>
* Usage</h2> The recommended way to instantiate a PutBucketOptions object is to statically import * Usage</h2> The recommended way to instantiate a PutBucketOptions object is to statically import
@ -47,6 +57,23 @@ import org.jclouds.http.options.BaseHttpRequestOptions;
public class PutBucketOptions extends BaseHttpRequestOptions { public class PutBucketOptions extends BaseHttpRequestOptions {
private CannedAccessPolicy acl = CannedAccessPolicy.PRIVATE; private CannedAccessPolicy acl = CannedAccessPolicy.PRIVATE;
private String headerTag;
@Inject
public void setHeaderTag(@Named(PROPERTY_HEADER_TAG) String headerTag) {
this.headerTag = headerTag;
}
@Override
public Multimap<String, String> buildRequestHeaders() {
checkState(headerTag != null, "headerTag should have been injected!");
Multimap<String, String> returnVal = LinkedHashMultimap.create();
for (Entry<String, String> entry : headers.entries()) {
returnVal.put(entry.getKey().replace("aws", headerTag), entry.getValue());
}
return returnVal;
}
/** /**
* Override the default ACL (private) with the specified one. * Override the default ACL (private) with the specified one.
* *

View File

@ -18,11 +18,20 @@
*/ */
package org.jclouds.aws.s3.options; package org.jclouds.aws.s3.options;
import java.util.Map.Entry;
import javax.inject.Inject;
import javax.inject.Named;
import org.jclouds.aws.s3.domain.CannedAccessPolicy; import org.jclouds.aws.s3.domain.CannedAccessPolicy;
import org.jclouds.aws.s3.reference.S3Headers; import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.http.options.BaseHttpRequestOptions; import org.jclouds.http.options.BaseHttpRequestOptions;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import static com.google.common.base.Preconditions.*; import static com.google.common.base.Preconditions.*;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
/** /**
* Contains options supported in the REST API for the PUT object operation. * Contains options supported in the REST API for the PUT object operation.
@ -51,6 +60,22 @@ public class PutObjectOptions extends BaseHttpRequestOptions {
private CannedAccessPolicy acl = CannedAccessPolicy.PRIVATE; private CannedAccessPolicy acl = CannedAccessPolicy.PRIVATE;
private String headerTag;
@Inject
public void setHeaderTag(@Named(PROPERTY_HEADER_TAG) String headerTag) {
this.headerTag = headerTag;
}
@Override
public Multimap<String, String> buildRequestHeaders() {
checkState(headerTag != null, "headerTag should have been injected!");
Multimap<String, String> returnVal = LinkedHashMultimap.create();
for (Entry<String, String> entry : headers.entries()) {
returnVal.put(entry.getKey().replace("aws", headerTag), entry.getValue());
}
return returnVal;
}
/** /**
* Override the default ACL (private) with the specified one. * Override the default ACL (private) with the specified one.
* *

View File

@ -33,10 +33,7 @@ public interface S3Constants {
public static final String MARKER = "marker"; public static final String MARKER = "marker";
public static final String MAX_KEYS = "max-keys"; public static final String MAX_KEYS = "max-keys";
public static final String DELIMITER = "delimiter"; public static final String DELIMITER = "delimiter";
public static final String PROPERTY_S3_SERVICE_PATH = "jclouds.s3.service-path";
public static final String PROPERTY_S3_SERVICE_EXPR = "jclouds.service.expr"; public static final String PROPERTY_S3_VIRTUAL_HOST_BUCKETS = "jclouds.s3.virtual-host-buckets";
public static final String PROPERTY_S3_AUTH_TAG = "jclouds.s3.auth.tag";
public static final String PROPERTY_S3_HEADER_TAG = "jclouds.s3.header.tag";
} }

View File

@ -36,7 +36,5 @@ public interface S3Headers {
*/ */
public static final String CANNED_ACL = "x-amz-acl"; public static final String CANNED_ACL = "x-amz-acl";
public static final String AMZ_MD5 = "x-amz-meta-object-eTag"; public static final String AMZ_MD5 = "x-amz-meta-object-eTag";
public static final String REQUEST_ID = "x-amz-request-id";
public static final String REQUEST_TOKEN = "x-amz-id-2";
} }

View File

@ -21,20 +21,9 @@ package org.jclouds.aws.s3.util;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.s3.S3Client; import org.jclouds.aws.s3.S3Client;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.aws.util.AWSUtils;
import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpResponse;
import org.jclouds.util.Patterns; import org.jclouds.util.Patterns;
/** /**
@ -42,27 +31,8 @@ import org.jclouds.util.Patterns;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Singleton
public class S3Utils { public class S3Utils {
@Inject
AWSUtils util;
public AWSError parseAWSErrorFromContent(HttpCommand command, HttpResponse response,
InputStream content) throws HttpException {
AWSError error = util.parseAWSErrorFromContent(command.getRequest(), response, content);
if (error.getRequestId() == null)
error.setRequestId(response.getFirstHeaderOrNull(S3Headers.REQUEST_ID));
error.setRequestToken(response.getFirstHeaderOrNull(S3Headers.REQUEST_TOKEN));
return error;
}
public AWSError parseAWSErrorFromContent(HttpCommand command, HttpResponse response,
String content) throws HttpException {
return parseAWSErrorFromContent(command, response, new ByteArrayInputStream(content
.getBytes()));
}
public static final Pattern BUCKET_NAME_PATTERN = Pattern.compile("^[a-z0-9][-_.a-z0-9]+"); public static final Pattern BUCKET_NAME_PATTERN = Pattern.compile("^[a-z0-9][-_.a-z0-9]+");
// TODO add validatorparam so that this is actually used // TODO add validatorparam so that this is actually used

View File

@ -20,6 +20,8 @@ package org.jclouds.aws.sqs;
import static org.jclouds.Constants.PROPERTY_API_VERSION; import static org.jclouds.Constants.PROPERTY_API_VERSION;
import static org.jclouds.Constants.PROPERTY_ENDPOINT; import static org.jclouds.Constants.PROPERTY_ENDPOINT;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_AUTH_TAG;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_REGIONS; import static org.jclouds.aws.reference.AWSConstants.PROPERTY_REGIONS;
import java.util.Properties; import java.util.Properties;
@ -38,6 +40,8 @@ public class SQSPropertiesBuilder extends PropertiesBuilder {
@Override @Override
protected Properties defaultProperties() { protected Properties defaultProperties() {
Properties properties = super.defaultProperties(); Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
properties.setProperty(PROPERTY_HEADER_TAG, "amz");
properties.setProperty(PROPERTY_API_VERSION, SQSAsyncClient.VERSION); properties.setProperty(PROPERTY_API_VERSION, SQSAsyncClient.VERSION);
properties.setProperty(PROPERTY_REGIONS, Joiner.on(',').join(Region.US_EAST_1, properties.setProperty(PROPERTY_REGIONS, Joiner.on(',').join(Region.US_EAST_1,
Region.US_WEST_1, Region.EU_WEST_1, Region.AP_SOUTHEAST_1)); Region.US_WEST_1, Region.EU_WEST_1, Region.AP_SOUTHEAST_1));

View File

@ -18,19 +18,22 @@
*/ */
package org.jclouds.aws.util; package org.jclouds.aws.util;
import java.io.ByteArrayInputStream; import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
import java.io.InputStream;
import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider; import javax.inject.Provider;
import javax.inject.Singleton; import javax.inject.Singleton;
import org.jclouds.aws.domain.AWSError; import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.xml.ErrorHandler; import org.jclouds.aws.xml.ErrorHandler;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ParseSax.Factory; import org.jclouds.http.functions.ParseSax.Factory;
import org.jclouds.logging.Logger;
import org.jclouds.rest.RequestSigner; import org.jclouds.rest.RequestSigner;
/** /**
@ -43,27 +46,43 @@ public class AWSUtils {
private final RequestSigner signer; private final RequestSigner signer;
private final ParseSax.Factory factory; private final ParseSax.Factory factory;
private final Provider<ErrorHandler> errorHandlerProvider; private final Provider<ErrorHandler> errorHandlerProvider;
private final String requestId;
private final String requestToken;
@Resource
protected Logger logger = Logger.NULL;
@Inject @Inject
AWSUtils(RequestSigner signer, Factory factory, Provider<ErrorHandler> errorHandlerProvider) { AWSUtils(@Named(PROPERTY_HEADER_TAG) String headerTag, RequestSigner signer, Factory factory,
Provider<ErrorHandler> errorHandlerProvider) {
this.signer = signer; this.signer = signer;
this.factory = factory; this.factory = factory;
this.errorHandlerProvider = errorHandlerProvider; this.errorHandlerProvider = errorHandlerProvider;
this.requestId = String.format("x-%s-request-id", headerTag);
this.requestToken = String.format("x-%s-id-2", headerTag);
} }
public AWSError parseAWSErrorFromContent(HttpRequest request, HttpResponse response, public AWSError parseAWSErrorFromContent(HttpRequest request, HttpResponse response) {
InputStream content) { // HEAD has no content
AWSError error = (AWSError) factory.create(errorHandlerProvider.get()).parse(content); if (response.getPayload() == null)
if ("SignatureDoesNotMatch".equals(error.getCode())) { return null;
error.setStringSigned(signer.createStringToSign(request)); // Eucalyptus and Walrus occasionally return text/plain
error.setSignature(signer.sign(error.getStringSigned())); if (response.getPayload().getContentType() != null
&& response.getPayload().getContentType().indexOf("text") != -1)
return null;
try {
AWSError error = (AWSError) factory.create(errorHandlerProvider.get()).setContext(request)
.apply(response);
if (error.getRequestId() == null)
error.setRequestId(response.getFirstHeaderOrNull(requestId));
error.setRequestToken(response.getFirstHeaderOrNull(requestToken));
if ("SignatureDoesNotMatch".equals(error.getCode())) {
error.setStringSigned(signer.createStringToSign(request));
error.setSignature(signer.sign(error.getStringSigned()));
}
return error;
} catch (HttpException e) {
logger.warn(e, "error parsing error");
return null;
} }
return error;
}
public AWSError parseAWSErrorFromContent(HttpRequest request, HttpResponse response,
String content) {
return parseAWSErrorFromContent(request, response, new ByteArrayInputStream(content
.getBytes()));
} }
} }

View File

@ -5,6 +5,7 @@ import static org.easymock.EasyMock.reportMatcher;
import static org.easymock.classextension.EasyMock.createMock; import static org.easymock.classextension.EasyMock.createMock;
import static org.easymock.classextension.EasyMock.replay; import static org.easymock.classextension.EasyMock.replay;
import static org.easymock.classextension.EasyMock.verify; import static org.easymock.classextension.EasyMock.verify;
import static org.jclouds.aws.reference.AWSConstants.PROPERTY_HEADER_TAG;
import java.net.URI; import java.net.URI;
@ -22,6 +23,7 @@ import org.testng.annotations.Test;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
import com.google.inject.Guice; import com.google.inject.Guice;
import com.google.inject.name.Names;
/** /**
* *
@ -57,7 +59,7 @@ public class ParseAWSErrorFromXmlContentTest {
@Override @Override
protected void configure() { protected void configure() {
bind(RequestSigner.class).toInstance(createMock(RequestSigner.class)); bind(RequestSigner.class).toInstance(createMock(RequestSigner.class));
bindConstant().annotatedWith(Names.named(PROPERTY_HEADER_TAG)).to("amz");
} }
}).getInstance(ParseAWSErrorFromXmlContent.class); }).getInstance(ParseAWSErrorFromXmlContent.class);

View File

@ -0,0 +1,74 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.jclouds.aws.s3;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Properties;
import org.jclouds.aws.s3.blobstore.functions.BlobToObject;
import org.jclouds.aws.s3.filters.RequestAuthorizeSignature;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.RestContextFactory.ContextSpec;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.BeforeClass;
import com.google.inject.TypeLiteral;
public abstract class BaseS3AsyncClientTest extends RestClientTest<S3AsyncClient> {
protected BlobToObject blobToS3Object;
protected RequestAuthorizeSignature filter;
@Override
protected void checkFilters(HttpRequest request) {
assertEquals(request.getFilters().size(), 1);
assertEquals(request.getFilters().get(0).getClass(), RequestAuthorizeSignature.class);
}
@Override
protected TypeLiteral<RestAnnotationProcessor<S3AsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<S3AsyncClient>>() {
};
}
@BeforeClass
@Override
protected void setupFactory() throws IOException {
super.setupFactory();
blobToS3Object = injector.getInstance(BlobToObject.class);
filter = injector.getInstance(RequestAuthorizeSignature.class);
}
public BaseS3AsyncClientTest() {
super();
}
@Override
public ContextSpec<?, ?> createContextSpec() {
return new RestContextFactory().createContextSpec("s3", "identity", "credential",
new Properties());
}
}

View File

@ -23,10 +23,8 @@ import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Array; import java.lang.reflect.Array;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Properties;
import org.jclouds.aws.domain.Region; import org.jclouds.aws.domain.Region;
import org.jclouds.aws.s3.blobstore.functions.BlobToObject;
import org.jclouds.aws.s3.config.S3RestClientModule; import org.jclouds.aws.s3.config.S3RestClientModule;
import org.jclouds.aws.s3.domain.AccessControlList; import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.BucketLogging; import org.jclouds.aws.s3.domain.BucketLogging;
@ -36,7 +34,6 @@ import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee; import org.jclouds.aws.s3.domain.AccessControlList.EmailAddressGrantee;
import org.jclouds.aws.s3.domain.AccessControlList.Grant; import org.jclouds.aws.s3.domain.AccessControlList.Grant;
import org.jclouds.aws.s3.domain.AccessControlList.Permission; import org.jclouds.aws.s3.domain.AccessControlList.Permission;
import org.jclouds.aws.s3.filters.RequestAuthorizeSignature;
import org.jclouds.aws.s3.functions.ParseObjectFromHeadersAndHttpContent; import org.jclouds.aws.s3.functions.ParseObjectFromHeadersAndHttpContent;
import org.jclouds.aws.s3.functions.ParseObjectMetadataFromHeaders; import org.jclouds.aws.s3.functions.ParseObjectMetadataFromHeaders;
import org.jclouds.aws.s3.functions.ReturnFalseIfBucketAlreadyOwnedByYou; import org.jclouds.aws.s3.functions.ReturnFalseIfBucketAlreadyOwnedByYou;
@ -61,25 +58,19 @@ import org.jclouds.blobstore.functions.ThrowKeyNotFoundOn404;
import org.jclouds.date.TimeStamp; import org.jclouds.date.TimeStamp;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp; import org.jclouds.http.RequiresHttp;
import org.jclouds.http.functions.ReleasePayloadAndReturn;
import org.jclouds.http.functions.ParseETagHeader; import org.jclouds.http.functions.ParseETagHeader;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ReleasePayloadAndReturn;
import org.jclouds.http.functions.ReturnTrueIf2xx; import org.jclouds.http.functions.ReturnTrueIf2xx;
import org.jclouds.http.options.GetOptions; import org.jclouds.http.options.GetOptions;
import org.jclouds.rest.ConfiguresRestClient; import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.RestContextFactory.ContextSpec;
import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404; import org.jclouds.rest.functions.ReturnVoidOnNotFoundOr404;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.jclouds.util.Utils; import org.jclouds.util.Utils;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.base.Supplier; import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.inject.Module; import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/** /**
* Tests behavior of {@code S3Client} * Tests behavior of {@code S3Client}
@ -87,7 +78,7 @@ import com.google.inject.TypeLiteral;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "s3.S3ClientTest") @Test(groups = "unit", testName = "s3.S3ClientTest")
public class S3AsyncClientTest extends RestClientTest<S3AsyncClient> { public class S3AsyncClientTest extends BaseS3AsyncClientTest {
public void testAllRegions() throws SecurityException, NoSuchMethodException, IOException { public void testAllRegions() throws SecurityException, NoSuchMethodException, IOException {
Method method = S3AsyncClient.class.getMethod("putBucketInRegion", String.class, Method method = S3AsyncClient.class.getMethod("putBucketInRegion", String.class,
@ -228,8 +219,7 @@ public class S3AsyncClientTest extends RestClientTest<S3AsyncClient> {
assertRequestLineEquals(request, assertRequestLineEquals(request,
"PUT https://destinationbucket.s3.amazonaws.com/destinationObject HTTP/1.1"); "PUT https://destinationbucket.s3.amazonaws.com/destinationObject HTTP/1.1");
assertNonPayloadHeadersEqual( assertNonPayloadHeadersEqual(request,
request,
"Host: destinationbucket.s3.amazonaws.com\nx-amz-copy-source: /sourceBucket/sourceObject\n"); "Host: destinationbucket.s3.amazonaws.com\nx-amz-copy-source: /sourceBucket/sourceObject\n");
assertPayloadEquals(request, null, null, false); assertPayloadEquals(request, null, null, false);
@ -416,8 +406,7 @@ public class S3AsyncClientTest extends RestClientTest<S3AsyncClient> {
HttpRequest request = processor.createRequest(method, "EU", "bucket"); HttpRequest request = processor.createRequest(method, "EU", "bucket");
assertRequestLineEquals(request, "PUT https://bucket.s3.amazonaws.com/ HTTP/1.1"); assertRequestLineEquals(request, "PUT https://bucket.s3.amazonaws.com/ HTTP/1.1");
assertNonPayloadHeadersEqual(request, assertNonPayloadHeadersEqual(request, "Host: bucket.s3.amazonaws.com\n");
"Host: bucket.s3.amazonaws.com\n");
assertPayloadEquals( assertPayloadEquals(
request, request,
"<CreateBucketConfiguration><LocationConstraint>EU</LocationConstraint></CreateBucketConfiguration>", "<CreateBucketConfiguration><LocationConstraint>EU</LocationConstraint></CreateBucketConfiguration>",
@ -434,7 +423,7 @@ public class S3AsyncClientTest extends RestClientTest<S3AsyncClient> {
IllegalArgumentException, NoSuchMethodException, IOException { IllegalArgumentException, NoSuchMethodException, IOException {
Method method = S3AsyncClient.class.getMethod("putObject", String.class, S3Object.class, Method method = S3AsyncClient.class.getMethod("putObject", String.class, S3Object.class,
Array.newInstance(PutObjectOptions.class, 0).getClass()); PutObjectOptions[].class);
HttpRequest request = processor.createRequest(method, "bucket", blobToS3Object HttpRequest request = processor.createRequest(method, "bucket", blobToS3Object
.apply(BindBlobToMultipartFormTest.TEST_BLOB)); .apply(BindBlobToMultipartFormTest.TEST_BLOB));
@ -522,37 +511,9 @@ public class S3AsyncClientTest extends RestClientTest<S3AsyncClient> {
checkFilters(request); checkFilters(request);
} }
BlobToObject blobToS3Object;
RequestAuthorizeSignature filter;
@Override
protected void checkFilters(HttpRequest request) {
assertEquals(request.getFilters().size(), 1);
assertEquals(request.getFilters().get(0).getClass(), RequestAuthorizeSignature.class);
}
@Override
protected TypeLiteral<RestAnnotationProcessor<S3AsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<S3AsyncClient>>() {
};
}
@BeforeClass
@Override
protected void setupFactory() throws IOException {
super.setupFactory();
blobToS3Object = injector.getInstance(BlobToObject.class);
filter = injector.getInstance(RequestAuthorizeSignature.class);
}
@Override
protected Module createModule() {
return new TestS3RestClientModule();
}
@RequiresHttp @RequiresHttp
@ConfiguresRestClient @ConfiguresRestClient
private static final class TestS3RestClientModule extends S3RestClientModule { protected static final class TestS3RestClientModule extends S3RestClientModule {
@Override @Override
protected void configure() { protected void configure() {
super.configure(); super.configure();
@ -565,9 +526,8 @@ public class S3AsyncClientTest extends RestClientTest<S3AsyncClient> {
} }
@Override @Override
public ContextSpec<?, ?> createContextSpec() { protected Module createModule() {
return new RestContextFactory().createContextSpec("s3", "identity", "credential", return new TestS3RestClientModule();
new Properties());
} }
} }

View File

@ -0,0 +1,81 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.jclouds.aws.s3.binders;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_SERVICE_PATH;
import static org.jclouds.aws.s3.reference.S3Constants.PROPERTY_S3_VIRTUAL_HOST_BUCKETS;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.net.URI;
import java.util.Properties;
import org.jclouds.aws.s3.BaseS3AsyncClientTest;
import org.jclouds.http.HttpRequest;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
/**
* Tests behavior of {@code BindAsHostPrefixIfConfigured}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "s3.BindAsHostPrefixIfConfiguredTest")
public class BindAsHostPrefixIfConfiguredTest extends BaseS3AsyncClientTest {
public void testBucket() throws IOException {
HttpRequest request = new HttpRequest("GET", URI.create("http://euc/services/Walrus"));
BindAsHostPrefixIfConfigured binder = injector
.getInstance(BindAsHostPrefixIfConfigured.class);
binder.bindToRequest(request, "bucket");
assertEquals(request.getRequestLine(), "GET http://euc/services/Walrus/bucket HTTP/1.1");
}
@Test(dataProvider = "objects")
public void testObject(String key) throws InterruptedException {
HttpRequest request = new HttpRequest("GET", URI.create("http://euc/services/Walrus/object"));
BindAsHostPrefixIfConfigured binder = injector
.getInstance(BindAsHostPrefixIfConfigured.class);
binder.bindToRequest(request, "bucket");
assertEquals(request.getRequestLine(),
"GET http://euc/services/Walrus/bucket/object HTTP/1.1");
}
@DataProvider(name = "objects")
public Object[][] createData() {
return new Object[][] { { "normal" }, { "sp ace" }, { "qu?stion" }, { "unic₪de" },
{ "path/foo" }, { "colon:" }, { "asteri*k" }, { "quote\"" }, { "{great<r}" },
{ "lesst>en" }, { "p|pe" } };
}
@Override
protected Properties getProperties() {
Properties properties = new Properties();
properties.setProperty(PROPERTY_S3_SERVICE_PATH, "/services/Walrus");
properties.setProperty(PROPERTY_S3_VIRTUAL_HOST_BUCKETS, "false");
return properties;
}
}

View File

@ -23,8 +23,8 @@ import static org.testng.Assert.assertEquals;
import java.io.IOException; import java.io.IOException;
import java.net.URI; import java.net.URI;
import org.jclouds.aws.s3.BaseS3AsyncClientTest;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.BaseHandlerTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
/** /**
@ -33,7 +33,7 @@ import org.testng.annotations.Test;
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(groups = "unit", testName = "s3.BindNoBucketLoggingToXmlPayloadTest") @Test(groups = "unit", testName = "s3.BindNoBucketLoggingToXmlPayloadTest")
public class BindNoBucketLoggingToXmlPayloadTest extends BaseHandlerTest { public class BindNoBucketLoggingToXmlPayloadTest extends BaseS3AsyncClientTest {
public void testApplyInputStream() throws IOException { public void testApplyInputStream() throws IOException {
@ -41,8 +41,7 @@ public class BindNoBucketLoggingToXmlPayloadTest extends BaseHandlerTest {
BindNoBucketLoggingToXmlPayload binder = injector BindNoBucketLoggingToXmlPayload binder = injector
.getInstance(BindNoBucketLoggingToXmlPayload.class); .getInstance(BindNoBucketLoggingToXmlPayload.class);
binder.bindToRequest(request, null); binder.bindToRequest(request, "bucket");
assertEquals(request.getPayload().getContentType(), "text/xml");
assertEquals(request.getPayload().getRawContent(), assertEquals(request.getPayload().getRawContent(),
"<BucketLoggingStatus xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"/>"); "<BucketLoggingStatus xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"/>");

View File

@ -18,43 +18,33 @@
*/ */
package org.jclouds.aws.s3.filters; package org.jclouds.aws.s3.filters;
import static org.jclouds.Constants.PROPERTY_SESSION_INTERVAL;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.net.URI;
import java.util.Properties; import java.util.Properties;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import org.jclouds.Constants; import org.jclouds.aws.s3.BaseS3AsyncClientTest;
import org.jclouds.aws.s3.S3AsyncClient;
import org.jclouds.aws.s3.domain.AccessControlList;
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
import org.jclouds.aws.s3.domain.S3Object;
import org.jclouds.aws.s3.options.PutObjectOptions;
import org.jclouds.blobstore.binders.BindBlobToMultipartFormTest;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.logging.config.NullLoggingModule; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.BaseRestClientTest.MockModule;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider; import org.testng.annotations.DataProvider;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Injector;
@Test(groups = "unit", testName = "s3.RequestAuthorizeSignatureTest") @Test(groups = "unit", testName = "s3.RequestAuthorizeSignatureTest")
public class RequestAuthorizeSignatureTest { public class RequestAuthorizeSignatureTest extends BaseS3AsyncClientTest {
private RequestAuthorizeSignature filter;
@DataProvider(parallel = true) @DataProvider(parallel = true)
public Object[][] dataProvider() { public Object[][] dataProvider() throws NoSuchMethodException {
return new Object[][] { return new Object[][] { { listOwnedBuckets() }, { putObject() }, { putBucketAcl() }
{ new HttpRequest(HttpMethod.GET, URI.create("http://s3.amazonaws.com:80")) },
{ new HttpRequest(
HttpMethod.GET,
URI
.create("http://adriancole.s3int5.s3-external-3.amazonaws.com:80/testObject")) },
{ new HttpRequest(HttpMethod.GET, URI.create("http://s3.amazonaws.com:80/?acl"))
} }; };
} }
/** /**
@ -62,7 +52,7 @@ public class RequestAuthorizeSignatureTest {
* this was once per second. If this timestamp update interval is increased, it could make this * this was once per second. If this timestamp update interval is increased, it could make this
* test appear to hang for a long time. * test appear to hang for a long time.
*/ */
@Test(threadPoolSize = 3, dataProvider = "dataProvider", timeOut = 3000) @Test(threadPoolSize = 3, dataProvider = "dataProvider", timeOut = 10000)
void testIdempotent(HttpRequest request) { void testIdempotent(HttpRequest request) {
filter.filter(request); filter.filter(request);
String signature = request.getFirstHeaderOrNull(HttpHeaders.AUTHORIZATION); String signature = request.getFirstHeaderOrNull(HttpHeaders.AUTHORIZATION);
@ -84,70 +74,69 @@ public class RequestAuthorizeSignatureTest {
} }
@Test @Test
void testAppendBucketNameHostHeader() { void testAppendBucketNameHostHeader() throws SecurityException, NoSuchMethodException {
URI host = URI.create("http://s3.amazonaws.com:80"); HttpRequest request = processor.createRequest(S3AsyncClient.class.getMethod(
HttpRequest request = new HttpRequest(HttpMethod.GET, host); "getBucketLocation", String.class), "bucket");
request.getHeaders().put(HttpHeaders.HOST, "adriancole.s3int5.s3.amazonaws.com");
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
filter.appendBucketName(request, builder); filter.appendBucketName(request, builder);
assertEquals(builder.toString(), "/adriancole.s3int5"); assertEquals(builder.toString(), "/bucket");
} }
@Test @Test
void testAclQueryString() { void testAclQueryString() throws SecurityException, NoSuchMethodException {
URI host = URI.create("http://s3.amazonaws.com:80/?acl"); HttpRequest request = putBucketAcl();
HttpRequest request = new HttpRequest(HttpMethod.GET, host);
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
filter.appendUriPath(request, builder); filter.appendUriPath(request, builder);
assertEquals(builder.toString(), "/?acl"); assertEquals(builder.toString(), "/?acl");
} }
private GeneratedHttpRequest<S3AsyncClient> putBucketAcl() throws NoSuchMethodException {
return processor.createRequest(S3AsyncClient.class.getMethod("putBucketACL", String.class,
AccessControlList.class), "bucket", AccessControlList.fromCannedAccessPolicy(
CannedAccessPolicy.PRIVATE, "1234"));
}
// "?acl", "?location", "?logging", or "?torrent" // "?acl", "?location", "?logging", or "?torrent"
@Test @Test
void testAppendBucketNameHostHeaderService() { void testAppendBucketNameHostHeaderService() throws SecurityException, NoSuchMethodException {
URI host = URI.create("http://s3.amazonaws.com:80"); HttpRequest request = listOwnedBuckets();
HttpRequest request = new HttpRequest(HttpMethod.GET, host);
request.getHeaders().put(HttpHeaders.HOST, "s3.amazonaws.com");
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
filter.appendBucketName(request, builder); filter.appendBucketName(request, builder);
assertEquals(builder.toString(), ""); assertEquals(builder.toString(), "");
} }
@Test private GeneratedHttpRequest<S3AsyncClient> listOwnedBuckets() throws NoSuchMethodException {
void testHeadersGoLowercase() { return processor.createRequest(S3AsyncClient.class.getMethod("listOwnedBuckets"));
URI host = URI.create("http://s3.amazonaws.com:80");
HttpRequest request = new HttpRequest(HttpMethod.GET, host);
request.getHeaders().put("x-amz-adrian", "s3.amazonaws.com");
StringBuilder builder = new StringBuilder();
filter.appendBucketName(request, builder);
assertEquals(builder.toString(), "");
} }
@Test @Test
void testAppendBucketNameURIHost() { void testHeadersGoLowercase() throws SecurityException, NoSuchMethodException {
URI host = URI.create("http://adriancole.s3int5.s3-external-3.amazonaws.com:80"); HttpRequest request = putObject();
HttpRequest request = new HttpRequest(HttpMethod.GET, host);
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
filter.appendBucketName(request, builder); filter.appendAmzHeaders(request, builder);
assertEquals(builder.toString(), "/adriancole.s3int5"); assertEquals(builder.toString(), "x-amz-meta-x-amz-adrian:foo\n");
} }
/** private HttpRequest putObject() throws NoSuchMethodException {
* before class, as we need to ensure that the filter is threadsafe. S3Object object = blobToS3Object.apply(BindBlobToMultipartFormTest.TEST_BLOB);
*
* @throws IOException
*
*/
@BeforeClass
protected void createFilter() throws IOException {
Properties overrides = new Properties();
overrides.setProperty(Constants.PROPERTY_SESSION_INTERVAL, "1");
Injector injector = new RestContextFactory().createContextBuilder("s3", "foo", "bar",
ImmutableSet.of(new MockModule(), new NullLoggingModule()), overrides)
.buildInjector();
filter = injector.getInstance(RequestAuthorizeSignature.class); object.getMetadata().getUserMetadata().put("x-amz-Adrian", "foo");
HttpRequest request = processor.createRequest(S3AsyncClient.class.getMethod("putObject",
String.class, S3Object.class, PutObjectOptions[].class), "bucket", object);
return request;
} }
@Test
void testAppendBucketNameURIHost() throws SecurityException, NoSuchMethodException {
HttpRequest request = processor.createRequest(S3AsyncClient.class.getMethod(
"getBucketLocation", String.class), "bucket");
assertEquals(request.getEndpoint().getHost(), "bucket.s3.amazonaws.com");
}
protected Properties getProperties() {
Properties overrides= new Properties();
overrides.setProperty(PROPERTY_SESSION_INTERVAL, 1 + "");
return overrides;
}
} }

View File

@ -32,7 +32,6 @@ import org.jclouds.aws.s3.blobstore.functions.BlobToObjectMetadata;
import org.jclouds.aws.s3.domain.MutableObjectMetadata; import org.jclouds.aws.s3.domain.MutableObjectMetadata;
import org.jclouds.aws.s3.domain.ObjectMetadata.StorageClass; import org.jclouds.aws.s3.domain.ObjectMetadata.StorageClass;
import org.jclouds.aws.s3.domain.internal.MutableObjectMetadataImpl; import org.jclouds.aws.s3.domain.internal.MutableObjectMetadataImpl;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.blobstore.domain.MutableBlobMetadata; import org.jclouds.blobstore.domain.MutableBlobMetadata;
import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl; import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
import org.jclouds.blobstore.functions.ParseSystemAndUserMetadataFromHeaders; import org.jclouds.blobstore.functions.ParseSystemAndUserMetadataFromHeaders;
@ -61,7 +60,7 @@ public class ParseObjectMetadataFromHeadersTest {
http.getHeaders().put("Content-Disposition", "contentDisposition"); http.getHeaders().put("Content-Disposition", "contentDisposition");
http.getHeaders().put(HttpHeaders.CONTENT_ENCODING, "encoding"); http.getHeaders().put(HttpHeaders.CONTENT_ENCODING, "encoding");
ParseObjectMetadataFromHeaders parser = new ParseObjectMetadataFromHeaders(blobParser(http, ParseObjectMetadataFromHeaders parser = new ParseObjectMetadataFromHeaders(blobParser(http,
"\"abc\""), blobToObjectMetadata, encryptionService); "\"abc\""), blobToObjectMetadata, encryptionService, "x-amz-meta-");
MutableObjectMetadata response = parser.apply(http); MutableObjectMetadata response = parser.apply(http);
assertEquals(response, expects); assertEquals(response, expects);
} }
@ -75,9 +74,9 @@ public class ParseObjectMetadataFromHeadersTest {
http.getHeaders().put(HttpHeaders.CACHE_CONTROL, "cacheControl"); http.getHeaders().put(HttpHeaders.CACHE_CONTROL, "cacheControl");
http.getHeaders().put("Content-Disposition", "contentDisposition"); http.getHeaders().put("Content-Disposition", "contentDisposition");
http.getHeaders().put(HttpHeaders.CONTENT_ENCODING, "encoding"); http.getHeaders().put(HttpHeaders.CONTENT_ENCODING, "encoding");
http.getHeaders().put(S3Headers.AMZ_MD5, "\"abc\""); http.getHeaders().put("x-amz-meta-object-eTag", "\"abc\"");
ParseObjectMetadataFromHeaders parser = new ParseObjectMetadataFromHeaders(blobParser(http, ParseObjectMetadataFromHeaders parser = new ParseObjectMetadataFromHeaders(blobParser(http,
null), blobToObjectMetadata, encryptionService); null), blobToObjectMetadata, encryptionService, "x-amz-meta-");
MutableObjectMetadata response = parser.apply(http); MutableObjectMetadata response = parser.apply(http);
assertEquals(response, expects); assertEquals(response, expects);
} }

View File

@ -70,6 +70,7 @@ public class CopyObjectOptionsTest {
void testGoodMetaStatic() { void testGoodMetaStatic() {
CopyObjectOptions options = overrideMetadataWith(goodMeta); CopyObjectOptions options = overrideMetadataWith(goodMeta);
options.setMetadataPrefix("x-amz-meta-"); options.setMetadataPrefix("x-amz-meta-");
options.setHeaderTag("amz");
assertGoodMeta(options); assertGoodMeta(options);
} }
@ -92,6 +93,7 @@ public class CopyObjectOptionsTest {
@Test @Test
void testGoodMeta() { void testGoodMeta() {
CopyObjectOptions options = new CopyObjectOptions(); CopyObjectOptions options = new CopyObjectOptions();
options.setHeaderTag("amz");
options.setMetadataPrefix("x-amz-meta-"); options.setMetadataPrefix("x-amz-meta-");
options.overrideMetadataWith(goodMeta); options.overrideMetadataWith(goodMeta);
assertGoodMeta(options); assertGoodMeta(options);
@ -269,6 +271,8 @@ public class CopyObjectOptionsTest {
@Test @Test
void testBuildRequestHeadersWhenMetadataNull() throws UnsupportedEncodingException { void testBuildRequestHeadersWhenMetadataNull() throws UnsupportedEncodingException {
CopyObjectOptions options = new CopyObjectOptions(); CopyObjectOptions options = new CopyObjectOptions();
options.setHeaderTag("amz");
options.setMetadataPrefix("x-amz-meta-"); options.setMetadataPrefix("x-amz-meta-");
assert options.buildRequestHeaders() != null; assert options.buildRequestHeaders() != null;
} }
@ -277,6 +281,8 @@ public class CopyObjectOptionsTest {
void testBuildRequestHeaders() throws UnsupportedEncodingException { void testBuildRequestHeaders() throws UnsupportedEncodingException {
CopyObjectOptions options = ifSourceModifiedSince(now).ifSourceETagDoesntMatch(etag) CopyObjectOptions options = ifSourceModifiedSince(now).ifSourceETagDoesntMatch(etag)
.overrideMetadataWith(goodMeta); .overrideMetadataWith(goodMeta);
options.setHeaderTag("amz");
options.setMetadataPrefix("x-amz-meta-"); options.setMetadataPrefix("x-amz-meta-");
Multimap<String, String> headers = options.buildRequestHeaders(); Multimap<String, String> headers = options.buildRequestHeaders();
@ -304,6 +310,8 @@ public class CopyObjectOptionsTest {
@Test @Test
void testBuildRequestHeadersACL() throws UnsupportedEncodingException { void testBuildRequestHeadersACL() throws UnsupportedEncodingException {
CopyObjectOptions options = overrideAcl(CannedAccessPolicy.AUTHENTICATED_READ); CopyObjectOptions options = overrideAcl(CannedAccessPolicy.AUTHENTICATED_READ);
options.setHeaderTag("amz");
options.setMetadataPrefix("x-amz-meta-"); options.setMetadataPrefix("x-amz-meta-");
Multimap<String, String> headers = options.buildRequestHeaders(); Multimap<String, String> headers = options.buildRequestHeaders();

View File

@ -52,8 +52,10 @@ public class PutBucketOptionsTest {
@Test @Test
void testBuildRequestHeaders() throws UnsupportedEncodingException { void testBuildRequestHeaders() throws UnsupportedEncodingException {
Multimap<String, String> headers = withBucketAcl(CannedAccessPolicy.AUTHENTICATED_READ) PutBucketOptions options = withBucketAcl(CannedAccessPolicy.AUTHENTICATED_READ);
.buildRequestHeaders();
options.setHeaderTag("amz");
Multimap<String, String> headers = options.buildRequestHeaders();
assertEquals(headers.get(S3Headers.CANNED_ACL).iterator().next(), assertEquals(headers.get(S3Headers.CANNED_ACL).iterator().next(),
CannedAccessPolicy.AUTHENTICATED_READ.toString()); CannedAccessPolicy.AUTHENTICATED_READ.toString());
} }

View File

@ -18,18 +18,17 @@
*/ */
package org.jclouds.aws.s3.options; package org.jclouds.aws.s3.options;
import com.google.common.collect.Multimap;
import static org.jclouds.aws.s3.options.PutObjectOptions.Builder.withAcl; import static org.jclouds.aws.s3.options.PutObjectOptions.Builder.withAcl;
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
import org.jclouds.aws.s3.options.PutObjectOptions;
import org.jclouds.aws.s3.reference.S3Headers;
import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertEquals;
import org.testng.annotations.Test;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import org.jclouds.aws.s3.domain.CannedAccessPolicy;
import org.jclouds.aws.s3.reference.S3Headers;
import org.testng.annotations.Test;
import com.google.common.collect.Multimap;
/** /**
* Tests possible uses of PutObjectOptions and PutObjectOptions.Builder.* * Tests possible uses of PutObjectOptions and PutObjectOptions.Builder.*
* *
@ -38,24 +37,26 @@ import java.io.UnsupportedEncodingException;
@Test(groups = "unit", testName = "s3.PutObjectOptionsTest") @Test(groups = "unit", testName = "s3.PutObjectOptionsTest")
public class PutObjectOptionsTest { public class PutObjectOptionsTest {
@Test @Test
public void testAclDefault() { public void testAclDefault() {
PutObjectOptions options = new PutObjectOptions(); PutObjectOptions options = new PutObjectOptions();
assertEquals(options.getAcl(), CannedAccessPolicy.PRIVATE); assertEquals(options.getAcl(), CannedAccessPolicy.PRIVATE);
} }
@Test @Test
public void testAclStatic() { public void testAclStatic() {
PutObjectOptions options = withAcl(CannedAccessPolicy.AUTHENTICATED_READ); PutObjectOptions options = withAcl(CannedAccessPolicy.AUTHENTICATED_READ);
assertEquals(options.getAcl(), CannedAccessPolicy.AUTHENTICATED_READ); assertEquals(options.getAcl(), CannedAccessPolicy.AUTHENTICATED_READ);
} }
@Test @Test
void testBuildRequestHeaders() throws UnsupportedEncodingException { void testBuildRequestHeaders() throws UnsupportedEncodingException {
Multimap<String, String> headers = withAcl( PutObjectOptions options = withAcl(CannedAccessPolicy.AUTHENTICATED_READ);
CannedAccessPolicy.AUTHENTICATED_READ).buildRequestHeaders(); options.setHeaderTag("amz");
assertEquals(headers.get(S3Headers.CANNED_ACL).iterator().next(),
CannedAccessPolicy.AUTHENTICATED_READ.toString()); Multimap<String, String> headers = options.buildRequestHeaders();
} assertEquals(headers.get(S3Headers.CANNED_ACL).iterator().next(),
CannedAccessPolicy.AUTHENTICATED_READ.toString());
}
} }

View File

@ -16,7 +16,7 @@
* limitations under the License. * limitations under the License.
* ==================================================================== * ====================================================================
*/ */
package org.jclouds.aws.s3.util; package org.jclouds.aws.util;
import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expect;
import static org.easymock.classextension.EasyMock.createMock; import static org.easymock.classextension.EasyMock.createMock;
@ -28,16 +28,13 @@ import java.io.InputStream;
import java.util.Properties; import java.util.Properties;
import org.jclouds.aws.domain.AWSError; import org.jclouds.aws.domain.AWSError;
import org.jclouds.aws.s3.reference.S3Headers;
import org.jclouds.http.HttpCommand; import org.jclouds.http.HttpCommand;
import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.http.Payloads; import org.jclouds.http.Payloads;
import org.jclouds.logging.config.NullLoggingModule; import org.jclouds.logging.config.NullLoggingModule;
import org.jclouds.rest.RestContextFactory; import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.BaseRestClientTest.MockModule; import org.jclouds.rest.BaseRestClientTest.MockModule;
import org.jclouds.util.Utils;
import org.testng.annotations.AfterTest; import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeTest; import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
@ -50,10 +47,9 @@ import com.google.inject.Injector;
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
@Test(sequential = true, groups = { "unit" }, testName = "s3.S3UtilsTest") @Test(sequential = true, groups = { "unit" }, testName = "aws.AWSUtilsTest")
public class S3UtilsTest { public class AWSUtilsTest {
S3Utils utils = null; AWSUtils utils = null;
private HttpResponse response;
private HttpCommand command; private HttpCommand command;
@BeforeTest @BeforeTest
@ -63,10 +59,8 @@ public class S3UtilsTest {
ImmutableSet.of(new MockModule(), new NullLoggingModule()), new Properties()) ImmutableSet.of(new MockModule(), new NullLoggingModule()), new Properties())
.buildInjector(); .buildInjector();
utils = injector.getInstance(S3Utils.class); utils = injector.getInstance(AWSUtils.class);
response = new HttpResponse(400, "boa", Payloads.newStringPayload(""));
response.getHeaders().put(S3Headers.REQUEST_ID, "requestid");
response.getHeaders().put(S3Headers.REQUEST_TOKEN, "requesttoken");
command = createMock(HttpCommand.class); command = createMock(HttpCommand.class);
expect(command.getRequest()).andReturn(createMock(HttpRequest.class)).atLeastOnce(); expect(command.getRequest()).andReturn(createMock(HttpRequest.class)).atLeastOnce();
replay(command); replay(command);
@ -77,14 +71,17 @@ public class S3UtilsTest {
utils = null; utils = null;
} }
@Test HttpResponse response(InputStream content) {
public void testParseAWSErrorFromContentHttpCommandHttpResponseInputStream() { HttpResponse response = new HttpResponse(400, "boa", Payloads.newInputStreamPayload(content));
InputStream content = getClass().getResourceAsStream("/error.xml"); response.getHeaders().put("x-amz-request-id", "requestid");
AWSError error = utils.parseAWSErrorFromContent(command, response, content); response.getHeaders().put("x-amz-id-2", "requesttoken");
validate(error); return response;
} }
private void validate(AWSError error) { @Test
public void testParseAWSErrorFromContentHttpCommandHttpResponseInputStream() {
AWSError error = utils.parseAWSErrorFromContent(command.getRequest(), response(getClass()
.getResourceAsStream("/error.xml")));
assertEquals(error.getCode(), "NoSuchKey"); assertEquals(error.getCode(), "NoSuchKey");
assertEquals(error.getMessage(), "The resource you requested does not exist"); assertEquals(error.getMessage(), "The resource you requested does not exist");
assertEquals(error.getRequestToken(), "requesttoken"); assertEquals(error.getRequestToken(), "requesttoken");
@ -92,15 +89,6 @@ public class S3UtilsTest {
assertEquals(error.getDetails().get("Resource"), "/mybucket/myfoto.jpg"); assertEquals(error.getDetails().get("Resource"), "/mybucket/myfoto.jpg");
} }
@Test
public void testParseAWSErrorFromContentHttpCommandHttpResponseString() throws HttpException,
IOException {
InputStream content = getClass().getResourceAsStream("/error.xml");
AWSError error = utils.parseAWSErrorFromContent(command, response, Utils
.toStringAndClose(content));
validate(error);
}
@Test @Test
public void testValidateBucketName() { public void testValidateBucketName() {
// TODO // TODO

View File

@ -144,7 +144,7 @@
<category name="jclouds.wire"> <category name="jclouds.wire">
<priority value="DEBUG" /> <priority value="DEBUG" />
<appender-ref ref="ASYNCWIRE" /> <appender-ref ref="ASYNCWIRE" />
</category> </category><!--
<category name="jclouds.signature"> <category name="jclouds.signature">
<priority value="DEBUG" /> <priority value="DEBUG" />
@ -152,7 +152,7 @@
</category> </category>
<!-- ======================= --> --><!-- ======================= -->
<!-- Setup the Root category --> <!-- Setup the Root category -->
<!-- ======================= --> <!-- ======================= -->

View File

@ -23,9 +23,9 @@ import javax.inject.Singleton;
import org.jclouds.azure.storage.blob.domain.AzureBlob; import org.jclouds.azure.storage.blob.domain.AzureBlob;
import org.jclouds.azure.storage.blob.domain.MutableBlobProperties; import org.jclouds.azure.storage.blob.domain.MutableBlobProperties;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -57,8 +57,10 @@ public class ParseBlobFromHeadersAndHttpContent implements Function<HttpResponse
return blob; return blob;
} }
public void setContext(GeneratedHttpRequest<?> request) { @Override
public ParseBlobFromHeadersAndHttpContent setContext(HttpRequest request) {
metadataParser.setContext(request); metadataParser.setContext(request);
return this;
} }
} }

View File

@ -27,9 +27,9 @@ import org.jclouds.azure.storage.blob.blobstore.functions.BlobMetadataToBlobProp
import org.jclouds.azure.storage.blob.domain.MutableBlobProperties; import org.jclouds.azure.storage.blob.domain.MutableBlobProperties;
import org.jclouds.blobstore.domain.BlobMetadata; import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.functions.ParseSystemAndUserMetadataFromHeaders; import org.jclouds.blobstore.functions.ParseSystemAndUserMetadataFromHeaders;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -64,8 +64,10 @@ public class ParseBlobPropertiesFromHeaders implements
return to; return to;
} }
public void setContext(GeneratedHttpRequest<?> request) { @Override
public ParseBlobPropertiesFromHeaders setContext(HttpRequest request) {
blobMetadataParser.setContext(request); blobMetadataParser.setContext(request);
return this;
} }
} }

View File

@ -18,6 +18,8 @@
*/ */
package org.jclouds.azure.storage.blob.functions; package org.jclouds.azure.storage.blob.functions;
import static com.google.common.base.Preconditions.checkArgument;
import java.util.Map.Entry; import java.util.Map.Entry;
import javax.inject.Inject; import javax.inject.Inject;
@ -30,6 +32,7 @@ import org.jclouds.azure.storage.blob.domain.internal.MutableContainerProperties
import org.jclouds.blobstore.reference.BlobStoreConstants; import org.jclouds.blobstore.reference.BlobStoreConstants;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
@ -99,8 +102,12 @@ public class ParseContainerPropertiesFromHeaders implements
} }
} }
public void setContext(GeneratedHttpRequest<?> request) { @Override
this.request = request; public ParseContainerPropertiesFromHeaders setContext(HttpRequest request) {
checkArgument(request instanceof GeneratedHttpRequest<?>,
"note this handler requires a GeneratedHttpRequest");
this.request = (GeneratedHttpRequest<?>) request;
return this;
} }
} }

View File

@ -18,11 +18,13 @@
*/ */
package org.jclouds.blobstore.functions; package org.jclouds.blobstore.functions;
import static com.google.common.base.Preconditions.checkArgument;
import static org.jclouds.util.Utils.propagateOrNull; import static org.jclouds.util.Utils.propagateOrNull;
import org.jclouds.blobstore.BlobStore; import org.jclouds.blobstore.BlobStore;
import org.jclouds.blobstore.internal.BlobRuntimeException; import org.jclouds.blobstore.internal.BlobRuntimeException;
import org.jclouds.blobstore.strategy.ClearContainerStrategy; import org.jclouds.blobstore.strategy.ClearContainerStrategy;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
@ -64,8 +66,12 @@ public class ClearAndDeleteIfNotEmpty implements Function<Exception, Void>, Invo
return Void.class.cast(propagateOrNull(from)); return Void.class.cast(propagateOrNull(from));
} }
public void setContext(GeneratedHttpRequest<?> request) { @Override
this.request = request; public ClearAndDeleteIfNotEmpty setContext(HttpRequest request) {
checkArgument(request instanceof GeneratedHttpRequest<?>,
"note this handler requires a GeneratedHttpRequest");
this.request = (GeneratedHttpRequest<?>) request;
return this;
} }
} }

View File

@ -22,9 +22,9 @@ import javax.inject.Inject;
import org.jclouds.blobstore.domain.Blob; import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.MutableBlobMetadata; import org.jclouds.blobstore.domain.MutableBlobMetadata;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -54,8 +54,10 @@ public class ParseBlobFromHeadersAndHttpContent implements Function<HttpResponse
return object; return object;
} }
public void setContext(GeneratedHttpRequest<?> request) { @Override
public ParseBlobFromHeadersAndHttpContent setContext(HttpRequest request) {
metadataParser.setContext(request); metadataParser.setContext(request);
return this;
} }
} }

View File

@ -18,6 +18,8 @@
*/ */
package org.jclouds.blobstore.functions; package org.jclouds.blobstore.functions;
import static com.google.common.base.Preconditions.checkArgument;
import static org.jclouds.Constants.PROPERTY_API_VERSION;
import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX; import static org.jclouds.blobstore.reference.BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX;
import static org.jclouds.blobstore.util.BlobStoreUtils.getKeyFor; import static org.jclouds.blobstore.util.BlobStoreUtils.getKeyFor;
import static org.jclouds.http.HttpUtils.attemptToParseSizeAndRangeFromHeaders; import static org.jclouds.http.HttpUtils.attemptToParseSizeAndRangeFromHeaders;
@ -32,6 +34,7 @@ import javax.ws.rs.core.HttpHeaders;
import org.jclouds.blobstore.domain.MutableBlobMetadata; import org.jclouds.blobstore.domain.MutableBlobMetadata;
import org.jclouds.date.DateService; import org.jclouds.date.DateService;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
@ -47,14 +50,18 @@ public class ParseSystemAndUserMetadataFromHeaders implements
private final String metadataPrefix; private final String metadataPrefix;
private final DateService dateParser; private final DateService dateParser;
private final Provider<MutableBlobMetadata> metadataFactory; private final Provider<MutableBlobMetadata> metadataFactory;
private final String apiVersion;
private GeneratedHttpRequest<?> request; private GeneratedHttpRequest<?> request;
@Inject @Inject
public ParseSystemAndUserMetadataFromHeaders(Provider<MutableBlobMetadata> metadataFactory, public ParseSystemAndUserMetadataFromHeaders(Provider<MutableBlobMetadata> metadataFactory,
DateService dateParser, @Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix) { DateService dateParser, @Named(PROPERTY_USER_METADATA_PREFIX) String metadataPrefix,
@Named(PROPERTY_API_VERSION) String apiVersion) {
this.metadataFactory = metadataFactory; this.metadataFactory = metadataFactory;
this.dateParser = dateParser; this.dateParser = dateParser;
this.metadataPrefix = metadataPrefix; this.metadataPrefix = metadataPrefix;
this.apiVersion = apiVersion;
} }
public MutableBlobMetadata apply(HttpResponse from) { public MutableBlobMetadata apply(HttpResponse from) {
@ -92,7 +99,13 @@ public class ParseSystemAndUserMetadataFromHeaders implements
if (lastModified == null) if (lastModified == null)
throw new HttpException(HttpHeaders.LAST_MODIFIED + " header not present in response: " throw new HttpException(HttpHeaders.LAST_MODIFIED + " header not present in response: "
+ from.getStatusLine()); + from.getStatusLine());
metadata.setLastModified(dateParser.rfc822DateParse(lastModified)); // Eucalyptus 1.6 returns iso8601 dates
if (apiVersion.indexOf("Walrus-1.6") != -1) {
metadata.setLastModified(dateParser.iso8601DateParse(lastModified.replace("+0000", "Z")));
} else {
metadata.setLastModified(dateParser.rfc822DateParse(lastModified));
}
if (metadata.getLastModified() == null) if (metadata.getLastModified() == null)
throw new HttpException("could not parse: " + HttpHeaders.LAST_MODIFIED + ": " throw new HttpException("could not parse: " + HttpHeaders.LAST_MODIFIED + ": "
+ lastModified); + lastModified);
@ -122,7 +135,10 @@ public class ParseSystemAndUserMetadataFromHeaders implements
throw new HttpException(HttpHeaders.CONTENT_TYPE + " not found in headers"); throw new HttpException(HttpHeaders.CONTENT_TYPE + " not found in headers");
} }
public void setContext(GeneratedHttpRequest<?> request) { public ParseSystemAndUserMetadataFromHeaders setContext(HttpRequest request) {
this.request = request; checkArgument(request instanceof GeneratedHttpRequest<?>,
"note this handler requires a GeneratedHttpRequest");
this.request = (GeneratedHttpRequest<?>) request;
return this;
} }
} }

View File

@ -58,7 +58,7 @@ public class ParseBlobMetadataFromHeadersTest {
void setUp() { void setUp() {
parser = new ParseSystemAndUserMetadataFromHeaders(blobMetadataProvider, parser = new ParseSystemAndUserMetadataFromHeaders(blobMetadataProvider,
new SimpleDateFormatDateService(), "prefix"); new SimpleDateFormatDateService(), "prefix", "default");
GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class); GeneratedHttpRequest<?> request = createMock(GeneratedHttpRequest.class);
expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes(); expect(request.getEndpoint()).andReturn(URI.create("http://localhost/key")).anyTimes();

View File

@ -487,8 +487,8 @@ public class HttpUtils {
return formBuilder.toString(); return formBuilder.toString();
} }
public void setPayloadPropertiesFromHeaders(Multimap<String, String> headers, HttpMessage request) { public void setPayloadPropertiesFromHeaders(Multimap<String, String> headers, HttpMessage message) {
Payload payload = request.getPayload(); Payload payload = message.getPayload();
boolean chunked = any(headers.entries(), new Predicate<Entry<String, String>>() { boolean chunked = any(headers.entries(), new Predicate<Entry<String, String>>() {
@Override @Override
public boolean apply(Entry<String, String> input) { public boolean apply(Entry<String, String> input) {
@ -508,32 +508,32 @@ public class HttpUtils {
if (payload != null) if (payload != null)
payload.setContentType(header.getValue()); payload.setContentType(header.getValue());
} else { } else {
request.getHeaders().put(header.getKey(), header.getValue()); message.getHeaders().put(header.getKey(), header.getValue());
} }
} }
String contentRange = request.getFirstHeaderOrNull("Content-Range"); if (message instanceof HttpRequest) {
if (contentRange != null) { checkArgument(
payload.setContentLength(Long.parseLong(contentRange.substring(0, contentRange message.getPayload() == null
.lastIndexOf('/')))); || message.getFirstHeaderOrNull(CONTENT_TYPE) == null,
"configuration error please use request.getPayload().setContentType(value) as opposed to adding a content type header: "
+ message);
checkArgument(
message.getPayload() == null
|| message.getFirstHeaderOrNull(CONTENT_LENGTH) == null,
"configuration error please use request.getPayload().setContentLength(value) as opposed to adding a content length header: "
+ message);
checkArgument(message.getPayload() == null
|| message.getPayload().getContentLength() != null
|| "chunked".equalsIgnoreCase(message.getFirstHeaderOrNull("Transfer-Encoding")),
"either chunked encoding must be set on the http request or contentlength set on the payload: "
+ message);
checkArgument(
message.getPayload() == null
|| message.getFirstHeaderOrNull("Content-MD5") == null,
"configuration error please use request.getPayload().setContentMD5(value) as opposed to adding a content md5 header: "
+ message);
} }
checkArgument(
request.getPayload() == null || request.getFirstHeaderOrNull(CONTENT_TYPE) == null,
"configuration error please use request.getPayload().setContentType(value) as opposed to adding a content type header: "
+ request);
checkArgument(
request.getPayload() == null || request.getFirstHeaderOrNull(CONTENT_LENGTH) == null,
"configuration error please use request.getPayload().setContentLength(value) as opposed to adding a content length header: "
+ request);
checkArgument(request.getPayload() == null || request.getPayload().getContentLength() != null
|| "chunked".equalsIgnoreCase(request.getFirstHeaderOrNull("Transfer-Encoding")),
"either chunked encoding must be set on the http request or contentlength set on the payload: "
+ request);
checkArgument(
request.getPayload() == null || request.getFirstHeaderOrNull("Content-MD5") == null,
"configuration error please use request.getPayload().setContentMD5(value) as opposed to adding a content md5 header: "
+ request);
} }
public static void releasePayload(HttpResponse from) { public static void releasePayload(HttpResponse from) {

View File

@ -22,10 +22,10 @@ import static org.jclouds.http.HttpUtils.releasePayload;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -38,16 +38,16 @@ public class ParseContentMD5FromHeaders implements Function<HttpResponse, byte[]
public static class NoContentMD5Exception extends RuntimeException { public static class NoContentMD5Exception extends RuntimeException {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final GeneratedHttpRequest<?> request; private final HttpRequest request;
private final HttpResponse response; private final HttpResponse response;
public NoContentMD5Exception(GeneratedHttpRequest<?> request, HttpResponse response) { public NoContentMD5Exception(HttpRequest request, HttpResponse response) {
super(String.format("no MD5 returned from request: %s; response %s", request, response)); super(String.format("no MD5 returned from request: %s; response %s", request, response));
this.request = request; this.request = request;
this.response = response; this.response = response;
} }
public GeneratedHttpRequest<?> getRequest() { public HttpRequest getRequest() {
return request; return request;
} }
@ -59,7 +59,7 @@ public class ParseContentMD5FromHeaders implements Function<HttpResponse, byte[]
@Resource @Resource
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private GeneratedHttpRequest<?> request; private HttpRequest request;
public byte[] apply(HttpResponse from) { public byte[] apply(HttpResponse from) {
releasePayload(from); releasePayload(from);
@ -69,8 +69,10 @@ public class ParseContentMD5FromHeaders implements Function<HttpResponse, byte[]
throw new NoContentMD5Exception(request, from); throw new NoContentMD5Exception(request, from);
} }
public void setContext(GeneratedHttpRequest<?> request) { @Override
public ParseContentMD5FromHeaders setContext(HttpRequest request) {
this.request = request; this.request = request;
return this;
} }
} }

View File

@ -18,40 +18,43 @@
*/ */
package org.jclouds.http.functions; package org.jclouds.http.functions;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Throwables.propagate;
import static com.google.common.io.Closeables.closeQuietly;
import java.io.InputStream; import java.io.InputStream;
import java.io.StringReader;
import javax.annotation.Resource; import javax.annotation.Resource;
import javax.inject.Inject; import javax.inject.Inject;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.logging.Logger; import org.jclouds.logging.Logger;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.util.Utils;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
import org.xml.sax.XMLReader; import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.DefaultHandler;
import com.google.common.base.Function; import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.io.Closeables;
/** /**
* This object will parse the body of an HttpResponse and return the result of * This object will parse the body of an HttpResponse and return the result of type <T> back to the
* type <T> back to the caller. * caller.
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public class ParseSax<T> implements Function<HttpResponse, T>, public class ParseSax<T> implements Function<HttpResponse, T>, InvocationContext {
InvocationContext {
private final XMLReader parser; private final XMLReader parser;
private final HandlerWithResult<T> handler; private final HandlerWithResult<T> handler;
@Resource @Resource
protected Logger logger = Logger.NULL; protected Logger logger = Logger.NULL;
private GeneratedHttpRequest<?> request; private HttpRequest request;
public static interface Factory { public static interface Factory {
<T> ParseSax<T> create(HandlerWithResult<T> handler); <T> ParseSax<T> create(HandlerWithResult<T> handler);
@ -63,34 +66,67 @@ public class ParseSax<T> implements Function<HttpResponse, T>,
this.handler = checkNotNull(handler, "handler"); this.handler = checkNotNull(handler, "handler");
} }
public T apply(HttpResponse from) throws HttpException { public T apply(HttpResponse from) {
try {
checkNotNull(from, "http response");
checkNotNull(from.getPayload(), "payload in " + from);
} catch (NullPointerException e) {
return addRequestDetailsToException(e);
}
if (from.getStatusCode() >= 300)
return convertStreamToStringAndParse(from);
return parse(from.getPayload().getInput()); return parse(from.getPayload().getInput());
} }
public T parse(InputStream from) throws HttpException { private T convertStreamToStringAndParse(HttpResponse from) {
if (from == null)
throw new HttpException("No input to parse");
try { try {
return parse(Utils.toStringAndClose(from.getPayload().getInput()));
} catch (Exception e) {
return addRequestDetailsToException(e);
}
}
public T parse(String from) {
try {
checkNotNull(from, "xml string");
checkArgument(from.indexOf('<') >= 0, String.format("not an xml document [%s] ",from));
} catch (RuntimeException e) {
return addRequestDetailsToException(e);
}
return parse(new InputSource(new StringReader(from)));
}
public T parse(InputStream from) {
try {
return parse(new InputSource(from));
} finally {
closeQuietly(from);
}
}
public T parse(InputSource from) {
try {
checkNotNull(from, "xml inputsource");
parser.setContentHandler(getHandler()); parser.setContentHandler(getHandler());
// This method should accept documents with a BOM (Byte-order mark) // This method should accept documents with a BOM (Byte-order mark)
parser.parse(new InputSource(from)); parser.parse(from);
return getHandler().getResult(); return getHandler().getResult();
} catch (Exception e) { } catch (Exception e) {
if (request != null) { return addRequestDetailsToException(e);
}
}
StringBuilder message = new StringBuilder(); private T addRequestDetailsToException(Exception e) {
message.append("Error parsing input for ").append( if (request != null) {
request.getRequestLine()).append(": "); StringBuilder message = new StringBuilder();
message.append(e.getMessage()); message.append("Error parsing input for ").append(request.getRequestLine()).append(": ");
logger.error(e, message.toString()); message.append(e.getMessage());
throw new HttpException(message.toString(), e); logger.error(e, message.toString());
} else { throw new HttpException(message.toString(), e);
Throwables.propagate(e); } else {
assert false : "should have propagated: " + e; propagate(e);
return null; assert false : "should have propagated: " + e;
} return null;
} finally {
Closeables.closeQuietly(from);
} }
} }
@ -99,26 +135,38 @@ public class ParseSax<T> implements Function<HttpResponse, T>,
} }
/** /**
* Handler that produces a useable domain object accessible after parsing * Handler that produces a useable domain object accessible after parsing completes.
* completes.
* *
* @author Adrian Cole * @author Adrian Cole
*/ */
public abstract static class HandlerWithResult<T> extends DefaultHandler public abstract static class HandlerWithResult<T> extends DefaultHandler implements
implements InvocationContext { InvocationContext {
protected GeneratedHttpRequest<?> request; protected HttpRequest request;
public abstract T getResult(); public abstract T getResult();
@Override @Override
public void setContext(GeneratedHttpRequest<?> request) { public HandlerWithResult<T> setContext(HttpRequest request) {
this.request = request; this.request = request;
return this;
}
}
public abstract static class HandlerForGeneratedRequestWithResult<T> extends
HandlerWithResult<T> {
@Override
public HandlerForGeneratedRequestWithResult<T> setContext(HttpRequest request) {
checkArgument(request instanceof GeneratedHttpRequest<?>,
"note this handler requires a GeneratedHttpRequest");
super.setContext(request);
return this;
} }
} }
@Override @Override
public void setContext(GeneratedHttpRequest<?> request) { public ParseSax<T> setContext(HttpRequest request) {
handler.setContext(request); handler.setContext(request);
this.request = request; this.request = request;
return this;
} }
} }

View File

@ -30,10 +30,10 @@ import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriBuilder; import javax.ws.rs.core.UriBuilder;
import org.jclouds.http.HttpException; import org.jclouds.http.HttpException;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.http.HttpResponseException; import org.jclouds.http.HttpResponseException;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.util.Utils; import org.jclouds.util.Utils;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -52,7 +52,7 @@ public class ParseURIFromListOrLocationHeaderIf20x implements Function<HttpRespo
this.uriBuilderProvider = uriBuilderProvider; this.uriBuilderProvider = uriBuilderProvider;
} }
private GeneratedHttpRequest<?> request; private HttpRequest request;
public URI apply(HttpResponse from) { public URI apply(HttpResponse from) {
if (from.getStatusCode() > 206) if (from.getStatusCode() > 206)
@ -93,7 +93,9 @@ public class ParseURIFromListOrLocationHeaderIf20x implements Function<HttpRespo
} }
} }
public void setContext(GeneratedHttpRequest<?> request) { @Override
public ParseURIFromListOrLocationHeaderIf20x setContext(HttpRequest request) {
this.request = request; this.request = request;
return this;
} }
} }

View File

@ -20,7 +20,7 @@ package org.jclouds.rest;
import javax.ws.rs.PathParam; import javax.ws.rs.PathParam;
import org.jclouds.rest.internal.GeneratedHttpRequest; import org.jclouds.http.HttpRequest;
/** /**
* Passes generated Http request into this object; * Passes generated Http request into this object;
@ -29,5 +29,5 @@ import org.jclouds.rest.internal.GeneratedHttpRequest;
* @author Adrian Cole * @author Adrian Cole
*/ */
public interface InvocationContext { public interface InvocationContext {
void setContext(GeneratedHttpRequest<?> request); Object setContext(HttpRequest request);
} }

View File

@ -0,0 +1,59 @@
/**
*
* Copyright (C) 2009 Cloud Conscious, LLC. <info@cloudconscious.com>
*
* ====================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
package org.jclouds.rest.binders;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.net.InternetDomainName.isValid;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.ws.rs.core.UriBuilder;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.Binder;
import com.google.common.net.InternetDomainName;
/**
*
* @author Adrian Cole
*/
@Singleton
public class BindAsHostPrefix implements Binder {
private final Provider<UriBuilder> uriBuilderProvider;
@Inject
public BindAsHostPrefix(Provider<UriBuilder> uriBuilderProvider) {
this.uriBuilderProvider = uriBuilderProvider;
}
public void bindToRequest(HttpRequest request, Object payload) {
checkNotNull(payload, "hostprefix");
checkArgument(isValid(request.getEndpoint().getHost()), "this is only valid for hostnames: "
+ request);
UriBuilder builder = uriBuilderProvider.get().uri(request.getEndpoint());
InternetDomainName name = InternetDomainName.from(request.getEndpoint().getHost()).child(
payload.toString());
builder.host(name.name());
request.setEndpoint(builder.build());
}
}

View File

@ -19,7 +19,6 @@
package org.jclouds.rest.internal; package org.jclouds.rest.internal;
import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.Collections2.filter; import static com.google.common.collect.Collections2.filter;
import static com.google.common.collect.Collections2.transform; import static com.google.common.collect.Collections2.transform;
import static com.google.common.collect.Iterables.concat; import static com.google.common.collect.Iterables.concat;
@ -100,7 +99,6 @@ import org.jclouds.rest.annotations.EndpointParam;
import org.jclouds.rest.annotations.ExceptionParser; import org.jclouds.rest.annotations.ExceptionParser;
import org.jclouds.rest.annotations.FormParams; import org.jclouds.rest.annotations.FormParams;
import org.jclouds.rest.annotations.Headers; import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.HostPrefixParam;
import org.jclouds.rest.annotations.MapBinder; import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.MapPayloadParam; import org.jclouds.rest.annotations.MapPayloadParam;
import org.jclouds.rest.annotations.MatrixParams; import org.jclouds.rest.annotations.MatrixParams;
@ -150,7 +148,6 @@ public class RestAnnotationProcessor<T> {
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToDecoratorParamAnnotation = createMethodToIndexOfParamToAnnotation(BinderParam.class); private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToDecoratorParamAnnotation = createMethodToIndexOfParamToAnnotation(BinderParam.class);
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToHeaderParamAnnotations = createMethodToIndexOfParamToAnnotation(HeaderParam.class); private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToHeaderParamAnnotations = createMethodToIndexOfParamToAnnotation(HeaderParam.class);
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToHostPrefixParamAnnotations = createMethodToIndexOfParamToAnnotation(HostPrefixParam.class);
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointAnnotations = createMethodToIndexOfParamToAnnotation(Endpoint.class); private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointAnnotations = createMethodToIndexOfParamToAnnotation(Endpoint.class);
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointParamAnnotations = createMethodToIndexOfParamToAnnotation(EndpointParam.class); private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToEndpointParamAnnotations = createMethodToIndexOfParamToAnnotation(EndpointParam.class);
private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToMatrixParamAnnotations = createMethodToIndexOfParamToAnnotation(MatrixParam.class); private final Map<Method, Map<Integer, Set<Annotation>>> methodToIndexOfParamToMatrixParamAnnotations = createMethodToIndexOfParamToAnnotation(MatrixParam.class);
@ -299,7 +296,6 @@ public class RestAnnotationProcessor<T> {
for (int index = 0; index < method.getParameterTypes().length; index++) { for (int index = 0; index < method.getParameterTypes().length; index++) {
methodToIndexOfParamToDecoratorParamAnnotation.get(method).get(index); methodToIndexOfParamToDecoratorParamAnnotation.get(method).get(index);
methodToIndexOfParamToHeaderParamAnnotations.get(method).get(index); methodToIndexOfParamToHeaderParamAnnotations.get(method).get(index);
methodToIndexOfParamToHostPrefixParamAnnotations.get(method).get(index);
methodToIndexOfParamToMatrixParamAnnotations.get(method).get(index); methodToIndexOfParamToMatrixParamAnnotations.get(method).get(index);
methodToIndexOfParamToFormParamAnnotations.get(method).get(index); methodToIndexOfParamToFormParamAnnotations.get(method).get(index);
methodToIndexOfParamToQueryParamAnnotations.get(method).get(index); methodToIndexOfParamToQueryParamAnnotations.get(method).get(index);
@ -385,7 +381,7 @@ public class RestAnnotationProcessor<T> {
} }
String httpMethod = getHttpMethodOrConstantOrThrowException(method); String httpMethod = getHttpMethodOrConstantOrThrowException(method);
UriBuilder builder = addHostPrefixIfPresent(endpoint, method, args); UriBuilder builder = uriBuilderProvider.get().uri(endpoint);
Multimap<String, String> tokenValues = LinkedHashMultimap.create(); Multimap<String, String> tokenValues = LinkedHashMultimap.create();
@ -631,26 +627,6 @@ public class RestAnnotationProcessor<T> {
return null; return null;
} }
private UriBuilder addHostPrefixIfPresent(URI endpoint, Method method, Object... args) {
Map<Integer, Set<Annotation>> map = indexWithOnlyOneAnnotation(method, "@HostPrefixParam",
methodToIndexOfParamToHostPrefixParamAnnotations);
UriBuilder builder = uriBuilderProvider.get().uri(endpoint);
if (map.size() == 1) {
HostPrefixParam param = (HostPrefixParam) map.values().iterator().next().iterator().next();
int index = map.keySet().iterator().next();
String prefix = checkNotNull(args[index],
String.format("argument at index %d on method %s", index, method)).toString();
checkArgument(!prefix.equals(""), String.format(
"argument at index %d must be a valid hostname for method %s", index, method));
String joinOn = param.value();
String host = endpoint.getHost();
builder.host(prefix + joinOn + host);
}
return builder;
}
public static final TypeLiteral<ListenableFuture<Boolean>> futureBooleanLiteral = new TypeLiteral<ListenableFuture<Boolean>>() { public static final TypeLiteral<ListenableFuture<Boolean>> futureBooleanLiteral = new TypeLiteral<ListenableFuture<Boolean>>() {
}; };

View File

@ -21,6 +21,7 @@ package org.jclouds.rest;
import static org.jclouds.rest.RestContextFactory.createContextBuilder; import static org.jclouds.rest.RestContextFactory.createContextBuilder;
import java.io.IOException; import java.io.IOException;
import java.util.Properties;
import org.jclouds.http.HttpRequest; import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseSax; import org.jclouds.http.functions.ParseSax;
@ -60,10 +61,13 @@ public abstract class RestClientTest<T> extends BaseRestClientTest {
protected void setupFactory() throws IOException { protected void setupFactory() throws IOException {
ContextSpec<?, ?> contextSpec = createContextSpec(); ContextSpec<?, ?> contextSpec = createContextSpec();
injector = createContextBuilder(contextSpec, injector = createContextBuilder(contextSpec,
ImmutableSet.of(new MockModule(), new NullLoggingModule(), createModule())) ImmutableSet.of(new MockModule(), new NullLoggingModule(), createModule()),
.buildInjector(); getProperties()).buildInjector();
parserFactory = injector.getInstance(ParseSax.Factory.class); parserFactory = injector.getInstance(ParseSax.Factory.class);
processor = injector.getInstance(Key.get(createTypeLiteral())); processor = injector.getInstance(Key.get(createTypeLiteral()));
} }
protected Properties getProperties() {
return new Properties();
}
} }

View File

@ -109,7 +109,6 @@ import org.jclouds.rest.annotations.Endpoint;
import org.jclouds.rest.annotations.EndpointParam; import org.jclouds.rest.annotations.EndpointParam;
import org.jclouds.rest.annotations.FormParams; import org.jclouds.rest.annotations.FormParams;
import org.jclouds.rest.annotations.Headers; import org.jclouds.rest.annotations.Headers;
import org.jclouds.rest.annotations.HostPrefixParam;
import org.jclouds.rest.annotations.MapBinder; import org.jclouds.rest.annotations.MapBinder;
import org.jclouds.rest.annotations.MapPayloadParam; import org.jclouds.rest.annotations.MapPayloadParam;
import org.jclouds.rest.annotations.MatrixParams; import org.jclouds.rest.annotations.MatrixParams;
@ -121,6 +120,7 @@ import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.ResponseParser; import org.jclouds.rest.annotations.ResponseParser;
import org.jclouds.rest.annotations.SkipEncoding; import org.jclouds.rest.annotations.SkipEncoding;
import org.jclouds.rest.annotations.VirtualHost; import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.binders.BindAsHostPrefix;
import org.jclouds.rest.binders.BindMapToMatrixParams; import org.jclouds.rest.binders.BindMapToMatrixParams;
import org.jclouds.rest.binders.BindToJsonPayload; import org.jclouds.rest.binders.BindToJsonPayload;
import org.jclouds.rest.binders.BindToStringPayload; import org.jclouds.rest.binders.BindToStringPayload;
@ -1494,8 +1494,9 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public HttpRequest request; public HttpRequest request;
public void setContext(GeneratedHttpRequest<?> request) { public ReturnStringIf200Context setContext(HttpRequest request) {
this.request = request; this.request = request;
return this;
} }
} }
@ -1723,27 +1724,17 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
.singletonList("localhost")); .singletonList("localhost"));
} }
public class TestVirtualHost { public interface TestVirtualHost {
@GET @GET
@Path("/{id}") @Path("/{id}")
@VirtualHost @VirtualHost
public ListenableFuture<String> get(@PathParam("id") String id, String foo) { ListenableFuture<String> get(@PathParam("id") String id, String foo);
return null;
}
@GET @GET
@Path("/{id}") @Path("/{id}")
public ListenableFuture<String> getPrefix(@PathParam("id") String id, ListenableFuture<String> getPrefix(@PathParam("id") String id,
@HostPrefixParam("") String foo) { @BinderParam(BindAsHostPrefix.class) String foo);
return null;
}
@GET
@Path("/{id}")
public ListenableFuture<String> getPrefixDot(@PathParam("id") String id,
@HostPrefixParam String foo) {
return null;
}
} }
@Test @Test
@ -1762,17 +1753,6 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@Test @Test
public void testHostPrefix() throws SecurityException, NoSuchMethodException { public void testHostPrefix() throws SecurityException, NoSuchMethodException {
Method method = TestVirtualHost.class.getMethod("getPrefix", String.class, String.class); Method method = TestVirtualHost.class.getMethod("getPrefix", String.class, String.class);
HttpRequest request = factory(TestVirtualHost.class).createRequest(method,
new Object[] { "1", "holy" });
assertEquals(request.getEndpoint().getHost(), "holylocalhost");
assertEquals(request.getEndpoint().getPath(), "/1");
assertEquals(request.getMethod(), HttpMethod.GET);
assertEquals(request.getHeaders().size(), 0);
}
@Test
public void testHostPrefixDot() throws SecurityException, NoSuchMethodException {
Method method = TestVirtualHost.class.getMethod("getPrefixDot", String.class, String.class);
HttpRequest request = factory(TestVirtualHost.class).createRequest(method, HttpRequest request = factory(TestVirtualHost.class).createRequest(method,
new Object[] { "1", "holy" }); new Object[] { "1", "holy" });
assertEquals(request.getEndpoint().getHost(), "holy.localhost"); assertEquals(request.getEndpoint().getHost(), "holy.localhost");
@ -1782,15 +1762,9 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
} }
@Test(expectedExceptions = IllegalArgumentException.class) @Test(expectedExceptions = IllegalArgumentException.class)
public void testHostPrefixDotEmpty() throws SecurityException, NoSuchMethodException { public void testHostPrefixEmpty() throws SecurityException, NoSuchMethodException {
Method method = TestVirtualHost.class.getMethod("getPrefixDot", String.class, String.class); Method method = TestVirtualHost.class.getMethod("getPrefix", String.class, String.class);
factory(TestVirtualHost.class).createRequest(method, new Object[] { "1", "" }); factory(TestVirtualHost.class).createRequest(method, "1", "");
}
@Test(expectedExceptions = NullPointerException.class)
public void testHostPrefixDotNull() throws SecurityException, NoSuchMethodException {
Method method = TestVirtualHost.class.getMethod("getPrefixDot", String.class, String.class);
factory(TestVirtualHost.class).createRequest(method, new Object[] { "1", null });
} }
public class TestHeaders { public class TestHeaders {

View File

@ -18,12 +18,14 @@
*/ */
package org.jclouds.mezeo.pcs2.functions; package org.jclouds.mezeo.pcs2.functions;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import java.util.Map; import java.util.Map;
import javax.inject.Inject; import javax.inject.Inject;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ReturnStringIf200; import org.jclouds.http.functions.ReturnStringIf200;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
@ -64,8 +66,12 @@ public class AddMetadataItemIntoMap implements Function<HttpResponse, Void>, Inv
return null; return null;
} }
public void setContext(GeneratedHttpRequest<?> request) { @Override
this.request = request; public AddMetadataItemIntoMap setContext(HttpRequest request) {
checkArgument(request instanceof GeneratedHttpRequest<?>,
"note this handler requires a GeneratedHttpRequest");
this.request = (GeneratedHttpRequest<?>) request;
return this;
} }
} }

View File

@ -22,12 +22,12 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.net.URI; import java.net.URI;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata; import org.jclouds.rackspace.cloudfiles.domain.AccountMetadata;
import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata; import org.jclouds.rackspace.cloudfiles.domain.ContainerCDNMetadata;
import org.jclouds.rackspace.cloudfiles.reference.CloudFilesHeaders; import org.jclouds.rackspace.cloudfiles.reference.CloudFilesHeaders;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -39,7 +39,7 @@ import com.google.common.base.Function;
public class ParseContainerCDNMetadataFromHeaders implements public class ParseContainerCDNMetadataFromHeaders implements
Function<HttpResponse, ContainerCDNMetadata>, InvocationContext { Function<HttpResponse, ContainerCDNMetadata>, InvocationContext {
private GeneratedHttpRequest<?> request; private HttpRequest request;
/** /**
* parses the http response headers to create a new {@link ContainerCDNMetadata} object. * parses the http response headers to create a new {@link ContainerCDNMetadata} object.
@ -60,7 +60,9 @@ public class ParseContainerCDNMetadataFromHeaders implements
} }
} }
public void setContext(GeneratedHttpRequest<?> request) { @Override
public ParseContainerCDNMetadataFromHeaders setContext(HttpRequest request) {
this.request = request; this.request = request;
return this;
} }
} }

View File

@ -20,11 +20,11 @@ package org.jclouds.rackspace.cloudfiles.functions;
import javax.inject.Inject; import javax.inject.Inject;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.rackspace.cloudfiles.domain.CFObject; import org.jclouds.rackspace.cloudfiles.domain.CFObject;
import org.jclouds.rackspace.cloudfiles.domain.MutableObjectInfoWithMetadata; import org.jclouds.rackspace.cloudfiles.domain.MutableObjectInfoWithMetadata;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -57,8 +57,9 @@ public class ParseObjectFromHeadersAndHttpContent implements Function<HttpRespon
return object; return object;
} }
public void setContext(GeneratedHttpRequest<?> request) { @Override
public ParseObjectFromHeadersAndHttpContent setContext(HttpRequest request) {
infoParser.setContext(request); infoParser.setContext(request);
return this;
} }
} }

View File

@ -25,11 +25,11 @@ import javax.inject.Inject;
import org.jclouds.blobstore.domain.BlobMetadata; import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.functions.ParseSystemAndUserMetadataFromHeaders; import org.jclouds.blobstore.functions.ParseSystemAndUserMetadataFromHeaders;
import org.jclouds.encryption.EncryptionService; import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.rackspace.cloudfiles.blobstore.functions.ResourceToObjectInfo; import org.jclouds.rackspace.cloudfiles.blobstore.functions.ResourceToObjectInfo;
import org.jclouds.rackspace.cloudfiles.domain.MutableObjectInfoWithMetadata; import org.jclouds.rackspace.cloudfiles.domain.MutableObjectInfoWithMetadata;
import org.jclouds.rest.InvocationContext; import org.jclouds.rest.InvocationContext;
import org.jclouds.rest.internal.GeneratedHttpRequest;
import org.jclouds.util.Utils; import org.jclouds.util.Utils;
import com.google.common.base.Function; import com.google.common.base.Function;
@ -68,8 +68,10 @@ public class ParseObjectInfoFromHeaders implements
return to; return to;
} }
public void setContext(GeneratedHttpRequest<?> request) { @Override
public ParseObjectInfoFromHeaders setContext(HttpRequest request) {
blobMetadataParser.setContext(request); blobMetadataParser.setContext(request);
return this;
} }
} }

View File

@ -33,6 +33,7 @@ import javax.inject.Inject;
import org.jclouds.blobstore.domain.PageSet; import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.internal.PageSetImpl; import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.encryption.EncryptionService; import org.jclouds.encryption.EncryptionService;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.functions.ParseJson; import org.jclouds.http.functions.ParseJson;
import org.jclouds.rackspace.cloudfiles.domain.ObjectInfo; import org.jclouds.rackspace.cloudfiles.domain.ObjectInfo;
import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions; import org.jclouds.rackspace.cloudfiles.options.ListContainerOptions;
@ -180,7 +181,11 @@ public class ParseObjectInfoListFromJsonResponse extends ParseJson<PageSet<Objec
} }
} }
public void setContext(GeneratedHttpRequest<?> request) { @Override
this.request = request; public ParseObjectInfoListFromJsonResponse setContext(HttpRequest request) {
checkArgument(request instanceof GeneratedHttpRequest<?>,
"note this handler requires a GeneratedHttpRequest");
this.request = (GeneratedHttpRequest<?>) request;
return this;
} }
} }

View File

@ -25,6 +25,7 @@ import static org.testng.Assert.assertNotNull;
import java.net.URI; import java.net.URI;
import org.jclouds.Constants;
import org.jclouds.blobstore.reference.BlobStoreConstants; import org.jclouds.blobstore.reference.BlobStoreConstants;
import org.jclouds.http.HttpResponse; import org.jclouds.http.HttpResponse;
import org.jclouds.http.Payloads; import org.jclouds.http.Payloads;
@ -52,6 +53,7 @@ public class ParseObjectInfoFromHeadersTest {
bindConstant() bindConstant()
.annotatedWith(Names.named(BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX)).to( .annotatedWith(Names.named(BlobStoreConstants.PROPERTY_USER_METADATA_PREFIX)).to(
"sdf"); "sdf");
bindConstant().annotatedWith(Names.named(Constants.PROPERTY_API_VERSION)).to("1");
} }
}); });