Modeller.java
/* $Id$
*******************************************************************************
* Copyright (c) 2013 Contributors - see below
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Laurent BRAUD (From Java module)
*******************************************************************************
*/
package org.argouml.language.sql.reveng;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.argouml.application.api.Argo;
import org.argouml.kernel.ProjectManager;
import org.argouml.language.sql.TableDefinition;
import org.argouml.model.Model;
import org.argouml.profile.Profile;
public class Modeller {
public static final int ASSOCIATION = 1;
public static final int GENERALIZATION = 2;
// these next const need to be in a generic class
public static final String ASSOCIATION_1 = "1";
public static final String ASSOCIATION_01 = "0..1";
/**
* Current working model.
*/
private Object model;
/*
* Sql profile model.
*
private Profile sqlProfile;
*/
/**
* The name of the file being parsed.
*/
private String fileName;
/**
* New model elements that were created during this reverse engineering
* session. TODO: We want a stronger type here, but ArgoUML treats all
* elements as just simple Objects.
*/
private Collection<Object> newElements;
/**
*
*/
private String settingLevel;
private Map<String, TableDefinition> tablesByName;
/////////
public Modeller(Object theModel, Profile theSqlProfile,
String theFileName) {
model = theModel;
//sqlProfile = theSqlProfile;
newElements = new HashSet<Object>();
fileName = theFileName;
tablesByName = new HashMap<String, TableDefinition>();
}
public String getMappingDataTypeSQLToUML(final String typeSQL) {
String typeUML = "String";
if (typeSQL.toLowerCase().indexOf("char") > 0) {
// char, varchar, nvarchar [oracle], ...
typeUML = "String";
} else if (typeSQL.toLowerCase().indexOf("int") > 0) {
// integer , *int,
typeUML = "Integer";
} else if (typeSQL.toLowerCase().indexOf("Boolean") > 0) {
typeUML = "Boolean";
} else if (typeSQL.toLowerCase().indexOf("text") > 0) {
typeUML = "String";
}
return typeUML;
}
/**
* Get the elements which were created while reverse engineering this file.
*
* @return the collection of elements
*/
public Collection<Object> getNewElements() {
return newElements;
}
//////////////////////////
/**
* Call by the SqlParser
* Build all elements
*/
public void generateModele() {
ModellerLevel generation = null;
if (this.settingLevel.equals(SqlImportSettings.LEVEL_MCD)) {
generation =new ModellerC(this);
} else {
// default : this.settingLevel.equals(SqlImportSettings.LEVEL_MPD)
generation =new ModellerP(this);
}
generation.genereInModele();
}
/**
*
* @param name : TODO can be null, not done.
* @param mClassifier
* @param mClassifierEnd
* @return
*/
public Object getAssociationEnd(String name, Object mClassifier, Object mClassifierEnd) {
Object mAssociationEnd = null;
for (Iterator<Object> i = Model.getFacade().getAssociationEnds(mClassifier)
.iterator(); i.hasNext();) {
Object ae = i.next();
Object assoc = Model.getFacade().getAssociation(ae);
if (name.equals(Model.getFacade().getName(ae))
&& Model.getFacade().getConnections(assoc).size() == 2
&& Model.getFacade().getType(Model.getFacade().getNextEnd(ae)) == mClassifierEnd) {
mAssociationEnd = ae;
}
}
if (mAssociationEnd == null) {
Object mAssociation = buildDirectedAssociation(name, mClassifierEnd, mClassifier);
// this causes a problem when mClassifier is not only
// at one assoc end: (which one is the right one?)
mAssociationEnd =
Model.getFacade().getAssociationEnd(
mClassifier,
mAssociation);
}
return mAssociationEnd;
}
/**
* Build a unidirectional association between two Classifiers.(From SQL/JAVA)
*
* @param name name of the association
* @param sourceClassifier source classifier (end which is non-navigable)
* @param destClassifier destination classifier (end which is navigable)
* @return newly created Association
*/
public static Object buildDirectedAssociation(String name,
Object sourceClassifier, Object destClassifier) {
return Model.getCoreFactory().buildAssociation(destClassifier, true,
sourceClassifier, false, name);
}
/**
* Call by the SqlParser
* Must be call before the end of pasring a table (so, only when then name is known), because a FK can reference himself.
*/
public void addTable(final TableDefinition table) {
tablesByName.put(table.getName(), table);
}
public TableDefinition getTableFromName(final String nameTable) {
TableDefinition ret = tablesByName.get(nameTable);
if (ret == null) {
ret = new TableDefinition();
ret.setName(nameTable);
addTable(ret);
}
return ret;
}
public Map<String, TableDefinition> getTablesByName() {
return tablesByName;
}
public Object addClass(final TableDefinition table) {
Object mClass = addClassifier(Model.getCoreFactory().createClass(),
table.getName(), table.getComment(), null);
/*Model.getCoreHelper().setAbstract(mClass,
(modifiers & JavaParser.ACC_ABSTRACT) > 0);
Model.getCoreHelper().setLeaf(mClass,
(modifiers & JavaParser.ACC_FINAL) > 0);
*/
if (Model.getFacade().getUmlVersion().charAt(0) == '1') {
Model.getCoreHelper().setRoot(mClass, false);
}
newElements.add(mClass);
return mClass;
}
public Object getOrAddDatatype(Object packageOfType, String typeSpec) {
Object mClassifierType = Model.getFacade().lookupIn(packageOfType, typeSpec);
if (mClassifierType == null) {
mClassifierType = Model.getCoreFactory().buildDataType(typeSpec, packageOfType);
newElements.add(mClassifierType);
}
return mClassifierType;
}
private Object addClassifier(Object newClassifier, String name,
String documentation, List<String> typeParameters) {
Object mClassifier;
Object mNamespace;
Object currentPackage = this.model;
mClassifier = Model.getFacade().lookupIn(currentPackage, name);
mNamespace = currentPackage;
if (mClassifier == null) {
// if the classifier could not be found in the model
//if (LOG.isInfoEnabled()) {
// LOG.info("Created new classifier for " + name);
//}
mClassifier = newClassifier;
Model.getCoreHelper().setName(mClassifier, name);
Model.getCoreHelper().setNamespace(mClassifier, mNamespace);
newElements.add(mClassifier);
}/* else {
// it was found and we delete any existing tagged values.
if (LOG.isInfoEnabled()) {
LOG.info("Found existing classifier for " + name);
}
// TODO: Rewrite existing elements instead? - tfm
cleanModelElement(mClassifier);
} */
/*
// set up the artifact manifestation (only for top level classes)
if (parseState.getClassifier() == null) {
if (Model.getFacade().getUmlVersion().charAt(0) == '1') {
// set the classifier to be a resident in its component:
// (before we push a new parse state on the stack)
// This test is carried over from a previous implementation,
// but I'm not sure why it would already be set - tfm
if (Model.getFacade()
.getElementResidences(mClassifier).isEmpty()) {
Object resident = Model.getCoreFactory()
.createElementResidence();
Model.getCoreHelper().setResident(resident, mClassifier);
Model.getCoreHelper().setContainer(resident,
parseState.getArtifact());
}
} else {
Object artifact = parseState.getArtifact();
Collection c =
Model.getCoreHelper().getUtilizedElements(artifact);
if (!c.contains(mClassifier)) {
Object manifestation = Model.getCoreFactory()
.buildManifestation(mClassifier);
Model.getCoreHelper()
.addManifestation(artifact, manifestation);
}
}
}*/
/*
// change the parse state to a classifier parse state
parseStateStack.push(parseState);
parseState = new ParseState(parseState, mClassifier, currentPackage);
*/
// Add classifier documentation tags during first (or only) pass only
//if (getLevel() <= 0) {
addDocumentationTag(mClassifier, documentation);
//}
// addTypeParameters(mClassifier, typeParameters);
return mClassifier;
}
private void addDocumentationTag(Object modelElement, String sDocumentation) {
if ((sDocumentation != null) && (sDocumentation.trim().length() >= 1)) {
//Now store documentation text in a tagged value
String[] docs = {
sDocumentation
};
buildTaggedValue(modelElement, Argo.DOCUMENTATION_TAG, docs);
addStereotypes(modelElement);
}
}
private void buildTaggedValue(Object me,
String sTagName,
String[] sTagData) {
Object tv = Model.getFacade().getTaggedValue(me, sTagName);
if (tv == null) {
// using deprecated buildTaggedValue here, because getting the tag
// definition from a tag name is the critical step, and this is
// implemented in ExtensionMechanismsFactory in a central place,
// but not as a public method:
Model.getExtensionMechanismsHelper().addTaggedValue(
me,
Model.getExtensionMechanismsFactory()
.buildTaggedValue(sTagName, sTagData[0]));
} else {
Model.getExtensionMechanismsHelper().setDataValues(tv, sTagData);
}
}
private void addStereotypes(Object modelElement) {
// TODO: What we do here is allowed for UML 1.x only!
if (Model.getFacade().getUmlVersion().charAt(0) == '1') {
Object tv = Model.getFacade()
.getTaggedValue(modelElement, "stereotype");
if (tv != null) {
String stereo = Model.getFacade().getValueOfTag(tv);
if (stereo != null && stereo.length() > 0) {
StringTokenizer st = new StringTokenizer(stereo, ", ");
while (st.hasMoreTokens()) {
Model.getCoreHelper().addStereotype(modelElement,
getUML1Stereotype(st.nextToken().trim()));
}
ProjectManager.getManager().updateRoots();
}
Model.getUmlFactory().delete(tv);
}
}
}
/**
* Get the stereotype with a specific name. UML 1.x only.
*
* @param name The name of the stereotype.
* @return The stereotype.
*/
private Object getUML1Stereotype(String name) {
//LOG.debug("Trying to find a stereotype of name <<" + name + ">>");
// Is this line really safe wouldn't it just return the first
// model element of the same name whether or not it is a stereotype
Object stereotype = Model.getFacade().lookupIn(model, name);
if (stereotype == null) {
//LOG.debug("Couldn't find so creating it");
return Model.getExtensionMechanismsFactory().buildStereotype(name,
model);
}
if (!Model.getFacade().isAStereotype(stereotype)) {
// and so this piece of code may create an existing stereotype
// in error.
//LOG.debug("Found something that isn't a stereotype so creating it");
return Model.getExtensionMechanismsFactory().buildStereotype(name,
model);
}
//LOG.debug("Found it");
return stereotype;
}
public Object buildAttribute(Object classifier, Object type, String name) {
Object mAttribute = Model.getCoreFactory().buildAttribute2(classifier,
type);
newElements.add(mAttribute);
Model.getCoreHelper().setName(mAttribute, name);
return mAttribute;
}
public void setLevel(final String level) {
this.settingLevel = level;
}
public Object getGeneralization(Object mPackage,
Object parent,
Object child) {
Object mGeneralization = Model.getFacade().getGeneralization(child,
parent);
if (mGeneralization == null) {
mGeneralization = Model.getCoreFactory().buildGeneralization(child,
parent);
newElements.add(mGeneralization);
}
if (mGeneralization != null) {
Model.getCoreHelper().setNamespace(mGeneralization, mPackage);
}
return mGeneralization;
}
public Object getModel() {
return this.model;
}
}