/** * Copyright (C) 2008 Progress Software, Inc. All rights reserved. * http://fusesource.com * * The software in this package is published under the terms of the AGPL license * a copy of which has been included with this distribution in the license.txt file. */ package org.fusesource.cloudmix.common.dto; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; /** * @version $Revision$ */ @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class FeatureDetails extends IdentifiedType { @XmlAttribute private String resource; @XmlAttribute private String minimumInstances = "1"; @XmlAttribute private String maximumInstances = "1"; @XmlAttribute private Boolean ownsMachine = Boolean.FALSE; @XmlElement(name = "dependency") private List<Dependency> dependencies = new ArrayList<Dependency>(); @XmlElement(name = "preferredMachine") private Set<String> preferredMachines = new HashSet<String>(); @XmlElement(name = "property") private List<PropertyDefinition> properties = new ArrayList<PropertyDefinition>(); @XmlAttribute private String[] packageTypes; @XmlAttribute(required = false) private String ownedByProfileId; @XmlAttribute(required = false) private List<String> validContainerTypes = new ArrayList<String>(); public FeatureDetails() { } public FeatureDetails(String id) { super(id); } public FeatureDetails(String id, String resource) { super(id); this.resource = resource; } public long getDigest() { long rc = 17; // need to make sure that the order in which these lists are processed is not significant for (Dependency dep : dependencies) { // rc = 37 * rc + dep.getDigest() is not good because it is order-significant rc += dep.getDigest(); } for (String pm : preferredMachines) { rc += pm.hashCode(); } for (String pm : validContainerTypes) { rc += pm.hashCode(); } rc = 37 * rc + minimumInstances.hashCode(); rc = 37 * rc + maximumInstances.hashCode(); rc = 37 * rc + (ownsMachine.booleanValue() ? 1 : 2); return rc; } @Override public String toString() { return "Feature[id: " + getId() + " min: " + getMinimumInstances() + " max: " + getMaximumInstances() + "]"; } public void addPreferredMachine(String preferredMachine) { getPreferredMachines().add(preferredMachine); } public void addProperty(String propertyId, String expression) { addProperty(new PropertyDefinition(propertyId, expression)); } public void addProperty(PropertyDefinition property) { getProperties().add(property); } // Fluent API //------------------------------------------------------------------------- public FeatureDetails depends(FeatureDetails feature) { return depends(feature.getId()); } public FeatureDetails depends(String featureId) { Dependency answer = new Dependency(); answer.setFeatureId(featureId); dependencies.add(answer); return this; } public FeatureDetails maximumInstances(String aNumber) { setMaximumInstances(aNumber); return this; } public FeatureDetails minimumInstances(String aNumber) { setMinimumInstances(aNumber); return this; } public FeatureDetails preferredMachine(String preferredMachine) { addPreferredMachine(preferredMachine); return this; } public FeatureDetails validContainerType(String containerType) { validContainerTypes.add(containerType); return this; } public FeatureDetails ownsMachine() { setOwnsMachine(Boolean.TRUE); return this; } public FeatureDetails property(String propertyId, String expression) { addProperty(propertyId, expression); return this; } public boolean isOwnsMachine() { return ownsMachine != null && ownsMachine.booleanValue(); } // Properties //------------------------------------------------------------------------- public String getResource() { return resource; } public void setResource(String resource) { this.resource = resource; } public List<Dependency> getDependencies() { return dependencies; } /** * Sets the dependent features which must be provisioned (to their minimum * instance count) before this feature can be provisioned */ public void setDependencies(List<Dependency> dependencies) { this.dependencies = dependencies; } public String getMaximumInstances() { return maximumInstances; } /** * Sets the maximum number of instances of the feature as an expression so * that it can be dynamic based on the number of agents or instances of some * other feature et */ public void setMaximumInstances(String maximumInstances) { this.maximumInstances = maximumInstances; } public String getMinimumInstances() { return minimumInstances; } /** * Sets the minimum number of instances of the feature as an expression so * that it can be dynamic based on the number of agents or instances of some * other feature et */ public void setMinimumInstances(String minimumInstances) { this.minimumInstances = minimumInstances; } public Set<String> getPreferredMachines() { return preferredMachines; } /** * Sets list of preferred machine host names on which the feature should be * provisioned */ public void setPreferredMachines(Set<String> preferredMachines) { this.preferredMachines = preferredMachines; } public Boolean getOwnsMachine() { return ownsMachine; } /** * Sets whether or not this feature owns the entire machine. i.e. an empty * agent is required to provision this feature and no other features are * allowed to be provisioned on the same agent once this feature is * provisioned */ public void setOwnsMachine(Boolean ownsMachine) { this.ownsMachine = ownsMachine; } public String[] getPackageTypes() { return packageTypes; } public void setPackageTypes(String[] packageTypes) { this.packageTypes = packageTypes; } public String getOwnedByProfileId() { return ownedByProfileId; } /** * Sets the profile which is the exclusive owner of this feature (for * features which are local only to a single profile) otherwise leave null * so that the feature can be used in any profile. * * If a feature is associated with a single profile, then deleting a profile * should also delete the associated features. This is used when integration * testing, where a profile is created temporarily, a number of features * added for that profile - then the profile is deleted. * * * @param ownedByProfileId * the profile which should own this feature; or null to imply * the feature is used for any profile */ public void setOwnedByProfileId(String ownedByProfileId) { this.ownedByProfileId = ownedByProfileId; } /** * The required type of container needed to host this feature, an empty list * signifies any container type will do. * * @param validContainerTypes * the validContainerTypes to set */ public void setValidContainerTypes(List<String> validContainerTypes) { this.validContainerTypes = validContainerTypes; if (this.validContainerTypes == null) { this.validContainerTypes = new ArrayList<String>(0); } } /** * The required type of container needed to host this feature, an empty list * signifies any container type will do. * * @return the validContainerTypes */ public List<String> getValidContainerTypes() { return validContainerTypes; } public List<PropertyDefinition> getProperties() { return properties; } /** * Sets the configuration properties that should be created based on the * provisioned features that can then be injected into other services. For * example we may create a property which is the list of host names of all * the features of A so that B can be injected with this list in its * configuration * * @param properties * the dynamic properties to be used for this feature */ public void setProperties(List<PropertyDefinition> properties) { this.properties = properties; } }