/**
* This file is part of CloudML [ http://cloudml.org ]
*
* Copyright (C) 2012 - SINTEF ICT
* Contact: Franck Chauvel <franck.chauvel@sintef.no>
*
* Module: root
*
* CloudML is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* CloudML is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with CloudML. If not, see
* <http://www.gnu.org/licenses/>.
*/
package org.cloudml.deployer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.cloudml.core.*;
/**
* A class to compare two deployment models
*
* @author Nicolas Ferry
* @author Brice Morin
*/
public class CloudMLModelComparator {
private static final Logger journal = Logger.getLogger(CloudMLModelComparator.class.getName());
//Attributes related to model comparison
private Map<ExternalComponentInstance<? extends ExternalComponent>, ExternalComponentInstance<? extends ExternalComponent>> matchingECs = new Hashtable<ExternalComponentInstance<? extends ExternalComponent>, ExternalComponentInstance<? extends ExternalComponent>>();
private Map<ExternalComponentInstance<? extends ExternalComponent>,List<InternalComponentInstance>> removedECs = new Hashtable<ExternalComponentInstance<? extends ExternalComponent>,List<InternalComponentInstance>>();
private List<ExternalComponentInstance<? extends ExternalComponent>> addedECs = new ArrayList<ExternalComponentInstance<? extends ExternalComponent>>();
private Map<InternalComponentInstance, InternalComponentInstance> matchingComponents = new Hashtable<InternalComponentInstance, InternalComponentInstance>();
private List<InternalComponentInstance> removedComponents = new ArrayList<InternalComponentInstance>();
private List<InternalComponentInstance> addedComponents = new ArrayList<InternalComponentInstance>();
private List<RelationshipInstance> addedRelationships = new ArrayList<RelationshipInstance>();
private Map<RelationshipInstance, RelationshipInstance> matchingRelationships = new Hashtable<RelationshipInstance, RelationshipInstance>();
private List<RelationshipInstance> removedRelationships = new ArrayList<RelationshipInstance>();
private List<ExecuteInstance> addedExecutes = new ArrayList<ExecuteInstance>();
private Map<ExecuteInstance, ExecuteInstance> matchingExecutes = new Hashtable<ExecuteInstance, ExecuteInstance>();
private List<ExecuteInstance> removedExecutes = new ArrayList<ExecuteInstance>();
private List<CloudMLElementComparator> ecComparator = null;
private List<CloudMLElementComparator> icComparator = null;
private List<CloudMLElementComparator> rlComparator = null;
private List<CloudMLElementComparator> exComparator = null;
// The commands resulting from the diff
private Set<String> commands = new HashSet<String>();
//The models
private Deployment currentDM;
private Deployment targetDM;
public CloudMLModelComparator(Deployment currentDM, Deployment targetDM) {
this.currentDM = currentDM;
this.targetDM = targetDM;
}
public void setTargetDeploymentModel(Deployment targetDM) {
this.targetDM = targetDM;
clean();
}
public void setCurrentDeploymentModel(Deployment currentDM) {
this.currentDM = currentDM;
clean();
}
public Set<String> getCommands() {
return this.commands;
}
//TODO diff on attributes
/**
* Compare the targeted deployment model to the deployment model of the
* current system
*/
public void compareCloudMLModel() {
compareECs();
journal.log(Level.INFO, ">> Removed VMs :" + removedECs.toString());
journal.log(Level.INFO, ">> Added VMs :" + addedECs.toString());
compareComponents();
journal.log(Level.INFO, ">> Removed components: " + removedComponents.toString());
journal.log(Level.INFO, ">> Added components: " + addedComponents.toString());
compareRelationships();
journal.log(Level.INFO, ">> Removed relationships :" + removedRelationships.toString());
journal.log(Level.INFO, ">> Added relationships :" + addedRelationships.toString());
compareExecutes();
journal.log(Level.INFO, ">> Removed executes: " + removedExecutes.toString());
journal.log(Level.INFO, ">> Added executes: " + addedExecutes.toString());
}
/**
* Compares the vms between the targeted and the current deployment model
*/
public void compareECs() {
journal.log(Level.INFO, ">> Comparing ExternalComponents ...");
Boolean match = false;
for (ExternalComponentInstance ni : currentDM.getComponentInstances().onlyExternals()) {
secondloop:
{
for (ExternalComponentInstance ni2 : targetDM.getComponentInstances().onlyExternals()) {
match = ni.equals(ni2);
if (match) {
matchingECs.put(ni, ni2);
break secondloop;
}
}
}
if (!match) {
removeEC(ni);
}
}
//add the rest
addECs();
}
private void removeEC(ExternalComponentInstance<? extends ExternalComponent> ni) {
removedECs.put(ni,currentDM.getComponentInstances().onlyInternals().hostedOn(ni).toList());
//create action
}
private void addECs() {
addedECs = new ArrayList<ExternalComponentInstance<? extends ExternalComponent>>(targetDM.getComponentInstances().onlyExternals());
addedECs.removeAll(matchingECs.values());
}
/**
* Compares the relationships between the targeted and the current
* deployment model
*/
public void compareRelationships() {
journal.log(Level.INFO, ">> Comparing relationships ...");
Boolean match = false;
for (RelationshipInstance ni : currentDM.getRelationshipInstances()) {
secondloop:
{
for (RelationshipInstance ni2 : targetDM.getRelationshipInstances()) {
match = ni.equals(ni2);
if (ni.equals(ni2)) {
matchingRelationships.put(ni, ni2);
break secondloop;
}
}
}
if (!match) {
removedRelationships.add(ni);
}
}
//add the rest
addRelationships();
}
private void addRelationships() {
addedRelationships = new ArrayList<RelationshipInstance>(targetDM.getRelationshipInstances());
addedRelationships.removeAll(matchingRelationships.values());
for (RelationshipInstance ni : addedRelationships) {
int i = currentDM.getComponentInstances().toList().indexOf(ni.getRequiredEnd().getOwner().get());
if (i >= 0) {
ComponentInstance a = currentDM.getComponentInstances().toList().get(i);
if (a.isInternal()) {
int j = ((InternalComponentInstance) a).getRequiredPorts().toList().indexOf(ni.getRequiredEnd());
ni.setRequiredEnd(((InternalComponentInstance) a).getRequiredPorts().toList().get(j));
}
}
i = currentDM.getComponentInstances().toList().indexOf(ni.getProvidedEnd().getOwner().get());
if (i >= 0) {
ComponentInstance a = currentDM.getComponentInstances().toList().get(i);
int j = a.getProvidedPorts().toList().indexOf(ni.getProvidedEnd());
List<ProvidedPortInstance> l = a.getProvidedPorts().toList();
ni.setProvidedEnd(l.get(j));
}
}
}
/**
* Compares the components between the targeted and the current deployment
* model
*/
public void compareComponents() {
journal.log(Level.INFO, ">> Comparing Internal Components ...");
Boolean match = false;
for (InternalComponentInstance ni : currentDM.getComponentInstances().onlyInternals()) {
secondloop:
{
for (InternalComponentInstance ni2 : targetDM.getComponentInstances().onlyInternals()) {
match = ni.equals(ni2);
if (ni.equals(ni2) && ni.externalHost().equals(ni2.externalHost())) {
matchingComponents.put(ni, ni2);
break secondloop;
}
}
}
if (!match) {
removedComponents.add(ni);
}
}
//add the rest
addComponents();
}
private void removedComponent(InternalComponentInstance ni) {
removedComponents.add(ni);
//create action
}
private void addComponents() {
addedComponents = new ArrayList<InternalComponentInstance>(targetDM.getComponentInstances().onlyInternals());
addedComponents.removeAll(matchingComponents.values());
}
/**
* Compares the executeInstances between the current and target model
*/
public void compareExecutes() {
journal.log(Level.INFO, ">> Comparing Executes Instances ...");
Boolean match = false;
for (ExecuteInstance ei : currentDM.getExecuteInstances()) {
secondloop:
{
for (ExecuteInstance ei2 : targetDM.getExecuteInstances()) {
match = ei.equals(ei2);
if (ei.equals(ei2)) {
matchingExecutes.put(ei, ei2);
break secondloop;
}
}
}
if (!match) {
removedExecutes.add(ei);
}
}
//add the rest
addExecutes();
}
private void addExecutes(){
addedExecutes = new ArrayList<ExecuteInstance>(targetDM.getExecuteInstances());
addedExecutes.removeAll(matchingExecutes.values());
for (ExecuteInstance ei : addedExecutes) {
int i = currentDM.getComponentInstances().toList().indexOf(ei.getRequiredEnd().getOwner().get());
if (i >= 0) {
ComponentInstance a = currentDM.getComponentInstances().toList().get(i);
ei.setRequiredEnd(((InternalComponentInstance) a).getRequiredExecutionPlatform());
}
i = currentDM.getComponentInstances().toList().indexOf(ei.getProvidedEnd().getOwner().get());
if (i >= 0) {
ComponentInstance a = currentDM.getComponentInstances().toList().get(i);
int j = a.getProvidedExecutionPlatforms().toList().indexOf(ei.getProvidedEnd());
List<ProvidedExecutionPlatformInstance> l = a.getProvidedExecutionPlatforms().toList();
ei.setProvidedEnd(l.get(j));
}
}
}
/**
* Clean all the lists resulting from the previous comparison
*/
private void clean() {
matchingECs.clear();
removedECs.clear();
addedECs.clear();
matchingComponents.clear();
removedComponents.clear();
addedComponents.clear();
matchingRelationships.clear();
removedRelationships.clear();
addedRelationships.clear();
matchingExecutes.clear();
removedExecutes.clear();
addedExecutes.clear();
commands.clear();
this.ecComparator = null;
this.icComparator = null;
this.exComparator = null;
this.rlComparator = null;
}
public List<InternalComponentInstance> getRemovedComponents() {
return this.removedComponents;
}
public List<InternalComponentInstance> getAddedComponents() {
return this.addedComponents;
}
public Map<ExternalComponentInstance<? extends ExternalComponent>,List<InternalComponentInstance>> getRemovedECs() {
return this.removedECs;
}
public List<ExternalComponentInstance<? extends ExternalComponent>> getAddedECs() {
return this.addedECs;
}
public List<RelationshipInstance> getRemovedRelationships() {
return this.removedRelationships;
}
public List<RelationshipInstance> getAddedRelationships() {
return this.addedRelationships;
}
public List<ExecuteInstance> getRemovedExecutes(){
return this.removedExecutes;
}
public List<ExecuteInstance> getAddedExecutes(){
return this.addedExecutes;
}
public Map<ExecuteInstance,ExecuteInstance> getMatchingExecutes(){
return this.matchingExecutes;
}
public Map<RelationshipInstance, RelationshipInstance> getMatchingRelationships() {
return this.matchingRelationships;
}
public Map<InternalComponentInstance, InternalComponentInstance> getMatchingComponents() {
return this.matchingComponents;
}
public Map<ExternalComponentInstance<? extends ExternalComponent>, ExternalComponentInstance<? extends ExternalComponent>> getMatchingECs() {
return this.matchingECs;
}
public List<CloudMLElementComparator> getEcComparator(){
if(this.ecComparator!=null)
return this.ecComparator;
this.ecComparator = new ArrayList<CloudMLElementComparator>();
for(Map.Entry<ExternalComponentInstance<? extends ExternalComponent>, ExternalComponentInstance<? extends ExternalComponent>> entry: getMatchingECs().entrySet()){
CloudMLElementComparator comparator = new CloudMLElementComparator(entry.getKey(), entry.getValue());
comparator.compare();
this.ecComparator.add(comparator);
}
return this.ecComparator;
}
public List<CloudMLElementComparator.ElementUpdate> getAllEcUpdates(){
List<CloudMLElementComparator.ElementUpdate> allUpdates = new ArrayList<CloudMLElementComparator.ElementUpdate>();
for(CloudMLElementComparator c : this.getEcComparator()){
allUpdates.addAll(c.getUpdates());
}
return allUpdates;
}
public List<CloudMLElementComparator> getIcComparator(){
if(this.icComparator!=null)
return this.icComparator;
this.icComparator = new ArrayList<CloudMLElementComparator>();
for(Map.Entry<InternalComponentInstance, InternalComponentInstance> entry: this.getMatchingComponents().entrySet()){
CloudMLElementComparator comparator = new CloudMLElementComparator(entry.getKey(), entry.getValue());
comparator.compare();
this.icComparator.add(comparator);
}
return this.icComparator;
}
public List<CloudMLElementComparator.ElementUpdate> getAllIcUpdates(){
List<CloudMLElementComparator.ElementUpdate> allUpdates = new ArrayList<CloudMLElementComparator.ElementUpdate>();
for(CloudMLElementComparator c : this.getIcComparator()){
allUpdates.addAll(c.getUpdates());
}
return allUpdates;
}
public List<CloudMLElementComparator> getRlComparator(){
if(this.rlComparator!=null)
return this.rlComparator;
this.rlComparator = new ArrayList<CloudMLElementComparator>();
for(Map.Entry<RelationshipInstance, RelationshipInstance> entry: this.getMatchingRelationships().entrySet()){
CloudMLElementComparator comparator = new CloudMLElementComparator(entry.getKey(), entry.getValue());
comparator.compare();
this.rlComparator.add(comparator);
}
return this.rlComparator;
}
public List<CloudMLElementComparator.ElementUpdate> getAllRlUpdates(){
List<CloudMLElementComparator.ElementUpdate> allUpdates = new ArrayList<CloudMLElementComparator.ElementUpdate>();
for(CloudMLElementComparator c : this.getRlComparator()){
allUpdates.addAll(c.getUpdates());
}
return allUpdates;
}
public List<CloudMLElementComparator> getExComparator(){
if(this.exComparator!=null)
return this.exComparator;
this.exComparator = new ArrayList<CloudMLElementComparator>();
for(Map.Entry<ExecuteInstance, ExecuteInstance> entry: this.getMatchingExecutes().entrySet()){
CloudMLElementComparator comparator = new CloudMLElementComparator(entry.getKey(), entry.getValue());
comparator.compare();
this.exComparator.add(comparator);
}
return this.exComparator;
}
public List<CloudMLElementComparator.ElementUpdate> getAllExUpdates(){
List<CloudMLElementComparator.ElementUpdate> allUpdates = new ArrayList<CloudMLElementComparator.ElementUpdate>();
for(CloudMLElementComparator c : this.getExComparator()){
allUpdates.addAll(c.getUpdates());
}
return allUpdates;
}
}