mirror of https://github.com/apache/jclouds.git
Adding OptionalTypeAdaptorFactory to handle the parsing of Optional values
This commit is contained in:
parent
47ad9e2bac
commit
1797b27ed4
|
@ -42,6 +42,7 @@ import org.jclouds.openstack.nova.v1_1.compute.strategy.ApplyNovaTemplateOptions
|
|||
import org.jclouds.openstack.nova.v1_1.domain.Flavor;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Image;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.KeyPair;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.ServerCreated;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.RebootType;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.FlavorInZone;
|
||||
|
@ -119,17 +120,14 @@ public class NovaComputeServiceAdapter implements
|
|||
String flavorId = template.getHardware().getProviderId();
|
||||
|
||||
logger.debug(">> creating new server zone(%s) name(%s) image(%s) flavor(%s) options(%s)", zoneId, name, imageId, flavorId, options);
|
||||
Server lightweightServer = novaClient.getServerClientForZone(zoneId).createServer(name, imageId, flavorId, options);
|
||||
Server heavyweightServer = novaClient.getServerClientForZone(zoneId).getServer(lightweightServer.getId());
|
||||
Server server = Server.builder().fromServer(heavyweightServer)
|
||||
.adminPass(lightweightServer.getAdminPass())
|
||||
.build();
|
||||
ServerCreated lightweightServer = novaClient.getServerClientForZone(zoneId).createServer(name, imageId, flavorId, options);
|
||||
Server server = novaClient.getServerClientForZone(zoneId).getServer(lightweightServer.getId());
|
||||
|
||||
logger.trace("<< server(%s)", server.getId());
|
||||
|
||||
ServerInZone serverInZone = new ServerInZone(server, zoneId);
|
||||
if (!privateKey.isPresent())
|
||||
credentialsBuilder.password(server.getAdminPass());
|
||||
credentialsBuilder.password(lightweightServer.getAdminPass());
|
||||
return new NodeAndInitialCredentials<ServerInZone>(serverInZone, serverInZone.slashEncode(), credentialsBuilder
|
||||
.build());
|
||||
}
|
||||
|
|
|
@ -28,8 +28,11 @@ import org.jclouds.json.config.GsonModule;
|
|||
import org.jclouds.json.config.GsonModule.DateAdapter;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.HostResourceUsage;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.ServerExtendedAttributes;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.ServerExtendedStatus;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.ServerWithSecurityGroups;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Sets;
|
||||
import com.google.gson.JsonArray;
|
||||
|
@ -51,9 +54,10 @@ public class NovaParserModule extends AbstractModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
public Map<Type, Object> provideCustomAdapterBindings() {
|
||||
return ImmutableMap.<Type, Object> of(
|
||||
return ImmutableMap.<Type, Object>of(
|
||||
HostResourceUsage.class, new HostResourceUsageAdapter(),
|
||||
ServerWithSecurityGroups.class, new ServerWithSecurityGroupsAdapter()
|
||||
ServerWithSecurityGroups.class, new ServerWithSecurityGroupsAdapter(),
|
||||
Server.class, new ServerAdapter()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -98,7 +102,7 @@ public class NovaParserModule extends AbstractModule {
|
|||
Set<String> names = Sets.newLinkedHashSet();
|
||||
if (jsonElement.getAsJsonObject().get("security_groups") != null) {
|
||||
JsonArray x = jsonElement.getAsJsonObject().get("security_groups").getAsJsonArray();
|
||||
for(JsonElement y : x) {
|
||||
for (JsonElement y : x) {
|
||||
names.add(y.getAsJsonObject().get("name").getAsString());
|
||||
}
|
||||
result.securityGroupNames(names);
|
||||
|
@ -106,4 +110,33 @@ public class NovaParserModule extends AbstractModule {
|
|||
return result.build();
|
||||
}
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class ServerAdapter implements JsonDeserializer<Server> {
|
||||
@Override
|
||||
public Server deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context)
|
||||
throws JsonParseException {
|
||||
Server serverBase = apply((ServerInternal) context.deserialize(jsonElement, ServerInternal.class));
|
||||
Server.Builder result = Server.builder().fromServer(serverBase);
|
||||
ServerExtendedStatus extendedStatus = context.deserialize(jsonElement, ServerExtendedStatus.class);
|
||||
if (!Objects.equal(extendedStatus, ServerExtendedStatus.builder().build())) {
|
||||
result.extendedStatus(extendedStatus);
|
||||
}
|
||||
ServerExtendedAttributes extraAttributes = context.deserialize(jsonElement, ServerExtendedAttributes.class);
|
||||
if (!Objects.equal(extraAttributes, ServerExtendedAttributes.builder().build())) {
|
||||
result.extraAttributes(extraAttributes);
|
||||
}
|
||||
return result.build();
|
||||
}
|
||||
|
||||
public Server apply(ServerInternal in) {
|
||||
return in.toBuilder().build();
|
||||
}
|
||||
|
||||
private static class ServerInternal extends Server {
|
||||
protected ServerInternal() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ import org.jclouds.openstack.domain.Resource;
|
|||
import org.jclouds.openstack.nova.v1_1.extensions.KeyPairClient;
|
||||
import org.jclouds.util.Multimaps2;
|
||||
|
||||
import com.google.common.base.Objects.ToStringHelper;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicates;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.base.Objects.ToStringHelper;
|
||||
|
@ -67,7 +69,7 @@ public class Server extends Resource {
|
|||
NodeState.TERMINATED), UNKNOWN(NodeState.UNRECOGNIZED), ERROR(NodeState.ERROR), UNRECOGNIZED(
|
||||
NodeState.UNRECOGNIZED), PAUSED(NodeState.SUSPENDED);
|
||||
|
||||
private final NodeState nodeState;
|
||||
protected final NodeState nodeState;
|
||||
|
||||
Status(NodeState nodeState) {
|
||||
this.nodeState = nodeState;
|
||||
|
@ -111,17 +113,15 @@ public class Server extends Resource {
|
|||
private Server.Status status;
|
||||
private Resource image;
|
||||
private Resource flavor;
|
||||
private String adminPass;
|
||||
private String keyName;
|
||||
private String configDrive;
|
||||
private Multimap<String, Address> addresses = ImmutableMultimap.of();
|
||||
private Map<String, String> metadata = ImmutableMap.of();
|
||||
private String taskState;
|
||||
private String vmState;
|
||||
private String powerState;
|
||||
private String instanceName;
|
||||
private String hostName;
|
||||
private String hypervisorName;
|
||||
// Extended status extension
|
||||
private ServerExtendedStatus extendedStatus;
|
||||
// Extended server attributes extension
|
||||
private ServerExtendedAttributes extendedAttributes;
|
||||
// Disk Config extension
|
||||
private String diskConfig;
|
||||
|
||||
/**
|
||||
|
@ -212,14 +212,6 @@ public class Server extends Resource {
|
|||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Server#getAdminPass()
|
||||
*/
|
||||
public T adminPass(String adminPass) {
|
||||
this.adminPass = adminPass;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Server#getKeyName()
|
||||
*/
|
||||
|
@ -251,52 +243,20 @@ public class Server extends Resource {
|
|||
this.metadata = metadata;
|
||||
return self();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see Server#getTaskState()
|
||||
* @see Server#getExtendedStatus()
|
||||
*/
|
||||
public T taskState(String taskState) {
|
||||
this.taskState = taskState;
|
||||
public T extendedStatus(ServerExtendedStatus extendedStatus) {
|
||||
this.extendedStatus = extendedStatus;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Server#getVmState()
|
||||
* @see Server#getExtendedAttributes()
|
||||
*/
|
||||
public T vmState(String vmState) {
|
||||
this.vmState = vmState;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Server#getPowerState()
|
||||
*/
|
||||
public T powerState(String powerState) {
|
||||
this.powerState = powerState;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Server#getInstanceName()
|
||||
*/
|
||||
public T instanceName(String instanceName) {
|
||||
this.instanceName = instanceName;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Server#getHostName()
|
||||
*/
|
||||
public T hostName(String hostName) {
|
||||
this.hostName = hostName;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Server#getHypervisorName()
|
||||
*/
|
||||
public T hypervisorName(String hypervisorName) {
|
||||
this.hypervisorName = hypervisorName;
|
||||
public T extraAttributes(ServerExtendedAttributes extendedAttributes) {
|
||||
this.extendedAttributes = extendedAttributes;
|
||||
return self();
|
||||
}
|
||||
|
||||
|
@ -325,18 +285,13 @@ public class Server extends Resource {
|
|||
.status(in.getStatus())
|
||||
.image(in.getImage())
|
||||
.flavor(in.getFlavor())
|
||||
.adminPass(in.getAdminPass())
|
||||
.keyName(in.getKeyName())
|
||||
.configDrive(in.getConfigDrive())
|
||||
.addresses(in.getAddresses())
|
||||
.metadata(in.getMetadata())
|
||||
.taskState(in.getTaskState())
|
||||
.vmState(in.getVmState())
|
||||
.powerState(in.getPowerState())
|
||||
.instanceName(in.getInstanceName())
|
||||
.hostName(in.getHostName())
|
||||
.hypervisorName(in.getHypervisorName())
|
||||
.diskConfig(in.getDiskConfig());
|
||||
.extendedStatus(in.getExtendedStatus().orNull())
|
||||
.extraAttributes(in.getExtendedAttributes().orNull())
|
||||
.diskConfig(in.getDiskConfig().orNull());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -347,47 +302,38 @@ public class Server extends Resource {
|
|||
}
|
||||
}
|
||||
|
||||
protected final String uuid;
|
||||
private final String uuid;
|
||||
@SerializedName("tenant_id")
|
||||
protected final String tenantId;
|
||||
private final String tenantId;
|
||||
@SerializedName("user_id")
|
||||
protected final String userId;
|
||||
protected final Date updated;
|
||||
protected final Date created;
|
||||
protected final String hostId;
|
||||
protected final String accessIPv4;
|
||||
protected final String accessIPv6;
|
||||
protected final Status status;
|
||||
protected final Resource image;
|
||||
protected final Resource flavor;
|
||||
protected final String adminPass;
|
||||
private final String userId;
|
||||
private final Date updated;
|
||||
private final Date created;
|
||||
private final String hostId;
|
||||
private final String accessIPv4;
|
||||
private final String accessIPv6;
|
||||
private final Status status;
|
||||
private final Resource image;
|
||||
private final Resource flavor;
|
||||
@SerializedName("key_name")
|
||||
protected final String keyName;
|
||||
private final String keyName;
|
||||
@SerializedName("config_drive")
|
||||
protected final String configDrive;
|
||||
private final String configDrive;
|
||||
// TODO: get gson multimap adapter!
|
||||
protected final Map<String, Set<Address>> addresses;
|
||||
protected final Map<String, String> metadata;
|
||||
private final Map<String, Set<Address>> addresses;
|
||||
private final Map<String, String> metadata;
|
||||
|
||||
// Extended status extension
|
||||
@SerializedName("OS-EXT-STS:task_state")
|
||||
protected final String taskState;
|
||||
@SerializedName("OS-EXT-STS:vm_state")
|
||||
protected final String vmState;
|
||||
@SerializedName("OS-EXT-STS:power_state")
|
||||
protected final String powerState;
|
||||
// @Prefixed("OS-EXT-STS:")
|
||||
private final Optional<ServerExtendedStatus> extendedStatus;
|
||||
|
||||
// Extended server attributes extension
|
||||
@SerializedName("OS-EXT-SRV-ATTR:instance_name")
|
||||
protected final String instanceName;
|
||||
@SerializedName("OS-EXT-SRV-ATTR:host")
|
||||
protected final String hostName;
|
||||
@SerializedName("OS-EXT-SRV-ATTR:hypervisor_hostname")
|
||||
protected final String hypervisorName;
|
||||
// @Prefixed("OS-EXT-SRV-ATTR:")
|
||||
private final Optional<ServerExtendedAttributes> extendedAttributes;
|
||||
|
||||
// Disk Config extension
|
||||
@SerializedName("OS-DCF:diskConfig")
|
||||
protected final String diskConfig;
|
||||
private final Optional<String> diskConfig;
|
||||
|
||||
protected Server(Builder<?> builder) {
|
||||
super(builder);
|
||||
|
@ -405,17 +351,34 @@ public class Server extends Resource {
|
|||
this.flavor = checkNotNull(builder.flavor, "flavor");
|
||||
this.metadata = Maps.newHashMap(builder.metadata);
|
||||
this.addresses = Multimaps2.toOldSchool(ImmutableMultimap.copyOf(checkNotNull(builder.addresses, "addresses")));
|
||||
this.adminPass = builder.adminPass;
|
||||
this.keyName = builder.keyName;
|
||||
this.taskState = builder.taskState;
|
||||
this.vmState = builder.vmState;
|
||||
this.powerState = builder.powerState;
|
||||
this.instanceName = builder.instanceName;
|
||||
this.hostName = builder.hostName;
|
||||
this.hypervisorName = builder.hypervisorName;
|
||||
this.diskConfig = builder.diskConfig;
|
||||
this.extendedStatus = Optional.fromNullable(builder.extendedStatus);
|
||||
this.extendedAttributes = Optional.fromNullable(builder.extendedAttributes);
|
||||
this.diskConfig = builder.diskConfig == null ? Optional.<String>absent() : Optional.of(builder.diskConfig);
|
||||
}
|
||||
|
||||
protected Server() {
|
||||
// for GSON
|
||||
this.uuid = null;
|
||||
this.tenantId = null;
|
||||
this.userId = null;
|
||||
this.updated = null;
|
||||
this.created = null;
|
||||
this.hostId = null;
|
||||
this.accessIPv4 = null;
|
||||
this.accessIPv6 = null;
|
||||
this.status = null;
|
||||
this.configDrive = null;
|
||||
this.image = null;
|
||||
this.flavor = null;
|
||||
this.metadata = ImmutableMap.of();
|
||||
this.addresses = ImmutableMap.of();
|
||||
this.keyName = null;
|
||||
this.extendedStatus = Optional.absent();
|
||||
this.extendedAttributes = Optional.absent();
|
||||
this.diskConfig = Optional.absent();
|
||||
}
|
||||
|
||||
/**
|
||||
* only present until the id is in uuid form
|
||||
*
|
||||
|
@ -489,14 +452,6 @@ public class Server extends Resource {
|
|||
return Multimaps2.fromOldSchool(addresses);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the administrative password for this server; only present on first request.
|
||||
*/
|
||||
@Nullable
|
||||
public String getAdminPass() {
|
||||
return adminPass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return keyName if extension is present and there is a valur for this server
|
||||
* @see KeyPairClient
|
||||
|
@ -508,64 +463,21 @@ public class Server extends Resource {
|
|||
|
||||
|
||||
/**
|
||||
* State of task running against this instance (e.g. "suspending")
|
||||
* Retrieves the extended server status fields
|
||||
* <p/>
|
||||
* NOTE: This field is only present if the Extended Status extension is installed.
|
||||
*/
|
||||
@Nullable
|
||||
public String getTaskState() {
|
||||
return this.taskState;
|
||||
public Optional<ServerExtendedStatus> getExtendedStatus() {
|
||||
return this.extendedStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* State of task running against this instance (e.g. "suspending")
|
||||
* <p/>
|
||||
* NOTE: This field is only present if the Extended Status extension is installed.
|
||||
*/
|
||||
@Nullable
|
||||
public String getVmState() {
|
||||
return this.vmState;
|
||||
}
|
||||
|
||||
/**
|
||||
* State of task running against this instance (e.g. "suspending")
|
||||
* <p/>
|
||||
* NOTE: This field is only present if the Extended Status extension is installed.
|
||||
*/
|
||||
@Nullable
|
||||
public String getPowerState() {
|
||||
return this.powerState;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the instance?
|
||||
* Retrieves the extended server attributes fields
|
||||
* <p/>
|
||||
* NOTE: This field is only present if the The Extended Server Attributes API extension is installed.
|
||||
*/
|
||||
@Nullable
|
||||
public String getInstanceName() {
|
||||
return this.instanceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The host name of the host this Server is running on
|
||||
* <p/>
|
||||
* NOTE: This field is only present if the The Extended Server Attributes API extension is installed.
|
||||
* @see #getHostId()
|
||||
*/
|
||||
@Nullable
|
||||
public String getHostName() {
|
||||
return this.hostName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the hypervisor this Server is running on
|
||||
* <p/>
|
||||
* NOTE: This field is only present if the The Extended Server Attributes API extension is installed.
|
||||
*/
|
||||
@Nullable
|
||||
public String getHypervisorName() {
|
||||
return this.hypervisorName;
|
||||
public Optional<ServerExtendedAttributes> getExtendedAttributes() {
|
||||
return this.extendedAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -573,8 +485,7 @@ public class Server extends Resource {
|
|||
* <p/>
|
||||
* NOTE: This field is only present if the Disk Config extension is installed.
|
||||
*/
|
||||
@Nullable
|
||||
public String getDiskConfig() {
|
||||
public Optional<String> getDiskConfig() {
|
||||
return this.diskConfig;
|
||||
}
|
||||
|
||||
|
@ -587,6 +498,7 @@ public class Server extends Resource {
|
|||
"userId", userId).add("hostId", getHostId()).add("updated", updated).add("created", created).add(
|
||||
"accessIPv4", getAccessIPv4()).add("accessIPv6", getAccessIPv6()).add("status", status).add(
|
||||
"configDrive", getConfigDrive()).add("image", image).add("flavor", flavor).add("metadata", metadata)
|
||||
.add("addresses", getAddresses()).add("adminPass", adminPass);
|
||||
.add("addresses", getAddresses()).add("diskConfig", diskConfig)
|
||||
.add("extendedStatus", extendedStatus).add("extendedAttributes", extendedAttributes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.openstack.nova.v1_1.domain;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
import org.jclouds.openstack.domain.Resource;
|
||||
|
||||
import com.google.common.base.Objects.ToStringHelper;
|
||||
|
||||
/**
|
||||
* Server Resource with administrative password returned by ServerClient#CreateServer calls
|
||||
*
|
||||
* @author Adam Lowe
|
||||
* @see <a href=
|
||||
* "http://docs.openstack.org/api/openstack-compute/1.1/content/Get_Server_Details-d1e2623.html"
|
||||
* />
|
||||
*/
|
||||
public class ServerCreated extends Resource {
|
||||
|
||||
public static Builder<?> builder() {
|
||||
return new ConcreteBuilder();
|
||||
}
|
||||
|
||||
public Builder<?> toBuilder() {
|
||||
return new ConcreteBuilder().fromServerCreated(this);
|
||||
}
|
||||
|
||||
public static abstract class Builder<T extends Builder<T>> extends Resource.Builder<T> {
|
||||
private String adminPass;
|
||||
|
||||
/**
|
||||
* @see ServerCreated#getAdminPass()
|
||||
*/
|
||||
public T adminPass(String adminPass) {
|
||||
this.adminPass = adminPass;
|
||||
return self();
|
||||
}
|
||||
|
||||
public T fromServerCreated(ServerCreated in) {
|
||||
return super.fromResource(in).adminPass(in.getAdminPass());
|
||||
}
|
||||
|
||||
public ServerCreated build() {
|
||||
return new ServerCreated(this);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
|
||||
@Override
|
||||
protected ConcreteBuilder self() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
private final String adminPass;
|
||||
|
||||
protected ServerCreated(Builder<?> builder) {
|
||||
super(builder);
|
||||
this.adminPass = builder.adminPass;
|
||||
}
|
||||
|
||||
protected ServerCreated() {
|
||||
this.adminPass =null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the administrative password for this server. Note: this is not available in Server responses.
|
||||
*/
|
||||
public String getAdminPass() {
|
||||
return adminPass;
|
||||
}
|
||||
|
||||
// hashCode/equals from super is ok
|
||||
|
||||
@Override
|
||||
protected ToStringHelper string() {
|
||||
return super.string().add("adminPass", adminPass);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.openstack.nova.v1_1.domain;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Objects.ToStringHelper;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Additional attributes delivered by Extended Server Attributes extension
|
||||
*
|
||||
* @author Adam Lowe
|
||||
* @see <a href=
|
||||
* "http://nova.openstack.org/api/nova.api.openstack.compute.contrib.extended_server_attributes.html"
|
||||
* />
|
||||
*/
|
||||
public class ServerExtendedAttributes {
|
||||
public static final String PREFIX = "OS-EXT-SRV-ATTR:";
|
||||
|
||||
public static Builder<?> builder() {
|
||||
return new ConcreteBuilder();
|
||||
}
|
||||
|
||||
public Builder<?> toBuilder() {
|
||||
return new ConcreteBuilder().fromServerExtraAttributes(this);
|
||||
}
|
||||
|
||||
public static abstract class Builder<T extends Builder<T>> {
|
||||
protected abstract T self();
|
||||
|
||||
private String instanceName;
|
||||
private String hostName;
|
||||
private String hypervisorHostName;
|
||||
|
||||
/**
|
||||
* @see ServerExtendedAttributes#getInstanceName()
|
||||
*/
|
||||
public T instanceName(String instanceName) {
|
||||
this.instanceName = instanceName;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ServerExtendedAttributes#getHostName()
|
||||
*/
|
||||
public T hostName(String hostName) {
|
||||
this.hostName = hostName;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ServerExtendedAttributes#getHypervisorHostName()
|
||||
*/
|
||||
public T hypervisorHostame(String hypervisorHostName) {
|
||||
this.hypervisorHostName = hypervisorHostName;
|
||||
return self();
|
||||
}
|
||||
|
||||
public ServerExtendedAttributes build() {
|
||||
return new ServerExtendedAttributes(this);
|
||||
}
|
||||
|
||||
public T fromServerExtraAttributes(ServerExtendedAttributes in) {
|
||||
return this
|
||||
.instanceName(in.getInstanceName())
|
||||
.hostName(in.getHostName())
|
||||
.hypervisorHostame(in.getHypervisorHostName());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
|
||||
@Override
|
||||
protected ConcreteBuilder self() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@SerializedName(value=PREFIX + "instance_name")
|
||||
private final String instanceName;
|
||||
@SerializedName(value=PREFIX + "host")
|
||||
private final String hostName;
|
||||
@SerializedName(value=PREFIX + "hypervisor_hostname")
|
||||
private final String hypervisorHostName;
|
||||
|
||||
protected ServerExtendedAttributes(Builder<?> builder) {
|
||||
this.instanceName = builder.instanceName;
|
||||
this.hostName = builder.hostName;
|
||||
this.hypervisorHostName = builder.hypervisorHostName;
|
||||
}
|
||||
|
||||
public String getInstanceName() {
|
||||
return this.instanceName;
|
||||
}
|
||||
|
||||
public String getHostName() {
|
||||
return this.hostName;
|
||||
}
|
||||
|
||||
public String getHypervisorHostName() {
|
||||
return this.hypervisorHostName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(instanceName, hostName, hypervisorHostName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null || getClass() != obj.getClass()) return false;
|
||||
ServerExtendedAttributes that = ServerExtendedAttributes.class.cast(obj);
|
||||
return Objects.equal(this.instanceName, that.instanceName)
|
||||
&& Objects.equal(this.hostName, that.hostName)
|
||||
&& Objects.equal(this.hypervisorHostName, that.hypervisorHostName);
|
||||
}
|
||||
|
||||
protected ToStringHelper string() {
|
||||
return Objects.toStringHelper("")
|
||||
.add("instanceName", instanceName)
|
||||
.add("hostName", hostName)
|
||||
.add("hypervisorHostName", hypervisorHostName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return string().toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.openstack.nova.v1_1.domain;
|
||||
|
||||
import org.jclouds.javax.annotation.Nullable;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Objects.ToStringHelper;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
/**
|
||||
* Additional attributes delivered by Extended Server Status extension
|
||||
*
|
||||
* @author Adam Lowe
|
||||
* @see <a href=
|
||||
* "http://nova.openstack.org/api/nova.api.openstack.compute.contrib.extended_status.html"
|
||||
* />
|
||||
*/
|
||||
public class ServerExtendedStatus {
|
||||
public static final String PREFIX = "OS-EXT-STS:";
|
||||
|
||||
public static Builder<?> builder() {
|
||||
return new ConcreteBuilder();
|
||||
}
|
||||
|
||||
public Builder<?> toBuilder() {
|
||||
return new ConcreteBuilder().fromServerExtendedStatus(this);
|
||||
}
|
||||
|
||||
public static abstract class Builder<T extends Builder<T>> {
|
||||
protected abstract T self();
|
||||
|
||||
private String taskState;
|
||||
private String vmState;
|
||||
private int powerState = Integer.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* @see ServerExtendedStatus#getTaskState()
|
||||
*/
|
||||
public T taskState(String taskState) {
|
||||
this.taskState = taskState;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ServerExtendedStatus#getVmState()
|
||||
*/
|
||||
public T vmState(String vmState) {
|
||||
this.vmState = vmState;
|
||||
return self();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ServerExtendedStatus#getPowerState()
|
||||
*/
|
||||
public T powerState(int powerState) {
|
||||
this.powerState = powerState;
|
||||
return self();
|
||||
}
|
||||
|
||||
public ServerExtendedStatus build() {
|
||||
return new ServerExtendedStatus(this);
|
||||
}
|
||||
|
||||
public T fromServerExtendedStatus(ServerExtendedStatus in) {
|
||||
return this
|
||||
.taskState(in.getTaskState())
|
||||
.vmState(in.getVmState())
|
||||
.powerState(in.getPowerState());
|
||||
}
|
||||
}
|
||||
|
||||
private static class ConcreteBuilder extends Builder<ConcreteBuilder> {
|
||||
@Override
|
||||
protected ConcreteBuilder self() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@SerializedName(value=PREFIX + "task_state")
|
||||
private final String taskState;
|
||||
@SerializedName(value=PREFIX + "vm_state")
|
||||
private final String vmState;
|
||||
@SerializedName(value=PREFIX + "power_state")
|
||||
private final int powerState;
|
||||
|
||||
protected ServerExtendedStatus(Builder<?> builder) {
|
||||
this.taskState = builder.taskState;
|
||||
this.vmState = builder.vmState;
|
||||
this.powerState = builder.powerState;
|
||||
}
|
||||
|
||||
protected ServerExtendedStatus() {
|
||||
this.taskState = null;
|
||||
this.vmState = null;
|
||||
this.powerState = Integer.MIN_VALUE;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getTaskState() {
|
||||
return this.taskState;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getVmState() {
|
||||
return this.vmState;
|
||||
}
|
||||
|
||||
public int getPowerState() {
|
||||
return this.powerState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(taskState, vmState, powerState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (obj == null || getClass() != obj.getClass()) return false;
|
||||
ServerExtendedStatus that = ServerExtendedStatus.class.cast(obj);
|
||||
return Objects.equal(this.taskState, that.taskState)
|
||||
&& Objects.equal(this.vmState, that.vmState)
|
||||
&& Objects.equal(this.powerState, that.powerState)
|
||||
;
|
||||
}
|
||||
|
||||
protected ToStringHelper string() {
|
||||
return Objects.toStringHelper("")
|
||||
.add("taskState", taskState)
|
||||
.add("vmState", vmState)
|
||||
.add("powerState", powerState)
|
||||
;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return string().toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -32,6 +32,7 @@ import javax.ws.rs.core.MediaType;
|
|||
|
||||
import org.jclouds.openstack.domain.Resource;
|
||||
import org.jclouds.openstack.filters.AuthenticateRequest;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.ServerCreated;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.RebootType;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
||||
import org.jclouds.openstack.nova.v1_1.functions.ParseImageIdFromLocationHeader;
|
||||
|
@ -154,7 +155,7 @@ public interface ServerAsyncClient {
|
|||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
@Path("/servers")
|
||||
@MapBinder(CreateServerOptions.class)
|
||||
ListenableFuture<Server> createServer(@PayloadParam("name") String name, @PayloadParam("imageRef") String imageRef,
|
||||
ListenableFuture<ServerCreated> createServer(@PayloadParam("name") String name, @PayloadParam("imageRef") String imageRef,
|
||||
@PayloadParam("flavorRef") String flavorRef, CreateServerOptions... options);
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import org.jclouds.concurrent.Timeout;
|
||||
import org.jclouds.openstack.domain.Resource;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.ServerCreated;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.RebootType;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
||||
import org.jclouds.openstack.nova.v1_1.options.CreateServerOptions;
|
||||
|
@ -80,7 +81,7 @@ public interface ServerClient {
|
|||
*/
|
||||
// blocking call
|
||||
@Timeout(duration = 10, timeUnit = TimeUnit.MINUTES)
|
||||
Server createServer(String name, String imageRef, String flavorRef, CreateServerOptions... options);
|
||||
ServerCreated createServer(String name, String imageRef, String flavorRef, CreateServerOptions... options);
|
||||
|
||||
/**
|
||||
* Terminate and delete a server.
|
||||
|
|
|
@ -64,7 +64,7 @@ public class OrphanedGroupsByZoneIdTest {
|
|||
@Test
|
||||
public void testWhenComputeServiceSaysAllNodesAreDeadBothGroupsAreReturned() {
|
||||
|
||||
ServerInZone withoutHost = new ServerInZone(new ParseCreatedServerTest().expected(), "az-1.region-a.geo-1");
|
||||
ServerInZone withoutHost = new ServerInZone(new ServerInZoneToNodeMetadataTest().expectedServer(), "az-1.region-a.geo-1");
|
||||
ServerInZone withHost = new ServerInZone(new ParseServerTest().expected(), "az-1.region-a.geo-1");
|
||||
|
||||
ServerInZoneToNodeMetadata converter = new ServerInZoneToNodeMetadata(locationIndex, Suppliers
|
||||
|
@ -80,7 +80,7 @@ public class OrphanedGroupsByZoneIdTest {
|
|||
@Test
|
||||
public void testWhenComputeServiceSaysAllNodesAreDeadNoGroupsAreReturned() {
|
||||
|
||||
ServerInZone withoutHost = new ServerInZone(new ParseCreatedServerTest().expected(), "az-1.region-a.geo-1");
|
||||
ServerInZone withoutHost = new ServerInZone(new ServerInZoneToNodeMetadataTest().expectedServer(), "az-1.region-a.geo-1");
|
||||
ServerInZone withHost = new ServerInZone(new ParseServerTest().expected(), "az-1.region-a.geo-1");
|
||||
|
||||
ServerInZoneToNodeMetadata converter = new ServerInZoneToNodeMetadata(locationIndex, Suppliers
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.jclouds.openstack.nova.v1_1.compute.functions;
|
|||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -32,9 +33,12 @@ import org.jclouds.compute.domain.NodeMetadata;
|
|||
import org.jclouds.compute.domain.OperatingSystem;
|
||||
import org.jclouds.compute.domain.OsFamily;
|
||||
import org.jclouds.compute.functions.GroupNamingConvention;
|
||||
import org.jclouds.date.internal.SimpleDateFormatDateService;
|
||||
import org.jclouds.domain.Location;
|
||||
import org.jclouds.domain.LocationBuilder;
|
||||
import org.jclouds.domain.LocationScope;
|
||||
import org.jclouds.openstack.domain.Link;
|
||||
import org.jclouds.openstack.domain.Resource;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.zonescoped.ServerInZone;
|
||||
import org.jclouds.openstack.nova.v1_1.parse.ParseCreatedServerTest;
|
||||
|
@ -144,7 +148,7 @@ public class ServerInZoneToNodeMetadataTest {
|
|||
Set<Image> images = ImmutableSet.<Image> of();
|
||||
Set<Hardware> hardwares = ImmutableSet.<Hardware> of();
|
||||
|
||||
Server serverToConvert = new ParseCreatedServerTest().expected();
|
||||
Server serverToConvert = expectedServer();
|
||||
|
||||
ServerInZone serverInZoneToConvert = new ServerInZone(serverToConvert, "az-1.region-a.geo-1");
|
||||
|
||||
|
@ -160,4 +164,39 @@ public class ServerInZoneToNodeMetadataTest {
|
|||
assertEquals(convertedNodeMetadata.getLocation(), zone);
|
||||
|
||||
}
|
||||
|
||||
public Server expectedServer() {
|
||||
return Server
|
||||
.builder()
|
||||
.id("71752")
|
||||
.uuid("47491020-6a78-4f63-9475-23195ac4515c")
|
||||
.tenantId("37936628937291")
|
||||
.userId("54297837463082")
|
||||
.name("test-e92")
|
||||
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-03-19T06:21:13Z"))
|
||||
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-03-19T06:21:13Z"))
|
||||
.status(Server.Status.BUILD)
|
||||
.image(
|
||||
Resource
|
||||
.builder()
|
||||
.id("1241")
|
||||
.links(
|
||||
Link.create(
|
||||
Link.Relation.BOOKMARK,
|
||||
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/images/1241")))
|
||||
.build())
|
||||
.flavor(
|
||||
Resource
|
||||
.builder()
|
||||
.id("100")
|
||||
.links(
|
||||
Link.create(
|
||||
Link.Relation.BOOKMARK,
|
||||
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/flavors/100")))
|
||||
.build())
|
||||
.links(
|
||||
Link.create(Link.Relation.SELF, URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/37936628937291/servers/71752")),
|
||||
Link.create(Link.Relation.BOOKMARK, URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/servers/71752"))).build();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import static org.testng.Assert.fail;
|
|||
import org.jclouds.http.HttpResponseException;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.BackupType;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Image;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server.Status;
|
||||
import org.jclouds.openstack.nova.v1_1.features.ExtensionClient;
|
||||
import org.jclouds.openstack.nova.v1_1.features.ImageClient;
|
||||
import org.jclouds.openstack.nova.v1_1.features.ServerClient;
|
||||
|
@ -89,7 +89,7 @@ public class AdminActionsClientLiveTest extends BaseNovaClientLiveTest {
|
|||
|
||||
@AfterMethod(alwaysRun = true)
|
||||
public void ensureServerIsActiveAgain() {
|
||||
blockUntilServerInState(testServerId, serverClient, Server.Status.ACTIVE);
|
||||
blockUntilServerInState(testServerId, serverClient, Status.ACTIVE);
|
||||
}
|
||||
|
||||
public void testSuspendAndResume() {
|
||||
|
@ -103,14 +103,14 @@ public class AdminActionsClientLiveTest extends BaseNovaClientLiveTest {
|
|||
} catch (HttpResponseException e) {
|
||||
}
|
||||
assertTrue(client.suspendServer(testServerId));
|
||||
blockUntilServerInState(testServerId, serverClient, Server.Status.SUSPENDED);
|
||||
blockUntilServerInState(testServerId, serverClient, Status.SUSPENDED);
|
||||
try {
|
||||
client.suspendServer(testServerId);
|
||||
fail("Suspended an already suspended server!");
|
||||
} catch (HttpResponseException e) {
|
||||
}
|
||||
assertTrue(client.resumeServer(testServerId));
|
||||
blockUntilServerInState(testServerId, serverClient, Server.Status.ACTIVE);
|
||||
blockUntilServerInState(testServerId, serverClient, Status.ACTIVE);
|
||||
try {
|
||||
client.resumeServer(testServerId);
|
||||
fail("Resumed an already resumed server!");
|
||||
|
@ -153,14 +153,14 @@ public class AdminActionsClientLiveTest extends BaseNovaClientLiveTest {
|
|||
} catch (HttpResponseException e) {
|
||||
}
|
||||
assertTrue(client.pauseServer(testServerId));
|
||||
blockUntilServerInState(testServerId, serverClient, Server.Status.PAUSED);
|
||||
blockUntilServerInState(testServerId, serverClient, Status.PAUSED);
|
||||
try {
|
||||
client.pauseServer(testServerId);
|
||||
fail("paused a paused server!");
|
||||
} catch (HttpResponseException e) {
|
||||
}
|
||||
assertTrue(client.unpauseServer(testServerId));
|
||||
blockUntilServerInState(testServerId, serverClient, Server.Status.ACTIVE);
|
||||
blockUntilServerInState(testServerId, serverClient, Status.ACTIVE);
|
||||
try {
|
||||
client.unpauseServer(testServerId);
|
||||
fail("Unpaused a server we just unpaused!");
|
||||
|
@ -182,7 +182,7 @@ public class AdminActionsClientLiveTest extends BaseNovaClientLiveTest {
|
|||
Thread.sleep(30000);
|
||||
}
|
||||
|
||||
blockUntilServerInState(testServerId, serverClient, Server.Status.ACTIVE);
|
||||
blockUntilServerInState(testServerId, serverClient, Status.ACTIVE);
|
||||
|
||||
Image backupImage = imageClient.getImage(backupImageId);
|
||||
assertEquals(backupImage.getId(), backupImageId);
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.jclouds.openstack.nova.v1_1.NovaAsyncClient;
|
|||
import org.jclouds.openstack.nova.v1_1.NovaClient;
|
||||
import org.jclouds.openstack.nova.v1_1.config.NovaProperties;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Flavor;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.ServerCreated;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server.Status;
|
||||
import org.jclouds.openstack.nova.v1_1.features.FlavorClient;
|
||||
|
@ -78,9 +79,9 @@ public class BaseNovaClientLiveTest extends BaseComputeServiceContextLiveTest {
|
|||
|
||||
protected Server createServerInZone(String zoneId) {
|
||||
ServerClient serverClient = novaContext.getApi().getServerClientForZone(zoneId);
|
||||
Server server = serverClient.createServer("test", imageIdForZone(zoneId), flavorRefForZone(zoneId));
|
||||
ServerCreated server = serverClient.createServer("test", imageIdForZone(zoneId), flavorRefForZone(zoneId));
|
||||
blockUntilServerInState(server.getId(), serverClient, Status.ACTIVE);
|
||||
return server;
|
||||
return serverClient.getServer(server.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,7 +90,9 @@ public class BaseNovaClientLiveTest extends BaseComputeServiceContextLiveTest {
|
|||
*/
|
||||
protected void blockUntilServerInState(String serverId, ServerClient client, Status status) {
|
||||
Server currentDetails = null;
|
||||
for (currentDetails = client.getServer(serverId); currentDetails.getStatus() != status || currentDetails.getTaskState() != null; currentDetails = client
|
||||
for (currentDetails = client.getServer(serverId); currentDetails.getStatus() != status ||
|
||||
(currentDetails.getExtendedStatus().isPresent() && currentDetails.getExtendedStatus().get().getTaskState() != null);
|
||||
currentDetails = client
|
||||
.getServer(serverId)) {
|
||||
System.out.printf("blocking on status %s%n%s%n", status, currentDetails);
|
||||
try {
|
||||
|
|
|
@ -27,11 +27,12 @@ import org.jclouds.date.internal.SimpleDateFormatDateService;
|
|||
import org.jclouds.json.BaseItemParserTest;
|
||||
import org.jclouds.json.config.GsonModule;
|
||||
import org.jclouds.openstack.domain.Link;
|
||||
import org.jclouds.openstack.domain.Resource;
|
||||
import org.jclouds.openstack.domain.Link.Relation;
|
||||
import org.jclouds.openstack.domain.Resource;
|
||||
import org.jclouds.openstack.nova.v1_1.config.NovaParserModule;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server.Status;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.ServerCreated;
|
||||
import org.jclouds.rest.annotations.SelectJson;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
|
@ -42,7 +43,7 @@ import com.google.inject.Injector;
|
|||
* @author Adrian Cole
|
||||
*/
|
||||
@Test(groups = "unit", testName = "ParseCreatedServerTest")
|
||||
public class ParseCreatedServerTest extends BaseItemParserTest<Server> {
|
||||
public class ParseCreatedServerTest extends BaseItemParserTest<ServerCreated> {
|
||||
|
||||
@Override
|
||||
public String resource() {
|
||||
|
@ -52,36 +53,12 @@ public class ParseCreatedServerTest extends BaseItemParserTest<Server> {
|
|||
@Override
|
||||
@SelectJson("server")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Server expected() {
|
||||
return Server
|
||||
public ServerCreated expected() {
|
||||
return ServerCreated
|
||||
.builder()
|
||||
.id("71752")
|
||||
.uuid("47491020-6a78-4f63-9475-23195ac4515c")
|
||||
.tenantId("37936628937291")
|
||||
.userId("54297837463082")
|
||||
.name("test-e92")
|
||||
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-03-19T06:21:13Z"))
|
||||
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-03-19T06:21:13Z"))
|
||||
.status(Status.BUILD)
|
||||
.adminPass("ZWuHcmTMQ7eXoHeM")
|
||||
.image(
|
||||
Resource
|
||||
.builder()
|
||||
.id("1241")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/images/1241")))
|
||||
.build())
|
||||
.flavor(
|
||||
Resource
|
||||
.builder()
|
||||
.id("100")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/flavors/100")))
|
||||
.build())
|
||||
.links(
|
||||
Link.create(Relation.SELF, URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/v1.1/37936628937291/servers/71752")),
|
||||
Link.create(Relation.BOOKMARK, URI.create("https://az-1.region-a.geo-1.compute.hpcloudsvc.com/37936628937291/servers/71752"))).build();
|
||||
|
|
|
@ -33,6 +33,8 @@ import org.jclouds.openstack.domain.Link.Relation;
|
|||
import org.jclouds.openstack.nova.v1_1.config.NovaParserModule;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Address;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server.Status;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.ServerExtendedStatus;
|
||||
import org.jclouds.rest.annotations.SelectJson;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
|
@ -59,102 +61,108 @@ public class ParseServerDetailsEssexTest extends BaseSetParserTest<Server> {
|
|||
return ImmutableSet.<Server>of(
|
||||
Server.builder()
|
||||
.addresses(ImmutableMultimap.<String, Address>builder()
|
||||
.putAll("Net TenantA Front-Middle", Address.createV4("172.16.11.5"))
|
||||
.putAll("Public network", Address.createV4("172.16.1.13"), Address.createV4("10.193.112.119")).build())
|
||||
.putAll("Net TenantA Front-Middle", Address.createV4("172.16.11.5"))
|
||||
.putAll("Public network", Address.createV4("172.16.1.13"), Address.createV4("10.193.112.119")).build())
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.SELF,
|
||||
URI.create("http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/0c80b392-db30-4736-ae02-4480090f1207")),
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/0c80b392-db30-4736-ae02-4480090f1207")))
|
||||
Link.create(
|
||||
Relation.SELF,
|
||||
URI.create("http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/0c80b392-db30-4736-ae02-4480090f1207")),
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/0c80b392-db30-4736-ae02-4480090f1207")))
|
||||
.image(
|
||||
Resource.builder()
|
||||
.id("416af940-2d3c-4a7c-977c-a9030685ad5e")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e"))).build())
|
||||
Resource.builder()
|
||||
.id("416af940-2d3c-4a7c-977c-a9030685ad5e")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e"))).build())
|
||||
.flavor(
|
||||
Resource.builder()
|
||||
.id("1")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1"))).build())
|
||||
Resource.builder()
|
||||
.id("1")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1"))).build())
|
||||
.id("0c80b392-db30-4736-ae02-4480090f1207")
|
||||
.userId("df13814f6c354d00a8acf66502836323")
|
||||
.status(Server.Status.ACTIVE)
|
||||
.status(Status.ACTIVE)
|
||||
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:21:33Z"))
|
||||
.hostId("03d796ebb52b1b555e5f6d9262f7dbd52b3f7c181e3aa89b34ca5408")
|
||||
.name("VM proxy")
|
||||
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:21:23Z"))
|
||||
.tenantId("8d10e6646d5d4585937395b04839a353").build(),
|
||||
.tenantId("8d10e6646d5d4585937395b04839a353")
|
||||
.extendedStatus(ServerExtendedStatus.builder().vmState("active").powerState(1).build())
|
||||
.diskConfig("MANUAL").build(),
|
||||
Server.builder()
|
||||
.addresses(ImmutableMultimap.<String, Address>builder()
|
||||
.putAll("Net TenantA Front-Middle", Address.createV4("172.16.11.4"))
|
||||
.putAll("Net TenantA Middle-Back", Address.createV4("172.16.12.5")).build())
|
||||
.putAll("Net TenantA Front-Middle", Address.createV4("172.16.11.4"))
|
||||
.putAll("Net TenantA Middle-Back", Address.createV4("172.16.12.5")).build())
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.SELF,
|
||||
URI.create("http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/b332b5cd-535e-4677-b68e-fc8badc13236")),
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/b332b5cd-535e-4677-b68e-fc8badc13236")))
|
||||
Link.create(
|
||||
Relation.SELF,
|
||||
URI.create("http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/b332b5cd-535e-4677-b68e-fc8badc13236")),
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/b332b5cd-535e-4677-b68e-fc8badc13236")))
|
||||
.image(
|
||||
Resource.builder()
|
||||
.id("416af940-2d3c-4a7c-977c-a9030685ad5e")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e"))).build())
|
||||
Resource.builder()
|
||||
.id("416af940-2d3c-4a7c-977c-a9030685ad5e")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e"))).build())
|
||||
.flavor(
|
||||
Resource.builder()
|
||||
.id("1")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1"))).build())
|
||||
Resource.builder()
|
||||
.id("1")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1"))).build())
|
||||
.id("b332b5cd-535e-4677-b68e-fc8badc13236")
|
||||
.userId("df13814f6c354d00a8acf66502836323")
|
||||
.status(Server.Status.ACTIVE)
|
||||
.status(Status.ACTIVE)
|
||||
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:18:58Z"))
|
||||
.hostId("e5bbff80bebacfe1db63951e787b5341427060a602d33abfefb6a1bc")
|
||||
.name("VM blog")
|
||||
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:18:48Z"))
|
||||
.tenantId("8d10e6646d5d4585937395b04839a353").build(),
|
||||
Server.builder()
|
||||
.tenantId("8d10e6646d5d4585937395b04839a353")
|
||||
.extendedStatus(ServerExtendedStatus.builder().vmState("active").powerState(1).build())
|
||||
.diskConfig("MANUAL").build(),
|
||||
Server.builder()
|
||||
.addresses(ImmutableMultimap.<String, Address>builder()
|
||||
.putAll("Net TenantA Middle-Back", Address.createV4("172.16.12.4")).build())
|
||||
.putAll("Net TenantA Middle-Back", Address.createV4("172.16.12.4")).build())
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.SELF,
|
||||
URI.create("http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/f9d43436-4572-4c9b-9b74-5fa6890a2f21")),
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/f9d43436-4572-4c9b-9b74-5fa6890a2f21")))
|
||||
Link.create(
|
||||
Relation.SELF,
|
||||
URI.create("http://nova:8774/v1.1/8d10e6646d5d4585937395b04839a353/servers/f9d43436-4572-4c9b-9b74-5fa6890a2f21")),
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/servers/f9d43436-4572-4c9b-9b74-5fa6890a2f21")))
|
||||
.image(
|
||||
Resource.builder()
|
||||
.id("416af940-2d3c-4a7c-977c-a9030685ad5e")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e"))).build())
|
||||
Resource.builder()
|
||||
.id("416af940-2d3c-4a7c-977c-a9030685ad5e")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/images/416af940-2d3c-4a7c-977c-a9030685ad5e"))).build())
|
||||
.flavor(
|
||||
Resource.builder()
|
||||
.id("1")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1"))).build())
|
||||
Resource.builder()
|
||||
.id("1")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://nova:8774/8d10e6646d5d4585937395b04839a353/flavors/1"))).build())
|
||||
.id("f9d43436-4572-4c9b-9b74-5fa6890a2f21")
|
||||
.userId("df13814f6c354d00a8acf66502836323")
|
||||
.status(Server.Status.ACTIVE)
|
||||
.status(Status.ACTIVE)
|
||||
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:15:09Z"))
|
||||
.hostId("03d796ebb52b1b555e5f6d9262f7dbd52b3f7c181e3aa89b34ca5408")
|
||||
.name("VM MySQL")
|
||||
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-04-12T11:14:56Z"))
|
||||
.tenantId("8d10e6646d5d4585937395b04839a353").build());
|
||||
.tenantId("8d10e6646d5d4585937395b04839a353")
|
||||
.extendedStatus(ServerExtendedStatus.builder().vmState("active").powerState(1).build())
|
||||
.diskConfig("MANUAL").build());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.openstack.nova.v1_1.parse;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import javax.ws.rs.Consumes;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
|
||||
import org.jclouds.date.internal.SimpleDateFormatDateService;
|
||||
import org.jclouds.json.BaseItemParserTest;
|
||||
import org.jclouds.json.config.GsonModule;
|
||||
import org.jclouds.openstack.domain.Link;
|
||||
import org.jclouds.openstack.domain.Link.Relation;
|
||||
import org.jclouds.openstack.domain.Resource;
|
||||
import org.jclouds.openstack.nova.v1_1.config.NovaParserModule;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Address;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.Server.Status;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.ServerExtendedAttributes;
|
||||
import org.jclouds.openstack.nova.v1_1.domain.ServerExtendedStatus;
|
||||
import org.jclouds.rest.annotations.SelectJson;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.Injector;
|
||||
|
||||
/**
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
@Test(groups = "unit", testName = "ParseServerWithAllExtensionsTest")
|
||||
public class ParseServerWithAllExtensionsTest extends BaseItemParserTest<Server> {
|
||||
|
||||
@Override
|
||||
public String resource() {
|
||||
return "/server_details_devstack.json";
|
||||
}
|
||||
|
||||
@Override
|
||||
@SelectJson("server")
|
||||
@Consumes(MediaType.APPLICATION_JSON)
|
||||
public Server expected() {
|
||||
return Server
|
||||
.builder()
|
||||
.id("141b775f-7ac1-45f0-9a95-146260f33a53")
|
||||
.tenantId("7f312675f9b84c97bff8f5054e181419")
|
||||
.userId("89c01b67395d4bea945f7f5bfd7f344a")
|
||||
.name("test")
|
||||
.updated(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-05-04T15:07:48Z"))
|
||||
.created(new SimpleDateFormatDateService().iso8601SecondsDateParse("2012-05-04T15:07:36Z"))
|
||||
.hostId("eab9a77d1c44b8833e4a3dc6d2d9d50de556e780a319f184d8c82d9b")
|
||||
.status(Status.PAUSED)
|
||||
.image(
|
||||
Resource
|
||||
.builder()
|
||||
.id("8e6f5bc4-a210-45b2-841f-c510eae14300")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://172.16.89.149:8774/7f312675f9b84c97bff8f5054e181419/images/8e6f5bc4-a210-45b2-841f-c510eae14300")))
|
||||
.build())
|
||||
.flavor(
|
||||
Resource
|
||||
.builder()
|
||||
.id("1")
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://172.16.89.149:8774/7f312675f9b84c97bff8f5054e181419/flavors/1")))
|
||||
.build())
|
||||
.links(
|
||||
Link.create(
|
||||
Relation.SELF,
|
||||
URI.create("http://172.16.89.149:8774/v2/7f312675f9b84c97bff8f5054e181419/servers/141b775f-7ac1-45f0-9a95-146260f33a53")),
|
||||
Link.create(
|
||||
Relation.BOOKMARK,
|
||||
URI.create("http://172.16.89.149:8774/7f312675f9b84c97bff8f5054e181419/servers/141b775f-7ac1-45f0-9a95-146260f33a53")))
|
||||
.addresses(ImmutableMultimap.of("private", Address.createV4("10.0.0.8")))
|
||||
.diskConfig("MANUAL")
|
||||
.extendedStatus(ServerExtendedStatus.builder().vmState("paused").powerState(3).build())
|
||||
.extraAttributes(ServerExtendedAttributes.builder().instanceName("instance-00000014").hostName("ubuntu").build())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
protected Injector injector() {
|
||||
return Guice.createInjector(new NovaParserModule(), new GsonModule());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
{"server": {
|
||||
"OS-EXT-STS:task_state": null,
|
||||
"addresses": {
|
||||
"private": [{"version": 4, "addr": "10.0.0.8"}]
|
||||
},
|
||||
"links":
|
||||
[
|
||||
{
|
||||
"href": "http://172.16.89.149:8774/v2/7f312675f9b84c97bff8f5054e181419/servers/141b775f-7ac1-45f0-9a95-146260f33a53", "rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://172.16.89.149:8774/7f312675f9b84c97bff8f5054e181419/servers/141b775f-7ac1-45f0-9a95-146260f33a53", "rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"image": {
|
||||
"id": "8e6f5bc4-a210-45b2-841f-c510eae14300", "links": [
|
||||
{
|
||||
"href": "http://172.16.89.149:8774/7f312675f9b84c97bff8f5054e181419/images/8e6f5bc4-a210-45b2-841f-c510eae14300", "rel": "bookmark"
|
||||
}]
|
||||
},
|
||||
"OS-EXT-STS:vm_state": "paused",
|
||||
"OS-EXT-SRV-ATTR:instance_name": "instance-00000014",
|
||||
"flavor": {
|
||||
"id": "1",
|
||||
"links": [{"href": "http://172.16.89.149:8774/7f312675f9b84c97bff8f5054e181419/flavors/1", "rel": "bookmark"}]
|
||||
},
|
||||
"id": "141b775f-7ac1-45f0-9a95-146260f33a53",
|
||||
"user_id": "89c01b67395d4bea945f7f5bfd7f344a",
|
||||
"OS-DCF:diskConfig": "MANUAL",
|
||||
"accessIPv4": "",
|
||||
"accessIPv6": "",
|
||||
"OS-EXT-STS:power_state": 3,
|
||||
"config_drive": "",
|
||||
"status": "PAUSED",
|
||||
"updated": "2012-05-04T15:07:48Z",
|
||||
"hostId": "eab9a77d1c44b8833e4a3dc6d2d9d50de556e780a319f184d8c82d9b",
|
||||
"OS-EXT-SRV-ATTR:host": "ubuntu",
|
||||
"key_name": "",
|
||||
"OS-EXT-SRV-ATTR:hypervisor_hostname": null,
|
||||
"name": "test",
|
||||
"created": "2012-05-04T15:07:36Z",
|
||||
"tenant_id": "7f312675f9b84c97bff8f5054e181419",
|
||||
"metadata": {}
|
||||
}}
|
|
@ -116,6 +116,12 @@ public class Resource implements Comparable<Resource> {
|
|||
this.links = ImmutableSet.copyOf(checkNotNull(builder.links, "links"));
|
||||
}
|
||||
|
||||
protected Resource() {
|
||||
this.id = null;
|
||||
this.name = null;
|
||||
this.links = ImmutableSet.of();
|
||||
}
|
||||
|
||||
/**
|
||||
* When providing an ID, it is assumed that the resource exists in the current OpenStack
|
||||
* deployment
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.jclouds.json.Json;
|
|||
import org.jclouds.json.internal.EnumTypeAdapterThatReturnsFromValue;
|
||||
import org.jclouds.json.internal.GsonWrapper;
|
||||
import org.jclouds.json.internal.NullHackJsonLiteralAdapter;
|
||||
import org.jclouds.json.internal.OptionalTypeAdapterFactory;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableMap.Builder;
|
||||
|
@ -75,6 +76,7 @@ public class GsonModule extends AbstractModule {
|
|||
}.getType(), byteListAdapter.nullSafe());
|
||||
builder.registerTypeAdapter(byte[].class, byteArrayAdapter.nullSafe());
|
||||
builder.registerTypeAdapter(JsonBall.class, jsonAdapter.nullSafe());
|
||||
builder.registerTypeAdapterFactory(new OptionalTypeAdapterFactory());
|
||||
|
||||
// complicated (serializers/deserializers as they need context to operate)
|
||||
builder.registerTypeHierarchyAdapter(Enum.class, new EnumTypeAdapterThatReturnsFromValue());
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.json.internal;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.TypeAdapter;
|
||||
import com.google.gson.TypeAdapterFactory;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.google.gson.stream.JsonReader;
|
||||
import com.google.gson.stream.JsonToken;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
/**
|
||||
* Writes and reads Optional values as JSON
|
||||
*
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
public class OptionalTypeAdapterFactory implements TypeAdapterFactory {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
|
||||
Type type = typeToken.getType();
|
||||
if (typeToken.getRawType() != Optional.class || !(type instanceof ParameterizedType)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||
TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
|
||||
return (TypeAdapter<T>) newMultisetAdapter(elementAdapter);
|
||||
}
|
||||
|
||||
private <E> TypeAdapter<Optional<E>> newMultisetAdapter(
|
||||
final TypeAdapter<E> elementAdapter) {
|
||||
return new TypeAdapter<Optional<E>>() {
|
||||
public void write(JsonWriter out, Optional<E> value) throws IOException {
|
||||
if (!value.isPresent()) {
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
elementAdapter.write(out, value.get());
|
||||
}
|
||||
|
||||
public Optional<E> read(JsonReader in) throws IOException {
|
||||
Optional<E> result = Optional.absent();
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
} else {
|
||||
E element = elementAdapter.read(in);
|
||||
if (element != null) {
|
||||
result = Optional.of(element);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
/**
|
||||
* Licensed to jclouds, Inc. (jclouds) under one or more
|
||||
* contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. jclouds licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.jclouds.json.internal;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
import static org.testng.Assert.assertNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
|
||||
/**
|
||||
* Tests to verify and illustrate the behavior of the OptionalTypeAdaptorFactory.
|
||||
*
|
||||
* @author Adam Lowe
|
||||
*/
|
||||
@Test(testName = "OptionalTypeAdapterFactoryTest")
|
||||
public class OptionalTypeAdapterFactoryTest {
|
||||
|
||||
/**
|
||||
* Simple type with an Optional field
|
||||
*/
|
||||
static class SimpleBean {
|
||||
private Optional<String> value;
|
||||
private final String someOtherValue;
|
||||
|
||||
public SimpleBean(Optional<String> value, String someOtherValue) {
|
||||
this.value = value;
|
||||
this.someOtherValue = someOtherValue;
|
||||
}
|
||||
|
||||
// Required to ensure GSON doesn't initialize our Optional to null!
|
||||
private SimpleBean() {
|
||||
this.value = Optional.absent();
|
||||
this.someOtherValue = null;
|
||||
}
|
||||
|
||||
public Optional<String> getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getSomeOtherValue() {
|
||||
return someOtherValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(value, someOtherValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object that) {
|
||||
if (that == null || that.getClass() != getClass())
|
||||
return false;
|
||||
SimpleBean other = (SimpleBean) that;
|
||||
return Objects.equal(value, other.value) && Objects.equal(someOtherValue, other.someOtherValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return Objects.toStringHelper("SimpleBean").add("value", value).add("someOtherValue", someOtherValue).toString();
|
||||
}
|
||||
}
|
||||
|
||||
// register the type adapter so that gson can serialize/deserialize to it
|
||||
private Gson gsonAdapter = new GsonBuilder().registerTypeAdapterFactory(new OptionalTypeAdapterFactory()).create();
|
||||
|
||||
public void testValuePresent() {
|
||||
String json = "{\"value\":\"a test string!\"}";
|
||||
SimpleBean expected = new SimpleBean(Optional.of("a test string!"), null);
|
||||
|
||||
SimpleBean actual = gsonAdapter.fromJson(json, SimpleBean.class);
|
||||
|
||||
assertTrue(actual.value.isPresent());
|
||||
assertEquals(actual.getValue().get(), "a test string!");
|
||||
assertNull(actual.getSomeOtherValue());
|
||||
|
||||
assertEquals(actual, expected);
|
||||
assertEquals(gsonAdapter.toJson(actual), json);
|
||||
}
|
||||
|
||||
public void testValueAbsent() {
|
||||
String json = "{\"someOtherValue\":\"testvalue\"}";
|
||||
SimpleBean expected = new SimpleBean(Optional.<String>absent(), "testvalue");
|
||||
|
||||
SimpleBean actual = gsonAdapter.fromJson(json, SimpleBean.class);
|
||||
|
||||
assertFalse(actual.value.isPresent());
|
||||
assertEquals(actual.getSomeOtherValue(), "testvalue");
|
||||
|
||||
assertEquals(actual, expected);
|
||||
assertEquals(gsonAdapter.toJson(actual), json);
|
||||
}
|
||||
|
||||
public void testValueNull() {
|
||||
String json = "{\"value\":null}";
|
||||
SimpleBean expected = new SimpleBean(Optional.<String>absent(), null);
|
||||
|
||||
SimpleBean actual = gsonAdapter.fromJson(json, SimpleBean.class);
|
||||
|
||||
assertFalse(actual.value.isPresent());
|
||||
assertNull(actual.getSomeOtherValue());
|
||||
|
||||
assertEquals(actual, expected);
|
||||
// Note: the field is omitted from serialized form!
|
||||
assertEquals(gsonAdapter.toJson(actual), "{}");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue