View Javadoc

1   /**
2    *
3    * Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com>
4    *
5    * ====================================================================
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   * ====================================================================
18   */
19  package org.jclouds.vcloud.terremark.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.vcloud.reference.VCloudConstants.PROPERTY_VCLOUD_XML_NAMESPACE;
28  import static org.jclouds.vcloud.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.vcloud.domain.Status;
48  import org.jclouds.vcloud.domain.VCloudExpressVApp;
49  import org.jclouds.vcloud.terremark.domain.VAppConfiguration;
50  
51  import com.google.common.base.Function;
52  import com.google.inject.Inject;
53  import com.jamesmurty.utils.XMLBuilder;
54  
55  /**
56   * 
57   * @author Adrian Cole
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        VCloudExpressVApp 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(VCloudExpressVApp 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, VCloudExpressVApp 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, VCloudExpressVApp 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, VCloudExpressVApp 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(VCloudExpressVApp 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 VCloudExpressVApp findVAppInArgsOrNull(GeneratedHttpRequest<?> gRequest) {
185       for (Object arg : gRequest.getArgs()) {
186          if (arg instanceof VCloudExpressVApp) {
187             return (VCloudExpressVApp) arg;
188          } else if (arg instanceof VCloudExpressVApp[]) {
189             VCloudExpressVApp[] vapps = (VCloudExpressVApp[]) 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 VCloudExpressVApp.class.cast(checkNotNull(from, "from")).getHref();
220    }
221 }