blob: bde077adffa3843181660ec11cf5f6294018fb89 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jclouds.openstack.nova.v2_0.config;
import java.beans.ConstructorProperties;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import javax.inject.Singleton;
import com.google.common.collect.Maps;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import org.jclouds.javax.annotation.Nullable;
import org.jclouds.json.config.GsonModule;
import org.jclouds.json.config.GsonModule.DateAdapter;
import org.jclouds.openstack.nova.v2_0.domain.Address;
import org.jclouds.openstack.nova.v2_0.domain.BlockDeviceMapping;
import org.jclouds.openstack.nova.v2_0.domain.HostResourceUsage;
import org.jclouds.openstack.nova.v2_0.domain.Image;
import org.jclouds.openstack.nova.v2_0.domain.Server;
import org.jclouds.openstack.nova.v2_0.domain.ServerExtendedAttributes;
import org.jclouds.openstack.nova.v2_0.domain.ServerExtendedStatus;
import org.jclouds.openstack.nova.v2_0.domain.ServerWithSecurityGroups;
import org.jclouds.openstack.v2_0.domain.Link;
import org.jclouds.openstack.v2_0.domain.Resource;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.inject.AbstractModule;
import com.google.inject.Provides;
public class NovaParserModule extends AbstractModule {
@Provides
@Singleton
public final Map<Type, Object> provideCustomAdapterBindings() {
return ImmutableMap.<Type, Object>of(
HostResourceUsage.class, new HostResourceUsageAdapter(),
ServerWithSecurityGroups.class, new ServerWithSecurityGroupsAdapter(),
Server.class, new ServerAdapter(),
Image.class, new ImageAdapter()
);
}
@Override
protected void configure() {
bind(DateAdapter.class).to(GsonModule.Iso8601DateAdapter.class);
}
@Singleton
public static class HostResourceUsageAdapter implements JsonSerializer<HostResourceUsage>, JsonDeserializer<HostResourceUsage> {
public HostResourceUsage apply(HostResourceUsageView in) {
return in.resource.toBuilder().build();
}
@Override
public HostResourceUsage deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException {
return apply((HostResourceUsageView) context.deserialize(jsonElement, HostResourceUsageView.class));
}
@Override
public JsonElement serialize(HostResourceUsage hostResourceUsage, Type type, JsonSerializationContext context) {
return context.serialize(hostResourceUsage);
}
private static class HostResourceUsageView {
protected HostResourceUsageInternal resource;
}
private static class HostResourceUsageInternal extends HostResourceUsage {
@ConstructorProperties({
"host", "project", "memory_mb", "cpu", "disk_gb"
})
protected HostResourceUsageInternal(String host, @Nullable String project, int memoryMb, int cpu, int diskGb) {
super(host, project, memoryMb, cpu, diskGb);
}
}
}
@Singleton
public static class ServerWithSecurityGroupsAdapter implements JsonDeserializer<ServerWithSecurityGroups> {
@Override
public ServerWithSecurityGroups deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context)
throws JsonParseException {
Server server = context.deserialize(jsonElement, Server.class);
ServerWithSecurityGroups.Builder<?> result = ServerWithSecurityGroups.builder().fromServer(server);
Set<String> names = Sets.newLinkedHashSet();
if (jsonElement.getAsJsonObject().get("security_groups") != null) {
JsonArray x = jsonElement.getAsJsonObject().get("security_groups").getAsJsonArray();
for (JsonElement y : x) {
names.add(y.getAsJsonObject().get("name").getAsString());
}
result.securityGroupNames(names);
}
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;
// Servers can be created without an image so test if an image object is returned
if (jsonElement.getAsJsonObject().get("image").isJsonObject()) {
serverBase = apply((ServerInternal) context.deserialize(jsonElement, ServerInternal.class));
} else {
serverBase = apply((ServerInternalWithoutImage) context.deserialize(jsonElement, ServerInternalWithoutImage.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.extendedAttributes(extraAttributes);
}
return result.build();
}
public Server apply(Server in) {
return in.toBuilder().build();
}
private static class ServerInternal extends Server {
@ConstructorProperties({"id", "name", "links", "uuid", "tenant_id", "user_id", "updated", "created", "hostId", "accessIPv4", "accessIPv6", "status", "image", "flavor", "key_name", "config_drive", "addresses", "metadata", "extendedStatus", "extendedAttributes", "OS-DCF:diskConfig", "OS-EXT-AZ:availability_zone"})
protected ServerInternal(String id, @Nullable String name, java.util.Set<Link> links, @Nullable String uuid, String tenantId,
String userId, Date updated, Date created, @Nullable String hostId, @Nullable String accessIPv4,
@Nullable String accessIPv6, Server.Status status, Resource image, Resource flavor, @Nullable String keyName,
@Nullable String configDrive, Multimap<String, Address> addresses, Map<String, String> metadata,
@Nullable ServerExtendedStatus extendedStatus, @Nullable ServerExtendedAttributes extendedAttributes, @Nullable String diskConfig, @Nullable String availabilityZone) {
super(id, name, links, uuid, tenantId, userId, updated, created, hostId, accessIPv4, accessIPv6, status, image, flavor, keyName, configDrive, addresses, metadata, extendedStatus, extendedAttributes, diskConfig, availabilityZone);
}
}
private static class ServerInternalWithoutImage extends Server {
@ConstructorProperties({"id", "name", "links", "uuid", "tenant_id", "user_id", "updated", "created", "hostId", "accessIPv4", "accessIPv6", "status", "flavor", "key_name", "config_drive", "addresses", "metadata", "extendedStatus", "extendedAttributes", "OS-DCF:diskConfig", "OS-EXT-AZ:availability_zone"})
protected ServerInternalWithoutImage(String id, @Nullable String name, java.util.Set<Link> links, @Nullable String uuid, String tenantId,
String userId, Date updated, Date created, @Nullable String hostId, @Nullable String accessIPv4,
@Nullable String accessIPv6, Server.Status status, Resource flavor, @Nullable String keyName,
@Nullable String configDrive, Multimap<String, Address> addresses, Map<String, String> metadata,
@Nullable ServerExtendedStatus extendedStatus, @Nullable ServerExtendedAttributes extendedAttributes, @Nullable String diskConfig, @Nullable String availabilityZone) {
super(id, name, links, uuid, tenantId, userId, updated, created, hostId, accessIPv4, accessIPv6, status, null, flavor, keyName, configDrive, addresses, metadata, extendedStatus, extendedAttributes, diskConfig, availabilityZone);
}
}
}
@Singleton
public static class ImageAdapter implements JsonDeserializer<Image> {
public static final String METADATA = "metadata";
public static final String BLOCK_DEVICE_MAPPING = "block_device_mapping";
@Override
public Image deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context)
throws JsonParseException {
JsonObject json = jsonElement.getAsJsonObject();
Map<String, String> metadata = null;
List<BlockDeviceMapping> blockDeviceMapping = null;
JsonElement meta = json.get(METADATA);
if (meta != null && meta.isJsonObject()) {
metadata = Maps.newTreeMap();
for (Map.Entry<String, JsonElement> e : meta.getAsJsonObject().entrySet()) {
Object value;
if (e.getValue().isJsonArray()) {
value = context.deserialize(e.getValue().getAsJsonArray(), ArrayList.class);
} else if (e.getValue().isJsonObject()) {
value = context.deserialize(e.getValue().getAsJsonObject(), TreeMap.class);
} else if (e.getValue().isJsonPrimitive()) {
value = e.getValue().getAsJsonPrimitive().getAsString();
} else {
continue;
}
//keep non-string members out of normal metadata
if (value instanceof String) {
metadata.put(e.getKey(), (String) value);
} else if (value instanceof List && BLOCK_DEVICE_MAPPING.equals(e.getKey())) {
blockDeviceMapping = context.deserialize(e.getValue(), new TypeToken<List<BlockDeviceMapping>>(){}.getType());
}
}
json.remove(METADATA);
}
return apply(context.<ImageInternal>deserialize(json, ImageInternal.class), metadata, blockDeviceMapping);
}
public Image apply(ImageInternal in, Map<String, String> metadata, List<BlockDeviceMapping> blockDeviceMapping) {
return in.toBuilder().metadata(metadata).blockDeviceMapping(blockDeviceMapping).build();
}
private static class ImageInternal extends Image {
@ConstructorProperties({
"id", "name", "links", "updated", "created", "tenant_id", "user_id", "status", "progress", "minDisk", "minRam", "blockDeviceMapping", "server", "metadata"
})
protected ImageInternal(String id, @Nullable String name, java.util.Set<Link> links, @Nullable Date updated, @Nullable Date created,
String tenantId, @Nullable String userId, @Nullable Status status, int progress, int minDisk, int minRam,
@Nullable List<BlockDeviceMapping> blockDeviceMapping, @Nullable Resource server, @Nullable Map<String, String> metadata) {
super(id, name, links, updated, created, tenantId, userId, status, progress, minDisk, minRam, blockDeviceMapping, server, metadata);
}
}
}
}