/*
* 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.apache.brooklyn.location.jclouds.templates;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.compute.domain.TemplateBuilderSpec;
import org.jclouds.compute.options.TemplateOptions;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.primitives.Ints;
public class PortableTemplateBuilder<T extends PortableTemplateBuilder<?>> extends AbstractPortableTemplateBuilder<T> {
ComputeService svc;
List<TemplateOptions> additionalOptionalOptions = new ArrayList<TemplateOptions>();
@Override
public synchronized Template build() {
if (svc!=null) return newJcloudsTemplate(svc);
throw new IllegalStateException("Cannot build a portable template until a compute service is attached");
}
public synchronized ComputeService attachComputeService(ComputeService svc) {
ComputeService old = this.svc;
this.svc = svc;
return old;
}
public TemplateBuilder newJcloudsTemplateBuilder(ComputeService svc) {
TemplateBuilder tb = svc.templateBuilder();
for (Function<TemplateBuilder,TemplateBuilder> c: commands) {
tb = c.apply(tb);
}
tb.options(computeAggregatedOptions(true));
return tb;
}
public Template newJcloudsTemplate(ComputeService svc) {
return newJcloudsTemplateBuilder(svc).build();
}
/** Adds template options which are used for building, but not for matching/filtering.
* (eg tags added here will be set on any machine created by this template,
* but will not be required when matching this template to existing machines) */
@SuppressWarnings("unchecked")
public T addOptionalOptions(TemplateOptions options) {
additionalOptionalOptions.add(options);
return (T)this;
}
protected TemplateOptions computeAggregatedOptions(boolean includeOptional) {
TemplateOptions result;
if (getOptions()!=null) result = getOptions().clone();
else result = new TemplateOptions();
if (includeOptional)
for (TemplateOptions moreOptions: getAdditionalOptionalOptions()) result = addTemplateOptions(result, moreOptions);
for (TemplateOptions moreOptions: getAdditionalOptions()) result = addTemplateOptions(result, moreOptions);
return result;
}
public List<TemplateOptions> getAdditionalOptionalOptions() {
return ImmutableList.copyOf(additionalOptionalOptions);
}
/** like TemplateOptions.copyTo but additive wrt arrays, collections, and maps,
* putting moreOptions in on top of / at the end of options.
* currently applies to inboundPorts, tags, and userMetadata. */
public static TemplateOptions addTemplateOptions(TemplateOptions options, TemplateOptions moreOptions) {
TemplateOptions result = options.clone();
moreOptions.copyTo(result);
Set<String> tags = new LinkedHashSet<String>(options.getTags());
tags.addAll(moreOptions.getTags());
result.tags(tags);
Map<String,String> userMetadata = new LinkedHashMap<String,String>(options.getUserMetadata());
userMetadata.putAll(moreOptions.getUserMetadata());
result.userMetadata(userMetadata);
Set<Integer> inboundPorts = new TreeSet<Integer>();
for (int port: options.getInboundPorts()) inboundPorts.add(port);
for (int port: moreOptions.getInboundPorts()) inboundPorts.add(port);
int[] inboundPortsArray = new int[inboundPorts.size()];
int i=0;
for (Iterator<Integer> portI=inboundPorts.iterator(); portI.hasNext();) {
inboundPortsArray[i++] = portI.next();
}
result.inboundPorts(inboundPortsArray);
return result;
}
protected String makeNonTrivialArgumentsString() {
String s = super.makeNonTrivialArgumentsString();
TemplateOptions aggr = computeAggregatedOptions(false);
if (aggr.getInboundPorts().length>0) s = "ports="+Ints.asList(aggr.getInboundPorts())+(s!=null && s.length()>0 ? ", "+s : "");
if (!aggr.getUserMetadata().isEmpty()) s = "metadata="+aggr.getUserMetadata()+(s!=null && s.length()>0 ? ", "+s : "");
if (!aggr.getTags().isEmpty()) s = "tags="+aggr.getTags()+(s!=null && s.length()>0 ? ", "+s : "");
return s;
}
@Override
public TemplateBuilder from(TemplateBuilderSpec spec) {
TemplateOptions options = new TemplateOptions();
addOptionalOptions(options);
TemplateBuilder result = spec.copyTo(this, options);
return result;
}
@Override
public TemplateBuilder from(String spec) {
return from(TemplateBuilderSpec.parse(spec));
}
}