mirror of https://github.com/apache/jclouds.git
Merge branch 'master' of github.com:jclouds/jclouds
This commit is contained in:
commit
a1bf070c7a
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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('_'));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 + "]";
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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";
|
||||
}
|
|
@ -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;
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -43,7 +43,7 @@ public class EucalyptusComputeServiceLiveTestDisabled extends EC2ComputeServiceL
|
|||
@Override
|
||||
public void setServiceDefaults() {
|
||||
// security groups must be <30 characters
|
||||
tag = "euc";
|
||||
tag = "eu";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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";
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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"));
|
||||
}
|
||||
|
||||
}
|
|
@ -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"));
|
||||
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
20
aws/pom.xml
20
aws/pom.xml
|
@ -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>
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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}.
|
||||
*
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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")));
|
||||
|
|
|
@ -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))))
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 < > 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -89,6 +89,8 @@ public class ServerImage implements Comparable<ServerImage> {
|
|||
}
|
||||
|
||||
public String getDescription() {
|
||||
if (description == null)
|
||||
return "";
|
||||
return description;
|
||||
}
|
||||
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -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
Loading…
Reference in New Issue