Merge branch 'master' of github.com:jclouds/jclouds

This commit is contained in:
Lili Nader 2010-12-13 14:27:05 -08:00
commit a1bf070c7a
246 changed files with 11701 additions and 3940 deletions

View File

@ -19,10 +19,11 @@
package org.jclouds.atmosonline.saas.domain;
import javax.annotation.Nullable;
import org.jclouds.io.PayloadEnclosing;
import com.google.common.collect.Multimap;
import com.google.inject.internal.Nullable;
/**
* Amazon Atmos is designed to store objects. Objects are stored in buckets and consist of a

View File

@ -28,7 +28,8 @@ import com.google.common.collect.ImmutableSet;
* Regions used for all aws commands.
*
* @author Adrian Cole
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?LocationSelection.html"
* @see <a
* href="http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?LocationSelection.html"
* />
*
*/
@ -38,9 +39,8 @@ public class Region {
* <p/>
* <h3>S3</h3>
* <p/>
* In Amazon S3, the EU (Ireland) Region provides read-after-write
* consistency for PUTS of new objects in your Amazon S3 bucket and eventual
* consistency for overwrite PUTS and DELETES.
* In Amazon S3, the EU (Ireland) Region provides read-after-write consistency for PUTS of new
* objects in your Amazon S3 bucket and eventual consistency for overwrite PUTS and DELETES.
*/
public static final String EU = "EU";
@ -52,13 +52,11 @@ public class Region {
* <p/>
* <h3>S3</h3>
* <p/>
* This is the default Region. All requests sent to s3.amazonaws.com go to
* this Region unless you specify a LocationConstraint on a bucket. The US
* Standard Region automatically places your data in either Amazon's east or
* west coast data centers depending on what will provide you with the lowest
* latency. To use this region, do not set the LocationConstraint bucket
* parameter. The US Standard Region provides eventual consistency for all
* requests.
* This is the default Region. All requests sent to s3.amazonaws.com go to this Region unless you
* specify a LocationConstraint on a bucket. The US Standard Region automatically places your
* data in either Amazon's east or west coast data centers depending on what will provide you
* with the lowest latency. To use this region, do not set the LocationConstraint bucket
* parameter. The US Standard Region provides eventual consistency for all requests.
*/
public static final String US_STANDARD = "us-standard";
@ -68,27 +66,25 @@ public class Region {
public static final String US_EAST_1 = "us-east-1";
/**
* US-West (Northern California) <h3>S3</h3> Uses Amazon S3 servers in
* Northern California
* US-West (Northern California) <h3>S3</h3> Uses Amazon S3 servers in Northern California
* <p/>
* Optionally, use the endpoint s3-us-west-1.amazonaws.com on all requests to
* this bucket to reduce the latency you might experience after the first
* hour of creating a bucket in this Region.
* Optionally, use the endpoint s3-us-west-1.amazonaws.com on all requests to this bucket to
* reduce the latency you might experience after the first hour of creating a bucket in this
* Region.
* <p/>
* In Amazon S3, the US-West (Northern California) Region provides
* read-after-write consistency for PUTS of new objects in your Amazon S3
* bucket and eventual consistency for overwrite PUTS and DELETES.
* In Amazon S3, the US-West (Northern California) Region provides read-after-write consistency
* for PUTS of new objects in your Amazon S3 bucket and eventual consistency for overwrite PUTS
* and DELETES.
*/
public static final String US_WEST_1 = "us-west-1";
/**
* Region in Singapore, launched April 28, 2010. This region improves latency
* for Asia-based users
* Region in Singapore, launched April 28, 2010. This region improves latency for Asia-based
* users
*/
public static final String AP_SOUTHEAST_1 = "ap-southeast-1";
public static Set<String> ALL_S3 = ImmutableSet.of(EU, US_STANDARD,
US_WEST_1, AP_SOUTHEAST_1);
public static Set<String> ALL_SQS = ImmutableSet.of(EU_WEST_1, US_STANDARD,
US_EAST_1, US_WEST_1, AP_SOUTHEAST_1);
public static Set<String> ALL_SIMPLEDB = ImmutableSet.of(EU_WEST_1, US_EAST_1, US_WEST_1, AP_SOUTHEAST_1);
public static Set<String> ALL_S3 = ImmutableSet.of(EU, US_STANDARD, US_WEST_1, AP_SOUTHEAST_1);
public static Set<String> ALL_SQS = ImmutableSet.of(EU_WEST_1, US_STANDARD, US_EAST_1, US_WEST_1, AP_SOUTHEAST_1);
}

View File

@ -116,7 +116,7 @@ public class EC2ComputeService extends BaseComputeService {
ec2Client.getPlacementGroupServices().deletePlacementGroupInRegion(region, group);
checkState(placementGroupDeleted.apply(new PlacementGroup(region, group, "cluster", State.PENDING)),
String.format("placementGroup region(%s) name(%s) failed to delete", region, group));
placementGroupMap.remove(new RegionAndName(region, tag));
placementGroupMap.remove(new RegionAndName(region, group));
logger.debug("<< deleted placementGroup(%s)", group);
} catch (AWSResponseException e) {
if (e.getError().getCode().equals("InvalidPlacementGroup.InUse")) {
@ -142,7 +142,7 @@ public class EC2ComputeService extends BaseComputeService {
logger.debug(">> deleting securityGroup(%s)", group);
ec2Client.getSecurityGroupServices().deleteSecurityGroupInRegion(region, group);
// TODO: test this clear happens
securityGroupMap.remove(new RegionNameAndIngressRules(region, tag, null, false));
securityGroupMap.remove(new RegionNameAndIngressRules(region, group, null, false));
logger.debug("<< deleted securityGroup(%s)", group);
}
}

View File

@ -101,9 +101,20 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
builder.imageId(instance.getRegion() + "/" + instance.getImageId());
// extract the operating system from the image
Image image = instanceToImage.get(new RegionAndName(instance.getRegion(), instance.getImageId()));
if (image != null)
builder.operatingSystem(image.getOperatingSystem());
RegionAndName regionAndName = new RegionAndName(instance.getRegion(), instance.getImageId());
try {
Image image = instanceToImage.get(regionAndName);
if (image != null)
builder.operatingSystem(image.getOperatingSystem());
}
catch (NullPointerException e) {
// The instanceToImage Map may throw NullPointerException (actually subclass NullOutputException) if the
// computing Function returns a null value.
//
// See the following for more information:
// MapMaker.makeComputingMap()
// RegionAndIdToImage.apply()
}
return builder.build();
}
@ -209,4 +220,4 @@ public class RunningInstanceToNodeMetadata implements Function<RunningInstance,
}
}
}
}

View File

@ -21,10 +21,11 @@ package org.jclouds.aws.ec2.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.annotation.Nullable;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Multimap;
import com.google.inject.internal.Nullable;
/**
* Defines the mapping of volumes for

View File

@ -24,10 +24,11 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.internal.Nullable;
/**
*

View File

@ -21,7 +21,7 @@ package org.jclouds.aws.ec2.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.inject.internal.Nullable;
import javax.annotation.Nullable;
/**
*

View File

@ -21,7 +21,7 @@ package org.jclouds.aws.ec2.domain;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.inject.internal.Nullable;
import javax.annotation.Nullable;
/**
*

View File

@ -24,9 +24,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.LinkedHashSet;
import java.util.Set;
import javax.annotation.Nullable;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.inject.internal.Nullable;
/**
*

View File

@ -25,12 +25,13 @@ import java.util.Date;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import org.jclouds.aws.ec2.domain.Attachment.Status;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.internal.Nullable;
/**
*

View File

@ -94,7 +94,7 @@ public class ParseAWSErrorFromXmlContent implements HttpErrorHandler {
&& (error.getCode().endsWith(".NotFound") || error.getCode().endsWith(".Unknown")))
exception = new ResourceNotFoundException(message, exception);
else if ((error != null && error.getCode() != null && (error.getCode().equals("IncorrectState") || error
.getCode().endsWith(".Duplicate"))) || (message != null && message.indexOf("already exists") != -1))
.getCode().endsWith(".Duplicate"))) || (message != null && (message.indexOf("already exists") != -1)))
exception = new IllegalStateException(message, exception);
else if (error != null && error.getCode() != null && error.getCode().equals("AuthFailure"))
exception = new AuthorizationException(exception.getMessage(), exception);

View File

@ -0,0 +1,45 @@
/**
*
* Copyright (C) 2010 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.blobstore;
import java.util.List;
import java.util.Properties;
import org.jclouds.aws.s3.S3ContextBuilder;
import org.jclouds.aws.s3.blobstore.config.ScaleUpCloudBlobStoreContextModule;
import com.google.inject.Module;
/**
*
* @author Adrian Cole
*/
public class ScaleUpCloudBlobStoreContextContextBuilder extends S3ContextBuilder {
public ScaleUpCloudBlobStoreContextContextBuilder(Properties props) {
super(props);
}
@Override
protected void addContextModule(List<Module> modules) {
modules.add(new ScaleUpCloudBlobStoreContextModule());
}
}

View File

@ -29,6 +29,8 @@ import org.jclouds.aws.s3.S3Client;
import org.jclouds.aws.s3.blobstore.S3AsyncBlobStore;
import org.jclouds.aws.s3.blobstore.S3BlobRequestSigner;
import org.jclouds.aws.s3.blobstore.S3BlobStore;
import org.jclouds.aws.s3.blobstore.functions.LocationFromBucketLocation;
import org.jclouds.aws.s3.domain.BucketMetadata;
import org.jclouds.aws.suppliers.DefaultLocationSupplier;
import org.jclouds.blobstore.AsyncBlobStore;
import org.jclouds.blobstore.BlobRequestSigner;
@ -43,6 +45,7 @@ import org.jclouds.domain.LocationScope;
import org.jclouds.domain.internal.LocationImpl;
import org.jclouds.rest.annotations.Provider;
import com.google.common.base.Function;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.common.collect.Sets;
@ -70,6 +73,12 @@ public class S3BlobStoreContextModule extends AbstractModule {
bind(BlobStoreContext.class).to(new TypeLiteral<BlobStoreContextImpl<S3Client, S3AsyncClient>>() {
}).in(Scopes.SINGLETON);
bind(BlobRequestSigner.class).to(S3BlobRequestSigner.class);
bindBucketLocationStrategy();
}
protected void bindBucketLocationStrategy() {
bind(new TypeLiteral<Function<BucketMetadata, Location>>() {
}).to(LocationFromBucketLocation.class);
}
@Provides

View File

@ -0,0 +1,41 @@
/**
*
* Copyright (C) 2010 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.blobstore.config;
import org.jclouds.aws.s3.domain.BucketMetadata;
import org.jclouds.domain.Location;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.inject.TypeLiteral;
/**
*
* @author Adrian Cole
*/
public class ScaleUpCloudBlobStoreContextModule extends S3BlobStoreContextModule {
@SuppressWarnings("rawtypes")
@Override
protected void bindBucketLocationStrategy() {
bind(new TypeLiteral<Function<BucketMetadata, Location>>() {
}).toInstance((Function)Functions.constant(null));
}
}

View File

@ -19,80 +19,36 @@
package org.jclouds.aws.s3.blobstore.functions;
import java.util.NoSuchElementException;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.aws.s3.S3Client;
import org.jclouds.aws.s3.domain.BucketMetadata;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.domain.MutableStorageMetadata;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.blobstore.domain.internal.MutableStorageMetadataImpl;
import org.jclouds.collect.Memoized;
import org.jclouds.domain.Location;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
/**
* @author Adrian Cole
*/
@Singleton
public class BucketToResourceMetadata implements Function<BucketMetadata, StorageMetadata> {
private final S3Client client;
private final Location onlyLocation;
private final Supplier<Set<? extends Location>> locations;
@Resource
protected Logger logger = Logger.NULL;
private final Function<BucketMetadata, Location> locationOfBucket;
@Inject
BucketToResourceMetadata(S3Client client, @Memoized Supplier<Set<? extends Location>> locations) {
this.client = client;
this.onlyLocation = locations.get().size() == 1 ? Iterables.get(locations.get(), 0) : null;
this.locations = locations;
BucketToResourceMetadata(Function<BucketMetadata, Location> locationOfBucket) {
this.locationOfBucket = locationOfBucket;
}
public StorageMetadata apply(BucketMetadata from) {
MutableStorageMetadata to = new MutableStorageMetadataImpl();
to.setName(from.getName());
to.setType(StorageType.CONTAINER);
to.setLocation(onlyLocation != null ? onlyLocation : getLocation(from));
to.setLocation(locationOfBucket.apply(from));
return to;
}
private Location getLocation(BucketMetadata from) {
try {
Set<? extends Location> locations = this.locations.get();
final String region = client.getBucketLocation(from.getName());
assert region != null : String.format("could not get region for %s", from.getName());
if (region != null) {
try {
return Iterables.find(locations, new Predicate<Location>() {
@Override
public boolean apply(Location input) {
return input.getId().equalsIgnoreCase(region.toString());
}
});
} catch (NoSuchElementException e) {
logger.error("could not get location for region %s in %s", region, locations);
}
} else {
logger.error("could not get region for %s", from.getName());
}
} catch (ContainerNotFoundException e) {
logger.error(e, "could not get region for %s, as service suggests the bucket doesn't exist", from.getName());
}
return null;
}
}

View File

@ -0,0 +1,88 @@
/**
*
* Copyright (C) 2010 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.blobstore.functions;
import java.util.NoSuchElementException;
import java.util.Set;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.aws.s3.S3Client;
import org.jclouds.aws.s3.domain.BucketMetadata;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.collect.Memoized;
import org.jclouds.domain.Location;
import org.jclouds.logging.Logger;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Supplier;
import com.google.common.collect.Iterables;
/**
* @author Adrian Cole
*/
@Singleton
public class LocationFromBucketLocation implements Function<BucketMetadata, Location> {
private final Location onlyLocation;
private final Supplier<Set<? extends Location>> locations;
private final S3Client client;
@Resource
protected Logger logger = Logger.NULL;
@Inject
LocationFromBucketLocation(S3Client client, @Memoized Supplier<Set<? extends Location>> locations) {
this.client = client;
this.onlyLocation = locations.get().size() == 1 ? Iterables.get(locations.get(), 0) : null;
this.locations = locations;
}
public Location apply(BucketMetadata from) {
if (onlyLocation != null)
return onlyLocation;
try {
Set<? extends Location> locations = this.locations.get();
final String region = client.getBucketLocation(from.getName());
assert region != null : String.format("could not get region for %s", from.getName());
if (region != null) {
try {
return Iterables.find(locations, new Predicate<Location>() {
@Override
public boolean apply(Location input) {
return input.getId().equalsIgnoreCase(region.toString());
}
});
} catch (NoSuchElementException e) {
logger.error("could not get location for region %s in %s", region, locations);
}
} else {
logger.error("could not get region for %s", from.getName());
}
} catch (ContainerNotFoundException e) {
logger.error(e, "could not get region for %s, as service suggests the bucket doesn't exist", from.getName());
}
return null;
}
}

View File

@ -19,10 +19,11 @@
package org.jclouds.aws.s3.domain;
import javax.annotation.Nullable;
import org.jclouds.io.PayloadEnclosing;
import com.google.common.collect.Multimap;
import com.google.inject.internal.Nullable;
/**
* Amazon S3 is designed to store objects. Objects are stored in buckets and consist of a

View File

@ -19,8 +19,14 @@
package org.jclouds.aws.s3.functions;
import static com.google.common.base.Throwables.getCausalChain;
import static com.google.common.collect.Iterables.filter;
import static com.google.common.collect.Iterables.get;
import static com.google.common.collect.Iterables.size;
import static org.jclouds.util.Utils.propagateOrNull;
import java.util.List;
import javax.inject.Singleton;
import org.jclouds.aws.AWSResponseException;
@ -35,11 +41,12 @@ import com.google.common.base.Function;
public class ReturnFalseIfBucketAlreadyOwnedByYou implements Function<Exception, Boolean> {
public Boolean apply(Exception from) {
if (from instanceof AWSResponseException) {
AWSResponseException responseException = (AWSResponseException) from;
if ("BucketAlreadyOwnedByYou".equals(responseException.getError().getCode())) {
List<Throwable> throwables = getCausalChain(from);
Iterable<AWSResponseException> matchingAWSResponseException = filter(throwables, AWSResponseException.class);
if (size(matchingAWSResponseException) >= 1 && get(matchingAWSResponseException, 0).getError() != null) {
if (get(matchingAWSResponseException, 0).getError().getCode().equals("BucketAlreadyOwnedByYou"))
return false;
}
}
return Boolean.class.cast(propagateOrNull(from));
}

View File

@ -69,10 +69,11 @@ public class BucketNameValidator extends DnsNameValidator {
}
/**
* Amazon also permits periods in the dns name
* Amazon also permits periods in the dns name.
* It also permits underscores, although they aren't recommended.
*/
@Override
protected CharMatcher getAcceptableRange() {
return super.getAcceptableRange().or(is('.'));
return super.getAcceptableRange().or(is('.')).or(is('_'));
}
}

View File

@ -0,0 +1,83 @@
/**
*
* Copyright (C) 2010 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.simpledb;
import static org.jclouds.aws.simpledb.reference.SimpleDBParameters.ACTION;
import static org.jclouds.aws.simpledb.reference.SimpleDBParameters.VERSION;
import javax.annotation.Nullable;
import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import org.jclouds.aws.filters.FormSigner;
import org.jclouds.aws.functions.RegionToEndpoint;
import org.jclouds.aws.simpledb.domain.ListDomainsResponse;
import org.jclouds.aws.simpledb.options.ListDomainsOptions;
import org.jclouds.aws.simpledb.xml.ListDomainsResponseHandler;
import org.jclouds.rest.annotations.EndpointParam;
import org.jclouds.rest.annotations.FormParams;
import org.jclouds.rest.annotations.RequestFilters;
import org.jclouds.rest.annotations.VirtualHost;
import org.jclouds.rest.annotations.XMLResponseParser;
import com.google.common.util.concurrent.ListenableFuture;
/**
* Provides access to SimpleDB via their REST API.
* <p/>
*
* @author Adrian Cole
*/
@RequestFilters(FormSigner.class)
@FormParams(keys = VERSION, values = SimpleDBAsyncClient.VERSION)
@VirtualHost
public interface SimpleDBAsyncClient {
public static final String VERSION = "2009-04-15";
/**
* @see SimpleDBClient#listDomainsInRegion
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "ListDomains")
@XMLResponseParser(ListDomainsResponseHandler.class)
ListenableFuture<? extends ListDomainsResponse> listDomainsInRegion(
@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region, ListDomainsOptions... options);
/**
* @see SimpleDBClient#createDomainInRegion
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "CreateDomain")
ListenableFuture<Void> createDomainInRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region,
@FormParam("DomainName") String domainName);
/**
* @see SimpleDBClient#deleteDomain
*/
@POST
@Path("/")
@FormParams(keys = ACTION, values = "DeleteDomain")
ListenableFuture<Void> deleteDomainInRegion(@EndpointParam(parser = RegionToEndpoint.class) @Nullable String region,
@FormParam("DomainName") String domainName);
}

View File

@ -0,0 +1,107 @@
/**
*
* Copyright (C) 2010 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.simpledb;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
import org.jclouds.aws.simpledb.domain.ListDomainsResponse;
import org.jclouds.aws.simpledb.options.ListDomainsOptions;
import org.jclouds.concurrent.Timeout;
/**
* Provides access to SimpleDB via their REST API.
* <p/>
*
* @author Adrian Cole
*/
@Timeout(duration = 30, timeUnit = TimeUnit.SECONDS)
public interface SimpleDBClient {
/**
* The ListDomains operation lists all domains associated with the Access Key ID. It returns
* domain names up to the limit set by MaxNumberOfDomains. A NextToken is returned if there are
* more than MaxNumberOfDomains domains. Calling ListDomains successive times with the NextToken
* returns up to MaxNumberOfDomains more domain names each time.
*
*
* @param region
* Domains are Region-specific.
* @param options
* specify result count or other options
*
* @see <a href=
* "http://docs.amazonwebservices.com/AmazonSimpleDB/2009-04-15/DeveloperGuide/SDB_API_ListDomains.html"
* />
*/
ListDomainsResponse listDomainsInRegion(@Nullable String region, ListDomainsOptions... options);
/**
* The CreateDomain operation creates a new domain.
*
* <p/>
* The domain name must be unique among the domains associated with the Access Key ID provided in
* the request. The CreateDomain operation might take 10 or more seconds to complete.
*
*
* <h3>Note</h3>
* CreateDomain is an idempotent operation; running it multiple times using the same domain name
* will not result in an error response.
* <p/>
* You can create up to 100 domains per account.
* <p/>
* If you require additional domains, go to
* http://aws.amazon.com/contact-us/simpledb-limit-request/.
*
* @param region
* Domains are Region-specific.
* @param domainName
* The name of the domain to create. The name can range between 3 and 255 characters
* and can contain the following characters: a-z, A-Z, 0-9, '_', '-', and '.'.
*
* @see <a href=
* "http://docs.amazonwebservices.com/AmazonSimpleDB/2009-04-15/DeveloperGuide/SDB_API_ListDomains.html"
* />
*/
void createDomainInRegion(@Nullable String region, String domainName);
/**
* The DeleteDomain operation deletes a domain. Any items (and their attributes) in the domain
* are deleted as well. The DeleteDomain operation might take 10 or more seconds to complete. <h3>
* Note</h3>
*
* Running DeleteDomain on a domain that does not exist or running the function multiple times
* using the same domain name will not result in an error response.
*
*
* @param region
* Domains are Region-specific.
* @param domainName
* The name of the domain to delete.
*
*
* @see <a href=
* "http://docs.amazonwebservices.com/AmazonSimpleDB/2009-04-15/DeveloperGuide/SDB_API_ListDomains.html"
* />
*/
void deleteDomainInRegion(String region, String domainName);
}

View File

@ -0,0 +1,56 @@
/**
*
* Copyright (C) 2010 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.simpledb;
import java.util.List;
import java.util.Properties;
import org.jclouds.aws.simpledb.config.SimpleDBRestClientModule;
import org.jclouds.http.config.JavaUrlHttpCommandExecutorServiceModule;
import org.jclouds.logging.jdk.config.JDKLoggingModule;
import org.jclouds.rest.RestContextBuilder;
import com.google.inject.Injector;
import com.google.inject.Module;
/**
* Creates {@link SimpleDBContext} or {@link Injector} instances based on the most commonly requested
* arguments.
* <p/>
* Note that Threadsafe objects will be bound as singletons to the Injector or Context provided.
* <p/>
* <p/>
* If no <code>Module</code>s are specified, the default {@link JDKLoggingModule logging} and
* {@link JavaUrlHttpCommandExecutorServiceModule http transports} will be installed.
*
* @author Adrian Cole
* @see SimpleDBContext
*/
public class SimpleDBContextBuilder extends RestContextBuilder<SimpleDBClient, SimpleDBAsyncClient> {
public SimpleDBContextBuilder(Properties props) {
super(SimpleDBClient.class, SimpleDBAsyncClient.class, props);
}
@Override
protected void addClientModule(List<Module> modules) {
modules.add(new SimpleDBRestClientModule());
}
}

View File

@ -0,0 +1,69 @@
/**
*
* Copyright (C) 2010 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.simpledb;
import static org.jclouds.Constants.PROPERTY_API_VERSION;
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 java.util.Properties;
import org.jclouds.PropertiesBuilder;
import org.jclouds.aws.domain.Region;
import com.google.common.base.Joiner;
/**
* Builds properties used in SimpleDB Clients
*
* @author Adrian Cole
*/
public class SimpleDBPropertiesBuilder extends PropertiesBuilder {
@Override
protected Properties defaultProperties() {
Properties properties = super.defaultProperties();
properties.setProperty(PROPERTY_AUTH_TAG, "AWS");
properties.setProperty(PROPERTY_HEADER_TAG, "amz");
properties.setProperty(PROPERTY_API_VERSION, SimpleDBAsyncClient.VERSION);
properties.setProperty(PROPERTY_REGIONS, Joiner.on(',').join(Region.US_EAST_1,
Region.US_WEST_1, Region.EU_WEST_1, Region.AP_SOUTHEAST_1));
properties.setProperty(PROPERTY_ENDPOINT, "https://sdb.amazonaws.com");
properties.setProperty(PROPERTY_ENDPOINT + "." + Region.US_EAST_1,
"https://sdb.amazonaws.com");
properties.setProperty(PROPERTY_ENDPOINT + "." + Region.US_WEST_1,
"https://sdb.us-west-1.amazonaws.com");
properties.setProperty(PROPERTY_ENDPOINT + "." + Region.EU_WEST_1,
"https://sdb.eu-west-1.amazonaws.com");
properties.setProperty(PROPERTY_ENDPOINT + "." + Region.AP_SOUTHEAST_1,
"https://sdb.ap-southeast-1.amazonaws.com");
return properties;
}
public SimpleDBPropertiesBuilder() {
super();
}
public SimpleDBPropertiesBuilder(Properties properties) {
super(properties);
}
}

View File

@ -0,0 +1,41 @@
/**
*
* Copyright (C) 2010 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.simpledb.config;
import org.jclouds.aws.config.AWSFormSigningRestClientModule;
import org.jclouds.aws.simpledb.SimpleDBAsyncClient;
import org.jclouds.aws.simpledb.SimpleDBClient;
import org.jclouds.http.RequiresHttp;
import org.jclouds.rest.ConfiguresRestClient;
/**
* Configures the SimpleDB connection.
*
* @author Adrian Cole
*/
@RequiresHttp
@ConfiguresRestClient
public class SimpleDBRestClientModule extends AWSFormSigningRestClientModule<SimpleDBClient, SimpleDBAsyncClient> {
public SimpleDBRestClientModule() {
super(SimpleDBClient.class, SimpleDBAsyncClient.class);
}
}

View File

@ -0,0 +1,190 @@
/**
*
* Copyright (C) 2010 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.simpledb.domain;
import java.util.Date;
/**
*
* @see <a href=
* "http://docs.amazonwebservices.com/AmazonSimpleDB/2009-04-15/DeveloperGuide/index.html?SDB_API_CreateDomain.html"
* />
* @author Adrian Cole
*/
public class DomainMetadata {
private final String region;
private final String name;
private final Date timestamp;
private final long itemCount;
private final long attributeValueCount;
private final long attributeNameCount;
private final long itemNamesSizeBytes;
private final long attributeValuesSizeBytes;
private final long attributeNamesSizeBytes;
public DomainMetadata(String region, String name, Date timestamp, long itemCount, long attributeValueCount,
long attributeNameCount, long itemNamesSizeBytes, long attributeValuesSizeBytes, long attributeNamesSizeBytes) {
this.region = region;
this.name = name;
this.timestamp = timestamp;
this.itemCount = itemCount;
this.attributeValueCount = attributeValueCount;
this.attributeNameCount = attributeNameCount;
this.itemNamesSizeBytes = itemNamesSizeBytes;
this.attributeValuesSizeBytes = attributeValuesSizeBytes;
this.attributeNamesSizeBytes = attributeNamesSizeBytes;
}
/**
*
* @return region the domain belongs to
*/
public String getRegion() {
return region;
}
/**
*
* @return name of the domain
*/
public String getName() {
return name;
}
/**
*
* @return The number of all items in the domain.
*/
public Date getTimestamp() {
return timestamp;
}
/**
*
* @return
*/
public long getItemCount() {
return itemCount;
}
/**
*
* @return The number of all attribute name/value pairs in the domain.
*/
public long getAttributeValueCount() {
return attributeValueCount;
}
/**
*
* @return The number of unique attribute names in the domain.
*/
public long getAttributeNameCount() {
return attributeNameCount;
}
/**
*
* @return The total size of all item names in the domain, in bytes.
*/
public long getItemNamesSizeBytes() {
return itemNamesSizeBytes;
}
/**
*
* @return The total size of all attribute values, in bytes.
*/
public long getAttributeValuesSizeBytes() {
return attributeValuesSizeBytes;
}
/**
*
* @return The total size of all unique attribute names, in bytes.
*/
public long getAttributeNamesSizeBytes() {
return attributeNamesSizeBytes;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (attributeNameCount ^ (attributeNameCount >>> 32));
result = prime * result + (int) (attributeNamesSizeBytes ^ (attributeNamesSizeBytes >>> 32));
result = prime * result + (int) (attributeValueCount ^ (attributeValueCount >>> 32));
result = prime * result + (int) (attributeValuesSizeBytes ^ (attributeValuesSizeBytes >>> 32));
result = prime * result + (int) (itemCount ^ (itemCount >>> 32));
result = prime * result + (int) (itemNamesSizeBytes ^ (itemNamesSizeBytes >>> 32));
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((region == null) ? 0 : region.hashCode());
result = prime * result + ((timestamp == null) ? 0 : timestamp.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
DomainMetadata other = (DomainMetadata) obj;
if (attributeNameCount != other.attributeNameCount)
return false;
if (attributeNamesSizeBytes != other.attributeNamesSizeBytes)
return false;
if (attributeValueCount != other.attributeValueCount)
return false;
if (attributeValuesSizeBytes != other.attributeValuesSizeBytes)
return false;
if (itemCount != other.itemCount)
return false;
if (itemNamesSizeBytes != other.itemNamesSizeBytes)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (region == null) {
if (other.region != null)
return false;
} else if (!region.equals(other.region))
return false;
if (timestamp == null) {
if (other.timestamp != null)
return false;
} else if (!timestamp.equals(other.timestamp))
return false;
return true;
}
@Override
public String toString() {
return "[region=" + region + ", name=" + name + ", timestamp=" + timestamp + ", itemCount=" + itemCount
+ ", attributeValueCount=" + attributeValueCount + ", attributeNameCount=" + attributeNameCount
+ ", itemNamesSizeBytes=" + itemNamesSizeBytes + ", attributeValuesSizeBytes=" + attributeValuesSizeBytes
+ ", attributeNamesSizeBytes=" + attributeNamesSizeBytes + "]";
}
}

View File

@ -0,0 +1,37 @@
/**
*
* Copyright (C) 2010 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.simpledb.domain;
import java.util.Set;
/**
*
* @author Adrian Cole
* @see <a href="http://docs.amazonwebservices.com/AmazonS3/2006-03-01/index.html" />
*/
public interface ListDomainsResponse extends Set<String> {
/**
* An opaque token indicating that there are more than MaxNumberOfDomains domains still
* available.
*/
String getNextToken();
}

View File

@ -0,0 +1,101 @@
/**
*
* Copyright (C) 2010 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.simpledb.options;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import org.jclouds.http.options.BaseHttpRequestOptions;
/**
* Contains options supported in the Form API for the ListDomains operation. <h2>
* Usage</h2> The recommended way to instantiate a ListDomainsOptions object is to statically import
* ListDomainsOptions.Builder.* and invoke a static creation method followed by an instance mutator
* (if needed):
* <p/>
* <code>
* import static org.jclouds.aws.simpledb.options.ListDomainsOptions.Builder.*
* <p/>
* SimpleDBClient connection = // get connection
* Set<String> domains = connection.listDomainsInRegion(maxNumberOfDomains(1));
* <code>
*
* @author Adrian Cole
* @see <a href=
* "http://docs.amazonwebservices.com/AmazonSimpleDB/2009-04-15/DeveloperGuide/SDB_API_ListDomains.html"
* />
*/
public class ListDomainsOptions extends BaseHttpRequestOptions {
/**
* The maximum number of domain names you want returned.
*
* @param maxNumberOfDomains
* Maximum 100
*/
public ListDomainsOptions maxNumberOfDomains(int maxNumberOfDomains) {
checkArgument(maxNumberOfDomains > 0 && maxNumberOfDomains <= 100, "must be between 1-100");
formParameters.put("MaxNumberOfDomains", maxNumberOfDomains + "");
return this;
}
public String getMaxNumberOfDomains() {
return getFirstFormOrNull("MaxNumberOfDomains");
}
/**
*
* @param nextToken
* tells Amazon SimpleDB where to start the next list of domain names.
*/
public ListDomainsOptions nextToken(String nextToken) {
checkNotNull(nextToken, "nextToken");
formParameters.put("NextToken", nextToken);
return this;
}
/**
*
* @return String that tells Amazon SimpleDB where to start the next list of domain names.
*/
public String getNextToken() {
return getFirstFormOrNull("NextToken");
}
public static class Builder {
/**
* @see ListDomainsOptions#nextToken
*/
public static ListDomainsOptions nextToken(String nextToken) {
ListDomainsOptions options = new ListDomainsOptions();
return options.nextToken(nextToken);
}
/**
* @see ListDomainsOptions#maxNumberOfDomains
*/
public static ListDomainsOptions maxNumberOfDomains(int maxNumberOfDomains) {
ListDomainsOptions options = new ListDomainsOptions();
return options.maxNumberOfDomains(maxNumberOfDomains);
}
}
}

View File

@ -0,0 +1,25 @@
/**
*
* Copyright (C) 2010 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.
* ====================================================================
*/
/**
*
* @see <a href="http://docs.amazonwebservices.com/AmazonSimpleDB/2009-04-15/DeveloperGuide/index.html"/>
* @author Adrian Cole
*/
package org.jclouds.aws.simpledb;

View File

@ -0,0 +1,74 @@
/**
*
* Copyright (C) 2010 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.simpledb.reference;
/**
* Configuration properties and constants used in SimpleDB connections.
*
* @see <a href="http://docs.amazonwebservices.com/AWSSimpleDomainService/2009-02-01/APIReference/Query_QueryParams.html"
* />
* @author Adrian Cole
*/
public interface SimpleDBParameters {
/**
* The action to perform. For example: CreateDomain.
*/
public static final String ACTION = "Action";
/**
* The API version to use, as specified in the WSDL. For example: 2009-02-01.
*/
public static final String VERSION = "Version";
/**
* Your Access Key ID. For example: 0AS7253JW73RRM652K02. For more information, see Your AWS
* Identifiers in the Amazon SimpleDB Developer Guide.
*/
public static final String AWS_ACCESS_KEY_ID = "AWSAccessKeyId";
/**
* The date and time the request is signed, in the format YYYY-MM-DDThh:mm:ssZ, as specified in
* the ISO 8601 standard. Query requests must include either Timestamp or Expires, but not both.
*
*/
public static final String TIMESTAMP = "Timestamp";
/**
* The date and time at which the signature included in the request expires, in the format
* YYYY-MM-DDThh:mm:ssZ, as specified in the ISO 8601 standard. Query requests must include
* either Timestamp or Expires, but not both.
*/
public static final String EXPIRES = "Expires";
/**
* A request signature (for information, see Request Authentication in the Amazon SimpleDB Developer
* Guide). For example: Qnpl4Qk/7tINHzfXCiT7VbBatDA=.
*/
public static final String SIGNATURE = "Signature";
/**
*Required when you use signature version 2 with Query requests. For more information, see Query
* Request Authentication in the Amazon SimpleDB Developer Guide.
*/
public static final String SIGNATURE_METHOD = "SignatureMethod";
/**
* For more information, see Query Request Authentication in the Amazon SimpleDB Developer Guide.
*/
public static final String SIGNATURE_VERSION = "SignatureVersion";
}

View File

@ -0,0 +1,24 @@
/**
*
* Copyright (C) 2010 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.
* ====================================================================
*/
/**
* This package contains properties and reference data used in SimpleDB.
* @author Adrian Cole
*/
package org.jclouds.aws.simpledb.reference;

View File

@ -0,0 +1,83 @@
/**
*
* Copyright (C) 2010 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.simpledb.xml;
import java.util.LinkedHashSet;
import java.util.Set;
import org.jclouds.aws.simpledb.domain.ListDomainsResponse;
import org.jclouds.http.functions.ParseSax;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
/**
* Parses the following XML document:
* <p/>
* ListDomainsResponse
*
* @author Adrian Cole
* @see <a href=
* "http://docs.amazonwebservices.com/AmazonSimpleDB/2009-04-15/DeveloperGuide/SDB_API_ListDomains.htm l"
* />
*/
public class ListDomainsResponseHandler extends ParseSax.HandlerWithResult<ListDomainsResponse> {
private StringBuilder currentText = new StringBuilder();
private Set<String> domains = Sets.newLinkedHashSet();
private String nextToken;
@Override
public ListDomainsResponse getResult() {
return new ListDomainsResponseImpl(domains, nextToken);
}
public static class ListDomainsResponseImpl extends LinkedHashSet<String> implements ListDomainsResponse {
private static final long serialVersionUID = 1L;
private final String nextToken;
public ListDomainsResponseImpl(Iterable<String> domains, String nextToken) {
Iterables.addAll(this, domains);
this.nextToken = nextToken;
}
@Override
public String getNextToken() {
return nextToken;
}
}
public void endElement(String uri, String name, String qName) {
if (qName.equals("DomainName")) {
domains.add(currentText.toString().trim());
} else if (qName.equals("NextToken")) {
if (!currentText.toString().equals(""))
this.nextToken = currentText.toString().trim();
}
currentText = new StringBuilder();
}
public void characters(char ch[], int start, int length) {
currentText.append(ch, start, length);
}
}

View File

@ -106,7 +106,7 @@ public class EC2ComputeServiceLiveTest extends BaseComputeServiceLiveTest {
InstanceClient instanceClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi())
.getInstanceServices();
String tag = this.tag + "optionsandlogin";
String tag = this.tag + "o";
TemplateOptions options = client.templateOptions();
@ -190,7 +190,7 @@ public class EC2ComputeServiceLiveTest extends BaseComputeServiceLiveTest {
InstanceClient instanceClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi())
.getInstanceServices();
String tag = this.tag + "optionsnokey";
String tag = this.tag + "k";
TemplateOptions options = client.templateOptions();
@ -250,7 +250,7 @@ public class EC2ComputeServiceLiveTest extends BaseComputeServiceLiveTest {
InstanceClient instanceClient = EC2Client.class.cast(context.getProviderSpecificContext().getApi())
.getInstanceServices();
String tag = this.tag + "optionswithsubnetid";
String tag = this.tag + "g";
TemplateOptions options = client.templateOptions();

View File

@ -75,7 +75,7 @@ public class EC2TemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
assertEquals(template.getImage().getOperatingSystem().getVersion(), "10.10");
assertEquals(template.getImage().getOperatingSystem().is64Bit(), false);
assertEquals(template.getImage().getOperatingSystem().getFamily(), OsFamily.UBUNTU);
assertEquals(template.getImage().getVersion(), "20101106");
assertEquals(template.getImage().getVersion(), "20101204");
assertEquals(template.getImage().getUserMetadata().get("rootDeviceType"), "instance-store");
assertEquals(template.getLocation().getId(), "us-east-1");
assertEquals(getCores(template.getHardware()), 1.0d);
@ -107,7 +107,7 @@ public class EC2TemplateBuilderLiveTest extends BaseTemplateBuilderLiveTest {
Template defaultTemplate = context.getComputeService().templateBuilder().build();
assert (defaultTemplate.getImage().getProviderId().startsWith("ami-")) : defaultTemplate;
assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "0.9.9-beta");
assertEquals(defaultTemplate.getImage().getOperatingSystem().getVersion(), "2010.11.1-beta");
assertEquals(defaultTemplate.getImage().getOperatingSystem().is64Bit(), true);
assertEquals(defaultTemplate.getImage().getOperatingSystem().getFamily(), OsFamily.AMZN_LINUX);
assertEquals(defaultTemplate.getImage().getUserMetadata().get("rootDeviceType"), "ebs");

View File

@ -43,7 +43,7 @@ public class EucalyptusComputeServiceLiveTestDisabled extends EC2ComputeServiceL
@Override
public void setServiceDefaults() {
// security groups must be <30 characters
tag = "euc";
tag = "eu";
}
@Override

View File

@ -0,0 +1,106 @@
/**
*
* Copyright (C) 2010 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.ec2.compute;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
import org.jclouds.Constants;
import org.jclouds.compute.ComputeServiceContext;
import org.jclouds.compute.ComputeServiceContextFactory;
import org.jclouds.compute.RunNodesException;
import org.jclouds.compute.predicates.NodePredicates;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.ssh.jsch.config.JschSshClientModule;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Module;
/**
*
* @author Adrian Cole
*/
@Test(groups = "live")
public class TestCanRecreateTagLiveTest {
private ComputeServiceContext context;
protected String provider = "ec2";
protected String identity;
protected String credential;
protected String endpoint;
protected String apiversion;
@BeforeClass
protected void setupCredentials() {
identity = checkNotNull(System.getProperty("test." + provider + ".identity"), "test." + provider + ".identity");
credential = System.getProperty("test." + provider + ".credential");
endpoint = System.getProperty("test." + provider + ".endpoint");
apiversion = System.getProperty("test." + provider + ".apiversion");
}
protected Properties setupProperties() {
Properties overrides = new Properties();
overrides.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "true");
overrides.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, "true");
overrides.setProperty(provider + ".identity", identity);
if (credential != null)
overrides.setProperty(provider + ".credential", credential);
if (endpoint != null)
overrides.setProperty(provider + ".endpoint", endpoint);
if (apiversion != null)
overrides.setProperty(provider + ".apiversion", apiversion);
return overrides;
}
@BeforeGroups(groups = { "live" })
public void setupClient() throws FileNotFoundException, IOException {
setupCredentials();
Properties overrides = setupProperties();
context = new ComputeServiceContextFactory().createContext(provider,
ImmutableSet.<Module> of(new Log4JLoggingModule(), new JschSshClientModule()), overrides);
}
public void testCanRecreateTag() throws Exception {
String tag = PREFIX + "recreate";
context.getComputeService().destroyNodesMatching(NodePredicates.withTag(tag));
try {
context.getComputeService().runNodesWithTag(tag, 1);
context.getComputeService().destroyNodesMatching(NodePredicates.withTag(tag));
context.getComputeService().runNodesWithTag(tag, 1);
} catch (RunNodesException e) {
System.err.println(e.getNodeErrors().keySet());
Throwables.propagate(e);
} finally {
context.getComputeService().destroyNodesMatching(NodePredicates.withTag(tag));
}
}
public static final String PREFIX = System.getProperty("user.name") + "ec2";
}

View File

@ -51,6 +51,9 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.MapMaker;
import javax.annotation.Nullable;
/**
* @author Adrian Cole
@ -140,15 +143,44 @@ public class RunningInstanceToNodeMetadataTest {
"i-9slweygo").location(provider).build());
}
@Test
public void testHandleMissingAMIs() {
// Handle the case when the installed AMI no longer can be found in AWS.
// Create a null-returning function to simulate that the AMI can't be found.
Function<RegionAndName, Image> nullReturningFunction = new Function<RegionAndName, Image>() {
@Override
public Image apply(@Nullable RegionAndName from) {
return null;
}
};
Map<RegionAndName, Image> instanceToImage = new MapMaker().makeComputingMap(nullReturningFunction);
RunningInstanceToNodeMetadata parser = createNodeParser(ImmutableSet.of(m1_small().build()), ImmutableSet
.of(provider), ImmutableMap
.<String, Credentials>of(), EC2ComputeServiceDependenciesModule.instanceToNodeState, instanceToImage);
RunningInstance server = firstInstanceFromResource("/ec2/describe_instances_nova.xml");
assertEquals(parser.apply(server), new NodeMetadataBuilder().state(NodeState.TERMINATED).privateAddresses(
ImmutableSet.of("10.128.207.5")).tag("NOTAG-i-9slweygo").imageId("us-east-1/ami-25CB1213").id(
"us-east-1/i-9slweygo").providerId("i-9slweygo").hardware(m1_small().build()).location(
provider).build());
}
protected RunningInstance firstInstanceFromResource(String resource) {
RunningInstance server = Iterables.get(Iterables.get(DescribeInstancesResponseHandlerTest
.parseRunningInstances(resource), 0), 0);
.parseRunningInstances(resource), 0), 0);
return server;
}
protected RunningInstanceToNodeMetadata createNodeParser(final ImmutableSet<Hardware> hardware,
final ImmutableSet<Location> locations, Set<org.jclouds.compute.domain.Image> images,
Map<String, Credentials> credentialStore) {
final ImmutableSet<Location> locations,
Set<org.jclouds.compute.domain.Image> images,
Map<String, Credentials> credentialStore) {
Map<InstanceState, NodeState> instanceToNodeState = EC2ComputeServiceDependenciesModule.instanceToNodeState;
Map<RegionAndName, Image> instanceToImage = Maps.uniqueIndex(images, new Function<Image, RegionAndName>() {
@ -159,6 +191,13 @@ public class RunningInstanceToNodeMetadataTest {
}
});
return createNodeParser(hardware, locations, credentialStore, instanceToNodeState, instanceToImage);
}
private RunningInstanceToNodeMetadata createNodeParser(final ImmutableSet<Hardware> hardware, final
ImmutableSet<Location> locations, Map<String, Credentials> credentialStore, Map<InstanceState, NodeState>
instanceToNodeState, Map<RegionAndName, Image> instanceToImage) {
Supplier<Set<? extends Location>> locationSupplier = new Supplier<Set<? extends Location>>() {
@Override

View File

@ -0,0 +1,126 @@
/**
*
* Copyright (C) 2010 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.simpledb;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;
import org.jclouds.aws.domain.Region;
import org.jclouds.aws.filters.FormSigner;
import org.jclouds.aws.simpledb.config.SimpleDBRestClientModule;
import org.jclouds.aws.simpledb.options.ListDomainsOptions;
import org.jclouds.aws.simpledb.xml.ListDomainsResponseHandler;
import org.jclouds.http.HttpRequest;
import org.jclouds.http.RequiresHttp;
import org.jclouds.http.functions.ParseSax;
import org.jclouds.http.functions.ReleasePayloadAndReturn;
import org.jclouds.rest.ConfiguresRestClient;
import org.jclouds.rest.RestClientTest;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.RestContextSpec;
import org.jclouds.rest.internal.RestAnnotationProcessor;
import org.testng.annotations.Test;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
/**
* Tests behavior of {@code SimpleDBAsyncClient}
*
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "simpledb.SimpleDBAsyncClientTest")
public class SimpleDBAsyncClientTest extends RestClientTest<SimpleDBAsyncClient> {
@RequiresHttp
@ConfiguresRestClient
private static final class TestSimpleDBRestClientModule extends SimpleDBRestClientModule {
@Override
protected void configure() {
super.configure();
}
}
public void testListDomainsInRegion() throws SecurityException, NoSuchMethodException, IOException {
Method method = SimpleDBAsyncClient.class.getMethod("listDomainsInRegion", String.class,
ListDomainsOptions[].class);
HttpRequest request = processor.createRequest(method);
assertRequestLineEquals(request, "POST https://sdb.amazonaws.com/ HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Host: sdb.amazonaws.com\n");
assertPayloadEquals(request, "Version=2009-04-15&Action=ListDomains", "application/x-www-form-urlencoded", false);
assertResponseParserClassEquals(method, request, ParseSax.class);
assertSaxResponseParserClassEquals(method, ListDomainsResponseHandler.class);
assertExceptionParserClassEquals(method, null);
checkFilters(request);
}
public void testCreateDomainInRegion() throws SecurityException, NoSuchMethodException, IOException {
Method method = SimpleDBAsyncClient.class.getMethod("createDomainInRegion", String.class, String.class);
HttpRequest request = processor.createRequest(method, null, "domainName");
assertRequestLineEquals(request, "POST https://sdb.amazonaws.com/ HTTP/1.1");
assertNonPayloadHeadersEqual(request, "Host: sdb.amazonaws.com\n");
assertPayloadEquals(request, "Version=2009-04-15&Action=CreateDomain&DomainName=domainName",
"application/x-www-form-urlencoded", false);
assertResponseParserClassEquals(method, request, ReleasePayloadAndReturn.class);
assertSaxResponseParserClassEquals(method, null);
assertExceptionParserClassEquals(method, null);
checkFilters(request);
}
public void testAllRegions() throws SecurityException, NoSuchMethodException, IOException {
Method method = SimpleDBAsyncClient.class.getMethod("createDomainInRegion", String.class, String.class);
for (String region : Region.ALL_SIMPLEDB) {
processor.createRequest(method, region, "domainName");
}
}
@Override
protected void checkFilters(HttpRequest request) {
assertEquals(request.getFilters().size(), 1);
assertEquals(request.getFilters().get(0).getClass(), FormSigner.class);
}
@Override
protected TypeLiteral<RestAnnotationProcessor<SimpleDBAsyncClient>> createTypeLiteral() {
return new TypeLiteral<RestAnnotationProcessor<SimpleDBAsyncClient>>() {
};
}
@Override
protected Module createModule() {
return new TestSimpleDBRestClientModule();
}
@Override
public RestContextSpec<?, ?> createContextSpec() {
return new RestContextFactory().createContextSpec("simpledb", "identity", "credential", new Properties());
}
}

View File

@ -0,0 +1,174 @@
/**
*
* Copyright (C) 2010 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.simpledb;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.testng.Assert.assertNotNull;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
import org.jclouds.Constants;
import org.jclouds.aws.domain.Region;
import org.jclouds.aws.simpledb.domain.ListDomainsResponse;
import org.jclouds.logging.log4j.config.Log4JLoggingModule;
import org.jclouds.rest.RestContext;
import org.jclouds.rest.RestContextFactory;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.inject.Module;
/**
* Tests behavior of {@code SimpleDBClient}
*
* @author Adrian Cole
*/
@Test(groups = "live", sequential = true, testName = "simpledb.SimpleDBClientLiveTest")
public class SimpleDBClientLiveTest {
private SimpleDBClient client;
private RestContext<SimpleDBClient, SimpleDBAsyncClient> context;
private Set<String> domains = Sets.newHashSet();
protected String provider = "simpledb";
protected String identity;
protected String credential;
protected String endpoint;
protected String apiversion;
protected void setupCredentials() {
identity = checkNotNull(System.getProperty("test." + provider + ".identity"), "test." + provider + ".identity");
credential = checkNotNull(System.getProperty("test." + provider + ".credential"), "test." + provider
+ ".credential");
endpoint = System.getProperty("test." + provider + ".endpoint");
apiversion = System.getProperty("test." + provider + ".apiversion");
}
protected Properties setupProperties() {
Properties overrides = new Properties();
overrides.setProperty(Constants.PROPERTY_TRUST_ALL_CERTS, "true");
overrides.setProperty(Constants.PROPERTY_RELAX_HOSTNAME, "true");
overrides.setProperty(provider + ".identity", identity);
if (credential != null)
overrides.setProperty(provider + ".credential", credential);
if (endpoint != null)
overrides.setProperty(provider + ".endpoint", endpoint);
if (apiversion != null)
overrides.setProperty(provider + ".apiversion", apiversion);
return overrides;
}
@BeforeGroups(groups = { "live" })
public void setupClient() {
setupCredentials();
Properties overrides = setupProperties();
context = new RestContextFactory().createContext(provider, ImmutableSet.<Module> of(new Log4JLoggingModule()),
overrides);
this.client = context.getApi();
}
@Test
void testListDomainsInRegion() throws InterruptedException {
for (String region : Lists.newArrayList(null, Region.EU_WEST_1, Region.US_EAST_1, Region.US_WEST_1,
Region.AP_SOUTHEAST_1)) {
SortedSet<String> allResults = Sets.newTreeSet(client.listDomainsInRegion(region));
assertNotNull(allResults);
if (allResults.size() >= 1) {
String domain = allResults.last();
assertDomainInList(region, domain);
}
}
}
public static final String PREFIX = System.getProperty("user.name") + "-simpledb";
@Test
void testCreateDomain() throws InterruptedException {
String domainName = PREFIX + "1";
for (final String region : Lists.newArrayList(null, Region.EU_WEST_1, Region.US_EAST_1, Region.US_WEST_1,
Region.AP_SOUTHEAST_1)) {
try {
SortedSet<String> result = Sets.newTreeSet(client.listDomainsInRegion(region));
if (result.size() >= 1) {
client.deleteDomainInRegion(region, result.last());
domainName += 1;// cannot recreate a domain within 60 seconds
}
} catch (Exception e) {
}
client.createDomainInRegion(region, domainName);
// TODO get the domain metadata and ensure the region is correct
// if (region != null)
// assertEquals(domain.getRegion(), region);
// assertEquals(domain.getName(), domainName);
assertDomainInList(region, domainName);
domains.add(domainName);
}
}
private void assertDomainInList(final String region, final String domain) throws InterruptedException {
assertEventually(new Runnable() {
public void run() {
ListDomainsResponse domains = client.listDomainsInRegion(region);
assert domains.contains(domain) : domain + " not in " + domains;
}
});
}
private static final int INCONSISTENCY_WINDOW = 10000;
/**
* Due to eventual consistency, container commands may not return correctly immediately. Hence,
* we will try up to the inconsistency window to see if the assertion completes.
*/
protected static void assertEventually(Runnable assertion) throws InterruptedException {
long start = System.currentTimeMillis();
AssertionError error = null;
for (int i = 0; i < 30; i++) {
try {
assertion.run();
if (i > 0)
System.err.printf("%d attempts and %dms asserting %s%n", i + 1, System.currentTimeMillis() - start,
assertion.getClass().getSimpleName());
return;
} catch (AssertionError e) {
error = e;
}
Thread.sleep(INCONSISTENCY_WINDOW / 30);
}
if (error != null)
throw error;
}
@AfterTest
public void shutdown() {
context.close();
}
}

View File

@ -0,0 +1,93 @@
/**
*
* Copyright (C) 2010 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.simpledb.config;
import static org.testng.Assert.assertEquals;
import java.net.URI;
import java.util.Map;
import org.jclouds.aws.domain.Region;
import org.jclouds.aws.handlers.AWSClientErrorRetryHandler;
import org.jclouds.aws.handlers.AWSRedirectionRetryHandler;
import org.jclouds.aws.handlers.ParseAWSErrorFromXmlContent;
import org.jclouds.http.handlers.DelegatingErrorHandler;
import org.jclouds.http.handlers.DelegatingRetryHandler;
import org.jclouds.logging.config.NullLoggingModule;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.rest.BaseRestClientTest.MockModule;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "simpledb.SimpleDBRestClientModuleTest")
public class SimpleDBRestClientModuleTest {
Injector createInjector() {
return new RestContextFactory().createContextBuilder("simpledb", "uid", "key",
ImmutableSet.<Module> of(new MockModule(), new NullLoggingModule())).buildInjector();
}
@Test
void testServerErrorHandler() {
DelegatingErrorHandler handler = createInjector().getInstance(DelegatingErrorHandler.class);
assertEquals(handler.getServerErrorHandler().getClass(), ParseAWSErrorFromXmlContent.class);
}
@Test
void testRegions() {
Map<String, URI> regionMap = createInjector().getInstance(
new Key<Map<String, URI>>(org.jclouds.aws.Region.class) {
});
assertEquals(regionMap, ImmutableMap.<String, URI> of(Region.US_EAST_1, URI
.create("https://sdb.amazonaws.com"), Region.US_WEST_1, URI
.create("https://sdb.us-west-1.amazonaws.com"), Region.EU_WEST_1, URI
.create("https://sdb.eu-west-1.amazonaws.com"), Region.AP_SOUTHEAST_1, URI
.create("https://sdb.ap-southeast-1.amazonaws.com")));
}
@Test
void testClientErrorHandler() {
DelegatingErrorHandler handler = createInjector().getInstance(DelegatingErrorHandler.class);
assertEquals(handler.getClientErrorHandler().getClass(), ParseAWSErrorFromXmlContent.class);
}
@Test
void testClientRetryHandler() {
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
assertEquals(handler.getClientErrorRetryHandler().getClass(),
AWSClientErrorRetryHandler.class);
}
@Test
void testRedirectionRetryHandler() {
DelegatingRetryHandler handler = createInjector().getInstance(DelegatingRetryHandler.class);
assertEquals(handler.getRedirectionRetryHandler().getClass(),
AWSRedirectionRetryHandler.class);
}
}

View File

@ -0,0 +1,90 @@
/**
*
* Copyright (C) 2010 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.simpledb.options;
import static org.jclouds.aws.simpledb.options.ListDomainsOptions.Builder.maxNumberOfDomains;
import static org.jclouds.aws.simpledb.options.ListDomainsOptions.Builder.nextToken;
import static org.testng.Assert.assertEquals;
import java.util.Collections;
import org.jclouds.http.options.HttpRequestOptions;
import org.testng.annotations.Test;
/**
* Tests possible uses of ListDomainsOptions and ListDomainsOptions.Builder.*
*
* @author Adrian Cole
*/
public class ListDomainsOptionsTest {
@Test
public void testAssignability() {
assert HttpRequestOptions.class.isAssignableFrom(ListDomainsOptions.class);
assert !String.class.isAssignableFrom(ListDomainsOptions.class);
}
@Test
public void testNextToken() {
ListDomainsOptions options = new ListDomainsOptions();
options.nextToken("test");
assertEquals(options.buildFormParameters().get("NextToken"), Collections.singletonList("test"));
}
@Test
public void testNullNextToken() {
ListDomainsOptions options = new ListDomainsOptions();
assertEquals(options.buildFormParameters().get("NextToken"), Collections.EMPTY_LIST);
}
@Test
public void testNextTokenStatic() {
ListDomainsOptions options = nextToken("test");
assertEquals(options.buildFormParameters().get("NextToken"), Collections.singletonList("test"));
}
public void testInvalidMaxNumberOfDomainsZero() {
maxNumberOfDomains(0);
}
public void testInvalidMaxNumberOfDomainsOver100() {
maxNumberOfDomains(101);
}
@Test
public void testMaxNumberOfDomains() {
ListDomainsOptions options = new ListDomainsOptions();
options.maxNumberOfDomains(1);
assertEquals(options.buildFormParameters().get("MaxNumberOfDomains"), Collections.singletonList("1"));
}
@Test
public void testNullMaxNumberOfDomains() {
ListDomainsOptions options = new ListDomainsOptions();
assertEquals(options.buildFormParameters().get("MaxNumberOfDomains"), Collections.EMPTY_LIST);
}
@Test
public void testMaxNumberOfDomainsStatic() {
ListDomainsOptions options = maxNumberOfDomains(1);
assertEquals(options.buildFormParameters().get("MaxNumberOfDomains"), Collections.singletonList("1"));
}
}

View File

@ -0,0 +1,51 @@
/**
*
* Copyright (C) 2010 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.simpledb.xml;
import static org.testng.Assert.assertEquals;
import java.io.InputStream;
import org.jclouds.aws.simpledb.domain.ListDomainsResponse;
import org.jclouds.http.functions.BaseHandlerTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableSet;
/**
* Tests behavior of {@code ListDomainsResponseHandler}
*
* @author Adrian Cole
*/
@Test(groups = "unit", sequential = true, testName = "simpledb.ListDomainsResponseHandlerTest")
public class ListDomainsResponseHandlerTest extends BaseHandlerTest {
public void test() {
InputStream is = getClass().getResourceAsStream("/simpledb/list_domains.xml");
ListDomainsResponse result = factory.create(injector.getInstance(ListDomainsResponseHandler.class)).parse(is);
assertEquals(
result,
new ListDomainsResponseHandler.ListDomainsResponseImpl(ImmutableSet.of("Domain1-200706011651",
"Domain2-200706011652"), "TWV0ZXJpbmdUZXN0RG9tYWluMS0yMDA3MDYwMTE2NTY"));
}
}

View File

@ -0,0 +1,11 @@
<ListDomainsResponse>
<ListDomainsResult>
<DomainName>Domain1-200706011651</DomainName>
<DomainName>Domain2-200706011652</DomainName>
<NextToken>TWV0ZXJpbmdUZXN0RG9tYWluMS0yMDA3MDYwMTE2NTY=</NextToken>
</ListDomainsResult>
<ResponseMetadata>
<RequestId>eb13162f-1b95-4511-8b12-489b86acfd28</RequestId>
<BoxUsage>0.0000219907</BoxUsage>
</ResponseMetadata>
</ListDomainsResponse>

View File

@ -52,7 +52,7 @@
<dependency>
<groupId>com.google.code.guice</groupId>
<artifactId>guice-servlet</artifactId>
<version>2.1-r1201</version>
<version>3.0-snapshot-20101120</version>
</dependency>
<dependency>
<groupId>displaytag</groupId>

View File

@ -42,6 +42,10 @@
<test.aws.credential>FIXME</test.aws.credential>
<!-- when instances are hung, open a ticket and add here -->
<jclouds.compute.blacklist.nodes>trmkrun-ccc,test.trmk-924</jclouds.compute.blacklist.nodes>
<test.simpledb.endpoint>https://sdb.amazonaws.com</test.simpledb.endpoint>
<test.simpledb.apiversion>2009-04-15</test.simpledb.apiversion>
<test.simpledb.identity>${test.aws.identity}</test.simpledb.identity>
<test.simpledb.credential>${test.aws.credential}</test.simpledb.credential>
<test.s3.endpoint>https://s3.amazonaws.com</test.s3.endpoint>
<test.s3.apiversion>2006-03-01</test.s3.apiversion>
<test.s3.identity>${test.aws.identity}</test.s3.identity>
@ -187,6 +191,22 @@
<name>jclouds.compute.blacklist.nodes</name>
<value>${jclouds.compute.blacklist.nodes}</value>
</property>
<property>
<name>test.simpledb.endpoint</name>
<value>${test.simpledb.endpoint}</value>
</property>
<property>
<name>test.simpledb.apiversion</name>
<value>${test.simpledb.apiversion}</value>
</property>
<property>
<name>test.simpledb.identity</name>
<value>${test.simpledb.identity}</value>
</property>
<property>
<name>test.simpledb.credential</name>
<value>${test.simpledb.credential}</value>
</property>
<property>
<name>test.sqs.endpoint</name>
<value>${test.sqs.endpoint}</value>

View File

@ -26,6 +26,8 @@ import java.net.URI;
import java.util.Date;
import java.util.Map;
import javax.annotation.Nullable;
import org.jclouds.azure.storage.blob.domain.BlobProperties;
import org.jclouds.azure.storage.blob.domain.BlobType;
import org.jclouds.azure.storage.blob.domain.LeaseStatus;
@ -33,7 +35,6 @@ import org.jclouds.io.ContentMetadata;
import org.jclouds.io.payloads.BaseImmutableContentMetadata;
import com.google.common.collect.Maps;
import com.google.inject.internal.Nullable;
/**
* Allows you to manipulate metadata.

View File

@ -299,7 +299,7 @@ Options can also be specified for extension modules
([container-name]
(count-blobs container-name *blobstore*))
([container-name blobstore]
(.countBlob blobstore container-name)))
(.countBlobs blobstore container-name)))
(defn blobs
"List the blobs in a container:

View File

@ -49,27 +49,28 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Named;
import javax.ws.rs.core.HttpHeaders;
import org.jclouds.Constants;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.MutableBlobMetadata;
import org.jclouds.blobstore.domain.MutableStorageMetadata;
import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.blobstore.domain.internal.MutableStorageMetadataImpl;
import org.jclouds.blobstore.domain.internal.PageSetImpl;
import org.jclouds.blobstore.functions.HttpGetOptionsListToGetOptions;
@ -103,7 +104,6 @@ import com.google.common.collect.Iterables;
import com.google.common.collect.Multimaps;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.internal.Nullable;
/**
* Implementation of {@link BaseAsyncBlobStore} which keeps all data in a local Map object.

View File

@ -19,10 +19,12 @@
package org.jclouds.blobstore.domain;
import javax.annotation.Nullable;
import org.jclouds.io.Payload;
import org.jclouds.io.PayloadEnclosing;
import com.google.common.collect.Multimap;
import com.google.inject.internal.Nullable;
/**
* Value type for an HTTP Blob service. Blobs are stored in containers and consist of a

View File

@ -26,14 +26,14 @@ import java.net.URI;
import java.util.Date;
import java.util.Map;
import javax.annotation.Nullable;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.domain.Location;
import org.jclouds.io.ContentMetadata;
import com.google.inject.internal.Nullable;
/**
* System and user Metadata for the {@link Blob}.
*

View File

@ -26,13 +26,13 @@ import java.net.URI;
import java.util.Date;
import java.util.Map;
import javax.annotation.Nullable;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.domain.Location;
import org.jclouds.domain.internal.ResourceMetadataImpl;
import com.google.inject.internal.Nullable;
/**
* Idpayload of the object
*

View File

@ -87,8 +87,11 @@ public class ParseSystemAndUserMetadataFromHeaders implements Function<HttpRespo
@VisibleForTesting
void parseLastModifiedOrThrowException(HttpResponse from, MutableBlobMetadata metadata) throws HttpException {
String lastModified = from.getFirstHeaderOrNull(HttpHeaders.LAST_MODIFIED);
if (lastModified == null)
throw new HttpException(HttpHeaders.LAST_MODIFIED + " header not present in response: " + from.getStatusLine());
if (lastModified == null) {
// scaleup-storage uses the wrong case for the last modified header
if ((lastModified = from.getFirstHeaderOrNull("Last-modified")) == null)
throw new HttpException(HttpHeaders.LAST_MODIFIED + " header not present in response: " + from.getStatusLine());
}
// Eucalyptus 1.6 returns iso8601 dates
if (apiVersion.indexOf("Walrus-1.6") != -1) {
metadata.setLastModified(dateParser.iso8601DateParse(lastModified.replace("+0000", "Z")));

View File

@ -70,6 +70,7 @@
(is (= 1 (count (list-container "container" :max-results 1))))
(create-directory "container" "dir")
(is (upload-blob "container" "dir/blob2" "blob2"))
(is (= 3 (count-blobs "container")))
(is (= 3 (count (list-container "container"))))
(is (= 4 (count (list-container "container" :recursive true))))
(is (= 3 (count (list-container "container" :with-details true))))

View File

@ -97,7 +97,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
@SuppressWarnings("unchecked")
public static InputSupplier<InputStream> getTestDataSupplier() throws IOException {
byte[] oneConstitution = ByteStreams.toByteArray(new GZIPInputStream(BaseJettyTest.class
.getResourceAsStream("/const.txt.gz")));
.getResourceAsStream("/const.txt.gz")));
InputSupplier<ByteArrayInputStream> constitutionSupplier = ByteStreams.newInputStreamSupplier(oneConstitution);
InputSupplier<InputStream> temp = ByteStreams.join(constitutionSupplier);
@ -120,24 +120,24 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
Map<Integer, Future<?>> responses = Maps.newHashMap();
for (int i = 0; i < 10; i++) {
responses.put(i, Futures.compose(context.getAsyncBlobStore().getBlob(containerName, key),
new Function<Blob, Void>() {
responses.put(i,
Futures.compose(context.getAsyncBlobStore().getBlob(containerName, key), new Function<Blob, Void>() {
@Override
public Void apply(Blob from) {
try {
assertEquals(CryptoStreams.md5(from.getPayload()), oneHundredOneConstitutionsMD5);
checkContentDisposition(from, expectedContentDisposition);
} catch (IOException e) {
Throwables.propagate(e);
}
return null;
@Override
public Void apply(Blob from) {
try {
assertEquals(CryptoStreams.md5(from.getPayload()), oneHundredOneConstitutionsMD5);
checkContentDisposition(from, expectedContentDisposition);
} catch (IOException e) {
Throwables.propagate(e);
}
return null;
}
}, this.exec));
}, this.exec));
}
Map<Integer, Exception> exceptions = awaitCompletion(responses, exec, 30000l, Logger.CONSOLE,
"get constitution");
"get constitution");
assert exceptions.size() == 0 : exceptions;
} finally {
@ -156,7 +156,6 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
context.getBlobStore().putBlob(containerName, sourceObject);
}
@Test(groups = { "integration", "live" })
public void testGetIfModifiedSince() throws InterruptedException {
String containerName = getContainerName();
@ -365,15 +364,15 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
@DataProvider(name = "delete")
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" } };
return new Object[][] { { "normal" }, { "sp ace" }, { "qu?stion" }, { "unic₪de" }, { "path/foo" },
{ "colon:" }, { "asteri*k" }, { "quote\"" }, { "{great<r}" }, { "lesst>en" }, { "p|pe" } };
}
@Test(groups = { "integration", "live" }, dataProvider = "delete")
public void deleteObject(String key) throws InterruptedException {
String containerName = getContainerName();
try {
addBlobToContainer(containerName, key);
addBlobToContainer(containerName, key, key, MediaType.TEXT_PLAIN);
context.getBlobStore().removeBlob(containerName, key);
assertContainerEmptyDeleting(containerName, key);
} finally {
@ -383,17 +382,19 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
private void assertContainerEmptyDeleting(String containerName, String key) {
Iterable<? extends StorageMetadata> listing = Iterables.filter(context.getBlobStore().list(containerName),
new Predicate<StorageMetadata>() {
new Predicate<StorageMetadata>() {
@Override
public boolean apply(StorageMetadata input) {
return input.getType() == StorageType.BLOB;
}
@Override
public boolean apply(StorageMetadata input) {
return input.getType() == StorageType.BLOB;
}
});
assertEquals(Iterables.size(listing), 0, String.format(
"deleting %s, we still have %s blobs left in container %s, using encoding %s", key, Iterables
.size(listing), containerName, LOCAL_ENCODING));
});
assertEquals(
Iterables.size(listing),
0,
String.format("deleting %s, we still have %s blobs left in container %s, using encoding %s", key,
Iterables.size(listing), containerName, LOCAL_ENCODING));
}
@Test(groups = { "integration", "live" })
@ -413,13 +414,13 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
String realObject = Utils.toStringAndClose(new FileInputStream("pom.xml"));
return new Object[][] { { "file", "text/xml", new File("pom.xml"), realObject },
{ "string", "text/xml", realObject, realObject },
{ "bytes", "application/octet-stream", realObject.getBytes(), realObject } };
{ "string", "text/xml", realObject, realObject },
{ "bytes", "application/octet-stream", realObject.getBytes(), realObject } };
}
@Test(groups = { "integration", "live" }, dataProvider = "putTests")
public void testPutObject(String key, String type, Object content, Object realObject) throws InterruptedException,
IOException {
IOException {
Blob blob = context.getBlobStore().newBlob(key);
blob.setPayload(Payloads.newPayload(content));
blob.getMetadata().getContentMetadata().setContentType(type);
@ -486,32 +487,32 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
protected void checkContentType(Blob blob, String contentType) {
assert blob.getPayload().getContentMetadata().getContentType().startsWith(contentType) : blob.getPayload()
.getContentMetadata().getContentType();
.getContentMetadata().getContentType();
assert blob.getMetadata().getContentMetadata().getContentType().startsWith(contentType) : blob.getMetadata()
.getContentMetadata().getContentType();
.getContentMetadata().getContentType();
}
protected void checkContentDisposition(Blob blob, String contentDisposition) {
assert blob.getPayload().getContentMetadata().getContentDisposition().startsWith(contentDisposition) : blob
.getPayload().getContentMetadata().getContentDisposition();
.getPayload().getContentMetadata().getContentDisposition();
assert blob.getMetadata().getContentMetadata().getContentDisposition().startsWith(contentDisposition) : blob
.getMetadata().getContentMetadata().getContentDisposition();
.getMetadata().getContentMetadata().getContentDisposition();
}
protected void checkContentEncoding(Blob blob, String contentEncoding) {
assert blob.getPayload().getContentMetadata().getContentEncoding().startsWith(contentEncoding) : blob
.getPayload().getContentMetadata().getContentEncoding();
.getPayload().getContentMetadata().getContentEncoding();
assert blob.getMetadata().getContentMetadata().getContentEncoding().startsWith(contentEncoding) : blob
.getMetadata().getContentMetadata().getContentEncoding();
.getMetadata().getContentMetadata().getContentEncoding();
}
protected void checkContentLanguage(Blob blob, String contentLanguage) {
assert blob.getPayload().getContentMetadata().getContentLanguage().startsWith(contentLanguage) : blob
.getPayload().getContentMetadata().getContentLanguage();
.getPayload().getContentMetadata().getContentLanguage();
assert blob.getMetadata().getContentMetadata().getContentLanguage().startsWith(contentLanguage) : blob
.getMetadata().getContentMetadata().getContentLanguage();
.getMetadata().getContentMetadata().getContentLanguage();
}
@ -565,7 +566,7 @@ public class BaseBlobIntegrationTest extends BaseBlobStoreIntegrationTest {
protected void validateMetadata(BlobMetadata metadata) throws IOException {
assert metadata.getContentMetadata().getContentType().startsWith("text/plain") : metadata.getContentMetadata()
.getContentType();
.getContentType();
assertEquals(metadata.getContentMetadata().getContentLength(), new Long(TEST_STRING.length()));
assertEquals(metadata.getUserMetadata().get("adrian"), "powderpuff");
checkMD5(metadata);

View File

@ -25,8 +25,8 @@ import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CancellationException;
@ -35,6 +35,8 @@ import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import javax.ws.rs.core.MediaType;
import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.attr.ConsistencyModel;
import org.jclouds.blobstore.domain.Blob;
@ -60,13 +62,13 @@ public class BaseBlobStoreIntegrationTest {
protected static final String TEST_STRING = String.format(XML_STRING_FORMAT, "apple");
protected Map<String, String> fiveStrings = ImmutableMap.of("one", String.format(XML_STRING_FORMAT, "apple"), "two",
String.format(XML_STRING_FORMAT, "bear"), "three", String.format(XML_STRING_FORMAT, "candy"), "four",
String.format(XML_STRING_FORMAT, "dogma"), "five", String.format(XML_STRING_FORMAT, "emma"));
String.format(XML_STRING_FORMAT, "bear"), "three", String.format(XML_STRING_FORMAT, "candy"), "four",
String.format(XML_STRING_FORMAT, "dogma"), "five", String.format(XML_STRING_FORMAT, "emma"));
protected Map<String, String> fiveStringsUnderPath = ImmutableMap.of("path/1", String.format(XML_STRING_FORMAT,
"apple"), "path/2", String.format(XML_STRING_FORMAT, "bear"), "path/3", String.format(XML_STRING_FORMAT,
"candy"), "path/4", String.format(XML_STRING_FORMAT, "dogma"), "path/5", String.format(XML_STRING_FORMAT,
"emma"));
protected Map<String, String> fiveStringsUnderPath = ImmutableMap.of("path/1",
String.format(XML_STRING_FORMAT, "apple"), "path/2", String.format(XML_STRING_FORMAT, "bear"), "path/3",
String.format(XML_STRING_FORMAT, "candy"), "path/4", String.format(XML_STRING_FORMAT, "dogma"), "path/5",
String.format(XML_STRING_FORMAT, "emma"));
public static long INCONSISTENCY_WINDOW = 10000;
protected static volatile AtomicInteger containerIndex = new AtomicInteger(0);
@ -90,7 +92,7 @@ public class BaseBlobStoreIntegrationTest {
@SuppressWarnings("unchecked")
private BlobStoreContext getCloudResources(ITestContext testContext) throws ClassNotFoundException,
InstantiationException, IllegalAccessException, Exception {
InstantiationException, IllegalAccessException, Exception {
String initializerClass = checkNotNull(System.getProperty("test.initializer"), "test.initializer");
Class<BaseTestInitializer> clazz = (Class<BaseTestInitializer>) Class.forName(initializerClass);
BaseTestInitializer initializer = clazz.newInstance();
@ -123,7 +125,7 @@ public class BaseBlobStoreIntegrationTest {
private static volatile boolean initialized = false;
protected void createContainersSharedByAllThreads(BlobStoreContext context, ITestContext testContext)
throws Exception {
throws Exception {
while (!initialized) {
synchronized (BaseBlobStoreIntegrationTest.class) {
if (!initialized) {
@ -174,12 +176,12 @@ public class BaseBlobStoreIntegrationTest {
try {
for (int i = 0; i < 2; i++) {
Iterable<? extends StorageMetadata> testContainers = Iterables.filter(context.getBlobStore().list(),
new Predicate<StorageMetadata>() {
public boolean apply(StorageMetadata input) {
return (input.getType() == StorageType.CONTAINER || input.getType() == StorageType.FOLDER)
&& input.getName().startsWith(CONTAINER_PREFIX.toLowerCase());
}
});
new Predicate<StorageMetadata>() {
public boolean apply(StorageMetadata input) {
return (input.getType() == StorageType.CONTAINER || input.getType() == StorageType.FOLDER)
&& input.getName().startsWith(CONTAINER_PREFIX.toLowerCase());
}
});
for (StorageMetadata container : testContainers) {
deleteContainerOrWarnIfUnable(context, container.getName());
}
@ -200,7 +202,7 @@ public class BaseBlobStoreIntegrationTest {
* we will try up to the inconsistency window to see if the assertion completes.
*/
protected static void assertConsistencyAware(BlobStoreContext context, Runnable assertion)
throws InterruptedException {
throws InterruptedException {
if (context.getConsistencyModel() == ConsistencyModel.STRICT) {
assertion.run();
return;
@ -226,7 +228,7 @@ public class BaseBlobStoreIntegrationTest {
}
protected static void createContainerAndEnsureEmpty(BlobStoreContext context, final String containerName)
throws InterruptedException {
throws InterruptedException {
context.getBlobStore().createContainerInLocation(null, containerName);
if (context.getConsistencyModel() == ConsistencyModel.EVENTUAL)
Thread.sleep(1000);
@ -238,9 +240,13 @@ public class BaseBlobStoreIntegrationTest {
}
protected String addBlobToContainer(String sourceContainer, String key) {
return addBlobToContainer(sourceContainer, key, TEST_STRING, MediaType.TEXT_XML);
}
protected String addBlobToContainer(String sourceContainer, String key, String payload, String contentType) {
Blob sourceObject = context.getBlobStore().newBlob(key);
sourceObject.setPayload(TEST_STRING);
sourceObject.getMetadata().getContentMetadata().setContentType("text/xml");
sourceObject.setPayload(payload);
sourceObject.getMetadata().getContentMetadata().setContentType(contentType);
return addBlobToContainer(sourceContainer, sourceObject);
}
@ -270,19 +276,19 @@ public class BaseBlobStoreIntegrationTest {
}
protected void assertConsistencyAwareContainerSize(final String containerName, final int count)
throws InterruptedException {
throws InterruptedException {
assertConsistencyAware(new Runnable() {
public void run() {
try {
assert context.getBlobStore().countBlobs(containerName) == count : String.format(
"expected only %d values in %s: %s", count, containerName, Sets.newHashSet(Iterables.transform(
context.getBlobStore().list(containerName), new Function<StorageMetadata, String>() {
"expected only %d values in %s: %s", count, containerName, Sets.newHashSet(Iterables.transform(
context.getBlobStore().list(containerName), new Function<StorageMetadata, String>() {
public String apply(StorageMetadata from) {
return from.getName();
}
public String apply(StorageMetadata from) {
return from.getName();
}
})));
})));
} catch (Exception e) {
Throwables.propagateIfPossible(e);
}

View File

@ -35,11 +35,10 @@ import com.google.inject.Module;
*
* @author Adrian Cole
*/
public class StandaloneComputeServiceContextBuilder extends
ComputeServiceContextBuilder<ComputeService, ComputeService> {
public class StandaloneComputeServiceContextBuilder<D> extends ComputeServiceContextBuilder<D, D> {
public StandaloneComputeServiceContextBuilder(Properties props) {
super(ComputeService.class, ComputeService.class, props);
public StandaloneComputeServiceContextBuilder(Class<D> driverClass, Properties props) {
super(driverClass, driverClass, props);
if (properties.size() == 0)
properties.putAll(new PropertiesBuilder().build());
if (!properties.containsKey("jclouds.provider"))
@ -54,7 +53,7 @@ public class StandaloneComputeServiceContextBuilder extends
@Override
protected void addClientModule(List<Module> modules) {
modules.add(new StandaloneComputeServiceClientModule<ComputeService>(ComputeService.class));
modules.add(new StandaloneComputeServiceClientModule<D>(syncClientType));
}
}

View File

@ -20,24 +20,34 @@
package org.jclouds.compute;
import org.jclouds.PropertiesBuilder;
import org.jclouds.compute.config.StandaloneComputeServiceContextModule;
import org.jclouds.rest.RestContextSpec;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.inject.Module;
/**
* @author Adrian Cole
*/
public class StandaloneComputeServiceContextSpec<N, H, I, L> extends RestContextSpec<ComputeService, ComputeService> {
public class StandaloneComputeServiceContextSpec<D, N, H, I, L> extends RestContextSpec<D, D> {
public StandaloneComputeServiceContextSpec(String provider, String endpoint, String apiVersion, String identity,
String credential, Class<D> driverClass,
Class<? extends StandaloneComputeServiceContextBuilder<D>> contextBuilderClass) {
this(provider, endpoint, apiVersion, identity, credential, driverClass, contextBuilderClass, ImmutableSet
.<Module> of());
}
public StandaloneComputeServiceContextSpec(String provider, String endpoint, String apiVersion, String identity,
String credential, Class<D> driverClass,
Class<? extends StandaloneComputeServiceContextBuilder<D>> contextBuilderClass, Iterable<Module> modules) {
this(provider, endpoint, apiVersion, identity, credential, driverClass, PropertiesBuilder.class,
contextBuilderClass, modules);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public StandaloneComputeServiceContextSpec(String provider, String endpoint, String apiVersion, String identity,
String credential, StandaloneComputeServiceContextModule<N, H, I, L> contextModule, Iterable<Module> modules) {
super(provider, endpoint, apiVersion, identity, credential, ComputeService.class, ComputeService.class,
PropertiesBuilder.class, (Class) StandaloneComputeServiceContextBuilder.class, Iterables.concat(
ImmutableSet.of(contextModule), modules));
String credential, Class<D> driverClass, Class<? extends PropertiesBuilder> propertiesBuilderClass,
Class<? extends StandaloneComputeServiceContextBuilder<D>> contextBuilderClass, Iterable<Module> modules) {
super(provider, endpoint, apiVersion, identity, credential, driverClass, driverClass,
(Class) propertiesBuilderClass, (Class) contextBuilderClass, modules);
}
}

View File

@ -1,7 +1,25 @@
/**
*
* Copyright (C) 2010 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.compute.config;
import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.config.StandaloneComputeServiceContextModule;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
@ -10,6 +28,10 @@ import org.jclouds.domain.Location;
import com.google.common.base.Function;
import com.google.inject.TypeLiteral;
/**
*
* @author Adrian Cole
*/
public class JCloudsNativeStandaloneComputeServiceContextModule extends
StandaloneComputeServiceContextModule<NodeMetadata, Hardware, Image, Location> {
private final Class<? extends ComputeServiceAdapter<NodeMetadata, Hardware, Image, Location>> adapter;

View File

@ -21,6 +21,7 @@ package org.jclouds.compute.stub;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.ConcurrentMap;
import org.jclouds.compute.StandaloneComputeServiceContextBuilder;
import org.jclouds.compute.stub.config.StubComputeServiceContextModule;
@ -31,10 +32,11 @@ import com.google.inject.Module;
*
* @author Adrian Cole
*/
public class StubComputeServiceContextBuilder extends StandaloneComputeServiceContextBuilder {
@SuppressWarnings("rawtypes")
public class StubComputeServiceContextBuilder extends StandaloneComputeServiceContextBuilder<ConcurrentMap> {
public StubComputeServiceContextBuilder(Properties props) {
super(props);
super(ConcurrentMap.class, props);
}
@Override

View File

@ -19,9 +19,16 @@
package org.jclouds.compute.stub.config;
import java.util.concurrent.ConcurrentMap;
import javax.inject.Singleton;
import org.jclouds.compute.config.JCloudsNativeStandaloneComputeServiceContextModule;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.concurrent.SingleThreaded;
import com.google.inject.Provides;
/**
*
* @author Adrian Cole
@ -33,6 +40,14 @@ public class StubComputeServiceContextModule extends JCloudsNativeStandaloneComp
super(StubComputeServiceAdapter.class);
}
// Ensure that a plain class is able to be bound as getProviderSpecificContext.getApi()
@SuppressWarnings("rawtypes")
@Provides
@Singleton
ConcurrentMap provideApi(ConcurrentMap<String, NodeMetadata> in) {
return in;
}
@Override
protected void configure() {
install(new StubComputeServiceDependenciesModule());

View File

@ -74,6 +74,7 @@ import org.jclouds.net.IPSocket;
import org.jclouds.predicates.RetryablePredicate;
import org.jclouds.predicates.SocketOpen;
import org.jclouds.rest.AuthorizationException;
import org.jclouds.rest.RestContextFactory;
import org.jclouds.scriptbuilder.domain.OsFamily;
import org.jclouds.ssh.ExecResponse;
import org.jclouds.ssh.SshClient;
@ -161,11 +162,15 @@ public abstract class BaseComputeServiceLiveTest {
if (context != null)
context.close();
Properties props = setupProperties();
context = new ComputeServiceContextFactory().createContext(provider,
context = new ComputeServiceContextFactory(getRestProperties()).createContext(provider,
ImmutableSet.of(new Log4JLoggingModule(), getSshModule()), props);
client = context.getComputeService();
}
protected Properties getRestProperties() {
return RestContextFactory.getPropertiesFromResource("/rest.properties");
}
abstract protected Module getSshModule();
// wait up to 5 seconds for an auth exception
@ -200,7 +205,7 @@ public abstract class BaseComputeServiceLiveTest {
// starting this one alphabetically before create2nodes..
@Test(enabled = true, dependsOnMethods = { "testCompareSizes" })
public void testAScriptExecutionAfterBootWithBasicTemplate() throws Exception {
String tag = this.tag + "run";
String tag = this.tag + "r";
try {
client.destroyNodesMatching(withTag(tag));
} catch (Exception e) {
@ -460,7 +465,7 @@ public abstract class BaseComputeServiceLiveTest {
@Test(enabled = true)
public void testCreateAndRunAService() throws Exception {
String tag = this.tag + "service";
String tag = this.tag + "s";
try {
client.destroyNodesMatching(withTag(tag));
} catch (Exception e) {

View File

@ -19,10 +19,12 @@
package org.jclouds.compute;
import java.util.concurrent.ConcurrentMap;
import org.jclouds.compute.domain.Hardware;
import org.jclouds.compute.domain.Image;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.stub.config.StubComputeServiceContextModule;
import org.jclouds.compute.stub.StubComputeServiceContextBuilder;
import org.jclouds.domain.Location;
import org.testng.annotations.Test;
@ -39,10 +41,11 @@ public class ComputeServiceContextFactoryTest {
@Test
public void testStandalone() {
@SuppressWarnings("rawtypes")
ComputeServiceContext context = new ComputeServiceContextFactory()
.createContext(new StandaloneComputeServiceContextSpec<NodeMetadata, Hardware, Image, Location>("stub",
"stub", "1", "identity", "credential", new StubComputeServiceContextModule(), ImmutableSet
.<Module> of()));
.createContext(new StandaloneComputeServiceContextSpec<ConcurrentMap, NodeMetadata, Hardware, Image, Location>(
"stub", "stub", "1", "identity", "credential", ConcurrentMap.class,
StubComputeServiceContextBuilder.class, ImmutableSet.<Module> of()));
context.getComputeService().listNodes();
}

View File

@ -81,7 +81,7 @@
<dependency>
<groupId>com.google.code.guice</groupId>
<artifactId>guice</artifactId>
<version>2.1-r1201</version>
<version>3.0-snapshot-20101120</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
@ -101,12 +101,12 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>1.5</version>
<version>1.6</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>r06</version>
<version>r07</version>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>

View File

@ -1,182 +0,0 @@
/**
*
* Copyright (C) 2010 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.
* ====================================================================
*/
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.gson;
import java.io.IOException;
/**
* The only reason I am pasting this class and changing 2 lines is because the
* gson project uses abstract classes and final otherwise for every part one
* might want to extend. We simply need to control the formatting of json
* literals, and hopefully one day gson will allow us to subclass something.
*
* @author Adrian Cole
* @author Inderjeet Singh
*/
public class JcloudsCompactFormatter implements JsonFormatter {
static class FormattingVisitor implements JsonElementVisitor {
private final Appendable writer;
private final Escaper escaper;
private final boolean serializeNulls;
FormattingVisitor(Appendable writer, Escaper escaper, boolean serializeNulls) {
this.writer = writer;
this.escaper = escaper;
this.serializeNulls = serializeNulls;
}
public void visitLiteral(JsonLiteral primitive) throws IOException {
primitive.toString(writer, escaper);
}
public void visitPrimitive(JsonPrimitive primitive) throws IOException {
primitive.toString(writer, escaper);
}
public void visitNull() throws IOException {
writer.append("null");
}
public void startArray(JsonArray array) throws IOException {
writer.append('[');
}
public void visitArrayMember(JsonArray parent, JsonPrimitive member, boolean isFirst) throws IOException {
if (!isFirst) {
writer.append(',');
}
member.toString(writer, escaper);
}
public void visitArrayMember(JsonArray parent, JsonArray member, boolean isFirst) throws IOException {
if (!isFirst) {
writer.append(',');
}
}
public void visitArrayMember(JsonArray parent, JsonObject member, boolean isFirst) throws IOException {
if (!isFirst) {
writer.append(',');
}
}
public void visitNullArrayMember(JsonArray parent, boolean isFirst) throws IOException {
if (!isFirst) {
writer.append(',');
}
}
public void endArray(JsonArray array) throws IOException {
writer.append(']');
}
public void startObject(JsonObject object) throws IOException {
writer.append('{');
}
public void visitObjectMember(JsonObject parent, String memberName, JsonLiteral member, boolean isFirst)
throws IOException {
if (!isFirst) {
writer.append(',');
}
writer.append('"');
writer.append(memberName);
writer.append("\":");
member.toString(writer, escaper);
}
public void visitObjectMember(JsonObject parent, String memberName, JsonPrimitive member, boolean isFirst)
throws IOException {
if (!isFirst) {
writer.append(',');
}
writer.append('"');
writer.append(memberName);
writer.append("\":");
member.toString(writer, escaper);
}
public void visitObjectMember(JsonObject parent, String memberName, JsonArray member, boolean isFirst)
throws IOException {
if (!isFirst) {
writer.append(',');
}
writer.append('"');
writer.append(memberName);
writer.append("\":");
}
public void visitObjectMember(JsonObject parent, String memberName, JsonObject member, boolean isFirst)
throws IOException {
if (!isFirst) {
writer.append(',');
}
writer.append('"');
writer.append(memberName);
writer.append("\":");
}
public void visitNullObjectMember(JsonObject parent, String memberName, boolean isFirst) throws IOException {
if (serializeNulls) {
visitObjectMember(parent, memberName, (JsonObject) null, isFirst);
}
}
public void endObject(JsonObject object) throws IOException {
writer.append('}');
}
}
private final boolean escapeHtmlChars;
public JcloudsCompactFormatter() {
this(true);
}
JcloudsCompactFormatter(boolean escapeHtmlChars) {
this.escapeHtmlChars = escapeHtmlChars;
}
public void format(JsonElement root, Appendable writer, boolean serializeNulls) throws IOException {
if (root == null) {
return;
}
FormattingVisitor visitor = new FormattingVisitor(writer, new Escaper(escapeHtmlChars), serializeNulls);
JcloudsTreeNavigator navigator = new JcloudsTreeNavigator(visitor, serializeNulls);
navigator.navigate(root);
}
}

View File

@ -1,928 +0,0 @@
/**
*
* Copyright (C) 2010 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.
* ====================================================================
*/
/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.gson;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.SortedSet;
import java.util.StringTokenizer;
import java.util.TreeSet;
import java.util.UUID;
import com.google.common.base.Function;
import com.google.common.collect.MapMaker;
/**
* List of all the default type adapters ({@link JsonSerializer}s, {@link JsonDeserializer}s, and
* {@link InstanceCreator}s.
*
* <h4>Note!</h4>
* changed to edit the default behaviour of enum parsing by Adrian Cole
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
final class JcloudsDefaultTypeAdapters {
private static final DefaultDateTypeAdapter DATE_TYPE_ADAPTER = new DefaultDateTypeAdapter();
private static final DefaultJavaSqlDateTypeAdapter JAVA_SQL_DATE_TYPE_ADAPTER = new DefaultJavaSqlDateTypeAdapter();
private static final DefaultTimeTypeAdapter TIME_TYPE_ADAPTER = new DefaultTimeTypeAdapter();
private static final DefaultTimestampDeserializer TIMESTAMP_DESERIALIZER = new DefaultTimestampDeserializer();
@SuppressWarnings({ "rawtypes" })
private static final EnumTypeAdapter ENUM_TYPE_ADAPTER = new EnumTypeAdapter();
private static final UrlTypeAdapter URL_TYPE_ADAPTER = new UrlTypeAdapter();
private static final UriTypeAdapter URI_TYPE_ADAPTER = new UriTypeAdapter();
private static final UuidTypeAdapter UUUID_TYPE_ADAPTER = new UuidTypeAdapter();
private static final LocaleTypeAdapter LOCALE_TYPE_ADAPTER = new LocaleTypeAdapter();
private static final CollectionTypeAdapter COLLECTION_TYPE_ADAPTER = new CollectionTypeAdapter();
private static final MapTypeAdapter MAP_TYPE_ADAPTER = new MapTypeAdapter();
private static final BigDecimalTypeAdapter BIG_DECIMAL_TYPE_ADAPTER = new BigDecimalTypeAdapter();
private static final BigIntegerTypeAdapter BIG_INTEGER_TYPE_ADAPTER = new BigIntegerTypeAdapter();
private static final BooleanTypeAdapter BOOLEAN_TYPE_ADAPTER = new BooleanTypeAdapter();
private static final ByteTypeAdapter BYTE_TYPE_ADAPTER = new ByteTypeAdapter();
private static final CharacterTypeAdapter CHARACTER_TYPE_ADAPTER = new CharacterTypeAdapter();
private static final DoubleDeserializer DOUBLE_TYPE_ADAPTER = new DoubleDeserializer();
private static final FloatDeserializer FLOAT_TYPE_ADAPTER = new FloatDeserializer();
private static final IntegerTypeAdapter INTEGER_TYPE_ADAPTER = new IntegerTypeAdapter();
private static final LongDeserializer LONG_DESERIALIZER = new LongDeserializer();
private static final NumberTypeAdapter NUMBER_TYPE_ADAPTER = new NumberTypeAdapter();
private static final ShortTypeAdapter SHORT_TYPE_ADAPTER = new ShortTypeAdapter();
private static final StringTypeAdapter STRING_TYPE_ADAPTER = new StringTypeAdapter();
private static final PropertiesCreator PROPERTIES_CREATOR = new PropertiesCreator();
private static final TreeSetCreator TREE_SET_CREATOR = new TreeSetCreator();
private static final HashSetCreator HASH_SET_CREATOR = new HashSetCreator();
private static final GregorianCalendarTypeAdapter GREGORIAN_CALENDAR_TYPE_ADAPTER = new GregorianCalendarTypeAdapter();
// The constants DEFAULT_SERIALIZERS, DEFAULT_DESERIALIZERS, and DEFAULT_INSTANCE_CREATORS
// must be defined after the constants for the type adapters. Otherwise, the type adapter
// constants will appear as nulls.
private static final ParameterizedTypeHandlerMap<JsonSerializer<?>> DEFAULT_SERIALIZERS = createDefaultSerializers();
private static final ParameterizedTypeHandlerMap<JsonDeserializer<?>> DEFAULT_DESERIALIZERS = createDefaultDeserializers();
private static final ParameterizedTypeHandlerMap<InstanceCreator<?>> DEFAULT_INSTANCE_CREATORS = createDefaultInstanceCreators();
private static ParameterizedTypeHandlerMap<JsonSerializer<?>> createDefaultSerializers() {
ParameterizedTypeHandlerMap<JsonSerializer<?>> map = new ParameterizedTypeHandlerMap<JsonSerializer<?>>();
map.registerForTypeHierarchy(Enum.class, ENUM_TYPE_ADAPTER);
map.register(URL.class, URL_TYPE_ADAPTER);
map.register(URI.class, URI_TYPE_ADAPTER);
map.register(UUID.class, UUUID_TYPE_ADAPTER);
map.register(Locale.class, LOCALE_TYPE_ADAPTER);
map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER);
map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER);
map.register(Date.class, DATE_TYPE_ADAPTER);
map.register(java.sql.Date.class, JAVA_SQL_DATE_TYPE_ADAPTER);
map.register(Timestamp.class, DATE_TYPE_ADAPTER);
map.register(Time.class, TIME_TYPE_ADAPTER);
map.register(Calendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
map.register(GregorianCalendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
map.register(BigDecimal.class, BIG_DECIMAL_TYPE_ADAPTER);
map.register(BigInteger.class, BIG_INTEGER_TYPE_ADAPTER);
// Add primitive serializers
map.register(Boolean.class, BOOLEAN_TYPE_ADAPTER);
map.register(boolean.class, BOOLEAN_TYPE_ADAPTER);
map.register(Byte.class, BYTE_TYPE_ADAPTER);
map.register(byte.class, BYTE_TYPE_ADAPTER);
map.register(Character.class, CHARACTER_TYPE_ADAPTER);
map.register(char.class, CHARACTER_TYPE_ADAPTER);
map.register(Integer.class, INTEGER_TYPE_ADAPTER);
map.register(int.class, INTEGER_TYPE_ADAPTER);
map.register(Number.class, NUMBER_TYPE_ADAPTER);
map.register(Short.class, SHORT_TYPE_ADAPTER);
map.register(short.class, SHORT_TYPE_ADAPTER);
map.register(String.class, STRING_TYPE_ADAPTER);
map.makeUnmodifiable();
return map;
}
private static ParameterizedTypeHandlerMap<JsonDeserializer<?>> createDefaultDeserializers() {
ParameterizedTypeHandlerMap<JsonDeserializer<?>> map = new ParameterizedTypeHandlerMap<JsonDeserializer<?>>();
map.registerForTypeHierarchy(Enum.class, wrapDeserializer(ENUM_TYPE_ADAPTER));
map.register(URL.class, wrapDeserializer(URL_TYPE_ADAPTER));
map.register(URI.class, wrapDeserializer(URI_TYPE_ADAPTER));
map.register(UUID.class, wrapDeserializer(UUUID_TYPE_ADAPTER));
map.register(Locale.class, wrapDeserializer(LOCALE_TYPE_ADAPTER));
map.registerForTypeHierarchy(Collection.class, wrapDeserializer(COLLECTION_TYPE_ADAPTER));
map.registerForTypeHierarchy(Map.class, wrapDeserializer(MAP_TYPE_ADAPTER));
map.register(Date.class, wrapDeserializer(DATE_TYPE_ADAPTER));
map.register(java.sql.Date.class, wrapDeserializer(JAVA_SQL_DATE_TYPE_ADAPTER));
map.register(Timestamp.class, wrapDeserializer(TIMESTAMP_DESERIALIZER));
map.register(Time.class, wrapDeserializer(TIME_TYPE_ADAPTER));
map.register(Calendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
map.register(GregorianCalendar.class, GREGORIAN_CALENDAR_TYPE_ADAPTER);
map.register(BigDecimal.class, wrapDeserializer(BIG_DECIMAL_TYPE_ADAPTER));
map.register(BigInteger.class, wrapDeserializer(BIG_INTEGER_TYPE_ADAPTER));
// Add primitive deserializers
map.register(Boolean.class, wrapDeserializer(BOOLEAN_TYPE_ADAPTER));
map.register(boolean.class, wrapDeserializer(BOOLEAN_TYPE_ADAPTER));
map.register(Byte.class, wrapDeserializer(BYTE_TYPE_ADAPTER));
map.register(byte.class, wrapDeserializer(BYTE_TYPE_ADAPTER));
map.register(Character.class, wrapDeserializer(CHARACTER_TYPE_ADAPTER));
map.register(char.class, wrapDeserializer(CHARACTER_TYPE_ADAPTER));
map.register(Double.class, wrapDeserializer(DOUBLE_TYPE_ADAPTER));
map.register(double.class, wrapDeserializer(DOUBLE_TYPE_ADAPTER));
map.register(Float.class, wrapDeserializer(FLOAT_TYPE_ADAPTER));
map.register(float.class, wrapDeserializer(FLOAT_TYPE_ADAPTER));
map.register(Integer.class, wrapDeserializer(INTEGER_TYPE_ADAPTER));
map.register(int.class, wrapDeserializer(INTEGER_TYPE_ADAPTER));
map.register(Long.class, wrapDeserializer(LONG_DESERIALIZER));
map.register(long.class, wrapDeserializer(LONG_DESERIALIZER));
map.register(Number.class, wrapDeserializer(NUMBER_TYPE_ADAPTER));
map.register(Short.class, wrapDeserializer(SHORT_TYPE_ADAPTER));
map.register(short.class, wrapDeserializer(SHORT_TYPE_ADAPTER));
map.register(String.class, wrapDeserializer(STRING_TYPE_ADAPTER));
map.makeUnmodifiable();
return map;
}
private static ParameterizedTypeHandlerMap<InstanceCreator<?>> createDefaultInstanceCreators() {
ParameterizedTypeHandlerMap<InstanceCreator<?>> map = new ParameterizedTypeHandlerMap<InstanceCreator<?>>();
map.registerForTypeHierarchy(Map.class, MAP_TYPE_ADAPTER);
// Add Collection type instance creators
map.registerForTypeHierarchy(Collection.class, COLLECTION_TYPE_ADAPTER);
map.registerForTypeHierarchy(Set.class, HASH_SET_CREATOR);
map.registerForTypeHierarchy(SortedSet.class, TREE_SET_CREATOR);
map.register(Properties.class, PROPERTIES_CREATOR);
map.makeUnmodifiable();
return map;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private static JsonDeserializer<?> wrapDeserializer(JsonDeserializer<?> deserializer) {
return new JsonDeserializerExceptionWrapper(deserializer);
}
static ParameterizedTypeHandlerMap<JsonSerializer<?>> getDefaultSerializers() {
return getDefaultSerializers(false, LongSerializationPolicy.DEFAULT);
}
static ParameterizedTypeHandlerMap<JsonSerializer<?>> getDefaultSerializers(
boolean serializeSpecialFloatingPointValues, LongSerializationPolicy longSerializationPolicy) {
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers = new ParameterizedTypeHandlerMap<JsonSerializer<?>>();
// Double primitive
JcloudsDefaultTypeAdapters.DoubleSerializer doubleSerializer = new JcloudsDefaultTypeAdapters.DoubleSerializer(
serializeSpecialFloatingPointValues);
serializers.registerIfAbsent(Double.class, doubleSerializer);
serializers.registerIfAbsent(double.class, doubleSerializer);
// Float primitive
JcloudsDefaultTypeAdapters.FloatSerializer floatSerializer = new JcloudsDefaultTypeAdapters.FloatSerializer(
serializeSpecialFloatingPointValues);
serializers.registerIfAbsent(Float.class, floatSerializer);
serializers.registerIfAbsent(float.class, floatSerializer);
// Long primitive
JcloudsDefaultTypeAdapters.LongSerializer longSerializer = new JcloudsDefaultTypeAdapters.LongSerializer(
longSerializationPolicy);
serializers.registerIfAbsent(Long.class, longSerializer);
serializers.registerIfAbsent(long.class, longSerializer);
serializers.registerIfAbsent(DEFAULT_SERIALIZERS);
return serializers;
}
static ParameterizedTypeHandlerMap<JsonDeserializer<?>> getDefaultDeserializers() {
return DEFAULT_DESERIALIZERS;
}
static ParameterizedTypeHandlerMap<InstanceCreator<?>> getDefaultInstanceCreators() {
return DEFAULT_INSTANCE_CREATORS;
}
static class DefaultDateTypeAdapter implements JsonSerializer<Date>, JsonDeserializer<Date> {
private final DateFormat format;
DefaultDateTypeAdapter() {
this.format = DateFormat.getDateTimeInstance();
}
DefaultDateTypeAdapter(final String datePattern) {
this.format = new SimpleDateFormat(datePattern);
}
DefaultDateTypeAdapter(final int style) {
this.format = DateFormat.getDateInstance(style);
}
public DefaultDateTypeAdapter(final int dateStyle, final int timeStyle) {
this.format = DateFormat.getDateTimeInstance(dateStyle, timeStyle);
}
// These methods need to be synchronized since JDK DateFormat classes are not thread-safe
// See issue 162
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
synchronized (format) {
String dateFormatAsString = format.format(src);
return new JsonPrimitive(dateFormatAsString);
}
}
public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
if (!(json instanceof JsonPrimitive)) {
throw new JsonParseException("The date should be a string value");
}
try {
synchronized (format) {
return format.parse(json.getAsString());
}
} catch (ParseException e) {
throw new JsonParseException(e);
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(DefaultDateTypeAdapter.class.getSimpleName());
sb.append('(').append(format.getClass().getSimpleName()).append(')');
return sb.toString();
}
}
static class DefaultJavaSqlDateTypeAdapter implements JsonSerializer<java.sql.Date>, JsonDeserializer<java.sql.Date> {
private final DateFormat format;
DefaultJavaSqlDateTypeAdapter() {
this.format = new SimpleDateFormat("MMM d, yyyy");
}
public JsonElement serialize(java.sql.Date src, Type typeOfSrc, JsonSerializationContext context) {
synchronized (format) {
String dateFormatAsString = format.format(src);
return new JsonPrimitive(dateFormatAsString);
}
}
public java.sql.Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
if (!(json instanceof JsonPrimitive)) {
throw new JsonParseException("The date should be a string value");
}
try {
synchronized (format) {
Date date = format.parse(json.getAsString());
return new java.sql.Date(date.getTime());
}
} catch (ParseException e) {
throw new JsonParseException(e);
}
}
}
static class DefaultTimestampDeserializer implements JsonDeserializer<Timestamp> {
public Timestamp deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
Date date = context.deserialize(json, Date.class);
return new Timestamp(date.getTime());
}
}
static class DefaultTimeTypeAdapter implements JsonSerializer<Time>, JsonDeserializer<Time> {
private final DateFormat format;
DefaultTimeTypeAdapter() {
this.format = new SimpleDateFormat("hh:mm:ss a");
}
public JsonElement serialize(Time src, Type typeOfSrc, JsonSerializationContext context) {
synchronized (format) {
String dateFormatAsString = format.format(src);
return new JsonPrimitive(dateFormatAsString);
}
}
public Time deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
if (!(json instanceof JsonPrimitive)) {
throw new JsonParseException("The date should be a string value");
}
try {
synchronized (format) {
Date date = format.parse(json.getAsString());
return new Time(date.getTime());
}
} catch (ParseException e) {
throw new JsonParseException(e);
}
}
}
private static class GregorianCalendarTypeAdapter implements JsonSerializer<GregorianCalendar>,
JsonDeserializer<GregorianCalendar> {
private static final String YEAR = "year";
private static final String MONTH = "month";
private static final String DAY_OF_MONTH = "dayOfMonth";
private static final String HOUR_OF_DAY = "hourOfDay";
private static final String MINUTE = "minute";
private static final String SECOND = "second";
public JsonElement serialize(GregorianCalendar src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject obj = new JsonObject();
obj.addProperty(YEAR, src.get(Calendar.YEAR));
obj.addProperty(MONTH, src.get(Calendar.MONTH));
obj.addProperty(DAY_OF_MONTH, src.get(Calendar.DAY_OF_MONTH));
obj.addProperty(HOUR_OF_DAY, src.get(Calendar.HOUR_OF_DAY));
obj.addProperty(MINUTE, src.get(Calendar.MINUTE));
obj.addProperty(SECOND, src.get(Calendar.SECOND));
return obj;
}
public GregorianCalendar deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
JsonObject obj = json.getAsJsonObject();
int year = obj.get(YEAR).getAsInt();
int month = obj.get(MONTH).getAsInt();
int dayOfMonth = obj.get(DAY_OF_MONTH).getAsInt();
int hourOfDay = obj.get(HOUR_OF_DAY).getAsInt();
int minute = obj.get(MINUTE).getAsInt();
int second = obj.get(SECOND).getAsInt();
return new GregorianCalendar(year, month, dayOfMonth, hourOfDay, minute, second);
}
@Override
public String toString() {
return GregorianCalendarTypeAdapter.class.getSimpleName();
}
}
@SuppressWarnings("unchecked")
private static class EnumTypeAdapter<T extends Enum<T>> implements JsonSerializer<T>, JsonDeserializer<T> {
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.name());
}
@SuppressWarnings("cast")
public T deserialize(JsonElement json, Type classOfT, JsonDeserializationContext context)
throws JsonParseException {
try {
return (T) Enum.valueOf((Class<T>) classOfT, json.getAsString());
} catch (IllegalArgumentException e) {
Method converter = classToConvert.get(classOfT);
if (converter != null)
try {
return (T) converter.invoke(null, json.getAsString());
} catch (Exception e1) {
throw e;
}
else
throw e;
}
}
private final static Map<Class<?>, Method> classToConvert = new MapMaker()
.makeComputingMap(new Function<Class<?>, Method>() {
@Override
public Method apply(Class<?> from) {
try {
Method method = from.getMethod("fromValue", String.class);
method.setAccessible(true);
return method;
} catch (Exception e) {
return null;
}
}
});
@Override
public String toString() {
return EnumTypeAdapter.class.getSimpleName();
}
}
private static class UrlTypeAdapter implements JsonSerializer<URL>, JsonDeserializer<URL> {
public JsonElement serialize(URL src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toExternalForm());
}
public URL deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
try {
return new URL(json.getAsString());
} catch (MalformedURLException e) {
throw new JsonParseException(e);
}
}
@Override
public String toString() {
return UrlTypeAdapter.class.getSimpleName();
}
}
private static class UriTypeAdapter implements JsonSerializer<URI>, JsonDeserializer<URI> {
public JsonElement serialize(URI src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toASCIIString());
}
public URI deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
try {
return new URI(json.getAsString());
} catch (URISyntaxException e) {
throw new JsonParseException(e);
}
}
@Override
public String toString() {
return UriTypeAdapter.class.getSimpleName();
}
}
private static class UuidTypeAdapter implements JsonSerializer<UUID>, JsonDeserializer<UUID> {
public JsonElement serialize(UUID src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toString());
}
public UUID deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return UUID.fromString(json.getAsString());
}
@Override
public String toString() {
return UuidTypeAdapter.class.getSimpleName();
}
}
private static class LocaleTypeAdapter implements JsonSerializer<Locale>, JsonDeserializer<Locale> {
public JsonElement serialize(Locale src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.toString());
}
public Locale deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
String locale = json.getAsString();
StringTokenizer tokenizer = new StringTokenizer(locale, "_");
String language = null;
String country = null;
String variant = null;
if (tokenizer.hasMoreElements()) {
language = tokenizer.nextToken();
}
if (tokenizer.hasMoreElements()) {
country = tokenizer.nextToken();
}
if (tokenizer.hasMoreElements()) {
variant = tokenizer.nextToken();
}
if (country == null && variant == null) {
return new Locale(language);
} else if (variant == null) {
return new Locale(language, country);
} else {
return new Locale(language, country, variant);
}
}
@Override
public String toString() {
return LocaleTypeAdapter.class.getSimpleName();
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private static class CollectionTypeAdapter implements JsonSerializer<Collection>, JsonDeserializer<Collection>,
InstanceCreator<Collection> {
public JsonElement serialize(Collection src, Type typeOfSrc, JsonSerializationContext context) {
if (src == null) {
return JsonNull.createJsonNull();
}
JsonArray array = new JsonArray();
Type childGenericType = null;
if (typeOfSrc instanceof ParameterizedType) {
childGenericType = new TypeInfoCollection(typeOfSrc).getElementType();
}
for (Object child : src) {
if (child == null) {
array.add(JsonNull.createJsonNull());
} else {
Type childType = (childGenericType == null || childGenericType == Object.class) ? child.getClass()
: childGenericType;
JsonElement element = context.serialize(child, childType);
array.add(element);
}
}
return array;
}
public Collection deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
if (json.isJsonNull()) {
return null;
}
// Use ObjectConstructor to create instance instead of hard-coding a specific type.
// This handles cases where users are using their own subclass of Collection.
Collection collection = constructCollectionType(typeOfT, context);
Type childType = new TypeInfoCollection(typeOfT).getElementType();
for (JsonElement childElement : json.getAsJsonArray()) {
if (childElement == null || childElement.isJsonNull()) {
collection.add(null);
} else {
Object value = context.deserialize(childElement, childType);
collection.add(value);
}
}
return collection;
}
private Collection constructCollectionType(Type collectionType, JsonDeserializationContext context) {
JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context;
ObjectConstructor objectConstructor = contextImpl.getObjectConstructor();
return (Collection) objectConstructor.construct(collectionType);
}
public Collection createInstance(Type type) {
return new LinkedList();
}
}
private static class PropertiesCreator implements InstanceCreator<Properties> {
public Properties createInstance(Type type) {
return new Properties();
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
static class MapTypeAdapter implements JsonSerializer<Map>, JsonDeserializer<Map>, InstanceCreator<Map> {
public JsonElement serialize(Map src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject map = new JsonObject();
Type childGenericType = null;
if (typeOfSrc instanceof ParameterizedType) {
childGenericType = new TypeInfoMap(typeOfSrc).getValueType();
}
for (Map.Entry entry : (Set<Map.Entry>) src.entrySet()) {
Object value = entry.getValue();
JsonElement valueElement;
if (value == null) {
valueElement = JsonNull.createJsonNull();
} else {
Type childType = (childGenericType == null) ? value.getClass() : childGenericType;
valueElement = context.serialize(value, childType);
}
map.add(String.valueOf(entry.getKey()), valueElement);
}
return map;
}
public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
// Use ObjectConstructor to create instance instead of hard-coding a specific type.
// This handles cases where users are using their own subclass of Map.
Map<Object, Object> map = constructMapType(typeOfT, context);
TypeInfoMap mapTypeInfo = new TypeInfoMap(typeOfT);
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
Object key = context.deserialize(new JsonPrimitive(entry.getKey()), mapTypeInfo.getKeyType());
Object value = context.deserialize(entry.getValue(), mapTypeInfo.getValueType());
map.put(key, value);
}
return map;
}
private Map constructMapType(Type mapType, JsonDeserializationContext context) {
JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context;
ObjectConstructor objectConstructor = contextImpl.getObjectConstructor();
return (Map) objectConstructor.construct(mapType);
}
public Map createInstance(Type type) {
return new LinkedHashMap();
}
@Override
public String toString() {
return MapTypeAdapter.class.getSimpleName();
}
}
private static class BigDecimalTypeAdapter implements JsonSerializer<BigDecimal>, JsonDeserializer<BigDecimal> {
public JsonElement serialize(BigDecimal src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src);
}
public BigDecimal deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return json.getAsBigDecimal();
}
@Override
public String toString() {
return BigDecimalTypeAdapter.class.getSimpleName();
}
}
private static class BigIntegerTypeAdapter implements JsonSerializer<BigInteger>, JsonDeserializer<BigInteger> {
public JsonElement serialize(BigInteger src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src);
}
public BigInteger deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return json.getAsBigInteger();
}
@Override
public String toString() {
return BigIntegerTypeAdapter.class.getSimpleName();
}
}
private static class NumberTypeAdapter implements JsonSerializer<Number>, JsonDeserializer<Number> {
public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src);
}
public Number deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return json.getAsNumber();
}
@Override
public String toString() {
return NumberTypeAdapter.class.getSimpleName();
}
}
private static class LongSerializer implements JsonSerializer<Long> {
private final LongSerializationPolicy longSerializationPolicy;
private LongSerializer(LongSerializationPolicy longSerializationPolicy) {
this.longSerializationPolicy = longSerializationPolicy;
}
public JsonElement serialize(Long src, Type typeOfSrc, JsonSerializationContext context) {
return longSerializationPolicy.serialize(src);
}
@Override
public String toString() {
return LongSerializer.class.getSimpleName();
}
}
private static class LongDeserializer implements JsonDeserializer<Long> {
public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return json.getAsLong();
}
@Override
public String toString() {
return LongDeserializer.class.getSimpleName();
}
}
private static class IntegerTypeAdapter implements JsonSerializer<Integer>, JsonDeserializer<Integer> {
public JsonElement serialize(Integer src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src);
}
public Integer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return json.getAsInt();
}
@Override
public String toString() {
return IntegerTypeAdapter.class.getSimpleName();
}
}
private static class ShortTypeAdapter implements JsonSerializer<Short>, JsonDeserializer<Short> {
public JsonElement serialize(Short src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src);
}
public Short deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return json.getAsShort();
}
@Override
public String toString() {
return ShortTypeAdapter.class.getSimpleName();
}
}
private static class ByteTypeAdapter implements JsonSerializer<Byte>, JsonDeserializer<Byte> {
public JsonElement serialize(Byte src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src);
}
public Byte deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return json.getAsByte();
}
@Override
public String toString() {
return ByteTypeAdapter.class.getSimpleName();
}
}
static class FloatSerializer implements JsonSerializer<Float> {
private final boolean serializeSpecialFloatingPointValues;
FloatSerializer(boolean serializeSpecialDoubleValues) {
this.serializeSpecialFloatingPointValues = serializeSpecialDoubleValues;
}
public JsonElement serialize(Float src, Type typeOfSrc, JsonSerializationContext context) {
if (!serializeSpecialFloatingPointValues) {
if (Float.isNaN(src) || Float.isInfinite(src)) {
throw new IllegalArgumentException(src
+ " is not a valid float value as per JSON specification. To override this"
+ " behavior, use GsonBuilder.serializeSpecialFloatingPointValues() method.");
}
}
return new JsonPrimitive(src);
}
}
private static class FloatDeserializer implements JsonDeserializer<Float> {
public Float deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return json.getAsFloat();
}
@Override
public String toString() {
return FloatDeserializer.class.getSimpleName();
}
}
static class DoubleSerializer implements JsonSerializer<Double> {
private final boolean serializeSpecialFloatingPointValues;
DoubleSerializer(boolean serializeSpecialDoubleValues) {
this.serializeSpecialFloatingPointValues = serializeSpecialDoubleValues;
}
public JsonElement serialize(Double src, Type typeOfSrc, JsonSerializationContext context) {
if (!serializeSpecialFloatingPointValues) {
if (Double.isNaN(src) || Double.isInfinite(src)) {
throw new IllegalArgumentException(src
+ " is not a valid double value as per JSON specification. To override this"
+ " behavior, use GsonBuilder.serializeSpecialDoubleValues() method.");
}
}
return new JsonPrimitive(src);
}
}
private static class DoubleDeserializer implements JsonDeserializer<Double> {
public Double deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return json.getAsDouble();
}
@Override
public String toString() {
return DoubleDeserializer.class.getSimpleName();
}
}
private static class CharacterTypeAdapter implements JsonSerializer<Character>, JsonDeserializer<Character> {
public JsonElement serialize(Character src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src);
}
public Character deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return json.getAsCharacter();
}
@Override
public String toString() {
return CharacterTypeAdapter.class.getSimpleName();
}
}
private static class StringTypeAdapter implements JsonSerializer<String>, JsonDeserializer<String> {
public JsonElement serialize(String src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src);
}
public String deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return json.getAsString();
}
@Override
public String toString() {
return StringTypeAdapter.class.getSimpleName();
}
}
private static class BooleanTypeAdapter implements JsonSerializer<Boolean>, JsonDeserializer<Boolean> {
public JsonElement serialize(Boolean src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src);
}
public Boolean deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return json.getAsBoolean();
}
@Override
public String toString() {
return BooleanTypeAdapter.class.getSimpleName();
}
}
private static class TreeSetCreator implements InstanceCreator<TreeSet<?>> {
public TreeSet<?> createInstance(Type type) {
return new TreeSet<Object>();
}
@Override
public String toString() {
return TreeSetCreator.class.getSimpleName();
}
}
private static class HashSetCreator implements InstanceCreator<HashSet<?>> {
public HashSet<?> createInstance(Type type) {
return new HashSet<Object>();
}
@Override
public String toString() {
return HashSetCreator.class.getSimpleName();
}
}
}

View File

@ -1,591 +0,0 @@
/**
*
* Copyright (C) 2010 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.
* ====================================================================
*/
/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.gson;
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import com.google.gson.JcloudsDefaultTypeAdapters.DefaultDateTypeAdapter;
/**
* <p>Use this builder to construct a {@link Gson} instance when you need to set configuration
* options other than the default. For {@link Gson} with default configuration, it is simpler to
* use {@code new Gson()}. {@code JcloudsGsonBuilder} is best used by creating it, and then invoking its
* various configuration methods, and finally calling create.</p>
*
* <p>The following is an example shows how to use the {@code JcloudsGsonBuilder} to construct a Gson
* instance:
*
* <pre>
* Gson gson = new JcloudsGsonBuilder()
* .registerTypeAdapter(Id.class, new IdTypeAdapter())
* .serializeNulls()
* .setDateFormat(DateFormat.LONG)
* .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
* .setPrettyPrinting()
* .setVersion(1.0)
* .create();
* </pre></p>
*
* <p>NOTE: the order of invocation of configuration methods does not matter.</p>
*
* @author Inderjeet Singh
* @author Joel Leitch
*/
public final class JcloudsGsonBuilder {
private static final InnerClassExclusionStrategy innerClassExclusionStrategy =
new InnerClassExclusionStrategy();
private static final ExposeAnnotationSerializationExclusionStrategy
exposeAnnotationSerializationExclusionStrategy =
new ExposeAnnotationSerializationExclusionStrategy();
private static final ExposeAnnotationDeserializationExclusionStrategy
exposeAnnotationDeserializationExclusionStrategy =
new ExposeAnnotationDeserializationExclusionStrategy();
private final Collection<ExclusionStrategy> exclusionStrategies =
new HashSet<ExclusionStrategy>();
private double ignoreVersionsAfter;
private ModifierBasedExclusionStrategy modifierBasedExclusionStrategy;
private boolean serializeInnerClasses;
private boolean excludeFieldsWithoutExposeAnnotation;
private LongSerializationPolicy longSerializationPolicy;
private FieldNamingStrategy2 fieldNamingPolicy;
private final ParameterizedTypeHandlerMap<InstanceCreator<?>> instanceCreators;
private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers;
private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers;
private boolean serializeNulls;
private String datePattern;
private int dateStyle;
private int timeStyle;
private boolean serializeSpecialFloatingPointValues;
private boolean escapeHtmlChars;
private boolean prettyPrinting;
private boolean generateNonExecutableJson;
/**
* Creates a JcloudsGsonBuilder instance that can be used to build Gson with various configuration
* settings. JcloudsGsonBuilder follows the builder pattern, and it is typically used by first
* invoking various configuration methods to set desired options, and finally calling
* {@link #create()}.
*/
public JcloudsGsonBuilder() {
// add default exclusion strategies
exclusionStrategies.add(Gson.DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY);
exclusionStrategies.add(Gson.DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY);
// setup default values
ignoreVersionsAfter = VersionConstants.IGNORE_VERSIONS;
serializeInnerClasses = true;
prettyPrinting = false;
escapeHtmlChars = true;
modifierBasedExclusionStrategy = Gson.DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY;
excludeFieldsWithoutExposeAnnotation = false;
longSerializationPolicy = LongSerializationPolicy.DEFAULT;
fieldNamingPolicy = Gson.DEFAULT_NAMING_POLICY;
instanceCreators = new ParameterizedTypeHandlerMap<InstanceCreator<?>>();
serializers = new ParameterizedTypeHandlerMap<JsonSerializer<?>>();
deserializers = new ParameterizedTypeHandlerMap<JsonDeserializer<?>>();
serializeNulls = false;
dateStyle = DateFormat.DEFAULT;
timeStyle = DateFormat.DEFAULT;
serializeSpecialFloatingPointValues = false;
generateNonExecutableJson = false;
}
/**
* Configures Gson to enable versioning support.
*
* @param ignoreVersionsAfter any field or type marked with a version higher than this value
* are ignored during serialization or deserialization.
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
*/
public JcloudsGsonBuilder setVersion(double ignoreVersionsAfter) {
this.ignoreVersionsAfter = ignoreVersionsAfter;
return this;
}
/**
* Configures Gson to excludes all class fields that have the specified modifiers. By default,
* Gson will exclude all fields marked transient or static. This method will override that
* behavior.
*
* @param modifiers the field modifiers. You must use the modifiers specified in the
* {@link java.lang.reflect.Modifier} class. For example,
* {@link java.lang.reflect.Modifier#TRANSIENT},
* {@link java.lang.reflect.Modifier#STATIC}.
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
*/
public JcloudsGsonBuilder excludeFieldsWithModifiers(int... modifiers) {
modifierBasedExclusionStrategy = new ModifierBasedExclusionStrategy(modifiers);
return this;
}
/**
* Makes the output JSON non-executable in Javascript by prefixing the generated JSON with some
* special text. This prevents attacks from third-party sites through script sourcing. See
* <a href="http://code.google.com/p/google-gson/issues/detail?id=42">Gson Issue 42</a>
* for details.
*
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
* @since 1.3
*/
public JcloudsGsonBuilder generateNonExecutableJson() {
this.generateNonExecutableJson = true;
return this;
}
/**
* Configures Gson to exclude all fields from consideration for serialization or deserialization
* that do not have the {@link com.google.gson.annotations.Expose} annotation.
*
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
*/
public JcloudsGsonBuilder excludeFieldsWithoutExposeAnnotation() {
excludeFieldsWithoutExposeAnnotation = true;
return this;
}
/**
* Configure Gson to serialize null fields. By default, Gson omits all fields that are null
* during serialization.
*
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
* @since 1.2
*/
public JcloudsGsonBuilder serializeNulls() {
this.serializeNulls = true;
return this;
}
/**
* Configures Gson to exclude inner classes during serialization.
*
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
* @since 1.3
*/
public JcloudsGsonBuilder disableInnerClassSerialization() {
serializeInnerClasses = false;
return this;
}
/**
* Configures Gson to apply a specific serialization policy for {@code Long} and {@code long}
* objects.
*
* @param serializationPolicy the particular policy to use for serializing longs.
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
* @since 1.3
*/
public JcloudsGsonBuilder setLongSerializationPolicy(LongSerializationPolicy serializationPolicy) {
this.longSerializationPolicy = serializationPolicy;
return this;
}
/**
* Configures Gson to apply a specific naming policy to an object's field during serialization
* and deserialization.
*
* @param namingConvention the JSON field naming convention to use for serialization and
* deserialization.
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
*/
public JcloudsGsonBuilder setFieldNamingPolicy(FieldNamingPolicy namingConvention) {
return setFieldNamingStrategy(namingConvention.getFieldNamingPolicy());
}
/**
* Configures Gson to apply a specific naming policy strategy to an object's field during
* serialization and deserialization.
*
* @param fieldNamingStrategy the actual naming strategy to apply to the fields
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
* @since 1.3
*/
public JcloudsGsonBuilder setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy) {
return setFieldNamingStrategy(new FieldNamingStrategy2Adapter(fieldNamingStrategy));
}
/**
* Configures Gson to apply a specific naming policy strategy to an object's field during
* serialization and deserialization.
*
* @param fieldNamingStrategy the actual naming strategy to apply to the fields
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
*/
JcloudsGsonBuilder setFieldNamingStrategy(FieldNamingStrategy2 fieldNamingStrategy) {
this.fieldNamingPolicy =
new SerializedNameAnnotationInterceptingNamingPolicy(fieldNamingStrategy);
return this;
}
/**
* Configures Gson to apply a set of exclusion strategies during both serialization and
* deserialization. Each of the {@code strategies} will be applied as a disjunction rule.
* This means that if one of the {@code strategies} suggests that a field (or class) should be
* skipped then that field (or object) is skipped during serializaiton/deserialization.
*
* @param strategies the set of strategy object to apply during object (de)serialization.
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
* @since 1.4
*/
public JcloudsGsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) {
for (ExclusionStrategy strategy : strategies) {
exclusionStrategies.add(strategy);
}
return this;
}
/**
* Configures Gson to output Json that fits in a page for pretty printing. This option only
* affects Json serialization.
*
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
*/
public JcloudsGsonBuilder setPrettyPrinting() {
prettyPrinting = true;
return this;
}
/**
* By default, Gson escapes HTML characters such as &lt; &gt; etc. Use this option to configure
* Gson to pass-through HTML characters as is.
*
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
* @since 1.3
*/
public JcloudsGsonBuilder disableHtmlEscaping() {
this.escapeHtmlChars = false;
return this;
}
/**
* Configures Gson to serialize {@code Date} objects according to the pattern provided. You can
* call this method or {@link #setDateFormat(int)} multiple times, but only the last invocation
* will be used to decide the serialization format.
*
* <p>Note that this pattern must abide by the convention provided by {@code SimpleDateFormat}
* class. See the documentation in {@link java.text.SimpleDateFormat} for more information on
* valid date and time patterns.</p>
*
* @param pattern the pattern that dates will be serialized/deserialized to/from
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
* @since 1.2
*/
public JcloudsGsonBuilder setDateFormat(String pattern) {
// TODO(Joel): Make this fail fast if it is an invalid date format
this.datePattern = pattern;
return this;
}
/**
* Configures Gson to to serialize {@code Date} objects according to the style value provided.
* You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
* invocation will be used to decide the serialization format.
*
* <p>Note that this style value should be one of the predefined constants in the
* {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more
* information on the valid style constants.</p>
*
* @param style the predefined date style that date objects will be serialized/deserialized
* to/from
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
* @since 1.2
*/
public JcloudsGsonBuilder setDateFormat(int style) {
this.dateStyle = style;
this.datePattern = null;
return this;
}
/**
* Configures Gson to to serialize {@code Date} objects according to the style value provided.
* You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
* invocation will be used to decide the serialization format.
*
* <p>Note that this style value should be one of the predefined constants in the
* {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more
* information on the valid style constants.</p>
*
* @param dateStyle the predefined date style that date objects will be serialized/deserialized
* to/from
* @param timeStyle the predefined style for the time portion of the date objects
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
* @since 1.2
*/
public JcloudsGsonBuilder setDateFormat(int dateStyle, int timeStyle) {
this.dateStyle = dateStyle;
this.timeStyle = timeStyle;
this.datePattern = null;
return this;
}
/**
* Configures Gson for custom serialization or deserialization. This method combines the
* registration of an {@link InstanceCreator}, {@link JsonSerializer}, and a
* {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter} implements
* all the required interfaces for custom serialization with Gson. If an instance creator,
* serializer or deserializer was previously registered for the specified {@code type}, it is
* overwritten.
*
* @param type the type definition for the type adapter being registered
* @param typeAdapter This object must implement at least one of the {@link InstanceCreator},
* {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces.
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
*/
public JcloudsGsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {
Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|| typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>);
if (typeAdapter instanceof InstanceCreator<?>) {
registerInstanceCreator(type, (InstanceCreator<?>) typeAdapter);
}
if (typeAdapter instanceof JsonSerializer<?>) {
registerSerializer(type, (JsonSerializer<?>) typeAdapter);
}
if (typeAdapter instanceof JsonDeserializer<?>) {
registerDeserializer(type, (JsonDeserializer<?>) typeAdapter);
}
return this;
}
/**
* Configures Gson to use a custom {@link InstanceCreator} for the specified type. If an instance
* creator was previously registered for the specified class, it is overwritten. Since this method
* takes a type instead of a Class object, it can be used to register a specific handler for a
* generic type corresponding to a raw type.
*
* @param <T> the type for which instance creator is being registered
* @param typeOfT The Type definition for T
* @param instanceCreator the instance creator for T
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
*/
private <T> JcloudsGsonBuilder registerInstanceCreator(Type typeOfT,
InstanceCreator<? extends T> instanceCreator) {
instanceCreators.register(typeOfT, instanceCreator);
return this;
}
/**
* Configures Gson to use a custom JSON serializer for the specified type. You should use this
* method if you want to register different serializers for different generic types corresponding
* to a raw type.
*
* @param <T> the type for which the serializer is being registered
* @param typeOfT The type definition for T
* @param serializer the custom serializer
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
*/
private <T> JcloudsGsonBuilder registerSerializer(Type typeOfT, final JsonSerializer<T> serializer) {
serializers.register(typeOfT, serializer);
return this;
}
/**
* Configures Gson to use a custom JSON deserializer for the specified type. You should use this
* method if you want to register different deserializers for different generic types
* corresponding to a raw type.
*
* @param <T> the type for which the deserializer is being registered
* @param typeOfT The type definition for T
* @param deserializer the custom deserializer
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
*/
private <T> JcloudsGsonBuilder registerDeserializer(Type typeOfT, JsonDeserializer<T> deserializer) {
deserializers.register(typeOfT, new JsonDeserializerExceptionWrapper<T>(deserializer));
return this;
}
/**
* Configures Gson for custom serialization or deserialization for an inheritance type hierarchy.
* This method combines the registration of an {@link InstanceCreator}, {@link JsonSerializer},
* and a {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter}
* implements all the required interfaces for custom serialization with Gson.
* If an instance creator, serializer or deserializer was previously registered for the specified
* type hierarchy, it is overwritten. If an instance creator, serializer or deserializer is
* registered for a specific type in the type hierarchy, it will be invoked instead of the one
* registered for the type hierarchy.
*
* @param baseType the class definition for the type adapter being registered for the base class
* or interface
* @param typeAdapter This object must implement at least one of the {@link InstanceCreator},
* {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces.
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
* @since 1.5
*/
JcloudsGsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter) {
Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
|| typeAdapter instanceof JsonDeserializer<?> || typeAdapter instanceof InstanceCreator<?>);
if (typeAdapter instanceof InstanceCreator<?>) {
registerInstanceCreatorForTypeHierarchy(baseType, (InstanceCreator<?>) typeAdapter);
}
if (typeAdapter instanceof JsonSerializer<?>) {
registerSerializerForTypeHierarchy(baseType, (JsonSerializer<?>) typeAdapter);
}
if (typeAdapter instanceof JsonDeserializer<?>) {
registerDeserializerForTypeHierarchy(baseType, (JsonDeserializer<?>) typeAdapter);
}
return this;
}
private <T> JcloudsGsonBuilder registerInstanceCreatorForTypeHierarchy(Class<?> classOfT,
InstanceCreator<? extends T> instanceCreator) {
instanceCreators.registerForTypeHierarchy(classOfT, instanceCreator);
return this;
}
private <T> JcloudsGsonBuilder registerSerializerForTypeHierarchy(Class<?> classOfT,
final JsonSerializer<T> serializer) {
serializers.registerForTypeHierarchy(classOfT, serializer);
return this;
}
private <T> JcloudsGsonBuilder registerDeserializerForTypeHierarchy(Class<?> classOfT,
JsonDeserializer<T> deserializer) {
deserializers.registerForTypeHierarchy(classOfT,
new JsonDeserializerExceptionWrapper<T>(deserializer));
return this;
}
/**
* Section 2.4 of <a href="http://www.ietf.org/rfc/rfc4627.txt">JSON specification</a> disallows
* special double values (NaN, Infinity, -Infinity). However,
* <a href="http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf">Javascript
* specification</a> (see section 4.3.20, 4.3.22, 4.3.23) allows these values as valid Javascript
* values. Moreover, most JavaScript engines will accept these special values in JSON without
* problem. So, at a practical level, it makes sense to accept these values as valid JSON even
* though JSON specification disallows them.
*
* <p>Gson always accepts these special values during deserialization. However, it outputs
* strictly compliant JSON. Hence, if it encounters a float value {@link Float#NaN},
* {@link Float#POSITIVE_INFINITY}, {@link Float#NEGATIVE_INFINITY}, or a double value
* {@link Double#NaN}, {@link Double#POSITIVE_INFINITY}, {@link Double#NEGATIVE_INFINITY}, it
* will throw an {@link IllegalArgumentException}. This method provides a way to override the
* default behavior when you know that the JSON receiver will be able to handle these special
* values.
*
* @return a reference to this {@code JcloudsGsonBuilder} object to fulfill the "Builder" pattern
* @since 1.3
*/
public JcloudsGsonBuilder serializeSpecialFloatingPointValues() {
this.serializeSpecialFloatingPointValues = true;
return this;
}
/**
* Creates a {@link Gson} instance based on the current configuration. This method is free of
* side-effects to this {@code JcloudsGsonBuilder} instance and hence can be called multiple times.
*
* @return an instance of Gson configured with the options currently set in this builder
*/
public Gson create() {
List<ExclusionStrategy> serializationStrategies =
new LinkedList<ExclusionStrategy>(exclusionStrategies);
List<ExclusionStrategy> deserializationStrategies =
new LinkedList<ExclusionStrategy>(exclusionStrategies);
serializationStrategies.add(modifierBasedExclusionStrategy);
deserializationStrategies.add(modifierBasedExclusionStrategy);
if (!serializeInnerClasses) {
serializationStrategies.add(innerClassExclusionStrategy);
deserializationStrategies.add(innerClassExclusionStrategy);
}
if (ignoreVersionsAfter != VersionConstants.IGNORE_VERSIONS) {
serializationStrategies.add(new VersionExclusionStrategy(ignoreVersionsAfter));
deserializationStrategies.add(new VersionExclusionStrategy(ignoreVersionsAfter));
}
if (excludeFieldsWithoutExposeAnnotation) {
serializationStrategies.add(exposeAnnotationSerializationExclusionStrategy);
deserializationStrategies.add(exposeAnnotationDeserializationExclusionStrategy);
}
ExclusionStrategy serializationExclusionStrategy =
new DisjunctionExclusionStrategy(serializationStrategies);
ExclusionStrategy deserializationExclusionStrategy =
new DisjunctionExclusionStrategy(deserializationStrategies);
ParameterizedTypeHandlerMap<JsonSerializer<?>> customSerializers = serializers.copyOf();
ParameterizedTypeHandlerMap<JsonDeserializer<?>> customDeserializers = deserializers.copyOf();
addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, customSerializers,
customDeserializers);
customSerializers.registerIfAbsent(JcloudsDefaultTypeAdapters.getDefaultSerializers(
serializeSpecialFloatingPointValues, longSerializationPolicy));
customDeserializers.registerIfAbsent(JcloudsDefaultTypeAdapters.getDefaultDeserializers());
ParameterizedTypeHandlerMap<InstanceCreator<?>> customInstanceCreators =
instanceCreators.copyOf();
customInstanceCreators.registerIfAbsent(JcloudsDefaultTypeAdapters.getDefaultInstanceCreators());
customSerializers.makeUnmodifiable();
customDeserializers.makeUnmodifiable();
instanceCreators.makeUnmodifiable();
MappedObjectConstructor objConstructor = new MappedObjectConstructor(customInstanceCreators);
JsonFormatter formatter = prettyPrinting ?
new JsonPrintFormatter(escapeHtmlChars) : new JsonCompactFormatter(escapeHtmlChars);
Gson gson = new Gson(serializationExclusionStrategy, deserializationExclusionStrategy,
fieldNamingPolicy, objConstructor, formatter, serializeNulls, customSerializers,
customDeserializers, generateNonExecutableJson);
return gson;
}
private static void addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle,
ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers,
ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers) {
DefaultDateTypeAdapter dateTypeAdapter = null;
if (datePattern != null && !"".equals(datePattern.trim())) {
dateTypeAdapter = new DefaultDateTypeAdapter(datePattern);
} else if (dateStyle != DateFormat.DEFAULT && timeStyle != DateFormat.DEFAULT) {
dateTypeAdapter = new DefaultDateTypeAdapter(dateStyle, timeStyle);
}
if (dateTypeAdapter != null) {
if (!serializers.hasSpecificHandlerFor(Date.class)) {
serializers.register(Date.class, dateTypeAdapter);
}
if (!deserializers.hasSpecificHandlerFor(Date.class)) {
deserializers.register(Date.class, dateTypeAdapter);
}
}
}
}

View File

@ -0,0 +1,33 @@
/**
*
* Copyright (C) 2010 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 com.google.gson;
/**
* handles the limitation in gson 1.6 where
* {@link GsonBuilder#registerTypeHierarchyAdapter(Class, Object)} is package private.
*
* @see <a href="http://code.google.com/p/google-gson/issues/detail?id=271" >gson issue 271</a>
* @author Adrian Cole
*/
public class JcloudsGsonPackageAccessor {
public static GsonBuilder registerTypeHierarchyAdapter(GsonBuilder builder, Class<?> baseType, Object typeAdapter) {
return builder.registerTypeHierarchyAdapter(baseType, typeAdapter);
}
}

View File

@ -1,138 +0,0 @@
/**
*
* Copyright (C) 2010 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.
* ====================================================================
*/
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.gson;
import java.io.IOException;
import java.util.Map;
import com.google.gson.JcloudsCompactFormatter.FormattingVisitor;
/**
* from JsonTreeNavigator modified so that we can use JsonLiteral.
*
* @author Inderjeet Singh
*/
public class JcloudsTreeNavigator {
private final FormattingVisitor visitor;
private final boolean visitNulls;
JcloudsTreeNavigator(FormattingVisitor visitor, boolean visitNulls) {
this.visitor = visitor;
this.visitNulls = visitNulls;
}
public void navigate(JsonElement element) throws IOException {
if (element.isJsonNull()) {
visitor.visitNull();
} else if (element.isJsonArray()) {
JsonArray array = element.getAsJsonArray();
visitor.startArray(array);
boolean isFirst = true;
for (JsonElement child : array) {
visitChild(array, child, isFirst);
if (isFirst) {
isFirst = false;
}
}
visitor.endArray(array);
} else if (element.isJsonObject()) {
JsonObject object = element.getAsJsonObject();
visitor.startObject(object);
boolean isFirst = true;
for (Map.Entry<String, JsonElement> member : object.entrySet()) {
boolean visited = visitChild(object, member.getKey(), member.getValue(), isFirst);
if (visited && isFirst) {
isFirst = false;
}
}
visitor.endObject(object);
} else if (element instanceof JsonLiteral) {
visitor.visitLiteral(JsonLiteral.class.cast(element));
} else { // must be JsonPrimitive
visitor.visitPrimitive(element.getAsJsonPrimitive());
}
}
/**
* Returns true if the child was visited, false if it was skipped.
*/
private boolean visitChild(JsonObject parent, String childName, JsonElement child, boolean isFirst)
throws IOException {
if (child.isJsonNull()) {
if (visitNulls) {
visitor.visitNullObjectMember(parent, childName, isFirst);
navigate(child.getAsJsonNull());
} else { // Null value is being skipped.
return false;
}
} else if (child.isJsonArray()) {
JsonArray childAsArray = child.getAsJsonArray();
visitor.visitObjectMember(parent, childName, childAsArray, isFirst);
navigate(childAsArray);
} else if (child.isJsonObject()) {
JsonObject childAsObject = child.getAsJsonObject();
visitor.visitObjectMember(parent, childName, childAsObject, isFirst);
navigate(childAsObject);
} else if (child instanceof JsonLiteral) {
visitor.visitObjectMember(parent, childName, JsonLiteral.class.cast(child), isFirst);
} else { // is a JsonPrimitive
visitor.visitObjectMember(parent, childName, child.getAsJsonPrimitive(), isFirst);
}
return true;
}
/**
* Returns true if the child was visited, false if it was skipped.
*/
private void visitChild(JsonArray parent, JsonElement child, boolean isFirst) throws IOException {
if (child instanceof JsonLiteral) {
visitor.visitLiteral(JsonLiteral.class.cast(child));
} else if (child.isJsonNull()) {
visitor.visitNullArrayMember(parent, isFirst);
navigate(child);
} else if (child.isJsonArray()) {
JsonArray childAsArray = child.getAsJsonArray();
visitor.visitArrayMember(parent, childAsArray, isFirst);
navigate(childAsArray);
} else if (child.isJsonObject()) {
JsonObject childAsObject = child.getAsJsonObject();
visitor.visitArrayMember(parent, childAsObject, isFirst);
navigate(childAsObject);
} else { // is a JsonPrimitive
visitor.visitArrayMember(parent, child.getAsJsonPrimitive(), isFirst);
}
}
}

View File

@ -0,0 +1,71 @@
package com.google.gson;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.jclouds.json.internal.ParseObjectFromElement;
@SuppressWarnings({ "unchecked", "rawtypes" })
public class MapTypeAdapter implements JsonSerializer<Map>, JsonDeserializer<Map>, InstanceCreator<Map> {
public JsonElement serialize(Map src, Type typeOfSrc, JsonSerializationContext context) {
JsonObject map = new JsonObject();
Type childGenericType = null;
if (typeOfSrc instanceof ParameterizedType) {
childGenericType = new TypeInfoMap(typeOfSrc).getValueType();
}
for (Map.Entry entry : (Set<Map.Entry>) src.entrySet()) {
Object value = entry.getValue();
JsonElement valueElement;
if (value == null) {
valueElement = JsonNull.createJsonNull();
} else {
Type childType = (childGenericType == null) ? value.getClass() : childGenericType;
valueElement = context.serialize(value, childType);
}
map.add(String.valueOf(entry.getKey()), valueElement);
}
return map;
}
public Map deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
// Use ObjectConstructor to create instance instead of hard-coding a specific type.
// This handles cases where users are using their own subclass of Map.
Map<Object, Object> map = constructMapType(typeOfT, context);
TypeInfoMap mapTypeInfo = new TypeInfoMap(typeOfT);
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
Object key = context.deserialize(new JsonPrimitive(entry.getKey()), mapTypeInfo.getKeyType());
// START JCLOUDS PATCH
Object value = null;
if (mapTypeInfo.getValueType() == Object.class) {
value = ParseObjectFromElement.SINGLETON.apply(entry.getValue());
}
if (value == null) {
value = context.deserialize(entry.getValue(), mapTypeInfo.getValueType());
}
// END JCLOUDS PATCH
map.put(key, value);
}
return map;
}
private Map constructMapType(Type mapType, JsonDeserializationContext context) {
JsonDeserializationContextDefault contextImpl = (JsonDeserializationContextDefault) context;
ObjectConstructor objectConstructor = contextImpl.getObjectConstructor();
return (Map) objectConstructor.construct(mapType);
}
public Map createInstance(Type type) {
return new LinkedHashMap();
}
@Override
public String toString() {
return MapTypeAdapter.class.getSimpleName();
}
}

View File

@ -0,0 +1,192 @@
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.gson;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import com.google.gson.stream.MalformedJsonException;
import java.io.EOFException;
import java.io.IOException;
import java.io.Writer;
import java.util.Map;
/**
* Reads and writes GSON parse trees over streams.
*/
final class Streams {
/**
* Takes a reader in any state and returns the next value as a JsonElement.
*/
static JsonElement parse(JsonReader reader) throws JsonParseException {
boolean isEmpty = true;
try {
reader.peek();
isEmpty = false;
return parseRecursive(reader);
} catch (EOFException e) {
/*
* For compatibility with JSON 1.5 and earlier, we return a JsonNull for
* empty documents instead of throwing.
*/
if (isEmpty) {
return JsonNull.createJsonNull();
}
throw new JsonIOException(e);
} catch (MalformedJsonException e) {
throw new JsonSyntaxException(e);
} catch (IOException e) {
throw new JsonIOException(e);
} catch (NumberFormatException e) {
throw new JsonSyntaxException(e);
}
}
private static JsonElement parseRecursive(JsonReader reader) throws IOException {
switch (reader.peek()) {
case STRING:
return new JsonPrimitive(reader.nextString());
case NUMBER:
String number = reader.nextString();
return new JsonPrimitive(JsonPrimitive.stringToNumber(number));
case BOOLEAN:
return new JsonPrimitive(reader.nextBoolean());
case NULL:
reader.nextNull();
return JsonNull.createJsonNull();
case BEGIN_ARRAY:
JsonArray array = new JsonArray();
reader.beginArray();
while (reader.hasNext()) {
array.add(parseRecursive(reader));
}
reader.endArray();
return array;
case BEGIN_OBJECT:
JsonObject object = new JsonObject();
reader.beginObject();
while (reader.hasNext()) {
object.add(reader.nextName(), parseRecursive(reader));
}
reader.endObject();
return object;
case END_DOCUMENT:
case NAME:
case END_OBJECT:
case END_ARRAY:
default:
throw new IllegalArgumentException();
}
}
/**
* Writes the JSON element to the writer, recursively.
*/
static void write(JsonElement element, boolean serializeNulls, JsonWriter writer)
throws IOException {
if (element == null || element.isJsonNull()) {
if (serializeNulls) {
writer.nullValue();
}
//BEGIN JCLOUDS PATCH
} else if (element instanceof JsonLiteral ) {
writer.value(JsonLiteral.class.cast(element));
//END JCLOUDS PATCH
} else if (element.isJsonPrimitive()) {
JsonPrimitive primitive = element.getAsJsonPrimitive();
if (primitive.isNumber()) {
writer.value(primitive.getAsNumber());
} else if (primitive.isBoolean()) {
writer.value(primitive.getAsBoolean());
} else {
writer.value(primitive.getAsString());
}
} else if (element.isJsonArray()) {
writer.beginArray();
for (JsonElement e : element.getAsJsonArray()) {
/* always print null when its parent element is an array! */
if (e.isJsonNull()) {
writer.nullValue();
continue;
}
write(e, serializeNulls, writer);
}
writer.endArray();
} else if (element.isJsonObject()) {
writer.beginObject();
for (Map.Entry<String, JsonElement> e : element.getAsJsonObject().entrySet()) {
JsonElement value = e.getValue();
if (!serializeNulls && value.isJsonNull()) {
continue;
}
writer.name(e.getKey());
write(value, serializeNulls, writer);
}
writer.endObject();
} else {
throw new IllegalArgumentException("Couldn't write " + element.getClass());
}
}
static Writer writerForAppendable(Appendable appendable) {
return appendable instanceof Writer ? (Writer) appendable : new AppendableWriter(appendable);
}
/**
* Adapts an {@link Appendable} so it can be passed anywhere a {@link Writer}
* is used.
*/
private static class AppendableWriter extends Writer {
private final Appendable appendable;
private final CurrentWrite currentWrite = new CurrentWrite();
private AppendableWriter(Appendable appendable) {
this.appendable = appendable;
}
@Override public void write(char[] chars, int offset, int length) throws IOException {
currentWrite.chars = chars;
appendable.append(currentWrite, offset, offset + length);
}
@Override public void write(int i) throws IOException {
appendable.append((char) i);
}
@Override public void flush() {}
@Override public void close() {}
/**
* A mutable char sequence pointing at a single char[].
*/
static class CurrentWrite implements CharSequence {
char[] chars;
public int length() {
return chars.length;
}
public char charAt(int i) {
return chars[i];
}
public CharSequence subSequence(int start, int end) {
return new String(chars, start, end - start);
}
}
}
}

View File

@ -0,0 +1,568 @@
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.gson.stream;
import java.io.Closeable;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import com.google.gson.JsonLiteral;
/**
* Writes a JSON (<a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>)
* encoded value to a stream, one token at a time. The stream includes both
* literal values (strings, numbers, booleans and nulls) as well as the begin
* and end delimiters of objects and arrays.
*
* <h3>Encoding JSON</h3>
* To encode your data as JSON, create a new {@code JsonWriter}. Each JSON
* document must contain one top-level array or object. Call methods on the
* writer as you walk the structure's contents, nesting arrays and objects as
* necessary:
* <ul>
* <li>To write <strong>arrays</strong>, first call {@link #beginArray()}.
* Write each of the array's elements with the appropriate {@link #value}
* methods or by nesting other arrays and objects. Finally close the array
* using {@link #endArray()}.
* <li>To write <strong>objects</strong>, first call {@link #beginObject()}.
* Write each of the object's properties by alternating calls to
* {@link #name} with the property's value. Write property values with the
* appropriate {@link #value} method or by nesting other objects or arrays.
* Finally close the object using {@link #endObject()}.
* </ul>
*
* <h3>Example</h3>
* Suppose we'd like to encode a stream of messages such as the following: <pre> {@code
* [
* {
* "id": 912345678901,
* "text": "How do I stream JSON in Java?",
* "geo": null,
* "user": {
* "name": "json_newb",
* "followers_count": 41
* }
* },
* {
* "id": 912345678902,
* "text": "@json_newb just use JsonWriter!",
* "geo": [50.454722, -104.606667],
* "user": {
* "name": "jesse",
* "followers_count": 2
* }
* }
* ]}</pre>
* This code encodes the above structure: <pre> {@code
* public void writeJsonStream(OutputStream out, List<Message> messages) throws IOException {
* JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8"));
* writer.setIndentSpaces(4);
* writeMessagesArray(writer, messages);
* writer.close();
* }
*
* public void writeMessagesArray(JsonWriter writer, List<Message> messages) throws IOException {
* writer.beginArray();
* for (Message message : messages) {
* writeMessage(writer, message);
* }
* writer.endArray();
* }
*
* public void writeMessage(JsonWriter writer, Message message) throws IOException {
* writer.beginObject();
* writer.name("id").value(message.getId());
* writer.name("text").value(message.getText());
* if (message.getGeo() != null) {
* writer.name("geo");
* writeDoublesArray(writer, message.getGeo());
* } else {
* writer.name("geo").nullValue();
* }
* writer.name("user");
* writeUser(writer, message.getUser());
* writer.endObject();
* }
*
* public void writeUser(JsonWriter writer, User user) throws IOException {
* writer.beginObject();
* writer.name("name").value(user.getName());
* writer.name("followers_count").value(user.getFollowersCount());
* writer.endObject();
* }
*
* public void writeDoublesArray(JsonWriter writer, List<Double> doubles) throws IOException {
* writer.beginArray();
* for (Double value : doubles) {
* writer.value(value);
* }
* writer.endArray();
* }}</pre>
*
* <p>Each {@code JsonWriter} may be used to write a single JSON stream.
* Instances of this class are not thread safe. Calls that would result in a
* malformed JSON string will fail with an {@link IllegalStateException}.
*
* @author Jesse Wilson
* @since 1.6
*/
public final class JsonWriter implements Closeable {
/** The output data, containing at most one top-level array or object. */
private final Writer out;
private final List<JsonScope> stack = new ArrayList<JsonScope>();
{
stack.add(JsonScope.EMPTY_DOCUMENT);
}
/**
* A string containing a full set of spaces for a single level of
* indentation, or null for no pretty printing.
*/
private String indent;
/**
* The name/value separator; either ":" or ": ".
*/
private String separator = ":";
private boolean lenient;
private boolean htmlSafe;
/**
* Creates a new instance that writes a JSON-encoded stream to {@code out}.
* For best performance, ensure {@link Writer} is buffered; wrapping in
* {@link java.io.BufferedWriter BufferedWriter} if necessary.
*/
public JsonWriter(Writer out) {
if (out == null) {
throw new NullPointerException("out == null");
}
this.out = out;
}
/**
* Sets the indentation string to be repeated for each level of indentation
* in the encoded document. If {@code indent.isEmpty()} the encoded document
* will be compact. Otherwise the encoded document will be more
* human-readable.
*
* @param indent a string containing only whitespace.
*/
public void setIndent(String indent) {
if (indent.length() == 0) {
this.indent = null;
this.separator = ":";
} else {
this.indent = indent;
this.separator = ": ";
}
}
/**
* Configure this writer to relax its syntax rules. By default, this writer
* only emits well-formed JSON as specified by <a
* href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. Setting the writer
* to lenient permits the following:
* <ul>
* <li>Top-level values of any type. With strict writing, the top-level
* value must be an object or an array.
* <li>Numbers may be {@link Double#isNaN() NaNs} or {@link
* Double#isInfinite() infinities}.
* </ul>
*/
public void setLenient(boolean lenient) {
this.lenient = lenient;
}
/**
* Returns true if this writer has relaxed syntax rules.
*/
public boolean isLenient() {
return lenient;
}
/**
* Configure this writer to emit JSON that's safe for direct inclusion in HTML
* and XML documents. This escapes the HTML characters {@code <}, {@code >},
* {@code &} and {@code =} before writing them to the stream. Without this
* setting, your XML/HTML encoder should replace these characters with the
* corresponding escape sequences.
*/
public void setHtmlSafe(boolean htmlSafe) {
this.htmlSafe = htmlSafe;
}
/**
* Returns true if this writer writes JSON that's safe for inclusion in HTML
* and XML documents.
*/
public boolean isHtmlSafe() {
return htmlSafe;
}
/**
* Begins encoding a new array. Each call to this method must be paired with
* a call to {@link #endArray}.
*
* @return this writer.
*/
public JsonWriter beginArray() throws IOException {
return open(JsonScope.EMPTY_ARRAY, "[");
}
/**
* Ends encoding the current array.
*
* @return this writer.
*/
public JsonWriter endArray() throws IOException {
return close(JsonScope.EMPTY_ARRAY, JsonScope.NONEMPTY_ARRAY, "]");
}
/**
* Begins encoding a new object. Each call to this method must be paired
* with a call to {@link #endObject}.
*
* @return this writer.
*/
public JsonWriter beginObject() throws IOException {
return open(JsonScope.EMPTY_OBJECT, "{");
}
/**
* Ends encoding the current object.
*
* @return this writer.
*/
public JsonWriter endObject() throws IOException {
return close(JsonScope.EMPTY_OBJECT, JsonScope.NONEMPTY_OBJECT, "}");
}
/**
* Enters a new scope by appending any necessary whitespace and the given
* bracket.
*/
private JsonWriter open(JsonScope empty, String openBracket) throws IOException {
beforeValue(true);
stack.add(empty);
out.write(openBracket);
return this;
}
/**
* Closes the current scope by appending any necessary whitespace and the
* given bracket.
*/
private JsonWriter close(JsonScope empty, JsonScope nonempty, String closeBracket)
throws IOException {
JsonScope context = peek();
if (context != nonempty && context != empty) {
throw new IllegalStateException("Nesting problem: " + stack);
}
stack.remove(stack.size() - 1);
if (context == nonempty) {
newline();
}
out.write(closeBracket);
return this;
}
/**
* Returns the value on the top of the stack.
*/
private JsonScope peek() {
return stack.get(stack.size() - 1);
}
/**
* Replace the value on the top of the stack with the given value.
*/
private void replaceTop(JsonScope topOfStack) {
stack.set(stack.size() - 1, topOfStack);
}
/**
* Encodes the property name.
*
* @param name the name of the forthcoming value. May not be null.
* @return this writer.
*/
public JsonWriter name(String name) throws IOException {
if (name == null) {
throw new NullPointerException("name == null");
}
beforeName();
string(name);
return this;
}
/**
* Encodes {@code value}.
*
* @param value the literal string value, or null to encode a null literal.
* @return this writer.
*/
public JsonWriter value(String value) throws IOException {
if (value == null) {
return nullValue();
}
beforeValue(false);
string(value);
return this;
}
/**
* Encodes {@code null}.
*
* @return this writer.
*/
public JsonWriter nullValue() throws IOException {
beforeValue(false);
out.write("null");
return this;
}
//BEGIN JCLOUDS PATCH
/**
* Writes {@code value} literally
*
* @return this writer.
*/
public JsonWriter value(JsonLiteral value) throws IOException {
beforeValue(false);
out.write(value.toString());
return this;
}
//END JCLOUDS PATCH
/**
* Encodes {@code value}.
*
* @return this writer.
*/
public JsonWriter value(boolean value) throws IOException {
beforeValue(false);
out.write(value ? "true" : "false");
return this;
}
/**
* Encodes {@code value}.
*
* @param value a finite value. May not be {@link Double#isNaN() NaNs} or
* {@link Double#isInfinite() infinities}.
* @return this writer.
*/
public JsonWriter value(double value) throws IOException {
if (Double.isNaN(value) || Double.isInfinite(value)) {
throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
}
beforeValue(false);
out.append(Double.toString(value));
return this;
}
/**
* Encodes {@code value}.
*
* @return this writer.
*/
public JsonWriter value(long value) throws IOException {
beforeValue(false);
out.write(Long.toString(value));
return this;
}
/**
* Encodes {@code value}.
*
* @param value a finite value. May not be {@link Double#isNaN() NaNs} or
* {@link Double#isInfinite() infinities}.
* @return this writer.
*/
public JsonWriter value(Number value) throws IOException {
if (value == null) {
return nullValue();
}
String string = value.toString();
if (!lenient
&& (string.equals("-Infinity") || string.equals("Infinity") || string.equals("NaN"))) {
throw new IllegalArgumentException("Numeric values must be finite, but was " + value);
}
beforeValue(false);
out.append(string);
return this;
}
/**
* Ensures all buffered data is written to the underlying {@link Writer}
* and flushes that writer.
*/
public void flush() throws IOException {
out.flush();
}
/**
* Flushes and closes this writer and the underlying {@link Writer}.
*
* @throws IOException if the JSON document is incomplete.
*/
public void close() throws IOException {
out.close();
if (peek() != JsonScope.NONEMPTY_DOCUMENT) {
throw new IOException("Incomplete document");
}
}
private void string(String value) throws IOException {
out.write("\"");
for (int i = 0, length = value.length(); i < length; i++) {
char c = value.charAt(i);
/*
* From RFC 4627, "All Unicode characters may be placed within the
* quotation marks except for the characters that must be escaped:
* quotation mark, reverse solidus, and the control characters
* (U+0000 through U+001F)."
*/
switch (c) {
case '"':
case '\\':
out.write('\\');
out.write(c);
break;
case '\t':
out.write("\\t");
break;
case '\b':
out.write("\\b");
break;
case '\n':
out.write("\\n");
break;
case '\r':
out.write("\\r");
break;
case '\f':
out.write("\\f");
break;
case '<':
case '>':
case '&':
case '=':
case '\'':
if (htmlSafe) {
out.write(String.format("\\u%04x", (int) c));
} else {
out.write(c);
}
break;
default:
if (c <= 0x1F) {
out.write(String.format("\\u%04x", (int) c));
} else {
out.write(c);
}
break;
}
}
out.write("\"");
}
private void newline() throws IOException {
if (indent == null) {
return;
}
out.write("\n");
for (int i = 1; i < stack.size(); i++) {
out.write(indent);
}
}
/**
* Inserts any necessary separators and whitespace before a name. Also
* adjusts the stack to expect the name's value.
*/
private void beforeName() throws IOException {
JsonScope context = peek();
if (context == JsonScope.NONEMPTY_OBJECT) { // first in object
out.write(',');
} else if (context != JsonScope.EMPTY_OBJECT) { // not in an object!
throw new IllegalStateException("Nesting problem: " + stack);
}
newline();
replaceTop(JsonScope.DANGLING_NAME);
}
/**
* Inserts any necessary separators and whitespace before a literal value,
* inline array, or inline object. Also adjusts the stack to expect either a
* closing bracket or another element.
*
* @param root true if the value is a new array or object, the two values
* permitted as top-level elements.
*/
private void beforeValue(boolean root) throws IOException {
switch (peek()) {
case EMPTY_DOCUMENT: // first in document
if (!lenient && !root) {
throw new IllegalStateException(
"JSON must start with an array or an object.");
}
replaceTop(JsonScope.NONEMPTY_DOCUMENT);
break;
case EMPTY_ARRAY: // first in array
replaceTop(JsonScope.NONEMPTY_ARRAY);
newline();
break;
case NONEMPTY_ARRAY: // another in array
out.append(',');
newline();
break;
case DANGLING_NAME: // value for name
out.append(separator);
replaceTop(JsonScope.NONEMPTY_OBJECT);
break;
case NONEMPTY_DOCUMENT:
throw new IllegalStateException(
"JSON must have only one top-level value.");
default:
throw new IllegalStateException("Nesting problem: " + stack);
}
}
}

View File

@ -164,10 +164,6 @@ public interface Constants {
* Name of the logger that records the steps of the request signing process of the HTTP_service.
*/
public static final String LOGGER_SIGNATURE = "jclouds.signature";
/**
* Name of the custom adapter bindings map for Json
*/
public static final String PROPERTY_GSON_ADAPTERS = "jclouds.gson-adapters";
/**
* String property.

View File

@ -25,11 +25,12 @@ import java.io.Serializable;
import java.net.URI;
import java.util.Map;
import javax.annotation.Nullable;
import org.jclouds.domain.Location;
import org.jclouds.domain.ResourceMetadata;
import com.google.common.collect.Maps;
import com.google.inject.internal.Nullable;
/**
* Idpayload of the object

View File

@ -19,18 +19,27 @@
package org.jclouds.io.payloads;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.jclouds.util.Utils;
import com.google.common.base.Charsets;
/**
* This implementation converts the String to a byte array using UTF-8 encoding. If you wish to use
* a different encoding, please use {@link ByteArrayPayload}.
*
* @author Adrian Cole
*/
public class StringPayload extends BasePayload<String> {
private final byte[] bytes;
// it is possible to discover length by walking the string and updating current length based on
// character code. However, this is process intense, and assumes an encoding type of UTF-8
public StringPayload(String content) {
super(content);
getContentMetadata().setContentLength((long) content.length());
this.bytes = content.getBytes(Charsets.UTF_8);
getContentMetadata().setContentLength(new Long(bytes.length));
}
/**
@ -38,7 +47,7 @@ public class StringPayload extends BasePayload<String> {
*/
@Override
public InputStream getInput() {
return Utils.toInputStream(content);
return new ByteArrayInputStream(bytes);
}
}

View File

@ -19,7 +19,6 @@
package org.jclouds.json.config;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.List;
@ -28,18 +27,18 @@ import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.crypto.CryptoStreams;
import org.jclouds.date.DateService;
import org.jclouds.domain.JsonBall;
import org.jclouds.json.Json;
import org.jclouds.json.internal.EnumTypeAdapterThatReturnsFromValue;
import org.jclouds.json.internal.GsonWrapper;
import com.google.common.collect.Maps;
import com.google.common.primitives.Bytes;
import com.google.gson.Gson;
import com.google.gson.JcloudsCompactFormatter;
import com.google.gson.JcloudsGsonBuilder;
import com.google.gson.GsonBuilder;
import com.google.gson.JcloudsGsonPackageAccessor;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
@ -48,11 +47,11 @@ import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.MapTypeAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.inject.AbstractModule;
import com.google.inject.ImplementedBy;
import com.google.inject.Provides;
import com.google.inject.name.Named;
/**
* Contains logic for parsing objects from Strings.
@ -61,13 +60,16 @@ import com.google.inject.name.Named;
*/
public class GsonModule extends AbstractModule {
@SuppressWarnings("rawtypes")
@Provides
@Singleton
Gson provideGson(JsonBallAdapter jsonObjectAdapter, DateAdapter adapter, ByteListAdapter byteListAdapter,
Gson provideGson(JsonBallAdapter jsonAdapter, DateAdapter adapter, ByteListAdapter byteListAdapter,
ByteArrayAdapter byteArrayAdapter, JsonAdapterBindings bindings) throws ClassNotFoundException, Exception {
JcloudsGsonBuilder builder = new JcloudsGsonBuilder();
builder.registerTypeAdapter(JsonBall.class, jsonObjectAdapter);
GsonBuilder builder = new GsonBuilder();
JcloudsGsonPackageAccessor.registerTypeHierarchyAdapter(builder, Enum.class,
new EnumTypeAdapterThatReturnsFromValue());
JcloudsGsonPackageAccessor.registerTypeHierarchyAdapter(builder, Map.class, new MapTypeAdapter());
builder.registerTypeAdapter(JsonBall.class, jsonAdapter);
builder.registerTypeAdapter(Date.class, adapter);
builder.registerTypeAdapter(new TypeToken<List<Byte>>() {
}.getType(), byteListAdapter);
@ -75,14 +77,26 @@ public class GsonModule extends AbstractModule {
for (Map.Entry<Type, Object> binding : bindings.getBindings().entrySet()) {
builder.registerTypeAdapter(binding.getKey(), binding.getValue());
}
JcloudsCompactFormatter formatter = new JcloudsCompactFormatter();
return builder.create();
}
@ImplementedBy(JsonBallAdapterImpl.class)
public static interface JsonBallAdapter extends JsonSerializer<JsonBall>, JsonDeserializer<JsonBall> {
}
@Singleton
public static class JsonBallAdapterImpl implements JsonBallAdapter {
public JsonElement serialize(JsonBall src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonLiteral(src);
}
public JsonBall deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return new JsonBall(json.toString());
}
Gson gson = builder.create();
// allow us to print json literals
Field statFinField = Gson.class.getDeclaredField("formatter");
statFinField.setAccessible(true);
statFinField.set(gson, formatter);
return gson;
}
@ImplementedBy(CDateAdapter.class)
@ -178,25 +192,6 @@ public class GsonModule extends AbstractModule {
}
@ImplementedBy(JsonBallAdapterImpl.class)
public static interface JsonBallAdapter extends JsonSerializer<JsonBall>, JsonDeserializer<JsonBall> {
}
@Singleton
public static class JsonBallAdapterImpl implements JsonBallAdapter {
public JsonElement serialize(JsonBall src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonLiteral(src);
}
public JsonBall deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return new JsonBall(json.toString());
}
}
@Singleton
public static class LongDateAdapter implements DateAdapter {
@ -219,7 +214,7 @@ public class GsonModule extends AbstractModule {
private final Map<Type, Object> bindings = Maps.newHashMap();
@com.google.inject.Inject(optional = true)
public void setBindings(@Named(Constants.PROPERTY_GSON_ADAPTERS) Map<Type, Object> bindings) {
public void setBindings(Map<Type, Object> bindings) {
this.bindings.putAll(bindings);
}

View File

@ -0,0 +1,82 @@
/**
*
* Copyright (C) 2010 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.json.internal;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map;
import com.google.common.base.Function;
import com.google.common.collect.MapMaker;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
/**
* @author Adrian Cole
*/
@SuppressWarnings("unchecked")
public class EnumTypeAdapterThatReturnsFromValue<T extends Enum<T>> implements JsonSerializer<T>, JsonDeserializer<T> {
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) {
return new JsonPrimitive(src.name());
}
@SuppressWarnings("cast")
public T deserialize(JsonElement json, Type classOfT, JsonDeserializationContext context) throws JsonParseException {
try {
return (T) Enum.valueOf((Class<T>) classOfT, json.getAsString());
} catch (IllegalArgumentException e) {
Method converter = classToConvert.get(classOfT);
if (converter != null)
try {
return (T) converter.invoke(null, json.getAsString());
} catch (Exception e1) {
throw e;
}
else
throw e;
}
}
private final static Map<Class<?>, Method> classToConvert = new MapMaker()
.makeComputingMap(new Function<Class<?>, Method>() {
@Override
public Method apply(Class<?> from) {
try {
Method method = from.getMethod("fromValue", String.class);
method.setAccessible(true);
return method;
} catch (Exception e) {
return null;
}
}
});
@Override
public String toString() {
return EnumTypeAdapterThatReturnsFromValue.class.getSimpleName();
}
}

View File

@ -0,0 +1,59 @@
/**
*
* Copyright (C) 2010 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.json.internal;
import java.lang.reflect.Field;
import java.util.Map;
import com.google.common.base.Function;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
/**
* Exposes the JsonObject as a map so that we can use gauva apis on it.
*
* @author Adrian Cole
*/
public enum JsonObjectAsMap implements Function<JsonObject, Map<String, JsonElement>> {
INSTANCE;
private final Field members;
JsonObjectAsMap() {
try {
members = JsonObject.class.getDeclaredField("members");
members.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new UnsupportedOperationException("cannot access gson internals", e);
}
}
@SuppressWarnings("unchecked")
@Override
public Map<String, JsonElement> apply(JsonObject in) {
try {
return (Map<String, JsonElement>) members.get(in);
} catch (IllegalArgumentException e) {
throw new UnsupportedOperationException("cannot access gson internals", e);
} catch (IllegalAccessException e) {
throw new UnsupportedOperationException("cannot access gson internals", e);
}
}
}

View File

@ -0,0 +1,59 @@
/**
*
* Copyright (C) 2010 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.json.internal;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.MapTypeAdapter;
/**
* This is a class that helps the default {@link MapTypeAdapter} make a sane object graph when the
* value is set to {@code Object}
*
* @author Adrian Cole
*/
public enum ParseObjectFromElement implements Function<JsonElement, Object> {
SINGLETON;
public Object apply(JsonElement input) {
Object value = null;
if (input == null || input.isJsonNull()) {
value = null;
} else if (input.isJsonPrimitive()) {
JsonPrimitive primitive = input.getAsJsonPrimitive();
if (primitive.isNumber()) {
value = primitive.getAsNumber();
} else if (primitive.isBoolean()) {
value = primitive.getAsBoolean();
} else {
value = primitive.getAsString();
}
} else if (input.isJsonArray()) {
value = Lists.newArrayList(Iterables.transform(input.getAsJsonArray(), this));
} else if (input.isJsonObject()) {
value = Maps.<String,Object>newLinkedHashMap(Maps.transformValues(JsonObjectAsMap.INSTANCE.apply(input.getAsJsonObject()),
this));
}
return value;
}
}

View File

@ -166,7 +166,7 @@ public class RestAnnotationProcessor<T> {
static final Map<MethodKey, Method> delegationMap = newHashMap();
static Map<Method, Map<Integer, Set<Annotation>>> createMethodToIndexOfParamToAnnotation(
final Class<? extends Annotation> annotation) {
final Class<? extends Annotation> annotation) {
return new MapMaker().makeComputingMap(new Function<Method, Map<Integer, Set<Annotation>>>() {
public Map<Integer, Set<Annotation>> apply(final Method method) {
return new MapMaker().makeComputingMap(new GetAnnotationsForMethodParameterIndex(method, annotation));
@ -200,7 +200,7 @@ public class RestAnnotationProcessor<T> {
}
private static final Class<? extends HttpRequestOptions[]> optionsVarArgsClass = new HttpRequestOptions[] {}
.getClass();
.getClass();
private static final Function<? super Entry<String, String>, ? extends Part> ENTRY_TO_PART = new Function<Entry<String, String>, Part>() {
@ -212,17 +212,17 @@ public class RestAnnotationProcessor<T> {
};
private final Map<Method, Set<Integer>> methodToIndexesOfOptions = new MapMaker()
.makeComputingMap(new Function<Method, Set<Integer>>() {
public Set<Integer> apply(final Method method) {
Set<Integer> toReturn = newHashSet();
for (int index = 0; index < method.getParameterTypes().length; index++) {
Class<?> type = method.getParameterTypes()[index];
if (HttpRequestOptions.class.isAssignableFrom(type) || optionsVarArgsClass.isAssignableFrom(type))
toReturn.add(index);
}
return toReturn;
.makeComputingMap(new Function<Method, Set<Integer>>() {
public Set<Integer> apply(final Method method) {
Set<Integer> toReturn = newHashSet();
for (int index = 0; index < method.getParameterTypes().length; index++) {
Class<?> type = method.getParameterTypes()[index];
if (HttpRequestOptions.class.isAssignableFrom(type) || optionsVarArgsClass.isAssignableFrom(type))
toReturn.add(index);
}
});
return toReturn;
}
});
private final ParseSax.Factory parserFactory;
private final HttpUtils utils;
@ -240,7 +240,7 @@ public class RestAnnotationProcessor<T> {
@VisibleForTesting
public static Function<HttpResponse, ?> createResponseParser(ParseSax.Factory parserFactory, Injector injector,
Method method, HttpRequest request) {
Method method, HttpRequest request) {
Function<HttpResponse, ?> transformer;
Class<? extends HandlerWithResult<?>> handler = getSaxResponseParserClassOrNull(method);
if (handler != null) {
@ -261,7 +261,7 @@ public class RestAnnotationProcessor<T> {
@VisibleForTesting
public static Function<Exception, ?> createExceptionParserOrThrowResourceNotFoundOn404IfNoAnnotation(
Injector injector, Method method) {
Injector injector, Method method) {
ExceptionParser annotation = method.getAnnotation(ExceptionParser.class);
if (annotation != null) {
return injector.getInstance(annotation.value());
@ -272,7 +272,7 @@ public class RestAnnotationProcessor<T> {
@SuppressWarnings("unchecked")
@Inject
public RestAnnotationProcessor(Injector injector, ParseSax.Factory parserFactory, HttpUtils utils,
TypeLiteral<T> typeLiteral) {
TypeLiteral<T> typeLiteral) {
this.declaring = (Class<T>) typeLiteral.getRawType();
this.injector = injector;
this.parserFactory = parserFactory;
@ -387,7 +387,7 @@ public class RestAnnotationProcessor<T> {
public GeneratedHttpRequest<T> createRequest(Method method, Object... args) {
inputParamValidator.validateMethodParametersOrThrow(method, args);
ClassMethodArgs cma = logger.isTraceEnabled() ? new ClassMethodArgs(method.getDeclaringClass(), method, args)
: null;
: null;
URI endpoint = callerEndpoint;
try {
@ -457,7 +457,7 @@ public class RestAnnotationProcessor<T> {
}
GeneratedHttpRequest<T> request = new GeneratedHttpRequest<T>(httpMethod, endpoint, skips, declaring, method,
args);
args);
addHostHeaderIfAnnotatedWithVirtualHost(headers, request.getEndpoint().getHost(), method);
addFiltersIfAnnotated(method, request);
@ -472,8 +472,9 @@ public class RestAnnotationProcessor<T> {
} else if (formParams.size() > 0) {
payload = Payloads.newUrlEncodedFormPayload(formParams, skips);
} else if (headers.containsKey(CONTENT_TYPE)) {
payload = Payloads.newByteArrayPayload(new byte[]{});
payload.getContentMetadata().setContentType(Iterables.get(headers.get(CONTENT_TYPE),0));
if (payload == null)
payload = Payloads.newByteArrayPayload(new byte[] {});
payload.getContentMetadata().setContentType(Iterables.get(headers.get(CONTENT_TYPE), 0));
}
if (payload != null) {
request.setPayload(payload);
@ -496,14 +497,14 @@ public class RestAnnotationProcessor<T> {
}
public static URI replaceQuery(Provider<UriBuilder> uriBuilderProvider, URI in, String newQuery,
@Nullable Comparator<Entry<String, String>> sorter, char... skips) {
@Nullable Comparator<Entry<String, String>> sorter, char... skips) {
UriBuilder builder = uriBuilderProvider.get().uri(in);
builder.replaceQuery(makeQueryLine(parseQueryToMap(newQuery), sorter, skips));
return builder.build();
}
private void addMatrixParams(UriBuilder builder, Collection<Entry<String, String>> tokenValues, Method method,
Object... args) {
Object... args) {
if (declaring.isAnnotationPresent(MatrixParams.class)) {
MatrixParams matrix = declaring.getAnnotation(MatrixParams.class);
addMatrix(builder, matrix, tokenValues);
@ -520,7 +521,7 @@ public class RestAnnotationProcessor<T> {
}
private Multimap<String, String> addFormParams(Collection<Entry<String, String>> tokenValues, Method method,
Object... args) {
Object... args) {
Multimap<String, String> formMap = LinkedListMultimap.create();
if (declaring.isAnnotationPresent(FormParams.class)) {
FormParams form = declaring.getAnnotation(FormParams.class);
@ -539,7 +540,7 @@ public class RestAnnotationProcessor<T> {
}
private Multimap<String, String> addQueryParams(Collection<Entry<String, String>> tokenValues, Method method,
Object... args) {
Object... args) {
Multimap<String, String> queryMap = LinkedListMultimap.create();
if (declaring.isAnnotationPresent(QueryParams.class)) {
QueryParams query = declaring.getAnnotation(QueryParams.class);
@ -558,7 +559,7 @@ public class RestAnnotationProcessor<T> {
}
private void addForm(Multimap<String, String> formParams, FormParams form,
Collection<Entry<String, String>> tokenValues) {
Collection<Entry<String, String>> tokenValues) {
for (int i = 0; i < form.keys().length; i++) {
if (form.values()[i].equals(FormParams.NULL)) {
formParams.removeAll(form.keys()[i]);
@ -570,7 +571,7 @@ public class RestAnnotationProcessor<T> {
}
private void addMapPayload(Map<String, String> postParams, MapPayloadParams mapDefaults,
Collection<Entry<String, String>> tokenValues) {
Collection<Entry<String, String>> tokenValues) {
for (int i = 0; i < mapDefaults.keys().length; i++) {
if (mapDefaults.values()[i].equals(MapPayloadParams.NULL)) {
postParams.put(mapDefaults.keys()[i], null);
@ -581,7 +582,7 @@ public class RestAnnotationProcessor<T> {
}
private void addQuery(Multimap<String, String> queryParams, QueryParams query,
Collection<Entry<String, String>> tokenValues) {
Collection<Entry<String, String>> tokenValues) {
for (int i = 0; i < query.keys().length; i++) {
if (query.values()[i].equals(QueryParams.NULL)) {
queryParams.removeAll(query.keys()[i]);
@ -624,7 +625,7 @@ public class RestAnnotationProcessor<T> {
@VisibleForTesting
public static URI getEndpointInParametersOrNull(Method method, final Object[] args, Injector injector) {
Map<Integer, Set<Annotation>> map = indexWithAtLeastOneAnnotation(method,
methodToIndexOfParamToEndpointParamAnnotations);
methodToIndexOfParamToEndpointParamAnnotations);
if (map.size() >= 1 && args.length > 0) {
EndpointParam firstAnnotation = (EndpointParam) get(get(map.values(), 0), 0);
Function<Object, URI> parser = injector.getInstance(firstAnnotation.parser());
@ -633,8 +634,8 @@ public class RestAnnotationProcessor<T> {
int index = map.keySet().iterator().next();
try {
URI returnVal = parser.apply(args[index]);
checkArgument(returnVal != null, String.format("endpoint for [%s] not configured for %s", args[index],
method));
checkArgument(returnVal != null,
String.format("endpoint for [%s] not configured for %s", args[index], method));
return returnVal;
} catch (NullPointerException e) {
throw new IllegalArgumentException(String.format("argument at index %d on method %s", index, method), e);
@ -651,12 +652,12 @@ public class RestAnnotationProcessor<T> {
});
try {
URI returnVal = parser.apply(argsToParse);
checkArgument(returnVal != null, String.format("endpoint for [%s] not configured for %s", argsToParse,
method));
checkArgument(returnVal != null,
String.format("endpoint for [%s] not configured for %s", argsToParse, method));
return returnVal;
} catch (NullPointerException e) {
throw new IllegalArgumentException(String.format("argument at indexes %s on method %s", map.keySet(),
method), e);
method), e);
}
}
}
@ -697,13 +698,13 @@ public class RestAnnotationProcessor<T> {
ResponseParser annotation = method.getAnnotation(ResponseParser.class);
if (annotation == null) {
if (method.getReturnType().equals(void.class)
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureVoidLiteral)) {
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureVoidLiteral)) {
return Key.get(ReleasePayloadAndReturn.class);
} else if (method.getReturnType().equals(boolean.class) || method.getReturnType().equals(Boolean.class)
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureBooleanLiteral)) {
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureBooleanLiteral)) {
return Key.get(ReturnTrueIf2xx.class);
} else if (method.getReturnType().equals(InputStream.class)
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureInputStreamLiteral)) {
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureInputStreamLiteral)) {
return Key.get(ReturnInputStream.class);
} else if (getAcceptHeadersOrNull(method).contains(MediaType.APPLICATION_JSON)) {
Type returnVal;
@ -724,10 +725,10 @@ public class RestAnnotationProcessor<T> {
parserType = Types.newParameterizedType(ParseJson.class, returnVal);
return (Key<? extends Function<HttpResponse, ?>>) Key.get(parserType);
} else if (method.getReturnType().equals(String.class)
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureStringLiteral)) {
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureStringLiteral)) {
return Key.get(ReturnStringIf2xx.class);
} else if (method.getReturnType().equals(URI.class)
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureURILiteral)) {
|| TypeLiteral.get(method.getGenericReturnType()).equals(futureURILiteral)) {
return Key.get(ParseURIFromListOrLocationHeaderIf20x.class);
} else {
throw new IllegalStateException("You must specify a ResponseParser annotation on: " + method.toString());
@ -759,7 +760,7 @@ public class RestAnnotationProcessor<T> {
} else {
if (postBinders[0] instanceof org.jclouds.rest.MapBinder) {
throw new IllegalArgumentException("we currently do not support multiple varargs postBinders in: "
+ method.getName());
+ method.getName());
}
}
} else if (arg instanceof org.jclouds.rest.MapBinder) {
@ -808,8 +809,8 @@ public class RestAnnotationProcessor<T> {
Set<String> requests = getHttpMethods(method);
if (requests == null || requests.size() != 1) {
throw new IllegalStateException(
"You must use at least one, but no more than one http method or pathparam annotation on: "
+ method.toString());
"You must use at least one, but no more than one http method or pathparam annotation on: "
+ method.toString());
}
return requests.iterator().next();
}
@ -831,12 +832,12 @@ public class RestAnnotationProcessor<T> {
mapBinder.bindToRequest(request, mapParams);
} else {
OUTER: for (Entry<Integer, Set<Annotation>> entry : filterValues(
methodToIndexOfParamToDecoratorParamAnnotation.get(request.getJavaMethod()),
new Predicate<Set<Annotation>>() {
public boolean apply(Set<Annotation> input) {
return input.size() >= 1;
}
}).entrySet()) {
methodToIndexOfParamToDecoratorParamAnnotation.get(request.getJavaMethod()),
new Predicate<Set<Annotation>>() {
public boolean apply(Set<Annotation> input) {
return input.size() >= 1;
}
}).entrySet()) {
boolean shouldBreak = false;
BinderParam payloadAnnotation = (BinderParam) entry.getValue().iterator().next();
Binder binder = injector.getInstance(payloadAnnotation.value());
@ -872,24 +873,24 @@ public class RestAnnotationProcessor<T> {
}
public static Map<Integer, Set<Annotation>> indexWithOnlyOneAnnotation(Method method, String description,
Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = indexWithAtLeastOneAnnotation(method, toRefine);
if (indexToPayloadAnnotation.size() > 1) {
throw new IllegalStateException(String.format(
"You must not specify more than one %s annotation on: %s; found %s", description, method.toString(),
indexToPayloadAnnotation));
"You must not specify more than one %s annotation on: %s; found %s", description, method.toString(),
indexToPayloadAnnotation));
}
return indexToPayloadAnnotation;
}
private static Map<Integer, Set<Annotation>> indexWithAtLeastOneAnnotation(Method method,
Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
Map<Method, Map<Integer, Set<Annotation>>> toRefine) {
Map<Integer, Set<Annotation>> indexToPayloadAnnotation = filterValues(toRefine.get(method),
new Predicate<Set<Annotation>>() {
public boolean apply(Set<Annotation> input) {
return input.size() == 1;
}
});
new Predicate<Set<Annotation>>() {
public boolean apply(Set<Annotation> input) {
return input.size() == 1;
}
});
return indexToPayloadAnnotation;
}
@ -908,7 +909,7 @@ public class RestAnnotationProcessor<T> {
} else {
if (options[0] instanceof HttpRequestOptions) {
throw new IllegalArgumentException("we currently do not support multiple varargs options in: "
+ method.getName());
+ method.getName());
}
}
} else {
@ -920,7 +921,7 @@ public class RestAnnotationProcessor<T> {
}
public Multimap<String, String> buildHeaders(Collection<Entry<String, String>> tokenValues, Method method,
final Object... args) {
final Object... args) {
Multimap<String, String> headers = LinkedHashMultimap.create();
addHeaderIfAnnotationPresentOnMethod(headers, method, tokenValues);
Map<Integer, Set<Annotation>> indexToHeaderParam = methodToIndexOfParamToHeaderParamAnnotations.get(method);
@ -967,7 +968,7 @@ public class RestAnnotationProcessor<T> {
}
public void addHeaderIfAnnotationPresentOnMethod(Multimap<String, String> headers, Method method,
Collection<Entry<String, String>> tokenValues) {
Collection<Entry<String, String>> tokenValues) {
if (declaring.isAnnotationPresent(Headers.class)) {
Headers header = declaring.getAnnotation(Headers.class);
addHeader(headers, header, tokenValues);
@ -979,7 +980,7 @@ public class RestAnnotationProcessor<T> {
}
private void addHeader(Multimap<String, String> headers, Headers header,
Collection<Entry<String, String>> tokenValues) {
Collection<Entry<String, String>> tokenValues) {
for (int i = 0; i < header.keys().length; i++) {
String value = header.values()[i];
value = replaceTokens(value, tokenValues);

View File

@ -21,7 +21,9 @@ package org.jclouds.util;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.equalTo;
import static com.google.common.base.Predicates.instanceOf;
import static com.google.common.base.Predicates.not;
import static com.google.common.base.Predicates.notNull;
import static com.google.common.base.Splitter.on;
import static com.google.common.base.Throwables.getCausalChain;
@ -32,6 +34,7 @@ import static com.google.common.collect.Iterables.find;
import static com.google.common.collect.Iterables.get;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.filterKeys;
import static com.google.common.io.ByteStreams.toByteArray;
import static com.google.common.io.Closeables.closeQuietly;
import static org.jclouds.util.Patterns.CHAR_TO_PATTERN;
@ -47,10 +50,10 @@ import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Properties;
import java.util.Set;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -70,6 +73,8 @@ import com.google.common.base.Predicate;
import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMap.Builder;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.io.OutputSupplier;
@ -84,6 +89,32 @@ import com.google.inject.spi.Message;
*/
public class Utils {
/**
* If the supplied map contains the key {@code k1}, its value will be assigned to the key
* {@code k2}. Note that this doesn't modify the input map.
*
* @param <V>
* type of value the map holds
* @param in
* the map you wish to make a copy of
* @param k1
* old key
* @param k2
* new key
* @return copy of the map with the value of the key re-routed, or the original, if it {@code k1}
* wasn't present.
*/
public static <V> Map<String, V> renameKey(Map<String, V> in, String k1, String k2) {
if (in.containsKey(k1)) {
Builder<String, V> builder = ImmutableMap.builder();
builder.putAll(filterKeys(in, not(equalTo(k1))));
V tags = in.get(k1);
builder.put(k2, tags);
in = builder.build();
}
return in;
}
public static <K, V> Supplier<Map<K, V>> composeMapSupplier(Iterable<Supplier<Map<K, V>>> suppliers) {
return new ListMapSupplier<K, V>(suppliers);
}
@ -164,10 +195,12 @@ public class Utils {
public static <T extends Throwable> T getFirstThrowableOfType(ProvisionException e, Class<T> clazz) {
for (Message message : e.getErrorMessages()) {
T cause = getFirstThrowableOfType(message.getCause(), clazz);
if (cause instanceof ProvisionException)
return getFirstThrowableOfType(ProvisionException.class.cast(cause), clazz);
return cause;
if (message.getCause() != null) {
T cause = getFirstThrowableOfType(message.getCause(), clazz);
if (cause instanceof ProvisionException)
return getFirstThrowableOfType(ProvisionException.class.cast(cause), clazz);
return cause;
}
}
return null;
}

View File

@ -35,6 +35,9 @@ sdn.propertiesbuilder=org.jclouds.nirvanix.sdn.SDNPropertiesBuilder
sqs.contextbuilder=org.jclouds.aws.sqs.SQSContextBuilder
sqs.propertiesbuilder=org.jclouds.aws.sqs.SQSPropertiesBuilder
simpledb.contextbuilder=org.jclouds.aws.simpledb.SimpleDBContextBuilder
simpledb.propertiesbuilder=org.jclouds.aws.simpledb.SimpleDBPropertiesBuilder
elb.contextbuilder=org.jclouds.aws.elb.ELBContextBuilder
elb.propertiesbuilder=org.jclouds.aws.elb.ELBPropertiesBuilder
@ -89,6 +92,12 @@ bluelock-vcdirector.propertiesbuilder=org.jclouds.vcloud.bluelock.BlueLockVCloud
gogrid.propertiesbuilder=org.jclouds.gogrid.GoGridPropertiesBuilder
gogrid.contextbuilder=org.jclouds.gogrid.GoGridContextBuilder
elasticstack.propertiesbuilder=org.jclouds.elasticstack.ElasticStackPropertiesBuilder
elasticstack.contextbuilder=org.jclouds.elasticstack.ElasticStackContextBuilder
cloudsigma.propertiesbuilder=org.jclouds.cloudsigma.CloudSigmaPropertiesBuilder
cloudsigma.contextbuilder=org.jclouds.cloudsigma.CloudSigmaContextBuilder
ibmdev.propertiesbuilder=org.jclouds.ibmdev.IBMDeveloperCloudPropertiesBuilder
ibmdev.contextbuilder=org.jclouds.ibmdev.IBMDeveloperCloudContextBuilder
@ -119,6 +128,10 @@ walrus.propertiesbuilder=org.jclouds.aws.s3.WalrusPropertiesBuilder
googlestorage.contextbuilder=org.jclouds.aws.s3.S3ContextBuilder
googlestorage.propertiesbuilder=org.jclouds.aws.s3.GoogleStoragePropertiesBuilder
scaleup-storage.contextbuilder=org.jclouds.aws.s3.blobstore.ScaleUpCloudBlobStoreContextContextBuilder
scaleup-storage.propertiesbuilder=org.jclouds.aws.s3.S3PropertiesBuilder
scaleup-storage.endpoint=https://scs.scaleupstorage.com
transient.contextbuilder=org.jclouds.blobstore.TransientBlobStoreContextBuilder
transient.propertiesbuilder=org.jclouds.blobstore.TransientBlobStorePropertiesBuilder

View File

@ -60,20 +60,17 @@ public class JsonBallTest {
Map<String, JsonBall> map = ImmutableMap.<String, JsonBall> of("tomcat6", new JsonBall("{\"ssl_port\":8433}"));
assertEquals(handler.apply(new HttpResponse(200, "ok", Payloads
.newStringPayload(json))), map);
assertEquals(handler.apply(new HttpResponse(200, "ok", Payloads.newStringPayload(json))), map);
assertEquals(mapper.toJson(map), json);
}
public void testList() {
String json = "{\"list\":[8431,8433]}";
Map<String, JsonBall> map = ImmutableMap.<String, JsonBall> of("list", new JsonBall("[8431,8433]"));
assertEquals(handler.apply(new HttpResponse(200, "ok", Payloads
.newStringPayload(json))), map);
assertEquals(handler.apply(new HttpResponse(200, "ok", Payloads.newStringPayload(json))), map);
assertEquals(mapper.toJson(map), json);
}
@ -83,20 +80,17 @@ public class JsonBallTest {
Map<String, JsonBall> map = ImmutableMap.<String, JsonBall> of("name", new JsonBall("fooy"));
assertEquals(handler.apply(new HttpResponse(200, "ok", Payloads
.newStringPayload(json))), map);
assertEquals(handler.apply(new HttpResponse(200, "ok", Payloads.newStringPayload(json))), map);
assertEquals(mapper.toJson(map), json);
}
public void testNumber() {
String json = "{\"number\":1}";
Map<String, JsonBall> map = ImmutableMap.<String, JsonBall> of("number", new JsonBall("1"));
assertEquals(handler.apply(new HttpResponse(200, "ok", Payloads
.newStringPayload(json))), map);
assertEquals(handler.apply(new HttpResponse(200, "ok", Payloads.newStringPayload(json))), map);
assertEquals(mapper.toJson(map), json);
}

View File

@ -0,0 +1,98 @@
/**
*
* Copyright (C) 2010 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.domain;
import static org.testng.Assert.assertEquals;
import java.io.IOException;
import java.util.Map;
import org.jclouds.http.HttpResponse;
import org.jclouds.http.functions.ParseJson;
import org.jclouds.io.Payloads;
import org.jclouds.json.Json;
import org.jclouds.json.config.GsonModule;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
/**
* @author Adrian Cole
*/
@Test(groups = "unit", testName = "jclouds.ObjectTest")
public class JsonObjectTest {
private ParseJson<Map<String, Object>> handler;
private Json mapper;
@BeforeTest
protected void setUpInjector() throws IOException {
Injector injector = Guice.createInjector(new GsonModule());
handler = injector.getInstance(Key.get(new TypeLiteral<ParseJson<Map<String, Object>>>() {
}));
mapper = injector.getInstance(Json.class);
}
public void testHash() {
String json = "{\"tomcat6\":{\"ssl_port\":8433}}";
Map<String, Object> map = ImmutableMap.<String, Object> of("tomcat6", ImmutableMap.of("ssl_port", 8433));
assertEquals(handler.apply(new HttpResponse(200, "ok", Payloads.newStringPayload(json))), map);
assertEquals(mapper.toJson(map), json);
}
public void testList() {
String json = "{\"list\":[8431,8433]}";
Map<String, Object> map = ImmutableMap.<String, Object> of("list", ImmutableList.of(8431, 8433));
assertEquals(handler.apply(new HttpResponse(200, "ok", Payloads.newStringPayload(json))), map);
assertEquals(mapper.toJson(map), json);
}
public void testString() {
String json = "{\"name\":\"fooy\"}";
Map<String, Object> map = ImmutableMap.<String, Object> of("name", "fooy");
assertEquals(handler.apply(new HttpResponse(200, "ok", Payloads.newStringPayload(json))), map);
assertEquals(mapper.toJson(map), json);
}
public void testNumber() {
String json = "{\"number\":1}";
Map<String, Object> map = ImmutableMap.<String, Object> of("number", 1);
assertEquals(handler.apply(new HttpResponse(200, "ok", Payloads.newStringPayload(json))), map);
assertEquals(mapper.toJson(map), json);
}
}

View File

@ -0,0 +1,40 @@
/**
*
* Copyright (C) 2010 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.io.payloads;
import static org.testng.Assert.assertEquals;
import org.jclouds.io.Payload;
import org.testng.annotations.Test;
import com.google.common.base.Charsets;
/**
*
* @author Adrian Cole
*/
@Test
public class StringPayloadTest {
public void testLengthIsCorrectPerUTF8() {
Payload stringPayload = new StringPayload("unic₪de");
assertEquals(stringPayload.getContentMetadata().getContentLength(), new Long(
"unic₪de".getBytes(Charsets.UTF_8).length));
}
}

View File

@ -21,11 +21,17 @@ package org.jclouds.json;
import static org.testng.Assert.assertEquals;
import java.util.Map;
import org.jclouds.json.config.GsonModule;
import org.testng.annotations.Test;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.gson.JsonParseException;
import com.google.inject.Guice;
import com.google.inject.TypeLiteral;
@Test
public class JsonTest {
@ -39,6 +45,41 @@ public class JsonTest {
private Test enumValue;
}
public void testMapStringObjectWithAllValidValuesOneDeep() {
Map<String, Object> map = Maps.newHashMap();
map.put("string", "string");
map.put("number", 1);
map.put("boolean", true);
map.put("map", ImmutableMap.of("key", "value"));
map.put("list", ImmutableList.of("key", "value"));
assertEquals(json.toJson(map),
"{\"string\":\"string\",\"map\":{\"key\":\"value\"},\"list\":[\"key\",\"value\"],\"boolean\":true,\"number\":1}");
Map<String, Object> map2 = json.fromJson(json.toJson(map), new TypeLiteral<Map<String, Object>>() {
}.getType());
assertEquals(map2, map);
assertEquals(json.toJson(map2), json.toJson(map));
}
public void testMapStringObjectWithNumericalKeysConvertToStrings() {
Map<String, Object> map = ImmutableMap.<String, Object> of("map", ImmutableMap.of(1, "value"));
assertEquals(json.toJson(map), "{\"map\":{\"1\":\"value\"}}");
Map<String, Object> map2 = json.fromJson(json.toJson(map), new TypeLiteral<Map<String, Object>>() {
}.getType());
// note conversion.. ensures valid
assertEquals(map2, ImmutableMap.<String, Object> of("map", ImmutableMap.of("1", "value")));
assertEquals(json.toJson(map2), json.toJson(map));
}
public void testMapStringObjectWithBooleanKeysConvertToStrings() {
Map<String, Object> map = ImmutableMap.<String, Object> of("map", ImmutableMap.of(true, "value"));
assertEquals(json.toJson(map), "{\"map\":{\"true\":\"value\"}}");
Map<String, Object> map2 = json.fromJson(json.toJson(map), new TypeLiteral<Map<String, Object>>() {
}.getType());
// note conversion.. ensures valid
assertEquals(map2, ImmutableMap.<String, Object> of("map", ImmutableMap.of("true", "value")));
assertEquals(json.toJson(map2), json.toJson(map));
}
public void testDeserializeEnum() {
assertEquals(json.fromJson("{enumValue : \"FOO\"}", EnumInside.class).enumValue, EnumInside.Test.FOO);
}

View File

@ -104,6 +104,7 @@ import org.jclouds.http.options.GetOptions;
import org.jclouds.http.options.HttpRequestOptions;
import org.jclouds.io.Payload;
import org.jclouds.io.PayloadEnclosing;
import org.jclouds.io.Payloads;
import org.jclouds.logging.config.NullLoggingModule;
import org.jclouds.rest.BaseRestClientTest;
import org.jclouds.rest.ConfiguresRestClient;
@ -208,7 +209,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@SuppressWarnings("unchecked")
public void testDelegateAsync() throws SecurityException, NoSuchMethodException, InterruptedException,
ExecutionException {
ExecutionException {
Injector child = injectorForClient();
TransformingHttpCommandExecutorService mock = child.getInstance(TransformingHttpCommandExecutorService.class);
@ -223,7 +224,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
AsyncCaller caller = child.getInstance(AsyncCaller.class);
expect(mock.submit(requestLineEquals("GET http://localhost:9999/client/foo HTTP/1.1"), eq(function))).andReturn(
createNiceMock(ListenableFuture.class)).atLeastOnce();
createNiceMock(ListenableFuture.class)).atLeastOnce();
replay(mock);
caller.getCallee().onePath("foo");
@ -252,7 +253,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
}
public void testDelegateWithOverridingEndpoint() throws SecurityException, NoSuchMethodException,
InterruptedException, ExecutionException {
InterruptedException, ExecutionException {
Injector child = injectorForClient();
TransformingHttpCommandExecutorService mock = child.getInstance(TransformingHttpCommandExecutorService.class);
@ -267,7 +268,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
Caller caller = child.getInstance(Caller.class);
expect(mock.submit(requestLineEquals("GET http://localhost:1111/client/foo HTTP/1.1"), eq(function))).andReturn(
Futures.<Void> immediateFuture(null)).atLeastOnce();
Futures.<Void> immediateFuture(null)).atLeastOnce();
replay(mock);
caller.getCallee().onePath("foo");
@ -278,9 +279,9 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
private Injector injectorForClient() {
RestContextSpec<Caller, AsyncCaller> contextSpec = contextSpec("test", "http://localhost:9999", "1", "userfoo", null,
Caller.class, AsyncCaller.class, ImmutableSet.<Module> of(new MockModule(), new NullLoggingModule(),
new CallerCalleeModule()));
RestContextSpec<Caller, AsyncCaller> contextSpec = contextSpec("test", "http://localhost:9999", "1", "userfoo",
null, Caller.class, AsyncCaller.class,
ImmutableSet.<Module> of(new MockModule(), new NullLoggingModule(), new CallerCalleeModule()));
return createContextBuilder(contextSpec).buildInjector();
@ -295,7 +296,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
};
@Target( { ElementType.METHOD })
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@javax.ws.rs.HttpMethod("FOO")
public @interface FOO {
@ -330,10 +331,10 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testUnEncodeQuery() {
URI expects = URI
.create("http://services.nirvanix.com/ws/Metadata/SetMetadata.ashx?output=json&path=adriancole-compute.testObjectOperations&metadata=chef:sushi&metadata=foo:bar&sessionToken=775ef26e-0740-4707-ad92-afe9814bc436");
.create("http://services.nirvanix.com/ws/Metadata/SetMetadata.ashx?output=json&path=adriancole-compute.testObjectOperations&metadata=chef:sushi&metadata=foo:bar&sessionToken=775ef26e-0740-4707-ad92-afe9814bc436");
URI start = URI
.create("http://services.nirvanix.com/ws/Metadata/SetMetadata.ashx?output=json&path=adriancole-compute.testObjectOperations&metadata=chef%3Asushi&metadata=foo%3Abar&sessionToken=775ef26e-0740-4707-ad92-afe9814bc436");
.create("http://services.nirvanix.com/ws/Metadata/SetMetadata.ashx?output=json&path=adriancole-compute.testObjectOperations&metadata=chef%3Asushi&metadata=foo%3Abar&sessionToken=775ef26e-0740-4707-ad92-afe9814bc436");
URI value = RestAnnotationProcessor.replaceQuery(uriBuilderProvider, start, start.getQuery(), null, '/', ':');
assertEquals(value, expects);
}
@ -373,21 +374,34 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@POST
@Path("")
public void post(HttpRequestOptions options);
@POST
@Path("")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public void post();
@POST
@Path("")
@Produces(MediaType.APPLICATION_OCTET_STREAM)
public void post(Payload payload);
}
public void testHttpRequestOptionsPayloadParam() throws SecurityException, NoSuchMethodException, IOException {
public void testHttpRequestOptionsNoPayloadParam() throws SecurityException, NoSuchMethodException, IOException {
Method method = TestPayloadParamVarargs.class.getMethod("post");
HttpRequest request = factory(TestQuery.class).createRequest(method);
assertRequestLineEquals(request, "POST http://localhost:9999?x-ms-version=2009-07-17 HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, "", "application/octet-stream", false);
}
public void testHttpRequestOptionsPayloadParam() throws SecurityException, NoSuchMethodException, IOException {
Method method = TestPayloadParamVarargs.class.getMethod("post", Payload.class);
HttpRequest request = factory(TestQuery.class).createRequest(method, Payloads.newStringPayload("foo"));
assertRequestLineEquals(request, "POST http://localhost:9999?x-ms-version=2009-07-17 HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, "foo", "application/octet-stream", false);
}
public void testHttpRequestWithOnlyContentType() throws SecurityException, NoSuchMethodException, IOException {
Method method = TestPayloadParamVarargs.class.getMethod("post", HttpRequestOptions.class);
verifyTestPostOptions(method);
@ -395,7 +409,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testPayloadParamVarargs() throws SecurityException, NoSuchMethodException, IOException {
Method method = TestPayloadParamVarargs.class.getMethod("varargs", Array.newInstance(HttpRequestOptions.class, 0)
.getClass());
.getClass());
verifyTestPostOptions(method);
}
@ -492,7 +506,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testOverriddenEndpointParameter() throws SecurityException, NoSuchMethodException {
Method method = TestOverriddenEndpoint.class.getMethod("foo", URI.class);
HttpRequest request = factory(TestOverriddenEndpoint.class).createRequest(method,
new Object[] { URI.create("http://wowsa:8001") });
new Object[] { URI.create("http://wowsa:8001") });
assertEquals(request.getEndpoint().getHost(), "wowsa");
assertEquals(request.getEndpoint().getPort(), 8001);
assertEquals(request.getEndpoint().getPath(), "");
@ -600,45 +614,45 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@POST
@Path("")
void withParamFileBinaryPart(@FormParam("name") String name,
@PartParam(name = "file", contentType = MediaType.APPLICATION_OCTET_STREAM) File path);
@PartParam(name = "file", contentType = MediaType.APPLICATION_OCTET_STREAM) File path);
@POST
@Path("")
void withParamByteArrayBinaryPart(
@FormParam("name") String name,
@PartParam(name = "file", contentType = MediaType.APPLICATION_OCTET_STREAM, filename = "{name}.tar.gz") byte[] content);
@FormParam("name") String name,
@PartParam(name = "file", contentType = MediaType.APPLICATION_OCTET_STREAM, filename = "{name}.tar.gz") byte[] content);
}
public void testMultipartWithStringPart() throws SecurityException, NoSuchMethodException, IOException {
Method method = TestMultipartForm.class.getMethod("withStringPart", String.class);
GeneratedHttpRequest<TestMultipartForm> httpRequest = factory(TestMultipartForm.class).createRequest(method,
"foobledata");
"foobledata");
assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "");
assertPayloadEquals(httpRequest,//
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"fooble\"\r\n" + //
"\r\n" + //
"foobledata\r\n" + //
"----JCLOUDS----\r\n", "multipart/form-data; boundary=--JCLOUDS--", false);
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"fooble\"\r\n" + //
"\r\n" + //
"foobledata\r\n" + //
"----JCLOUDS----\r\n", "multipart/form-data; boundary=--JCLOUDS--", false);
}
public void testMultipartWithParamStringPart() throws SecurityException, NoSuchMethodException, IOException {
Method method = TestMultipartForm.class.getMethod("withParamStringPart", String.class, String.class);
GeneratedHttpRequest<TestMultipartForm> httpRequest = factory(TestMultipartForm.class).createRequest(method,
"name", "foobledata");
"name", "foobledata");
assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "");
assertPayloadEquals(httpRequest,//
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"name\"\r\n" + //
"\r\n" + //
"name\r\n" + // /
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"file\"\r\n" + //
"\r\n" + //
"foobledata\r\n" + //
"----JCLOUDS----\r\n", "multipart/form-data; boundary=--JCLOUDS--", false);
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"name\"\r\n" + //
"\r\n" + //
"name\r\n" + // /
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"file\"\r\n" + //
"\r\n" + //
"foobledata\r\n" + //
"----JCLOUDS----\r\n", "multipart/form-data; boundary=--JCLOUDS--", false);
}
public void testMultipartWithParamFilePart() throws SecurityException, NoSuchMethodException, IOException {
@ -648,38 +662,38 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
file.deleteOnExit();
GeneratedHttpRequest<TestMultipartForm> httpRequest = factory(TestMultipartForm.class).createRequest(method,
"name", file);
"name", file);
assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "");
assertPayloadEquals(httpRequest,//
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"name\"\r\n" + //
"\r\n" + //
"name\r\n" + // /
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"\r\n" + //
"\r\n" + //
"foobledata\r\n" + //
"----JCLOUDS----\r\n", "multipart/form-data; boundary=--JCLOUDS--", false);
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"name\"\r\n" + //
"\r\n" + //
"name\r\n" + // /
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"\r\n" + //
"\r\n" + //
"foobledata\r\n" + //
"----JCLOUDS----\r\n", "multipart/form-data; boundary=--JCLOUDS--", false);
}
public void testMultipartWithParamByteArrayPart() throws SecurityException, NoSuchMethodException, IOException {
Method method = TestMultipartForm.class.getMethod("withParamByteArrayBinaryPart", String.class, byte[].class);
GeneratedHttpRequest<TestMultipartForm> httpRequest = factory(TestMultipartForm.class).createRequest(method,
"name", "goo".getBytes());
"name", "goo".getBytes());
assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "");
assertPayloadEquals(httpRequest,//
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"name\"\r\n" + //
"\r\n" + //
"name\r\n" + // /
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"file\"; filename=\"name.tar.gz\"\r\n" + //
"Content-Type: application/octet-stream\r\n" + //
"\r\n" + //
"goo\r\n" + //
"----JCLOUDS----\r\n", "multipart/form-data; boundary=--JCLOUDS--", false);
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"name\"\r\n" + //
"\r\n" + //
"name\r\n" + // /
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"file\"; filename=\"name.tar.gz\"\r\n" + //
"Content-Type: application/octet-stream\r\n" + //
"\r\n" + //
"goo\r\n" + //
"----JCLOUDS----\r\n", "multipart/form-data; boundary=--JCLOUDS--", false);
};
public void testMultipartWithParamFileBinaryPart() throws SecurityException, NoSuchMethodException, IOException {
@ -689,20 +703,20 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
file.deleteOnExit();
GeneratedHttpRequest<TestMultipartForm> httpRequest = factory(TestMultipartForm.class).createRequest(method,
"name", file);
"name", file);
assertRequestLineEquals(httpRequest, "POST http://localhost:9999 HTTP/1.1");
assertNonPayloadHeadersEqual(httpRequest, "");
assertPayloadEquals(httpRequest,//
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"name\"\r\n" + //
"\r\n" + //
"name\r\n" + // /
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"\r\n" + //
"Content-Type: application/octet-stream\r\n" + //
"\r\n" + //
"'(2\r\n" + //
"----JCLOUDS----\r\n", "multipart/form-data; boundary=--JCLOUDS--", false);
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"name\"\r\n" + //
"\r\n" + //
"name\r\n" + // /
"----JCLOUDS--\r\n" + //
"Content-Disposition: form-data; name=\"file\"; filename=\"" + file.getName() + "\"\r\n" + //
"Content-Type: application/octet-stream\r\n" + //
"\r\n" + //
"'(2\r\n" + //
"----JCLOUDS----\r\n", "multipart/form-data; boundary=--JCLOUDS--", false);
}
public interface TestPut {
@ -761,7 +775,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@Consumes(MediaType.APPLICATION_JSON)
ListenableFuture<? extends Set<String>> testUnwrap4();
@Target( { ElementType.METHOD })
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("ROWDY")
public @interface ROWDY {
@ -816,7 +830,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
// now test that it works!
Function<HttpResponse, Wrapper> parser = (Function<HttpResponse, Wrapper>) RestAnnotationProcessor
.createResponseParser(parserFactory, injector, method, request);
.createResponseParser(parserFactory, injector, method, request);
assertEquals(parser.apply(new HttpResponse(200, "ok", newStringPayload("{ foo:\"bar\"}"))).foo, "bar");
@ -831,10 +845,10 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
// now test that it works!
Function<HttpResponse, Map<String, String>> parser = (Function<HttpResponse, Map<String, String>>) RestAnnotationProcessor
.createResponseParser(parserFactory, injector, method, request);
.createResponseParser(parserFactory, injector, method, request);
assertEquals(parser.apply(new HttpResponse(200, "ok", newStringPayload("{ foo:\"bar\"}"))), ImmutableMap.of(
"foo", "bar"));
assertEquals(parser.apply(new HttpResponse(200, "ok", newStringPayload("{ foo:\"bar\"}"))),
ImmutableMap.of("foo", "bar"));
}
@ -847,10 +861,10 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
// now test that it works!
Function<HttpResponse, Map<String, String>> parser = (Function<HttpResponse, Map<String, String>>) RestAnnotationProcessor
.createResponseParser(parserFactory, injector, method, request);
.createResponseParser(parserFactory, injector, method, request);
assertEquals(parser.apply(new HttpResponse(200, "ok", newStringPayload("{ foo:\"bar\"}"))), ImmutableMap.of(
"foo", "bar"));
assertEquals(parser.apply(new HttpResponse(200, "ok", newStringPayload("{ foo:\"bar\"}"))),
ImmutableMap.of("foo", "bar"));
}
@ -863,10 +877,10 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
// now test that it works!
Function<HttpResponse, Map<String, String>> parser = (Function<HttpResponse, Map<String, String>>) RestAnnotationProcessor
.createResponseParser(parserFactory, injector, method, request);
.createResponseParser(parserFactory, injector, method, request);
assertEquals(parser.apply(new HttpResponse(200, "ok", newStringPayload("{ foo:\"bar\"}"))), ImmutableMap.of(
"foo", "bar"));
assertEquals(parser.apply(new HttpResponse(200, "ok", newStringPayload("{ foo:\"bar\"}"))),
ImmutableMap.of("foo", "bar"));
}
@ -879,7 +893,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
// now test that it works!
Function<HttpResponse, Map<String, String>> parser = (Function<HttpResponse, Map<String, String>>) RestAnnotationProcessor
.createResponseParser(parserFactory, injector, method, request);
.createResponseParser(parserFactory, injector, method, request);
assertEquals(parser.apply(new HttpResponse(200, "ok", newStringPayload("{ foo:\"bar\"}"))), "bar");
@ -894,7 +908,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
// now test that it works!
Function<HttpResponse, Map<String, String>> parser = (Function<HttpResponse, Map<String, String>>) RestAnnotationProcessor
.createResponseParser(parserFactory, injector, method, request);
.createResponseParser(parserFactory, injector, method, request);
assertEquals(parser.apply(new HttpResponse(200, "ok", newStringPayload("{ foo:\"bar\"}"))), "bar");
@ -909,10 +923,10 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
// now test that it works!
Function<HttpResponse, Map<String, String>> parser = (Function<HttpResponse, Map<String, String>>) RestAnnotationProcessor
.createResponseParser(parserFactory, injector, method, request);
.createResponseParser(parserFactory, injector, method, request);
assertEquals(parser.apply(new HttpResponse(200, "ok", newStringPayload("{\"runit\":[\"0.7.0\",\"0.7.1\"]}"))),
ImmutableSet.of("0.7.0", "0.7.1"));
ImmutableSet.of("0.7.0", "0.7.1"));
}
@SuppressWarnings("unchecked")
@ -924,10 +938,10 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
// now test that it works!
Function<HttpResponse, Map<String, String>> parser = (Function<HttpResponse, Map<String, String>>) RestAnnotationProcessor
.createResponseParser(parserFactory, injector, method, request);
.createResponseParser(parserFactory, injector, method, request);
assertEquals(parser.apply(new HttpResponse(200, "ok", newStringPayload("{\"runit\":[\"0.7.0\",\"0.7.1\"]}"))),
ImmutableSet.of("0.7.0", "0.7.1"));
ImmutableSet.of("0.7.0", "0.7.1"));
}
static class TestRequestFilter1 implements HttpRequestFilter {
@ -1014,7 +1028,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testConstantPathParam() throws SecurityException, NoSuchMethodException, IOException {
Method method = TestConstantPathParam.class.getMethod("twoPaths", String.class, String.class);
HttpRequest request = factory(TestConstantPathParam.class).createRequest(method,
new Object[] { "1", "localhost" });
new Object[] { "1", "localhost" });
assertRequestLineEquals(request, "GET http://localhost:9999/v1/ralphie/1/localhost HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, null, null, false);
@ -1151,7 +1165,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testBuildTwoHeader() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method oneHeader = TestHeader.class.getMethod("twoHeader", String.class);
Multimap<String, String> headers = factory(TestHeader.class).createRequest(oneHeader, new Object[] { "robot" })
.getHeaders();
.getHeaders();
assertEquals(headers.size(), 2);
assertEquals(headers.get("slash"), Collections.singletonList("/robot"));
assertEquals(headers.get("hyphen"), Collections.singletonList("-robot"));
@ -1169,7 +1183,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testBuildOneClassHeader() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method oneHeader = TestClassHeader.class.getMethod("oneHeader", String.class);
Multimap<String, String> headers = factory(TestClassHeader.class).createRequest(oneHeader,
new Object[] { "robot" }).getHeaders();
new Object[] { "robot" }).getHeaders();
assertEquals(headers.size(), 1);
assertEquals(headers.get("x-amz-copy-source"), Collections.singletonList("/robot"));
}
@ -1178,7 +1192,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testBuildOneHeader() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method oneHeader = TestHeader.class.getMethod("oneHeader", String.class);
Multimap<String, String> headers = factory(TestHeader.class).createRequest(oneHeader, new Object[] { "robot" })
.getHeaders();
.getHeaders();
assertEquals(headers.size(), 1);
assertEquals(headers.get("x-amz-copy-source"), Collections.singletonList("/robot"));
}
@ -1187,17 +1201,17 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testBuildTwoHeaders() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method twoHeaders = TestHeader.class.getMethod("twoHeaders", String.class, String.class);
Multimap<String, String> headers = factory(TestHeader.class).createRequest(twoHeaders,
new Object[] { "robot", "eggs" }).getHeaders();
new Object[] { "robot", "eggs" }).getHeaders();
assertEquals(headers.size(), 1);
assertEquals(headers.get("x-amz-copy-source"), Collections.singletonList("/robot/eggs"));
}
@Test
public void testBuildTwoHeadersOutOfOrder() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
UnsupportedEncodingException {
Method twoHeadersOutOfOrder = TestHeader.class.getMethod("twoHeadersOutOfOrder", String.class, String.class);
Multimap<String, String> headers = factory(TestHeader.class).createRequest(twoHeadersOutOfOrder,
new Object[] { "robot", "eggs" }).getHeaders();
new Object[] { "robot", "eggs" }).getHeaders();
assertEquals(headers.size(), 1);
assertEquals(headers.get("x-amz-copy-source"), Collections.singletonList("/eggs/robot"));
}
@ -1211,8 +1225,8 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@Test
public void testQueryInOptions() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method oneQuery = TestQueryReplace.class.getMethod("queryInOptions", String.class, TestReplaceQueryOptions.class);
String query = factory(TestQueryReplace.class).createRequest(oneQuery,
new Object[] { "robot", new TestReplaceQueryOptions() }).getEndpoint().getQuery();
String query = factory(TestQueryReplace.class)
.createRequest(oneQuery, new Object[] { "robot", new TestReplaceQueryOptions() }).getEndpoint().getQuery();
assertEquals(query, "x-amz-copy-source=/robot");
}
@ -1220,13 +1234,13 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@POST
@Path("/objects/{id}/action/{action}")
ListenableFuture<String> action(@PathParam("id") String id, @PathParam("action") String action,
@BinderParam(BindMapToMatrixParams.class) Map<String, String> options);
@BinderParam(BindMapToMatrixParams.class) Map<String, String> options);
}
public void testTestMapMatrixParams() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method method = TestMapMatrixParams.class.getMethod("action", String.class, String.class, Map.class);
HttpRequest request = factory(TestMapMatrixParams.class).createRequest(method,
new Object[] { "robot", "kill", ImmutableMap.of("death", "slow") });
new Object[] { "robot", "kill", ImmutableMap.of("death", "slow") });
assertRequestLineEquals(request, "POST http://localhost:9999/objects/robot/action/kill;death=slow HTTP/1.1");
assertEquals(request.getHeaders().size(), 0);
}
@ -1268,7 +1282,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testBuildTwoQuery() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method oneQuery = TestQueryReplace.class.getMethod("twoQuery", String.class);
String query = factory(TestQueryReplace.class).createRequest(oneQuery, new Object[] { "robot" }).getEndpoint()
.getQuery();
.getQuery();
assertEquals(query, "slash=/robot&hyphen=-robot");
}
@ -1284,7 +1298,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testBuildOneClassQuery() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method oneQuery = TestClassQuery.class.getMethod("oneQuery", String.class);
String query = factory(TestClassQuery.class).createRequest(oneQuery, new Object[] { "robot" }).getEndpoint()
.getQuery();
.getQuery();
assertEquals(query, "x-amz-copy-source=/robot");
}
@ -1292,7 +1306,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testBuildOneQuery() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method oneQuery = TestQueryReplace.class.getMethod("oneQuery", String.class);
String query = factory(TestQueryReplace.class).createRequest(oneQuery, new Object[] { "robot" }).getEndpoint()
.getQuery();
.getQuery();
assertEquals(query, "x-amz-copy-source=/robot");
}
@ -1300,16 +1314,16 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testBuildTwoQuerys() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method twoQuerys = TestQueryReplace.class.getMethod("twoQuerys", String.class, String.class);
String query = factory(TestQueryReplace.class).createRequest(twoQuerys, new Object[] { "robot", "eggs" })
.getEndpoint().getQuery();
.getEndpoint().getQuery();
assertEquals(query, "x-amz-copy-source=/robot/eggs");
}
@Test
public void testBuildTwoQuerysOutOfOrder() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
UnsupportedEncodingException {
Method twoQuerysOutOfOrder = TestQueryReplace.class.getMethod("twoQuerysOutOfOrder", String.class, String.class);
String query = factory(TestQueryReplace.class).createRequest(twoQuerysOutOfOrder,
new Object[] { "robot", "eggs" }).getEndpoint().getQuery();
String query = factory(TestQueryReplace.class)
.createRequest(twoQuerysOutOfOrder, new Object[] { "robot", "eggs" }).getEndpoint().getQuery();
assertEquals(query, "x-amz-copy-source=/eggs/robot");
}
@ -1322,9 +1336,9 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@Test
public void testMatrixInOptions() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method oneMatrix = TestMatrixReplace.class.getMethod("matrixInOptions", String.class,
TestReplaceMatrixOptions.class);
String path = factory(TestMatrixReplace.class).createRequest(oneMatrix,
new Object[] { "robot", new TestReplaceMatrixOptions() }).getEndpoint().getPath();
TestReplaceMatrixOptions.class);
String path = factory(TestMatrixReplace.class)
.createRequest(oneMatrix, new Object[] { "robot", new TestReplaceMatrixOptions() }).getEndpoint().getPath();
assertEquals(path, "/;x-amz-copy-source=/robot");
}
@ -1365,7 +1379,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testBuildTwoMatrix() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method oneMatrix = TestMatrixReplace.class.getMethod("twoMatrix", String.class);
String path = factory(TestMatrixReplace.class).createRequest(oneMatrix, new Object[] { "robot" }).getEndpoint()
.getPath();
.getPath();
assertEquals(path, "/;slash=/robot;hyphen=-robot");
}
@ -1382,7 +1396,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testBuildOneClassMatrix() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method oneMatrix = TestClassMatrix.class.getMethod("oneMatrix", String.class);
String path = factory(TestClassMatrix.class).createRequest(oneMatrix, new Object[] { "robot" }).getEndpoint()
.getPath();
.getPath();
assertEquals(path, "/;x-amz-copy-source=/robot");
}
@ -1390,7 +1404,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testBuildOneMatrix() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method oneMatrix = TestMatrixReplace.class.getMethod("oneMatrix", String.class);
String path = factory(TestMatrixReplace.class).createRequest(oneMatrix, new Object[] { "robot" }).getEndpoint()
.getPath();
.getPath();
assertEquals(path, "/;x-amz-copy-source=/robot");
}
@ -1398,17 +1412,17 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testBuildTwoMatrixs() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method twoMatrixs = TestMatrixReplace.class.getMethod("twoMatrixs", String.class, String.class);
String path = factory(TestMatrixReplace.class).createRequest(twoMatrixs, new Object[] { "robot", "eggs" })
.getEndpoint().getPath();
.getEndpoint().getPath();
assertEquals(path, "/;x-amz-copy-source=/robot/eggs");
}
@Test
public void testBuildTwoMatrixsOutOfOrder() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
UnsupportedEncodingException {
Method twoMatrixsOutOfOrder = TestMatrixReplace.class.getMethod("twoMatrixsOutOfOrder", String.class,
String.class);
String path = factory(TestMatrixReplace.class).createRequest(twoMatrixsOutOfOrder,
new Object[] { "robot", "eggs" }).getEndpoint().getPath();
String.class);
String path = factory(TestMatrixReplace.class)
.createRequest(twoMatrixsOutOfOrder, new Object[] { "robot", "eggs" }).getEndpoint().getPath();
assertEquals(path, "/;x-amz-copy-source=/eggs/robot");
}
@ -1460,7 +1474,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testPutPayloadEnclosing() throws SecurityException, NoSuchMethodException, IOException {
Method method = TestTransformers.class.getMethod("put", PayloadEnclosing.class);
HttpRequest request = factory(TestQuery.class).createRequest(method,
new PayloadEnclosingImpl(newStringPayload("whoops")));
new PayloadEnclosingImpl(newStringPayload("whoops")));
assertRequestLineEquals(request, "PUT http://localhost:9999?x-ms-version=2009-07-17 HTTP/1.1");
assertNonPayloadHeadersEqual(request, "");
assertPayloadEquals(request, "whoops", "application/unknown", false);
@ -1478,7 +1492,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
}
public void testPutInputStreamPayloadEnclosingGenerateMD5() throws SecurityException, NoSuchMethodException,
IOException {
IOException {
Method method = TestTransformers.class.getMethod("put", PayloadEnclosing.class);
PayloadEnclosing payloadEnclosing = new PayloadEnclosingImpl(newInputStreamPayload(toInputStream("whoops")));
@ -1537,7 +1551,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
}
public void testPutPayloadWithGeneratedMD5AndNoContentType() throws SecurityException, NoSuchMethodException,
IOException {
IOException {
Payload payload = newStringPayload("whoops");
calculateMD5(payload, crypto.md5());
Method method = TestTransformers.class.getMethod("put", Payload.class);
@ -1558,7 +1572,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
}
public void testPutInputStreamPayloadWithMD5() throws NoSuchAlgorithmException, IOException, SecurityException,
NoSuchMethodException {
NoSuchMethodException {
Payload payload = newStringPayload("whoops");
calculateMD5(payload, crypto.md5());
Method method = TestTransformers.class.getMethod("put", Payload.class);
@ -1582,9 +1596,9 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@SuppressWarnings("unchecked")
public static <T> Class<? extends Function<HttpResponse, ?>> unwrap(RestAnnotationProcessor<T> processor,
Method method) {
Method method) {
return (Class<? extends Function<HttpResponse, ?>>) RestAnnotationProcessor.getParserOrThrowException(method)
.getTypeLiteral().getRawType();
.getTypeLiteral().getRawType();
}
public void testURI() throws SecurityException, NoSuchMethodException {
@ -1620,8 +1634,8 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void oneTransformerWithContext() throws SecurityException, NoSuchMethodException {
RestAnnotationProcessor<TestTransformers> processor = factory(TestTransformers.class);
Method method = TestTransformers.class.getMethod("oneTransformerWithContext");
GeneratedHttpRequest<TestTransformers> request = new GeneratedHttpRequest<TestTransformers>("GET", URI
.create("http://localhost"), TestTransformers.class, method);
GeneratedHttpRequest<TestTransformers> request = new GeneratedHttpRequest<TestTransformers>("GET",
URI.create("http://localhost"), TestTransformers.class, method);
Function<HttpResponse, ?> transformer = processor.createResponseParser(method, request);
assertEquals(transformer.getClass(), ReturnStringIf200Context.class);
assertEquals(((ReturnStringIf200Context) transformer).request, request);
@ -1662,7 +1676,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@PUT
@Path("/{id}")
ListenableFuture<String> put(@PathParam("id") @ParamParser(FirstCharacter.class) String id,
@BinderParam(BindToStringPayload.class) String payload);
@BinderParam(BindToStringPayload.class) String payload);
@PUT
@Path("/{id}")
@ -1674,7 +1688,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@Headers(keys = "foo", values = "--{id}--")
@ResponseParser(ReturnTrueIf2xx.class)
ListenableFuture<String> putHeader(@PathParam("id") String id,
@BinderParam(BindToStringPayload.class) String payload);
@BinderParam(BindToStringPayload.class) String payload);
}
public void testCreateGetVarArgOptionsThatProducesHeaders() throws SecurityException, NoSuchMethodException {
@ -1688,8 +1702,8 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
assertEquals(request.getMethod(), HttpMethod.GET);
assertEquals(request.getHeaders().size(), 2);
assertEquals(request.getHeaders().get(HttpHeaders.HOST), Collections.singletonList("localhost"));
assertEquals(request.getHeaders().get(HttpHeaders.IF_MODIFIED_SINCE), Collections.singletonList(dateService
.rfc822DateFormat(date)));
assertEquals(request.getHeaders().get(HttpHeaders.IF_MODIFIED_SINCE),
Collections.singletonList(dateService.rfc822DateFormat(date)));
}
public void testCreateGetOptionsThatProducesHeaders() throws SecurityException, NoSuchMethodException {
@ -1702,8 +1716,8 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
assertEquals(request.getMethod(), HttpMethod.GET);
assertEquals(request.getHeaders().size(), 2);
assertEquals(request.getHeaders().get(HttpHeaders.HOST), Collections.singletonList("localhost"));
assertEquals(request.getHeaders().get(HttpHeaders.IF_MODIFIED_SINCE), Collections.singletonList(dateService
.rfc822DateFormat(date)));
assertEquals(request.getHeaders().get(HttpHeaders.IF_MODIFIED_SINCE),
Collections.singletonList(dateService.rfc822DateFormat(date)));
}
public class PrefixOptions extends BaseHttpRequestOptions {
@ -1766,7 +1780,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@Test(dataProvider = "strings")
public void testCreateGetRequest(String key) throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
UnsupportedEncodingException {
Method method = TestRequest.class.getMethod("get", String.class, String.class);
HttpRequest request = factory(TestRequest.class).createRequest(method, new Object[] { key, "localhost" });
assertEquals(request.getEndpoint().getHost(), "localhost");
@ -1809,7 +1823,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testVirtualHostMethod() throws SecurityException, NoSuchMethodException {
Method method = TestVirtualHostMethod.class.getMethod("get", String.class, String.class);
HttpRequest request = factory(TestVirtualHostMethod.class).createRequest(method,
new Object[] { "1", "localhost" });
new Object[] { "1", "localhost" });
assertEquals(request.getEndpoint().getHost(), "localhost");
assertEquals(request.getEndpoint().getPath(), "/1");
assertEquals(request.getMethod(), HttpMethod.GET);
@ -1874,7 +1888,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testOneHeader() throws SecurityException, NoSuchMethodException {
Method method = TestHeaders.class.getMethod("oneHeader", String.class);
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(
ImmutableMultimap.<String, String> of().entries(), method, "robot");
ImmutableMultimap.<String, String> of().entries(), method, "robot");
assertEquals(headers.size(), 1);
assertEquals(headers.get("header"), Collections.singletonList("robot"));
}
@ -1883,7 +1897,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testOneIntHeader() throws SecurityException, NoSuchMethodException {
Method method = TestHeaders.class.getMethod("oneIntHeader", int.class);
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(
ImmutableMultimap.<String, String> of().entries(), method, 1);
ImmutableMultimap.<String, String> of().entries(), method, 1);
assertEquals(headers.size(), 1);
assertEquals(headers.get("header"), Collections.singletonList("1"));
}
@ -1892,7 +1906,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testTwoDifferentHeaders() throws SecurityException, NoSuchMethodException {
Method method = TestHeaders.class.getMethod("twoDifferentHeaders", String.class, String.class);
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(
ImmutableMultimap.<String, String> of().entries(), method, "robot", "egg");
ImmutableMultimap.<String, String> of().entries(), method, "robot", "egg");
assertEquals(headers.size(), 2);
assertEquals(headers.get("header1"), Collections.singletonList("robot"));
assertEquals(headers.get("header2"), Collections.singletonList("egg"));
@ -1902,7 +1916,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testTwoSameHeaders() throws SecurityException, NoSuchMethodException {
Method method = TestHeaders.class.getMethod("twoSameHeaders", String.class, String.class);
Multimap<String, String> headers = factory(TestHeaders.class).buildHeaders(
ImmutableMultimap.<String, String> of().entries(), method, "robot", "egg");
ImmutableMultimap.<String, String> of().entries(), method, "robot", "egg");
assertEquals(headers.size(), 2);
Collection<String> values = headers.get("header");
assert values.contains("robot");
@ -1925,7 +1939,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@GET
void twoEndpointParams(@EndpointParam(parser = ConvertTwoToURI.class) String EndpointParam1,
@EndpointParam(parser = ConvertTwoToURI.class) String EndpointParam2);
@EndpointParam(parser = ConvertTwoToURI.class) String EndpointParam2);
@Singleton
public static class ConvertTwoToURI implements Function<Object, URI> {
@ -1945,7 +1959,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testOneEndpointParam() throws SecurityException, NoSuchMethodException {
Method method = TestEndpointParams.class.getMethod("oneEndpointParam", String.class);
URI uri = factory(TestEndpointParams.class).getEndpointInParametersOrNull(method, new Object[] { "robot" },
injector);
injector);
assertEquals(uri, URI.create("robot"));
}
@ -1955,7 +1969,7 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testTwoDifferentEndpointParams() throws SecurityException, NoSuchMethodException {
Method method = TestEndpointParams.class.getMethod("twoEndpointParams", String.class, String.class);
URI uri = factory(TestEndpointParams.class).getEndpointInParametersOrNull(method,
new Object[] { "robot", "egg" }, injector);
new Object[] { "robot", "egg" }, injector);
assertEquals(uri, URI.create("robot/egg"));
}
@ -1967,12 +1981,12 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@PUT
@Path("/{foo}")
public ListenableFuture<Void> putWithPath(@PathParam("foo") String path,
@BinderParam(BindToStringPayload.class) String content);
@BinderParam(BindToStringPayload.class) String content);
@PUT
@Path("")
public void twoEntities(@BinderParam(BindToStringPayload.class) String payload1,
@BinderParam(BindToStringPayload.class) String payload2);
@BinderParam(BindToStringPayload.class) String payload2);
}
@Test
@ -2070,23 +2084,23 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
public void testBuildTwoForms() throws SecurityException, NoSuchMethodException, UnsupportedEncodingException {
Method twoForms = TestFormReplace.class.getMethod("twoForms", String.class, String.class);
Object form = factory(TestFormReplace.class).createRequest(twoForms, "robot", "eggs").getPayload()
.getRawContent();
.getRawContent();
assertEquals(form, "x-amz-copy-source=/robot/eggs");
}
@Test
public void testBuildTwoFormsOutOfOrder() throws SecurityException, NoSuchMethodException,
UnsupportedEncodingException {
UnsupportedEncodingException {
Method twoFormsOutOfOrder = TestFormReplace.class.getMethod("twoFormsOutOfOrder", String.class, String.class);
Object form = factory(TestFormReplace.class).createRequest(twoFormsOutOfOrder, "robot", "eggs").getPayload()
.getRawContent();
.getRawContent();
assertEquals(form, "x-amz-copy-source=/eggs/robot");
}
@SuppressWarnings("unchecked")
private <T> RestAnnotationProcessor<T> factory(Class<T> clazz) {
return ((RestAnnotationProcessor<T>) injector.getInstance(Key.get(newParameterizedType(
RestAnnotationProcessor.class, clazz))));
RestAnnotationProcessor.class, clazz))));
}
DateService dateService = new SimpleDateFormatDateService();
@ -2094,16 +2108,15 @@ public class RestAnnotationProcessorTest extends BaseRestClientTest {
@BeforeClass
void setupFactory() {
RestContextSpec<String, Integer> contextSpec = contextSpec("test", "http://localhost:9999", "1", "userfoo", null,
String.class, Integer.class, ImmutableSet.<Module> of(new MockModule(), new NullLoggingModule(),
new AbstractModule() {
String.class, Integer.class,
ImmutableSet.<Module> of(new MockModule(), new NullLoggingModule(), new AbstractModule() {
@Override
protected void configure() {
bind(URI.class).annotatedWith(Localhost2.class).toInstance(
URI.create("http://localhost:1111"));
}
@Override
protected void configure() {
bind(URI.class).annotatedWith(Localhost2.class).toInstance(URI.create("http://localhost:1111"));
}
}));
}));
injector = createContextBuilder(contextSpec).buildInjector();
parserFactory = injector.getInstance(ParseSax.Factory.class);

View File

@ -23,6 +23,7 @@ import static org.easymock.classextension.EasyMock.createMock;
import static org.testng.Assert.assertEquals;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.concurrent.TimeoutException;
import org.jclouds.domain.Credentials;
@ -42,6 +43,15 @@ import com.google.inject.spi.Message;
*/
@Test(groups = "unit", testName = "jclouds.UtilsTest")
public class UtilsTest {
public void testRenameKeyWhenNotFound() {
Map<String, String> nothing = ImmutableMap.of();
assertEquals(Utils.renameKey(nothing, "foo", "bar"), nothing);
}
public void testRenameKeyWhenFound() {
Map<String, String> nothing = ImmutableMap.of("foo", "bar");
assertEquals(Utils.renameKey(nothing, "foo", "bar"), ImmutableMap.of("bar", "bar"));
}
public void testOverridingCredentialsWhenOverridingIsNull() {
Credentials defaultCredentials = new Credentials("foo", "bar");
@ -69,7 +79,7 @@ public class UtilsTest {
assertEquals(Utils.overrideCredentialsIfSupplied(defaultCredentials, overridingCredentials), new Credentials(
"foo", "bar"));
}
public void testGetCause() {
AuthorizationException aex = createMock(AuthorizationException.class);
Message message = new Message(ImmutableList.of(), "test", aex);
@ -95,6 +105,12 @@ public class UtilsTest {
ProvisionException pex = new ProvisionException(ImmutableSet.of(message));
assertEquals(Utils.getFirstThrowableOfType(pex, AuthorizationException.class), null);
}
public void testGetFirstThrowableOfTypeWhenCauseIsNull() {
Message message = new Message(ImmutableList.of(), "test", null);
ProvisionException pex = new ProvisionException(ImmutableSet.of(message));
assertEquals(Utils.getFirstThrowableOfType(pex, AuthorizationException.class), null);
}
public void testReplaceTokens() throws UnsupportedEncodingException {
assertEquals(Utils.replaceTokens("hello {where}", ImmutableMap.of("where", "world")), "hello world");

View File

@ -103,7 +103,7 @@
<dependency>
<groupId>com.google.code.guice</groupId>
<artifactId>guice-servlet</artifactId>
<version>2.1-r1201</version>
<version>3.0-snapshot-20101120</version>
</dependency>
<dependency>
<groupId>displaytag</groupId>

View File

@ -49,12 +49,13 @@ import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
@ -66,13 +67,13 @@ import org.jclouds.blobstore.BlobStoreContext;
import org.jclouds.blobstore.ContainerNotFoundException;
import org.jclouds.blobstore.KeyNotFoundException;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.blobstore.domain.BlobMetadata;
import org.jclouds.blobstore.domain.MutableBlobMetadata;
import org.jclouds.blobstore.domain.MutableStorageMetadata;
import org.jclouds.blobstore.domain.PageSet;
import org.jclouds.blobstore.domain.StorageMetadata;
import org.jclouds.blobstore.domain.StorageType;
import org.jclouds.blobstore.domain.Blob.Factory;
import org.jclouds.blobstore.domain.internal.MutableBlobMetadataImpl;
import org.jclouds.blobstore.domain.internal.MutableStorageMetadataImpl;
import org.jclouds.blobstore.domain.internal.PageSetImpl;
@ -107,7 +108,6 @@ import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.inject.internal.Nullable;
/**
*

View File

@ -19,8 +19,6 @@
package org.jclouds.gogrid.config;
import static org.jclouds.Constants.PROPERTY_GSON_ADAPTERS;
import java.lang.reflect.Type;
import java.util.Map;
@ -54,7 +52,6 @@ public class GoGridParserModule extends AbstractModule {
@Provides
@Singleton
@com.google.inject.name.Named(PROPERTY_GSON_ADAPTERS)
public Map<Type, Object> provideCustomAdapterBindings() {
Map<Type, Object> bindings = Maps.newHashMap();
bindings.put(ObjectType.class, new CustomDeserializers.ObjectTypeAdapter());

View File

@ -89,6 +89,8 @@ public class ServerImage implements Comparable<ServerImage> {
}
public String getDescription() {
if (description == null)
return "";
return description;
}

View File

@ -99,7 +99,8 @@ public class ParseServerNameToCredentialsMapFromJsonResponse implements
@Override
public int compareTo(Password o) {
return server.getName().compareTo(o.getServer().getName());
if (null == o.getServer() || null == server) return -1;
return server.getName().compareTo(o.getServer().getName());
}
}
@ -107,6 +108,7 @@ public class ParseServerNameToCredentialsMapFromJsonResponse implements
public Map<String, Credentials> apply(HttpResponse arg0) {
Map<String, Credentials> serverNameToCredentials = Maps.newHashMap();
for (Password password : json.apply(arg0).getList()) {
if( null != password.getServer())
serverNameToCredentials.put(password.getServer().getName(),
new Credentials(password.getUserName(), password.getPassword()));
}

View File

@ -28,7 +28,6 @@ import java.util.Map;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.domain.Credentials;
import org.jclouds.gogrid.config.DateSecondsAdapter;
import org.jclouds.gogrid.domain.IpState;
@ -71,7 +70,7 @@ public class ParseCredentialsFromJsonResponseTest {
ParseCredentialsFromJsonResponse parser = i.getInstance(ParseCredentialsFromJsonResponse.class);
Credentials creds = parser.apply(response);
assertEquals(creds.identity, "root");
assertEquals(creds.credential, "dig44sos");
assertEquals(creds.credential, "zot40ced");
}
@ -85,7 +84,6 @@ public class ParseCredentialsFromJsonResponseTest {
@Provides
@Singleton
@SuppressWarnings("unused")
@com.google.inject.name.Named(Constants.PROPERTY_GSON_ADAPTERS)
public Map<Type, Object> provideCustomAdapterBindings() {
Map<Type, Object> bindings = Maps.newHashMap();
bindings.put(IpState.class, new CustomDeserializers.IpStateAdapter());

View File

@ -30,7 +30,6 @@ import java.util.SortedSet;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.gogrid.config.DateSecondsAdapter;
import org.jclouds.gogrid.domain.Job;
import org.jclouds.gogrid.domain.JobProperties;
@ -88,7 +87,6 @@ public class ParseJobsFromJsonResponseTest {
@SuppressWarnings("unused")
@Provides
@Singleton
@com.google.inject.name.Named(Constants.PROPERTY_GSON_ADAPTERS)
public Map<Type, Object> provideCustomAdapterBindings() {
Map<Type, Object> bindings = Maps.newHashMap();
bindings.put(ObjectType.class, new CustomDeserializers.ObjectTypeAdapter());

View File

@ -29,7 +29,6 @@ import java.util.SortedSet;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.gogrid.config.DateSecondsAdapter;
import org.jclouds.gogrid.domain.Ip;
import org.jclouds.gogrid.domain.IpPortPair;
@ -87,7 +86,6 @@ public class ParseLoadBalancersFromJsonResponseTest {
@Provides
@Singleton
@SuppressWarnings( { "unused" })
@com.google.inject.name.Named(Constants.PROPERTY_GSON_ADAPTERS)
public Map<Type, Object> provideCustomAdapterBindings() {
Map<Type, Object> bindings = Maps.newHashMap();
bindings.put(LoadBalancerOs.class, new CustomDeserializers.LoadBalancerOsAdapter());

View File

@ -28,7 +28,6 @@ import java.util.Map;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.domain.Credentials;
import org.jclouds.gogrid.config.DateSecondsAdapter;
import org.jclouds.gogrid.domain.IpState;
@ -73,7 +72,6 @@ public class ParseServerNameToCredentialsMapFromJsonResponseTest {
@Provides
@Singleton
@SuppressWarnings("unused")
@com.google.inject.name.Named(Constants.PROPERTY_GSON_ADAPTERS)
public Map<Type, Object> provideCustomAdapterBindings() {
Map<Type, Object> bindings = Maps.newHashMap();
bindings.put(IpState.class, new CustomDeserializers.IpStateAdapter());

View File

@ -29,7 +29,6 @@ import java.util.SortedSet;
import javax.inject.Singleton;
import org.jclouds.Constants;
import org.jclouds.gogrid.config.GoGridParserModule;
import org.jclouds.gogrid.domain.BillingToken;
import org.jclouds.gogrid.domain.Customer;
@ -94,7 +93,6 @@ public class ParseServersFromJsonResponseTest {
@Provides
@Singleton
@SuppressWarnings( { "unused", "unchecked" })
@com.google.inject.name.Named(Constants.PROPERTY_GSON_ADAPTERS)
public Map<Class, Object> provideCustomAdapterBindings() {
Map<Class, Object> bindings = Maps.newHashMap();
bindings.put(IpState.class, new CustomDeserializers.IpStateAdapter());

View File

@ -1,103 +1,124 @@
{
"list": [
{
"password": "dig44sos",
"object": "password",
"username": "root",
"server": {
"object": "server",
"isSandbox": false,
{
"password": "zot40ced",
"object": "password",
"username": "root",
"server": {
"isSandbox": false,
"object": "server",
"type": {
"id": 1,
"description": "Web or Application Server",
"name": "Web Server",
"object": "option"
},
"os": {
"id": 17,
"description": "CentOS 5.3 (64-bit)",
"name": "CentOS 5.3 (64-bit)",
"object": "option"
},
"image": {
"type": {
"object": "option",
"id": 1,
"description": "Web or Application Server",
"name": "Web Server",
"id": 1
"object": "option"
},
"owner": {
"id": -1,
"name": "GoGrid",
"object": "customer"
},
"updatedTime": 1257789076417,
"isActive": true,
"id": 1532,
"isPublic": true,
"name": "centos5.3_64_base",
"billingtokens": [
{
"id": 47,
"price": 0,
"name": "CentOS 5.3 64bit",
"object": "billingtoken"
}
],
"object": "serverimage",
"friendlyName": "CentOS 5.3 (64-bit) w/ None",
"os": {
"object": "option",
"id": 17,
"description": "CentOS 5.3 (64-bit)",
"name": "CentOS 5.3 (64-bit)",
"id": 17
},
"image": {
"type": {
"object": "option",
"description": "Web or Application Server",
"name": "Web Server",
"id": 1
},
"owner": {
"object": "customer",
"name": "Gear6",
"id": 26443
},
"updatedTime": 1265675466171,
"isActive": true,
"id": 2500,
"createdTime": 1265412834154,
"isPublic": true,
"billingtokens": [
{
"price": 0,
"name": "CentOS 5.3 64bit",
"id": 47
},
{
"price": 60,
"name": "Gear 6 Paid Version",
"id": 76
}
],
"object": "serverimage",
"friendlyName": "gear6-memcache-server-2.3.6.2-x86_64",
"os": {
"object": "option",
"description": "CentOS 5.3 (64-bit)",
"name": "CentOS 5.3 (64-bit)",
"id": 17
},
"price": 60,
"description": "Gear6 Memcache Server 2.3.6.2 (64 bit)",
"state": {
"object": "option",
"description": "Image is available for adds",
"name": "Available",
"id": 2
},
"location": "26443/GSI-7f498260-2b8a-43ef-aa77-5b403f8f739a.img",
"name": "GSI-7f498260-2b8a-43ef-aa77-5b403f8f739a"
"object": "option"
},
"price": 0,
"description": "CentOS 5.3 (64-bit) w/ None",
"state": {
"object": "option",
"description": "Server is in active state.",
"name": "On",
"id": 1
"id": 2,
"description": "Image is available for adds",
"name": "Available",
"object": "option"
},
"ram": {
"object": "option",
"description": "Server with 512MB RAM",
"name": "512MB",
"id": 1
},
"name": "gogrid-19",
"ip": {
"object": "ip",
"public": true,
"subnet": "204.51.240.176/255.255.255.240",
"state": {
"object": "option",
"description": "IP is reserved or in use",
"name": "Assigned",
"id": 2
},
"ip": "204.51.240.189",
"id": 1313090
},
"id": 77332
"location": "gogrid/GSI-939ef909-84b8-4a2f-ad56-02ccd7da05ff.img",
"name": "bogus",
"architecture": {
"id": 2,
"description": "64 bit OS",
"name": "64-bit",
"object": "option"
}
},
"id": 82647,
"applicationtype": "os"
}
"state": {
"id": 1,
"description": "Server is in active state.",
"name": "On",
"object": "option"
},
"ram": {
"id": 1,
"description": "Server with 512MB RAM",
"name": "512MB",
"object": "option"
},
"name": "proxied-944",
"ip": {
"id": 1104200,
"subnet": "173.1.155.16/255.255.255.240",
"state": {
"id": 2,
"description": "IP is reserved or in use",
"name": "Assigned",
"object": "option"
},
"datacenter": {
"id": 1,
"description": "US West 1 Datacenter",
"name": "US-West-1",
"object": "option"
},
"object": "ip",
"public": true,
"ip": "173.1.155.19"
},
"datacenter": {
"id": 1,
"description": "US West 1 Datacenter",
"name": "US-West-1",
"object": "option"
},
"id": 134551
},
"id": 142243,
"applicationtype": "os"
},
{
"id": 28000,
"username": "22290",
"applicationtype": "cloudstorage",
"object": "password",
"password": "200FMd2nDeomtfW."
}
],
"summary": {
"total": 6,
@ -107,4 +128,4 @@
},
"status": "success",
"method": "/support/password/list"
}
}

View File

@ -19,10 +19,11 @@
package org.jclouds.rackspace.cloudfiles.domain;
import javax.annotation.Nullable;
import org.jclouds.io.PayloadEnclosing;
import com.google.common.collect.Multimap;
import com.google.inject.internal.Nullable;
/**
*

View File

@ -24,11 +24,12 @@ import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import javax.annotation.Nullable;
import org.jclouds.http.HttpRequest;
import org.jclouds.rest.binders.BindToJsonPayload;
import com.google.common.collect.ImmutableMap;
import com.google.inject.internal.Nullable;
/**
*

140
sandbox/cloudsigma/pom.xml Normal file
View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2010 Cloud Conscious, LLC <info@cloudconscious.com>
====================================================================
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.html
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.
====================================================================
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-project</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath>../../project/pom.xml</relativePath>
</parent>
<groupId>org.jclouds</groupId>
<artifactId>jclouds-cloudsigma</artifactId>
<name>jclouds cloudsigma core</name>
<description>jclouds components to access cloudsigma</description>
<!-- bootstrapping: need to fetch the project POM -->
<repositories>
<repository>
<id>jclouds-googlecode-deploy</id>
<url>http://jclouds.googlecode.com/svn/repo</url>
</repository>
<repository>
<id>jclouds-rimu-snapshots-nexus</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<properties>
<!-- when instances are hung, open a ticket and add here -->
<jclouds.compute.blacklist-nodes>trmkrun-ccc,test.trmk-924</jclouds.compute.blacklist-nodes>
<test.cloudsigma.endpoint>https://api.cloudsigma.com</test.cloudsigma.endpoint>
<test.cloudsigma.apiversion>1.0</test.cloudsigma.apiversion>
<test.cloudsigma.identity>FIXME</test.cloudsigma.identity>
<test.cloudsigma.credential>FIXME</test.cloudsigma.credential>
</properties>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-elasticstack</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-core</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-elasticstack</artifactId>
<version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>jclouds-log4j</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<profiles>
<profile>
<id>live</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>integration</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<systemProperties>
<property>
<name>test.cloudsigma.endpoint</name>
<value>${test.cloudsigma.endpoint}</value>
</property>
<property>
<name>test.cloudsigma.apiversion</name>
<value>${test.cloudsigma.apiversion}</value>
</property>
<property>
<name>test.cloudsigma.identity</name>
<value>${test.cloudsigma.identity}</value>
</property>
<property>
<name>test.cloudsigma.credential</name>
<value>${test.cloudsigma.credential}</value>
</property>
<property>
<name>jclouds.compute.blacklist-nodes</name>
<value>${jclouds.compute.blacklist-nodes}</value>
</property>
</systemProperties>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

Some files were not shown because too many files have changed in this diff Show More