//UML Model Transformation Tool (UMT)
//Copyright (C) 2003, 2004, 2005 SINTEF
//Authors: jon.oldevik at sintef.no | roy.gronmo at sintef.no | tor.neple at sintef.no | fredrik.vraalsen at sintef.no
//Webpage: http://umt.sourceforge.net
//Deloped in the projects: ACEGIS (EU project - IST-2002-37724),
// CAFE (EUREKA/ITEA - ip00004), FAMILIES (ITEA project ip02009)
//
//This program 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 2.1
//of the License, or (at your option) any later version.
//
//This program 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 this program; if not, write to the Free
//Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
//02111-1307 USA
package org.sintef.umt.systemfamily;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
import org.w3c.dom.*;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
/**
* @author jol
* DefaultVariabilityResolveEngineImpl
* Created 10.nov.2004
*/
public class DefaultVariabilityResolveEngineImpl implements VariabilityResolveEngine {
private Vector errorList = null;
private Element rootModel = null;
private Document doc = null;
private boolean removeCategories;
public Element resolveModel (Element model) {
System.out.println ("DefaultVariabilityResolveEngineImpl::resolveModel");
rootModel = model;
DocumentBuilderFactory docfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docbuild = null;
try {
docbuild = docfac.newDocumentBuilder();
doc = docbuild.newDocument();
} catch (ParserConfigurationException pcerr) {
System.out.println ("Could not create document :" + pcerr);
// Have to exit ---
}
errorList = new Vector ();
// Append root model
// Element derivedModel = doc.createElement(model.getNodeName());
Element derivedModel = doc.createElement("model");
Element importModel = (Element) doc.importNode(model, true);
derivedModel.appendChild(importModel);
((Element)importModel).setAttribute("name", model.getAttribute("name") + " UMT Derived Product");
((Element)derivedModel).setAttribute("name", model.getAttribute("name") + " UMT Derived Product");
// Element derivedModel = (Element) doc.importNode(model, true);
((Element)derivedModel).setAttribute("name", model.getAttribute("name") + " UMT Derived Product");
// doc.appendChild(derivedModel);
// TODO: Need to add attributes ????
NodeList children = derivedModel.getChildNodes();
Node child = null;
Element element = null;
for (int i = 0; i < children.getLength(); i++) {
child = children.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
element = (Element)child;
String nodename = element.getNodeName();
if (nodename.equalsIgnoreCase("package")) {
checkPackage (element, derivedModel);
} else if (nodename.equalsIgnoreCase("datatype")) {
// NOOP
// Element datatype = createNewElement(element, true);
// derivedModel.appendChild(datatype);
}
} else {
// derivedModel.appendChild(child.cloneNode(true));
}
}
checkTypeAlternatives(derivedModel);
checkDependencies(derivedModel);
return derivedModel;
}
private Element createNewElement (Element template, boolean deep) {
Element newElement = doc.createElement(template.getNodeName());
NodeList children = template.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
short ntype = child.getNodeType();
if (ntype == Node.ELEMENT_NODE && deep) {
Element e = createNewElement ((Element)child, deep);
newElement.appendChild(e);
} else if (ntype == Node.ATTRIBUTE_NODE) {
Attr attribute = doc.createAttribute(((Attr)child).getName());
attribute.setValue(((Attr)child).getValue());
newElement.appendChild(attribute);
} else if (ntype == Node.CDATA_SECTION_NODE) {
CDATASection cdata = doc.createCDATASection(((CDATASection)child).getData());
newElement.appendChild(cdata);
} else if (ntype == Node.COMMENT_NODE) {
Comment comment = doc.createComment(((Comment)child).getData());
newElement.appendChild(comment);
} else if (ntype == Node.TEXT_NODE) {
Text t = doc.createTextNode(((Text)child).getData());
newElement.appendChild(t);
}
}
return newElement;
}
/**
* Checks a model element's stereotype - if it matches 'checkType', then swap with 'newType'
* Casing ignored
* @param modelElement
* @param checkType
* @param newType
*/
private void modifyStereoType (Element modelElement, String checkType, String newType) {
String st = modelElement.getAttribute("stereoType");
if (st != null && st.equalsIgnoreCase(checkType)) {
modelElement.setAttribute("stereoType", newType);
}
}
/**
*
* @param modelElement
*/
private void family2ProductStereoType (Element modelElement) {
modifyStereoType (modelElement, "SystemFamily", "Product");
}
private void checkPackage (Element pElement, Element owner) {
// Element packageClone = (Element) pElement.cloneNode(false);
// Element packageClone = createNewElement (pElement, false);
// owner.appendChild(packageClone);
//
// Package notation for SystemFamily --- Here: Stereotype "SystemFamily"
// Remove / Change Stereotype
family2ProductStereoType (pElement);
NodeList children = pElement.getChildNodes();
Node child = null;
Element child_element = null;
for (int i = 0; i < children.getLength(); i++) {
child = children.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
child_element = (Element) child;
String nodename = child_element.getNodeName();
if (nodename.equalsIgnoreCase("package")){
checkPackage (child_element, pElement);
}
else if (nodename.equalsIgnoreCase("class")) {
checkClass (child_element, pElement);
}
else {
// NOOP
}
}
}
}
//
// Check Class
//
private void checkClass (Element classElement, Element owner) {
// Append class to owner
// Element classClone = createNewElement(classElement, false);
// owner.appendChild(classClone);
this.family2ProductStereoType(classElement);
String name = classElement.getAttribute("name");
String stereotype = classElement.getAttribute("stereoType");
String id = classElement.getAttribute("id");
NodeList attributes = classElement.getElementsByTagName("attribute");
NodeList associations = classElement.getElementsByTagName("association");
NodeList operations = classElement.getElementsByTagName("operation");
NodeList children = classElement.getChildNodes();
Node child = null;
String childStereoType = "";
for (int i = 0; i < children.getLength(); i++) {
child = children.item(i);
if (child.getNodeType() == Node.ELEMENT_NODE) {
childStereoType = ((Element)child).getAttribute("stereoType");
if (VariabilityManager.checkVariationPoint(childStereoType)) {
checkClassFeature ((Element)child, classElement);
}
}
}
// TODO: REMOVE - HAndled by other means
if(VariabilityManager.checkVariationPoint(stereotype)) {
//
// Handle type alternative
//
if (stereotype.equalsIgnoreCase("alternative")) {
String vpvalue = classElement.getAttribute(VariabilityManager.VARIABILITY_INDICATOR);
if (vpvalue == null || vpvalue.equals("")) {
// NOOP
} else {
classElement.setAttribute("stereoType", "");
// get the subclasses and remove all subclasses that are not 'IT'
Vector subs = VariabilityManager.getSubclasses(
classElement.getOwnerDocument().getDocumentElement(), id);
for (Iterator it = subs.iterator(); it.hasNext();) {
Element sub = (Element) it.next();
String subName = sub.getAttribute("name");
if (subName.equalsIgnoreCase(vpvalue)) {
// ok, keep this
} else {
// remove this class...
/*
* Strategy: Remove all subclasses, rename superclass
* to the selected alternative.
* Move all properties of the selected alternative to the
* original alternative class
*/
classElement.setAttribute("name", subName);
}
}
}
}
}
}
/*
* checkTypeAlternatives
*/
protected void checkTypeAlternatives (Element pElement) {
NodeList allClasses = pElement.getElementsByTagName("class");
for (int i = 0; i < allClasses.getLength(); i++) {
Element clazz = (Element) allClasses.item(i);
String stereotype = clazz.getAttribute("stereoType");
if (stereotype.equalsIgnoreCase("alternative")) {
Vector subClasses = VariabilityManager.getSubclasses(
pElement, clazz.getAttribute("id"));
NamedNodeMap attributes = clazz.getAttributes();
Vector toRemove = new Vector();
for (int j = 0; j < attributes.getLength(); j++) {
Attr attribute = (Attr)attributes.item(j);
String nodename = attribute.getNodeName();
String nodevalue = attribute.getNodeValue();
// Need to move associations from alternative class to the alternative
if (nodename.startsWith("CLASS-")) {
int assocIndex = nodename.lastIndexOf("ASSOC-");
String assocId = nodename.substring(assocIndex + 6, nodename.length());
// find the assoc and change to the appropriate sub class
Element theAssoc = VariabilityManager.getAssociationFromID(
pElement, assocId);
if (theAssoc != null) {
// Change the association target
for (Iterator it = subClasses.iterator(); it.hasNext();) {
Element subClazz = (Element)it.next();
if (subClazz.getAttribute("name").equalsIgnoreCase(nodevalue)) {
// change the assoc to this class
theAssoc.setAttribute("targetClass", subClazz.getAttribute("id"));
}
}
}
toRemove.add(attribute);
//clazz.removeAttributeNode(attribute);
}
}
// Remove the extra attributes
for (Iterator it = toRemove.iterator(); it.hasNext();) {
Attr attribute = (Attr)it.next();
clazz.removeAttributeNode(attribute);
}
toRemove.clear();
toRemove = null;
// Remove stereotype
clazz.setAttribute("stereoType", "");
}
}
}
//
// check attribute, operation, association
//
private void checkClassFeature (Element feature, Element owner) {
NamedNodeMap attributes = feature.getAttributes();
// Element featureClone = createNewElement(feature, true);
// VARIABILITY_INDICATOR
Element parent = (Element) feature.getParentNode();
String parentname = parent.getAttribute("name");
String vpvalue = feature.getAttribute(VariabilityManager.VARIABILITY_INDICATOR);
String name = feature.getAttribute("name");
String id = feature.getAttribute("id");
String stereotype = feature.getAttribute("stereoType");
String nodename = feature.getNodeName();
if (vpvalue == null || vpvalue.equals("")) {
// Error: Variability to checker by user
// Include the feature anyway
// owner.appendChild(featureClone);
// Do nothing, element remains here.
} else {
if (stereotype.equalsIgnoreCase("vp") || stereotype.equalsIgnoreCase("optional")) {
if (vpvalue.equalsIgnoreCase("false")) {
// Do not add the feature.
//
//
// Remove the feature
owner.removeChild(feature);
// TODO: Must also need to check to remove other features or classes....
} else {
// owner.appendChild(featureClone);
// Remove the variation point indicator
feature.setAttribute("stereoType", "");
}
} else if (stereotype.equalsIgnoreCase("range")) {
feature.setAttribute("stereoType", "");
feature.setAttribute("initialValue", vpvalue);
} else if (stereotype.equalsIgnoreCase("property")) {
feature.setAttribute("stereoType", "");
feature.setAttribute("initialValue", vpvalue);
} else if (stereotype.equalsIgnoreCase("alternative")) {
feature.setAttribute("stereoType", "");
feature.setAttribute("initialValue", vpvalue);
}
else {
// add the feature ...
// owner.appendChild(featureClone);
}
}
}
private void checkDependencies (Element pElement) {
NodeList children = pElement.getChildNodes();
Node child = null;
Element child_element = null;
NodeList classlist = pElement.getElementsByTagName("class");
NodeList associationlist = pElement.getElementsByTagName("association");
Hashtable classes = new Hashtable ();
Hashtable associations = new Hashtable ();
Hashtable classesWithAssocs = new Hashtable ();
Hashtable inheritance = new Hashtable ();
for (int i = 0; i < classlist.getLength(); i++) {
Element clazz = (Element)classlist.item(i);
classes.put(clazz.getAttribute("id"), clazz);
String superClass = clazz.getAttribute("superClass");
if (superClass!=null && !superClass.equals("")) {
inheritance.put(superClass, clazz.getAttribute("id"));
}
}
for (int i = 0; i < associationlist.getLength(); i++) {
Element assoc = (Element)associationlist.item(i);
associations.put(assoc.getAttribute("id"), assoc);
classesWithAssocs.put(assoc.getAttribute("targetClass"), assoc);
}
for (int i = 0; i < classlist.getLength(); i++) {
Element clazz = (Element) classlist.item(i);
String stereotype = clazz.getAttribute("stereoType");
if (stereotype == null || stereotype.equals("") &&
(!stereotype.equalsIgnoreCase("SystemFamily")
|| !stereotype.equalsIgnoreCase("Product"))){
// The simplest case: No associations at all exists to this class
Object exists = classesWithAssocs.get(clazz.getAttribute("id"));
if (exists != null) {
// ok, this class has some assoc to it
} else {
// This class does not have any assoc to it, remove the class
// Unless another class inherits from this class
// Check inheritance
Object inherit = inheritance.get(clazz.getAttribute("id"));
if (inherit != null) {
// Don't remove. This class has inheritance dependencies
} else {
Node parent = clazz.getParentNode();
parent.removeChild(clazz);
}
}
}
}
}
protected void copyClassProperties (Element toClass, Element fromClass) {
}
public Vector getErrors () {
return errorList;
}
}