package com.sixsq.slipstream.persistence; /* * +=================================================================+ * SlipStream Server (WAR) * ===== * Copyright (C) 2013 SixSq Sarl (sixsq.com) * ===== * Licensed 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. * -=================================================================- */ import com.sixsq.slipstream.exceptions.ValidationException; import org.hibernate.annotations.CollectionType; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; import org.simpleframework.xml.ElementMap; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.EntityManager; import javax.persistence.EntityTransaction; import javax.persistence.FetchType; import javax.persistence.OneToMany; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; @Entity @SuppressWarnings("serial") public class DeploymentModule extends TargetContainerModule { @ElementMap(required = false) @Fetch(FetchMode.SELECT) @OneToMany(mappedBy = "module", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true) @CollectionType(type = "com.sixsq.slipstream.persistence.ConcurrentHashMapType") private Map<String, Node> nodes = new ConcurrentHashMap<String, Node>(); @SuppressWarnings("unused") private DeploymentModule() { super(); } public DeploymentModule(String name) throws ValidationException { super(name, ModuleCategory.Deployment); } public Map<String, Node> getNodes() { return nodes; } public void setNodes(HashMap<String, Node> nodes) { this.nodes = nodes; } public void setNode(Node node) { node.setModule(this); getNodes().put(node.getName(), node); } public Node getNode(String nodename) { for (Node node : getNodes().values()) { if (node.getName().equals(nodename)) { return node; } } return null; } /** * Validates the integrity of the object. For example, checks that the * mapping for deployment instances is complete and no input parameter is * left unresolved. * * @throws ValidationException */ public void validate() throws ValidationException { super.validate(); HashMap<String, ImageModule> imagemap = buildImageNameImageMap(); validateThatAllParametersExist(imagemap); validateAllInputsHaveMappingOutputs(imagemap); for (Node n : getNodes().values()) { n.validate(); } } private HashMap<String, ImageModule> buildImageNameImageMap() throws ValidationException { List<ImageModule> images = new LinkedList<ImageModule>(); for (Node node : nodes.values()) { ImageModule image = node.getImage(); if (image == null) { throw new ValidationException("Cannot find image: " + node.getImageUri()); } images.add(image); } // Build a map of: "image qname" : "image" HashMap<String, ImageModule> imagemap = new HashMap<String, ImageModule>(); for (ImageModule image : images) { imagemap.put(image.getName(), image); } return imagemap; } private void validateThatAllParametersExist( HashMap<String, ImageModule> imagemap) throws ValidationException { // Iterate over each node for (Entry<String, Node> nodeEntry : getNodes().entrySet()) { Node node = nodeEntry.getValue(); validateInputParametersExistsInNodeImage(node); validateOutputParametersExistsInOtherNodes(imagemap, node); imageInputParameterPresentIfNoDefault(node); } } private void validateOutputParametersExistsInOtherNodes(HashMap<String, ImageModule> imagemap, Node node) throws ValidationException { // Check output params for (NodeParameter nodeParameter : node.getParameterMappings().values()) { if (nodeParameter.isStringValue()) { continue; } String nodeName = RuntimeParameter.extractNodeNamePart(nodeParameter.getValue()); String paramName = RuntimeParameter.extractParamNamePart(nodeParameter.getValue()); // Check that the node referring to by the oparam exists if (!this.getNodes().containsKey(nodeName)) { throw (new ValidationException( "Node: " + node.getName() + " defines an output parameter: " + nodeParameter.getValue() + " which referes to a node not defined in the deployment")); } if (!this.getNodes().get(nodeName).getImage().getOutputParametersExpanded().containsKey(paramName)) { throw (new ValidationException( "Failed to find output parameter: " + nodeParameter.getValue() + " as declared in: " + node.getName())); } } } private void validateInputParametersExistsInNodeImage(Node node) throws ValidationException { for (String paramName : node.getParameterMappings().keySet()) { ImageModule image = node.getImage(); if (!image.getParameters().containsKey(paramName) && !image.getInputParametersExpanded().containsKey(paramName)) { throw (new ValidationException("Input parameter: " + paramName + " doesn't exist in image: " + node.getName())); } } } private void validateAllInputsHaveMappingOutputs( HashMap<String, ImageModule> imagemap) throws ValidationException { // Iterate over each node and build a map of mappings across all images HashMap<String, NodeParameter> mapping = new HashMap<String, NodeParameter>(); for (Node node : getNodes().values()) { if (node.getParameterMappings() != null) { mapping.putAll(node.getParameterMappings()); } } for (Module image : imagemap.values()) { for (Parameter<Module> param : image.getParameters( ParameterCategory.Input.name()).values()) { if (!param.hasValueSet()) { if (!mapping.containsKey(param.getName())) { throw (new ValidationException( "Missing mapping for input parameter: " + param.getName())); } } } } } private void imageInputParameterPresentIfNoDefault(Node node) throws ValidationException { for (Parameter<Module> moduleParameter : node.getImage() .getParameters(ParameterCategory.Input.toString()).values()) { if (!moduleParameter.hasValueSet()) { if (!node.getParameterMappings().containsKey(moduleParameter.getName())) { throw (new ValidationException("Missing input parameter " + moduleParameter.getName() + " in node " + node.getName())); } } } } public static DeploymentModule load(String uri) { return (DeploymentModule) Module.load(uri); } public DeploymentModule copy() throws ValidationException { DeploymentModule copy = (DeploymentModule) copyTo(new DeploymentModule( getName())); for (Node node : getNodes().values()) { copy.setNode(node.copy()); } return copy; } public void postDeserialization() { super.postDeserialization(); // Assign containers inside parameters for (Entry<String, Node> n : getNodes().entrySet()) { for (Entry<String, NodeParameter> p : n.getValue().getParameters() .entrySet()) { p.getValue().setContainer(n.getValue()); } } } public DeploymentModule store() { setModuleToTargets(); if(nodes != null) { for(Node n : nodes.values()) { n.setModule(this); } } return (DeploymentModule) store(true); } public void remove() { EntityManager em = PersistenceUtil.createEntityManager(); EntityTransaction transaction = em.getTransaction(); transaction.begin(); DeploymentModule fromDb = em.find(this.getClass(), getResourceUri()); if (fromDb != null) { for(Node n : fromDb.getNodes().values()) { n.getParameters().clear(); n.getParameterMappings().clear(); em.remove(n); } em.remove(fromDb); } transaction.commit(); em.close(); } public Map<String, String> placementPoliciesPerComponent() { Map<String, String> result = new HashMap<>(); for (Node node : nodes.values()) { ImageModule image = node.getImage(); if(image != null) { Map<String, String> imagePolicies = image.placementPoliciesPerComponent(); result.putAll(imagePolicies); } } return result; } }