package org.alien4cloud.tosca.model.templates; import static alien4cloud.dao.model.FetchContext.SUMMARY; import java.util.Date; import java.util.Map; import java.util.Set; import org.alien4cloud.tosca.model.CSARDependency; import org.alien4cloud.tosca.model.definitions.DeploymentArtifact; import org.alien4cloud.tosca.model.definitions.PropertyDefinition; import org.elasticsearch.annotation.ESObject; import org.elasticsearch.annotation.Id; import org.elasticsearch.annotation.MapKeyValue; import org.elasticsearch.annotation.NestedObject; import org.elasticsearch.annotation.ObjectField; import org.elasticsearch.annotation.StringField; import org.elasticsearch.annotation.query.FetchContext; import org.elasticsearch.annotation.query.TermFilter; import org.elasticsearch.mapping.IndexType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.google.common.collect.Sets; import alien4cloud.exception.IndexingServiceException; import alien4cloud.model.common.IDatableResource; import alien4cloud.model.common.IWorkspaceResource; import alien4cloud.paas.wf.Workflow; import alien4cloud.utils.jackson.ConditionalAttributes; import alien4cloud.utils.jackson.ConditionalOnAttribute; import alien4cloud.utils.jackson.JSonMapEntryArrayDeSerializer; import alien4cloud.utils.jackson.JSonMapEntryArraySerializer; import alien4cloud.utils.version.Version; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @Getter @Setter @ESObject @NoArgsConstructor @AllArgsConstructor(suppressConstructorProperties = true) @JsonInclude(Include.NON_NULL) @JsonIgnoreProperties(ignoreUnknown = true) public class Topology implements IDatableResource, IWorkspaceResource { @StringField(indexType = IndexType.not_analyzed) @TermFilter private String archiveName; @StringField(indexType = IndexType.not_analyzed) @TermFilter private String archiveVersion; @ObjectField @TermFilter(paths = { "majorVersion", "minorVersion", "incrementalVersion", "buildNumber", "qualifier" }) private Version nestedVersion; @TermFilter @StringField(indexType = IndexType.not_analyzed) private String workspace; @StringField(indexType = IndexType.no) private String description; private Date creationDate; private Date lastUpdateDate = new Date(); /** The list of dependencies of this topology. */ @TermFilter(paths = { "name", "version" }) @NestedObject(nestedClass = CSARDependency.class) @FetchContext(contexts = { SUMMARY }, include = { false }) private Set<CSARDependency> dependencies = Sets.newHashSet(); @MapKeyValue @TermFilter(paths = "value.type") @ConditionalOnAttribute(ConditionalAttributes.ES) @JsonDeserialize(using = JSonMapEntryArrayDeSerializer.class) @JsonSerialize(using = JSonMapEntryArraySerializer.class) @FetchContext(contexts = { SUMMARY }, include = { false }) private Map<String, NodeTemplate> nodeTemplates; @ObjectField(enabled = false) @FetchContext(contexts = { SUMMARY }, include = { false }) private Map<String, PropertyDefinition> inputs; /** * Outputs coming from node properties: * <ul> * <li>key is the node template name. * <li>value is a list of node template property names. * </ul> */ @ObjectField(enabled = false) @FetchContext(contexts = { SUMMARY }, include = { false }) private Map<String, Set<String>> outputProperties; /** * Outputs coming from node template capability properties: * <ul> * <li>key is the node template name. * <li>key is the capability name. * <li>value is a list of output property names. * </ul> */ @ObjectField(enabled = false) @FetchContext(contexts = { SUMMARY }, include = { false }) private Map<String, Map<String, Set<String>>> outputCapabilityProperties; /** * Outputs coming from node attributes: * <ul> * <li>key is the node template name. * <li>value is a list of node template attribute names. * </ul> */ @ObjectField(enabled = false) @FetchContext(contexts = { SUMMARY }, include = { false }) private Map<String, Set<String>> outputAttributes; /** * These artifacts will be given at deployment time and can be shared by several nodes. */ @ObjectField(enabled = false) @FetchContext(contexts = { SUMMARY }, include = { false }) private Map<String, DeploymentArtifact> inputArtifacts; @ObjectField(enabled = false) @FetchContext(contexts = { SUMMARY }, include = { false }) private Map<String, NodeGroup> groups; /** * When not null, describe how this topology can be used to substitute a node type in another topology (topology composition). */ @ObjectField(enabled = false) @FetchContext(contexts = { SUMMARY }, include = { false }) private SubstitutionMapping substitutionMapping; /** * All the workflows associated with this topology. */ @ObjectField(enabled = false) @FetchContext(contexts = { SUMMARY }, include = { false }) private Map<String, Workflow> workflows; @Id public String getId() { if (archiveName == null) { throw new IndexingServiceException("Archive name is mandatory"); } if (archiveVersion == null) { throw new IndexingServiceException("Archive version is mandatory"); } return archiveName + ":" + archiveVersion; } public void setId(String id) { // Not authorized to set id as it's auto-generated from name and version } public void setArchiveVersion(String version) { this.archiveVersion = version; this.nestedVersion = new Version(version); } /** * /** * Return true if the topology is an empty topology (won't be saved on import). * * @return True if the topology is empty (doesn't contains any node). */ public boolean isEmpty() { return nodeTemplates == null || nodeTemplates.isEmpty(); } }