/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.rationalrose;
import java.io.File;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import org.openflexo.dataimporter.DataImporter;
import org.openflexo.foundation.FlexoEditor;
import org.openflexo.foundation.FlexoModelObject;
import org.openflexo.foundation.action.AddFlexoProperty;
import org.openflexo.foundation.action.FlexoAction;
import org.openflexo.foundation.dm.DMCardinality;
import org.openflexo.foundation.dm.DMEntity;
import org.openflexo.foundation.dm.DMMethod;
import org.openflexo.foundation.dm.DMMethod.DMMethodParameter;
import org.openflexo.foundation.dm.DMPackage;
import org.openflexo.foundation.dm.DMProperty;
import org.openflexo.foundation.dm.DMPropertyImplementationType;
import org.openflexo.foundation.dm.DMType;
import org.openflexo.foundation.dm.DMVisibilityType;
import org.openflexo.foundation.dm.DuplicateMethodSignatureException;
import org.openflexo.foundation.dm.RationalRoseRepository;
import org.openflexo.foundation.dm.action.CreateDMMethod;
import org.openflexo.foundation.rm.FlexoProject;
import org.openflexo.localization.FlexoLocalization;
import cb.parser.EOModelExtractor;
import cb.parser.PetalParser;
import cb.petal.Attribute;
import cb.petal.Class;
import cb.petal.ClassAttribute;
import cb.petal.List;
import cb.petal.Literal;
import cb.petal.Operation;
import cb.petal.Parameter;
import cb.petal.PetalFile;
import cb.petal.PetalNode;
import cb.petal.PetalObject;
import cb.petal.Role;
import cb.petal.Value;
public class Importer implements DataImporter {
private static final String ATTRIBUTES_PROPERTY_NAME = "attributes";
private static final String OPERATIONS_PROPERTY_NAME = "operations";
private static final String PARAMETERS_PROPERTY_NAME = "parameters";
private static final String DOCUMENTATION_PROPERTY_NAME = "documentation";
private static final String CLASS_ATTRIBUTES_PROPERTY_NAME = "class_attributes";
private static final String SUPER_CLASSES_PROPERTY_NAME = "superclasses";
private static final String ROLES_PROPERTY_NAME = "roles";
private static final String QUID_PROPERTY_NAME = "quid";
private static final String QUIDU_PROPERTY_NAME = "quidu";
private static final String[] PROPERTIES_TO_IGNORE = new String[] { QUID_PROPERTY_NAME, QUIDU_PROPERTY_NAME, ATTRIBUTES_PROPERTY_NAME,
OPERATIONS_PROPERTY_NAME, PARAMETERS_PROPERTY_NAME, ROLES_PROPERTY_NAME, DOCUMENTATION_PROPERTY_NAME,
CLASS_ATTRIBUTES_PROPERTY_NAME, SUPER_CLASSES_PROPERTY_NAME };
private static final String ORDER_ATTRIBUTE = "Import order";
private static final String RATIONAL_TYPE_ATTRIBUTE = "Rational type";
private FlexoProject project;
private FlexoAction<?, ? extends FlexoModelObject, ? extends FlexoModelObject> flexoAction;
private Hashtable<String, DMEntity> entities;
private EOModelExtractor extractor;
private PetalFile tree;
@Override
public Object importInProject(FlexoProject project, File importedFile, Object[] parameters) {
String repositoryName = parameters.length >= 1 ? (String) parameters[0] : null;
String packageName = parameters.length >= 2 ? (String) parameters[1] : DMPackage.DEFAULT_PACKAGE_NAME;
flexoAction = parameters.length >= 3 ? (FlexoAction<?, ? extends FlexoModelObject, ? extends FlexoModelObject>) parameters[2]
: null;
this.project = project;
String[] args = new String[] { importedFile.getAbsolutePath() };
if (flexoAction != null) {
flexoAction.setProgress(FlexoLocalization.localizedForKey("parsing") + " " + importedFile.getName());
}
tree = PetalParser.parse(args);
extractor = new EOModelExtractor(System.out);
tree.accept(extractor);
extractor.arrangeRelationship();
// data is now stored in extractor
// proceed to importation in flexo.
RationalRoseRepository repository = importInFlexo(repositoryName, packageName);
// Let's nullify the fields to be avoid memory leaks
project = null;
entities = null;
extractor = null;
flexoAction = null;
return repository;
}
public Importer() {
super();
}
private RationalRoseRepository importInFlexo(String repositoryName, String packageName) {
RationalRoseRepository repo = RationalRoseRepository.createNewRationalRoseRepository(repositoryName, project.getDataModel());
repo.setIsReadOnly(false);
try {
DMPackage pack = repo.packageWithName(packageName);
extractClasses(pack);
extractData();
} finally {
repo.setIsReadOnly(true);
}
return repo;
}
private Hashtable<String, DMEntity> extractClasses(DMPackage pack) {
if (flexoAction != null) {
flexoAction.setProgress(FlexoLocalization.localizedForKey("importing_data_structure"));
flexoAction.resetSecondaryProgress(extractor.classes.size());
}
entities = new Hashtable<String, DMEntity>();
int numberOfDigits = 0;
numberOfDigits = String.valueOf(extractor.classes.size() + 1).length();
String entityFormat = "%0" + numberOfDigits + "d";
Enumeration<cb.petal.Class> en = extractor.orderedClasses.elements();
int entityOrder = 1;
while (en.hasMoreElements()) {
cb.petal.Class currentClass = en.nextElement();
DMEntity entity = createClass(pack, String.format(entityFormat, entityOrder), currentClass);
entities.put(entity.getName(), entity);
entityOrder++;
}
return entities;
}
/**
* @param pack
* @param flexoAction
* @param entityFormat
* @param entityOrder
* @param currentClass
* @param className
* @return
*/
private DMEntity createClass(DMPackage pack, String order, cb.petal.Class currentClass) {
String className = EOModelExtractor.getLabel(currentClass);
if (flexoAction != null) {
flexoAction.setSecondaryProgress(FlexoLocalization.localizedForKey("importing") + " " + className);
}
DMEntity entity = createDMEntity(className, pack);
addProperty(RATIONAL_TYPE_ATTRIBUTE, "Class", entity);
extractProperties(currentClass, entity);
if (currentClass.getParameters() != null && currentClass.getParameters().size() > 0) {
addProperty("Parameters", currentClass.getParameters().toString(), entity);
}
addProperty(ORDER_ATTRIBUTE, order, entity);
java.util.List<cb.petal.Class> superClasses = currentClass.getSuperclasses();
if (superClasses != null && superClasses.size() > 0) {
StringBuilder sb = new StringBuilder();
for (Class klass : superClasses) {
if (sb.length() > 0) {
sb.append(",");
}
sb.append(EOModelExtractor.getLabel(klass));
}
addProperty("Super classes", sb.toString(), entity);
}
if (currentClass.getDocumentation() != null && currentClass.getDocumentation().trim().length() > 0) {
entity.setDescription(currentClass.getDocumentation());
}
return entity;
}
private void extractData() {
if (flexoAction != null) {
flexoAction.setProgress(FlexoLocalization.localizedForKey("importing_data_structure"));
flexoAction.resetSecondaryProgress(extractor.classes.size());
}
Enumeration en = extractor.classes.elements();
while (en.hasMoreElements()) {
try {
// The class
cb.petal.Class currentClass = (cb.petal.Class) en.nextElement();
String className = EOModelExtractor.getLabel(currentClass);
if (flexoAction != null) {
flexoAction.setSecondaryProgress(FlexoLocalization
.localizedForKey("extracting_attributes_operations_and_relationships_for") + " " + className);
}
DMEntity currentEntity = entities.get(className);
String superClassName = EOModelExtractor.getSuperClassLabel(currentClass);
if (superClassName != null && entities.get(superClassName) != null) {
currentEntity.setParentBaseEntity(entities.get(superClassName));
} else {
currentEntity.setParentBaseEntity(currentEntity.getDMModel().getDMEntity(Object.class));
}
// Class attributes
List classAttributes = currentClass.getClassAttributeList();
if (classAttributes != null && classAttributes.getChildCount() > 0) {
int numberOfDigits = String.valueOf(classAttributes.getChildCount() + 1).length();
String propertyFormat = "%0" + numberOfDigits + "d";
for (int j = 0; j < classAttributes.getChildCount(); j++) {
ClassAttribute attrib = (ClassAttribute) classAttributes.get(j);
createAttribute(currentEntity, String.format(propertyFormat, j + 1), attrib);
}
}
// Class operations
List classOperations = currentClass.getOperationList();
if (classOperations != null && classOperations.getChildCount() > 0) {
int numberOfDigits = String.valueOf(classOperations.getChildCount() + 1).length();
String propertyFormat = "%0" + numberOfDigits + "d";
for (int j = 0; j < classOperations.getChildCount(); j++) {
Operation operation = (Operation) classOperations.get(j);
createMethod(currentEntity, String.format(propertyFormat, j + 1), operation);
}
}
// Class relations
if (currentClass.getRelationsAsRole() != null) {
Enumeration en2 = currentClass.getRelationsAsRole().elements();
int numberOfDigits = String.valueOf(currentClass.getRelationsAsRole().size() + 1).length();
String propertyFormat = "%0" + numberOfDigits + "d";
int order = 1;
while (en2.hasMoreElements()) {
Role rel = (Role) en2.nextElement();
if (EOModelExtractor.getLabel(rel).indexOf("$") == -1) {
Class klass = null;
if (rel.hasQuidu()) {
klass = tree.getClassByQuid(rel.getQuidu());
}
DMEntity to = entities.get(EOModelExtractor.getSupplierShortName(rel));
DMProperty prop = createRelationship(rel, currentEntity, to);
addProperty(RATIONAL_TYPE_ATTRIBUTE, "Role", prop);
prop.setDescription(rel.commentaires);
addProperty(ORDER_ATTRIBUTE, String.format(propertyFormat, order), prop);
order++;
}
}
}
} finally {
}
}
}
/**
* @param flexoAction
* @param entity
* @param propertyFormat
* @param operationOrder
* @param operation
* @param operationName
*/
private void createMethod(DMEntity entity, String order, Operation operation) {
DMMethod m = createDMMethod(entity, EOModelExtractor.getLabel(operation), flexoAction != null ? flexoAction.getEditor() : null);
m.setDescription(operation.getDocumentation());
if (operation.isPrivate()) {
m.setVisibilityModifier(DMVisibilityType.PRIVATE);
} else if (operation.isProtected()) {
m.setVisibilityModifier(DMVisibilityType.PROTECTED);
} else if (operation.isPublic()) {
m.setVisibilityModifier(DMVisibilityType.PUBLIC);
} else {
m.setVisibilityModifier(DMVisibilityType.NONE);
}
if (operation.getResult() != null && entities.get(operation.getResult()) != null) {
m.setReturnType(DMType.makeResolvedDMType(entities.get(operation.getResult())), false);
}
addProperty(RATIONAL_TYPE_ATTRIBUTE, "Operation", m);
extractProperties(operation, m);
addProperty(ORDER_ATTRIBUTE, order, m);
List params = operation.getParameters();
if (params != null) {
for (int k = 0; k < params.getChildCount(); k++) {
Parameter p = (Parameter) params.get(k);
String paramName = EOModelExtractor.getLabel(p);
if (paramName != null) {
DMMethodParameter methodParam;
try {
methodParam = m.createNewParameter();
methodParam.setName(paramName);
if (p.getType() != null && entities.get(p.getType()) != null) {
methodParam.setType(DMType.makeResolvedDMType(entities.get(p.getType())), false);
} else {
methodParam.setType(DMType.makeResolvedDMType(project.getDataModel().getDMEntity(Object.class)), false);
}
} catch (DuplicateMethodSignatureException e) {
e.printStackTrace();
}
}
}
}
}
/**
* @param flexoAction
* @param entity
* @param propertyFormat
* @param j
* @param attrib
*/
private void createAttribute(DMEntity entity, String order, ClassAttribute attrib) {
String attributeName = EOModelExtractor.getLabel(attrib);
String card = null;
int start = attributeName.indexOf('[');
if (start > -1) {
int end = attributeName.indexOf(']');
if (end > start) {
card = attributeName.substring(start + 1, end).trim();
}
attributeName = attributeName.substring(0, start).trim();
}
DMProperty prop = createDMProperty(entity, attributeName);
if (attrib.getType() != null) {
DMEntity e = entities.get(attrib.getType());
if (e != null) {
prop.setType(DMType.makeResolvedDMType(e), false);
}
}
prop.setDescription(attrib.getDocumentation());
addProperty(RATIONAL_TYPE_ATTRIBUTE, "ClassAttribute", prop);
if (card != null) {
addProperty("client_cardinality", card, prop);
}
extractProperties(attrib, prop);
addProperty(ORDER_ATTRIBUTE, order, prop);
}
/**
* @param flexoAction
* @param petalObject
* @param modelObject
*/
private void extractProperties(cb.petal.PetalObject petalObject, FlexoModelObject modelObject) {
for (String name : petalObject.getNames()) {
if (propertyWithNameShouldBeIgnored(name)) {
continue;
}
PetalNode value = petalObject.getProperty(name);
String s = getStringRepresentation(value);
if (value != null) {
addProperty(name, s, modelObject);
}
}
ArrayList<PetalNode> attributes = petalObject.getProperties(ATTRIBUTES_PROPERTY_NAME);
if (attributes != null) {
for (PetalNode n : attributes) {
if (n instanceof List) {
List attributeList = (List) n;
for (Object o : attributeList.getElements()) {
if (o instanceof Attribute) {
Attribute a = (Attribute) o;
PetalNode value = a.getValue();
String s = getStringRepresentation(value);
addProperty(a.getAttributeName(), s, modelObject);
}
}
}
}
}
}
private boolean propertyWithNameShouldBeIgnored(String name) {
for (String propertiesToIgnore : PROPERTIES_TO_IGNORE) {
if (propertiesToIgnore.equals(name)) {
return true;
}
}
return false;
}
private String getStringRepresentation(PetalNode value) {
String s = value != null ? value.toString() : null;
if (value instanceof Value) {
s = ((Value) value).getStringValue();
} else if (value instanceof Literal) {
s = ((Literal) value).getLiteralValue().toString();
}
return s;
}
private DMProperty createRelationship(Role role, DMEntity from, DMEntity to) {
boolean isRoleToOne = role.getCardinality() != null && role.getCardinality().equals("1");
DMProperty newProperty = new DMProperty(from.getDMModel(), EOModelExtractor.getLabel(role), DMType.makeResolvedDMType(to), /*isRoleToOne?*/
DMCardinality.SINGLE/*:DMCardinality.VECTOR*/, from.getIsReadOnly(), true,
DMPropertyImplementationType.PUBLIC_ACCESSORS_PRIVATE_FIELD);
extractProperties(role, newProperty);
if (role.getParent() instanceof PetalObject) {
extractProperties((PetalObject) role.getParent(), newProperty);
}
from.registerProperty(newProperty, true);
return newProperty;
}
private DMProperty createDMProperty(DMEntity entity, String newPropertyName) {
DMEntity defaultType = entity.getDMModel().getDMEntity(String.class);
DMProperty newProperty = new DMProperty(entity.getDMModel(), /*entity,*/newPropertyName, DMType.makeResolvedDMType(defaultType),
DMCardinality.SINGLE, entity.getIsReadOnly(), true, DMPropertyImplementationType.PUBLIC_ACCESSORS_PRIVATE_FIELD);
entity.registerProperty(newProperty, true);
return newProperty;
}
private DMMethod createDMMethod(DMEntity entity, String newMethodName, FlexoEditor editor) {
CreateDMMethod createMethod = CreateDMMethod.actionType.makeNewAction(entity, null, editor);
createMethod.setNewMethodName(newMethodName);
createMethod.doAction();
return createMethod.getNewMethod();
}
private DMEntity createDMEntity(String entityName, DMPackage pack) {
DMEntity newEntity = new DMEntity(pack.getDMModel(), entityName, pack.getName(), entityName, null);
pack.getRepository().registerEntity(newEntity);
return newEntity;
}
/**
* @param flexoAction
* @param attrib
* @param prop
*/
private void addProperty(String name, String value, FlexoModelObject prop) {
if (value == null || value.length() == 0) {
return;
}
AddFlexoProperty add = AddFlexoProperty.actionType.makeNewAction(prop, null, flexoAction != null ? flexoAction.getEditor() : null);
add.setName(name);
add.setValue(value);
add.setInsertSorted(true);
add.doAction();
}
}