1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.jclouds.trmk.vcloud_0_8.binders;
20
21 import static com.google.common.base.Preconditions.checkArgument;
22 import static com.google.common.base.Preconditions.checkNotNull;
23 import static com.google.common.base.Preconditions.checkState;
24 import static com.google.common.collect.Iterables.filter;
25 import static com.google.common.collect.Iterables.find;
26 import static org.jclouds.Constants.PROPERTY_API_VERSION;
27 import static org.jclouds.trmk.vcloud_0_8.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE;
28 import static org.jclouds.trmk.vcloud_0_8.reference.VCloudConstants.PROPERTY_VCLOUD_XML_SCHEMA;
29
30 import java.net.URI;
31 import java.util.Map;
32 import java.util.Properties;
33
34 import javax.inject.Named;
35 import javax.inject.Singleton;
36 import javax.xml.parsers.FactoryConfigurationError;
37 import javax.xml.parsers.ParserConfigurationException;
38 import javax.xml.transform.TransformerException;
39
40 import org.jclouds.cim.CIMPredicates;
41 import org.jclouds.cim.ResourceAllocationSettingData;
42 import org.jclouds.cim.ResourceAllocationSettingData.ResourceType;
43 import org.jclouds.http.HttpRequest;
44 import org.jclouds.rest.MapBinder;
45 import org.jclouds.rest.binders.BindToStringPayload;
46 import org.jclouds.rest.internal.GeneratedHttpRequest;
47 import org.jclouds.trmk.vcloud_0_8.domain.Status;
48 import org.jclouds.trmk.vcloud_0_8.domain.VAppConfiguration;
49 import org.jclouds.trmk.vcloud_0_8.domain.VApp;
50
51 import com.google.common.base.Function;
52 import com.google.inject.Inject;
53 import com.jamesmurty.utils.XMLBuilder;
54
55
56
57
58
59
60 @Singleton
61 public class BindVAppConfigurationToXmlPayload implements MapBinder, Function<Object, URI> {
62
63 private static final String RESOURCE_ALLOCATION_NS = "http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData";
64
65 protected final String ns;
66 protected final String schema;
67 protected final BindToStringPayload stringBinder;
68 protected final String apiVersion;
69
70 @Inject
71 public BindVAppConfigurationToXmlPayload(@Named(PROPERTY_API_VERSION) String apiVersion,
72 BindToStringPayload stringBinder, @Named(PROPERTY_VCLOUD_XML_NAMESPACE) String ns,
73 @Named(PROPERTY_VCLOUD_XML_SCHEMA) String schema) {
74 this.apiVersion = apiVersion;
75 this.ns = ns;
76 this.schema = schema;
77 this.stringBinder = stringBinder;
78 }
79
80 @Override
81 public <R extends HttpRequest> R bindToRequest(R request, Map<String, String> postParams) {
82 checkArgument(checkNotNull(request, "request") instanceof GeneratedHttpRequest<?>,
83 "this binder is only valid for GeneratedHttpRequests!");
84 GeneratedHttpRequest<?> gRequest = (GeneratedHttpRequest<?>) request;
85 checkState(gRequest.getArgs() != null, "args should be initialized at this point");
86
87 VApp vApp = checkNotNull(findVAppInArgsOrNull(gRequest), "vApp");
88 checkArgument(vApp.getStatus() == Status.OFF, "vApp must be off!");
89 VAppConfiguration configuration = checkNotNull(findConfigInArgsOrNull(gRequest), "config");
90
91 try {
92 return stringBinder.bindToRequest(request, generateXml(vApp, configuration));
93 } catch (ParserConfigurationException e) {
94 throw new RuntimeException(e);
95 } catch (FactoryConfigurationError e) {
96 throw new RuntimeException(e);
97 } catch (TransformerException e) {
98 throw new RuntimeException(e);
99 }
100
101 }
102
103 protected String generateXml(VApp vApp, VAppConfiguration configuration)
104 throws ParserConfigurationException, FactoryConfigurationError, TransformerException {
105 String name = configuration.getName() != null ? configuration.getName() : vApp.getName();
106
107 XMLBuilder rootBuilder = buildRoot(vApp, name);
108
109 XMLBuilder sectionBuilder = rootBuilder.e("Section").a("xsi:type", "VirtualHardwareSection_Type").a("xmlns",
110 "http://schemas.dmtf.org/ovf/envelope/1").a("xmlns:q2", "http://www.vmware.com/vcloud/v1");
111 sectionBuilder.e("Info").t("Virtual Hardware");
112
113 addProcessorItem(sectionBuilder, vApp, configuration);
114 addMemoryItem(sectionBuilder, vApp, configuration);
115 addDiskItems(sectionBuilder, vApp, configuration);
116
117 Properties outputProperties = new Properties();
118 outputProperties.put(javax.xml.transform.OutputKeys.OMIT_XML_DECLARATION, "yes");
119 return rootBuilder.asString(outputProperties);
120 }
121
122 private void addProcessorItem(XMLBuilder sectionBuilder, VApp vApp, VAppConfiguration configuration) {
123 ResourceAllocationSettingData cpu = find(vApp.getResourceAllocations(), CIMPredicates
124 .resourceTypeIn(ResourceType.PROCESSOR));
125 long quantity = configuration.getProcessorCount() != null ? configuration.getProcessorCount() : cpu
126 .getVirtualQuantity();
127 addResourceWithQuantity(sectionBuilder, cpu, quantity);
128 }
129
130 private void addMemoryItem(XMLBuilder sectionBuilder, VApp vApp, VAppConfiguration configuration) {
131 ResourceAllocationSettingData memory = find(vApp.getResourceAllocations(), CIMPredicates
132 .resourceTypeIn(ResourceType.MEMORY));
133 long quantity = configuration.getMemory() != null ? configuration.getMemory() : memory.getVirtualQuantity();
134 addResourceWithQuantity(sectionBuilder, memory, quantity);
135 }
136
137 private void addDiskItems(XMLBuilder sectionBuilder, VApp vApp, VAppConfiguration configuration) {
138 for (ResourceAllocationSettingData disk : filter(vApp.getResourceAllocations(), CIMPredicates
139 .resourceTypeIn(ResourceType.DISK_DRIVE))) {
140 if (!configuration.getDisksToDelete().contains(new Integer(disk.getAddressOnParent()))) {
141 addDiskWithQuantity(sectionBuilder, disk);
142 }
143 }
144 for (Long quantity : configuration.getDisks()) {
145 ResourceAllocationSettingData disk = ResourceAllocationSettingData.builder().instanceID("9").addressOnParent(
146 "-1").elementName("").resourceType(ResourceType.DISK_DRIVE).virtualQuantity(quantity).build();
147 addDiskWithQuantity(sectionBuilder, disk);
148 }
149 }
150
151 private XMLBuilder addResourceWithQuantity(XMLBuilder sectionBuilder, ResourceAllocationSettingData resource,
152 long quantity) {
153 XMLBuilder itemBuilder = sectionBuilder.e("Item");
154 addCommonElements(itemBuilder, resource, quantity);
155 return itemBuilder;
156 }
157
158 private void addCommonElements(XMLBuilder itemBuilder, ResourceAllocationSettingData resource, long quantity) {
159 itemBuilder.e("InstanceID").a("xmlns", RESOURCE_ALLOCATION_NS).t(resource.getInstanceID() + "");
160 itemBuilder.e("ResourceType").a("xmlns", RESOURCE_ALLOCATION_NS).t(resource.getResourceType().value());
161 itemBuilder.e("VirtualQuantity").a("xmlns", RESOURCE_ALLOCATION_NS).t(quantity + "");
162 }
163
164 private XMLBuilder addDiskWithQuantity(XMLBuilder sectionBuilder, ResourceAllocationSettingData disk) {
165 XMLBuilder itemBuilder = sectionBuilder.e("Item");
166 itemBuilder.e("AddressOnParent").a("xmlns", RESOURCE_ALLOCATION_NS).t(disk.getAddressOnParent() + "");
167 for (String hostResource : disk.getHostResources())
168 itemBuilder.e("HostResource").a("xmlns", RESOURCE_ALLOCATION_NS).t(hostResource);
169 addCommonElements(itemBuilder, disk, disk.getVirtualQuantity());
170 return itemBuilder;
171 }
172
173 protected XMLBuilder buildRoot(VApp vApp, String name) throws ParserConfigurationException,
174 FactoryConfigurationError {
175 String status = vApp.getStatus().value();
176 if (apiVersion.indexOf("0.8") != -1 && "8".equals(status))
177 status = "2";
178 XMLBuilder rootBuilder = XMLBuilder.create("VApp").a("type", vApp.getType()).a("name", name).a("status", status)
179 .a("size", vApp.getSize() + "").a("xmlns", ns).a("xmlns:xsi",
180 "http://www.w3.org/2001/XMLSchema-instance").a("xsi:schemaLocation", ns + " " + schema);
181 return rootBuilder;
182 }
183
184 protected VApp findVAppInArgsOrNull(GeneratedHttpRequest<?> gRequest) {
185 for (Object arg : gRequest.getArgs()) {
186 if (arg instanceof VApp) {
187 return (VApp) arg;
188 } else if (arg instanceof VApp[]) {
189 VApp[] vapps = (VApp[]) arg;
190 return (vapps.length > 0) ? vapps[0] : null;
191 }
192 }
193 return null;
194 }
195
196 protected VAppConfiguration findConfigInArgsOrNull(GeneratedHttpRequest<?> gRequest) {
197 for (Object arg : gRequest.getArgs()) {
198 if (arg instanceof VAppConfiguration) {
199 return (VAppConfiguration) arg;
200 } else if (arg instanceof VAppConfiguration[]) {
201 VAppConfiguration[] configuration = (VAppConfiguration[]) arg;
202 return (configuration.length > 0) ? configuration[0] : null;
203 }
204 }
205 return null;
206 }
207
208 @Override
209 public <R extends HttpRequest> R bindToRequest(R request, Object input) {
210 throw new IllegalStateException("BindVAppConfigurationToXmlPayload needs parameters");
211 }
212
213 protected String ifNullDefaultTo(String value, String defaultValue) {
214 return value != null ? value : checkNotNull(defaultValue, "defaultValue");
215 }
216
217 @Override
218 public URI apply(Object from) {
219 return VApp.class.cast(checkNotNull(from, "from")).getHref();
220 }
221 }