/*
* Ocl2DeclCode.java
*
* Copyright (c) 2010 Bjoern Freitag
* Contact: <bjoern.freitag@mailbox.tu-dresden.de>
*
* This file is part of the Dresden OCL2.0 Toolkit
* created at Technische Universitaet Dresden (TUD), Germany.
* Visit http://dresden-ocl.sourceforge.net/ for details.
*
* This library 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 library 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 library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
*/
package org.dresdenocl.tools.codegen.declarativ.impl;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.eclipse.emf.ecore.EObject;
import org.dresdenocl.essentialocl.expressions.BooleanLiteralExp;
import org.dresdenocl.essentialocl.expressions.CollectionItem;
import org.dresdenocl.essentialocl.expressions.CollectionKind;
import org.dresdenocl.essentialocl.expressions.CollectionLiteralExp;
import org.dresdenocl.essentialocl.expressions.CollectionLiteralPart;
import org.dresdenocl.essentialocl.expressions.EnumLiteralExp;
import org.dresdenocl.essentialocl.expressions.ExpressionInOcl;
import org.dresdenocl.essentialocl.expressions.IfExp;
import org.dresdenocl.essentialocl.expressions.IntegerLiteralExp;
import org.dresdenocl.essentialocl.expressions.IteratorExp;
import org.dresdenocl.essentialocl.expressions.OclExpression;
import org.dresdenocl.essentialocl.expressions.OperationCallExp;
import org.dresdenocl.essentialocl.expressions.PrimitiveLiteralExp;
import org.dresdenocl.essentialocl.expressions.PropertyCallExp;
import org.dresdenocl.essentialocl.expressions.RealLiteralExp;
import org.dresdenocl.essentialocl.expressions.StringLiteralExp;
import org.dresdenocl.essentialocl.expressions.TypeLiteralExp;
import org.dresdenocl.essentialocl.expressions.Variable;
import org.dresdenocl.essentialocl.expressions.VariableExp;
import org.dresdenocl.essentialocl.expressions.util.ExpressionsSwitch;
import org.dresdenocl.essentialocl.types.AnyType;
import org.dresdenocl.essentialocl.types.BagType;
import org.dresdenocl.essentialocl.types.CollectionType;
import org.dresdenocl.essentialocl.types.SequenceType;
import org.dresdenocl.essentialocl.types.SetType;
import org.dresdenocl.pivotmodel.AssociationProperty;
import org.dresdenocl.pivotmodel.Constraint;
import org.dresdenocl.pivotmodel.ConstraintKind;
import org.dresdenocl.pivotmodel.Expression;
import org.dresdenocl.pivotmodel.Operation;
import org.dresdenocl.pivotmodel.PrimitiveType;
import org.dresdenocl.pivotmodel.PrimitiveTypeKind;
import org.dresdenocl.pivotmodel.Property;
import org.dresdenocl.pivotmodel.Type;
import org.dresdenocl.tools.codegen.declarativ.IOcl2DeclCode;
import org.dresdenocl.tools.codegen.declarativ.IOcl2DeclSettings;
import org.dresdenocl.tools.codegen.declarativ.code.ICode;
import org.dresdenocl.tools.codegen.declarativ.code.IComplexCode;
import org.dresdenocl.tools.codegen.declarativ.code.impl.Code;
import org.dresdenocl.tools.codegen.declarativ.code.impl.CodeString;
import org.dresdenocl.tools.codegen.declarativ.mapping.Guide;
import org.dresdenocl.tools.codegen.declarativ.mapping.IMappedClass;
import org.dresdenocl.tools.codegen.exception.Ocl2CodeException;
import org.dresdenocl.tools.template.ITemplate;
/**
* <p>
* The DeclarativeCodeGenerator generates declarative target code for a given
* ExpressionInOcl.
* </p>
* <p>
* The OclExpressions from a UML/OCL or MOF/OCL model are transformed to the
* target language using two different mappings:<br />
* <ul>
* <li>Mapping between models:<br />
* The first mapping maps the Classifiers, its attributes and association ends
* to a target model. The target model must implement the MappedModel interface
* and describes the model elements by Guide objects.</li>
* <li>Language mapping:<br />
* The second mapping maps OCL language artefacts to fragments of the target
* language using templates which are read by the DeclarativeTemplateEngine. The
* templates are parametrisized by the DeclarativeCodeGenerator using target
* model information queried via the MappedModel instance.
* </ul>
*
* @author Florian Heidenreich
* @author Bjoern Freitag
*
* @see org.dresdenocl.codegen.decl.mapping.IMappedModel
* @see org.dresdenocl.codegen.decl.mapping.IMappedClass
* @see org.dresdenocl.codegen.decl.mapping.Guide
*/
public class Ocl2DeclCode extends ExpressionsSwitch<ICode> implements
IOcl2DeclCode {
/** The Logger for this class. */
private static final Logger LOGGER = Logger.getLogger(Ocl2DeclCode.class);
/** The Settings used during code generation. */
private IOcl2DeclSettings mySettings;
/**
* This map is filled by assignGuides and maps an OclExpression to a list of
* Guide objects
*/
private Map<OclExpression, List<Guide>> navigationMap;
/**
* This map mapped a variable Name to a Guide.
*/
private Map<String, Guide> variableMap;
private int uniqueAlias;
/**
* If the variable true, than generated no allInstances code.
*/
private boolean useVariable;
private boolean closure;
/**
*
*/
private List<ICode> commonTableExpressions;
private String constraintName;
/**
* The actualNumber of commonTable
*/
private int cteNumber;
/**
* The number for not named constraints.
*/
private int uniqueConstraintNumber;
/**
* <p>
* Creates a new instance to transform code.
* </p>
*
* @throws Ocl2CodeException
* If the initialization fails.
*/
public Ocl2DeclCode() throws Ocl2CodeException {
init();
}
/**
* <p>
* Initializes the code generator.
* </p>
*
* @throws Ocl22CodeException
* Thrown, if a String template for code transformation can not be
* found.
*/
private void init() throws Ocl2CodeException {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("init() - start");
}
// no else.
resetEnvironment();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("init() - end");
}
// no else.
}
/*
* (non-Javadoc)
* @see org.dresdenocl.tools.codgen.IOcl2Code#getSettings()
*/
public IOcl2DeclSettings getSettings() {
return mySettings;
}
/*
* (non-Javadoc)
* @see org.dresdenocl.tools.codgen.IOcl2Code#resetEnviornment()
*/
public void resetEnvironment() {
uniqueConstraintNumber = 0;
navigationMap = new HashMap<OclExpression, List<Guide>>();
variableMap = new HashMap<String, Guide>();
useVariable = false;
commonTableExpressions = new LinkedList<ICode>();
constraintName = "";
closure = false;
}
/*
* (non-Javadoc)
* @see org.dresdenocl.tools.codgen.IOcl2Code#setSettings()
*/
public void setSettings(IOcl2DeclSettings settings) {
mySettings = settings;
}
/*
* (non-Javadoc)
* @see
* org.dresdenocl.tools.codgen.IOcl2Code#transformFragmentCode(java
* .util .List)
*/
public List<String> transformFragmentCode(List<Constraint> constraints)
throws Ocl2CodeException {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("transformFragmentCode(List<Constraint>) - start");
}
// no else.
List<String> result;
result = new ArrayList<String>();
for (Constraint aConstraint : constraints) {
String aResult = transformFragmentCode(aConstraint);
if (aResult == null)
continue;
result.add(aResult);
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("transformFragmentCode(List<Constraint>)"
+ " - end - return value=" + result);
}
// no else.
return result;
}
/**
* <p>
* This method transforms the fragment code for a given {@link Constraint}.
* </p>
*
* @param aConstraint
* The {@link Constraint} for which code shall be transformed.
* @return An {@link String} containing the Code transformed for the given
* {@link Constraint}'s {@link OclExpression}.
* @throws Ocl22CodeException
*/
private String transformFragmentCode(Constraint aConstraint)
throws Ocl2CodeException {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("transformFragmentCode(Constraint) - start");
}
// no else.
reset();
// Check of generated Constraint Types:
ITemplate template = null;
if (aConstraint.getKind() == ConstraintKind.INVARIANT) {
template =
mySettings.getTemplateGroup().getTemplate("constraint_invariant");
constraintName = aConstraint.getName();
} else if (aConstraint.getKind() == ConstraintKind.DEFINITION && aConstraint.getDefinedFeature() instanceof Property) {
template =
mySettings.getTemplateGroup().getTemplate("constraint_definition");
template.setAttribute("def_name", aConstraint.getDefinedFeature().getName());
} else {
return null;
}
ICode bodyExpression;
Expression anExpression;
anExpression = aConstraint.getSpecification();
bodyExpression = doSwitch(anExpression);
Guide classGuide = variableMap.values().iterator().next();
classGuide.reset();
if (aConstraint.getKind() == ConstraintKind.DEFINITION) {
template.setAttribute("attribute", classGuide.getSelect());
constraintName = classGuide.getFrom()+"_"+aConstraint.getDefinedFeature().getName();
}
if (constraintName == null || constraintName.equals("")) {
constraintName = getUniqueConstraintName();
}
template.setAttribute("constraint_name", constraintName);
template.setAttribute("context", classGuide.getFrom());
template.setAttribute("context_alias", classGuide.getAlias());
template.setAttribute("expression", bodyExpression.getResult());
if (commonTableExpressions.size() > 0) {
template.setAttribute("common_table", commonTableExpressions.get(0)
.getResult());
}
ITemplate comment =
mySettings.getTemplateGroup().getTemplate("constraint_comment");
comment.setAttribute("context", ((Type) aConstraint.getConstrainedElement()
.get(0)).getName());
comment.setAttribute("expression",
anExpression.getBody().replace("\r\n ", "").replace(" \r\n", "")
.replace("\r\n", ""));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("transformFragmentCode(Constraint)"
+ " - end - return value=" + template.toString());
}
// no else.
return comment.toString() + "\n" + template.toString();
}
/**
* Returns a unique name of a constraint.
*
* @return the name of constraint
*/
private String getUniqueConstraintName() {
uniqueConstraintNumber++;
return "UNAMED_CONSTRAINT" + uniqueConstraintNumber;
}
/*
* (non-Javadoc)
* @see org.dresdenocl.essentialocl.expressions.util.ExpressionsSwitch
* #caseBooleanLiteralExp(BooleanLiteralExp)
*/
public ICode caseBooleanLiteralExp(BooleanLiteralExp aBooleanLiteralExp) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseBooleanLiteralExp(BooleanLiteralExp) - start");
}
// no else.
IComplexCode template;
if (aBooleanLiteralExp.isBooleanSymbol()) {
template =
new Code("literal_boolean_true",mySettings);
}
else {
template =
new Code("literal_boolean_false",mySettings);
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseBooleanLiteralExp(BooleanLiteralExp)"
+ " - end - return value=" + template.toString());
}
// no else.
return template;
}
/*
* (non-Javadoc)
* @see org.dresdenocl.essentialocl.expressions.util.ExpressionsSwitch#
* caseCollectionLiteralExp
* (org.dresdenocl.essentialocl.expressions.CollectionLiteralExp)
*/
public ICode caseCollectionLiteralExp(
CollectionLiteralExp anCollectionLiteralExp) {
List<CollectionLiteralPart> parts = anCollectionLiteralExp.getPart();
String templateName = "";
IComplexCode template;
// determine template to use depending on collection kind
if (anCollectionLiteralExp.getKind() == CollectionKind.BAG) {
templateName = "literal_collection_bag";
}
else if (anCollectionLiteralExp.getKind() == CollectionKind.SET) {
templateName = "literal_collection_set";
}
else if (anCollectionLiteralExp.getKind() == CollectionKind.SEQUENCE) {
templateName = "literal_collection_sequence";
}
else {
assert (false) : "Unknown CollectionKind";
}
// get template for items in the collection
template =
new Code(templateName,mySettings);
// parameterize the template engine
for (CollectionLiteralPart clp : parts) {
template.addCode("items",
doSwitch((OclExpression) ((CollectionItem) clp).getItem()));
}
return template;
}
/*
* (non-Javadoc)
* @see org.dresdenocl.essentialocl.expressions.util.ExpressionsSwitch
* #caseEnumLiteralExp
* (org.dresdenocl.essentialocl.expressions.EnumLiteralExp)
*/
public ICode caseEnumLiteralExp(EnumLiteralExp anEnumLiteralExp) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseEnumLiteralExp(EnumLiteralExp) - start");
}
// no else.
IComplexCode template;
template =
new Code("literal_enum",mySettings);
template.addCode("value", new CodeString(anEnumLiteralExp
.getReferredEnumLiteral().getName()));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseEnumLiteralExp(EnumLiteralExp)"
+ " - end - return value=" + template.toString());
}
// no else.
return template;
}
/*
* (non-Javadoc)
* @see org.dresdenocl.essentialocl.expressions.util.ExpressionsSwitch
* #caseExpressionInOcl
* (org.dresdenocl.essentialocl.expressions.ExpressionInOcl)
*/
public ICode caseExpressionInOcl(ExpressionInOcl anExpressionInOcl) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseExpressionInOcl(ExpressionInOcl) - start");
}
// no else.
Variable v = anExpressionInOcl.getContext();
IMappedClass constrainedType =
getSettings().getMappedModel().getClass(v.getType().getName());
Guide classGuide =
getSettings().getMappedModel().getClass(constrainedType.getName())
.getClassGuide();
classGuide.setAlias(getUniqueAlias());
classGuide.reset();
variableMap.put(v.getName(), classGuide);
/* Transform bodyCode. */
ICode bodyExpression =
doSwitch((EObject) anExpressionInOcl.getBodyExpression());
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseExpressionInOcl(ExpressionInOcl)"
+ " - end - return value=" + bodyExpression);
}
// no else.
return bodyExpression;
}
/*
* (non-Javadoc)
* @see org.dresdenocl.essentialocl.expressions.util.ExpressionsSwitch
* #caseIfExp(org.dresdenocl.essentialocl.expressions.IfExp)
*/
public ICode caseIfExp(IfExp anIfExp) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseIfExp(IfExp) - start");
}
// no else.
IComplexCode template;
OclExpression ifExp;
OclExpression thenExp;
OclExpression elseExp;
ICode ifCode;
ICode thenCode;
ICode elseCode;
ifExp = anIfExp.getCondition();
thenExp = anIfExp.getThenExpression();
elseExp = anIfExp.getElseExpression();
/* Transform ifExp, thenExp and elseExp. */
ifCode = doSwitch((EObject) ifExp);
thenCode = doSwitch((EObject) thenExp);
elseCode = doSwitch((EObject) elseExp);
/* Transform ifExp. */
template =
new Code("if_expression",mySettings);
template.addCode("if_branch", ifCode);
template.addCode("then_branch", thenCode);
template.addCode("else_branch", elseCode);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseIfExp(IfExp)" + " - end - return value="
+ template.toString());
}
// no else.
return template;
}
/*
* (non-Javadoc)
* @see org.dresdenocl.essentialocl.expressions.util.ExpressionsSwitch
* #caseIntegerLiteralExp
* (org.dresdenocl.essentialocl.expressions.IntegerLiteralExp)
*/
public ICode caseIntegerLiteralExp(IntegerLiteralExp anIntegerLiteralExp) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseIntegerLiteralExp(IntegerLiteralExp) - start");
}
// no else.
IComplexCode template;
template = new Code("literal_integer",mySettings);
template.addCode(
"value",
new CodeString(new Integer(anIntegerLiteralExp.getIntegerSymbol())
.toString()));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseIntegerLiteralExp(IntegerLiteralExp)"
+ " - end - return value=" + template.toString());
}
// no else.
return template;
}
/*
* (non-Javadoc)
* @see org.dresdenocl.essentialocl.expressions.util.ExpressionsSwitch
* #caseIteratorExp
* (org.dresdenocl.essentialocl.expressions.IteratorExp)
*/
public ICode caseIteratorExp(IteratorExp anIteratorExp) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseIteratorExp(IteratorExp) - start - Iterator"
+ anIteratorExp);
}
String operationName = anIteratorExp.getName();
if (operationName.equals("iterate")) {
throw new UnsupportedOperationException(
"The iterate operation is not supported.");
}
ICode result = null;
OclExpression sourceExp = anIteratorExp.getSource();
OclExpression bodyExp = anIteratorExp.getBody();
// get code for source expression
IComplexCode sourceCode = (IComplexCode) doSwitch(sourceExp);
List<Guide> srcGuides = navigationMap.get(sourceExp);
Guide guideSrc = srcGuides.get(0);
guideSrc.reset();
if (guideSrc.numberOfSteps() > 1) {
guideSrc = new Guide(guideSrc.isNavigation(), guideSrc.getAlias());
guideSrc.add(srcGuides.get(0).getSelect(), srcGuides.get(0).getFrom(),
srcGuides.get(0).getWhere());
guideSrc.reset();
}
if (operationName.equals("closure")) {
result = handleIterClosure(anIteratorExp, bodyExp, guideSrc, srcGuides);
}
else {
Guide varGuide = guideSrc;
// evaluate the arguments
for (Variable v : anIteratorExp.getIterator()) {
variableMap.put(v.getName(), varGuide);
if (anIteratorExp.getIterator().size() > 1) {
varGuide =
new Guide(guideSrc.isNavigation(), getUniqueAlias());
varGuide.add(guideSrc.getSelect(), guideSrc.getFrom(),
guideSrc.getWhere());
varGuide.reset();
}
}
boolean saveAllInstances = useVariable;
useVariable = false;
IComplexCode arg = (IComplexCode) doSwitch(bodyExp);
useVariable = saveAllInstances;
if (operationName.equals("collect")) {
result =
handleIterCollect(anIteratorExp, bodyExp, arg, guideSrc, srcGuides,
sourceCode);
}
else if (operationName.equals("select") || operationName.equals("reject")) {
result =
handleIterSelectReject(operationName, sourceCode, arg,
anIteratorExp, bodyExp);
}
else if (operationName.equals("forAll") || operationName.equals("exists")) {
result =
handleIterForAllExits(operationName, sourceCode, arg, srcGuides,
anIteratorExp.getIterator());
}
}
for (Variable v : anIteratorExp.getIterator()) {
if (variableMap.containsKey(v.getName()))
variableMap.remove(v.getName());
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseIteratorExp(IteratorExp)" + " - end - return value="
+ result);
}
// no else.
return result;
}
/*
* (non-Javadoc)
* @see org.dresdenocl.essentialocl.expressions.util.ExpressionsSwitch#
* caseOperationCallExp
* (org.dresdenocl.essentialocl.expressions.OperationCallExp)
*/
public ICode caseOperationCallExp(OperationCallExp anOperationCallExp) {
if (LOGGER.isDebugEnabled()) {
LOGGER
.debug("caseOperationCallExp(OperationCallExp) - start - Operation:"
+ anOperationCallExp);
}
// no else.
ICode resultExp;
OclExpression sourceExp;
ICode sourceCode;
List<OclExpression> arguments = anOperationCallExp.getArgument();
List<ICode> args = new ArrayList<ICode>();
for (OclExpression oe : arguments) {
args.add(doSwitch(oe));
}
/* Transform Code for the source of the operation call. */
sourceExp = anOperationCallExp.getSource();
sourceCode = doSwitch((EObject) sourceExp);
navigationMap.put(anOperationCallExp, navigationMap.get(sourceExp));
Operation anOperation = anOperationCallExp.getReferredOperation();
resultExp =
handleAllOperations(anOperation.getName(),
anOperationCallExp.getType(), sourceExp, sourceCode, args,
arguments);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseOperationCallExp(OperationCallExp)"
+ " - end - return value=" + resultExp);
}
// no else.
return resultExp;
}
/*
* (non-Javadoc)
* @see org.dresdenocl.essentialocl.expressions.util.ExpressionsSwitch
* #casePropertyCallExp
* (org.dresdenocl.essentialocl.expressions.PropertyCallExp)
*/
public ICode casePropertyCallExp(PropertyCallExp anPropertyCallExp) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("casePropertyCallExp(PropertyCallExp) - start");
}
List<Guide> guides = assignGuides(anPropertyCallExp);
ICode result;
result =
handlePropProperty(anPropertyCallExp.getReferredProperty(), guides);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("casePropertyCallExp(PropertyCallExp)"
+ " - end - return value=" + result);
}
return result;
}
/*
* (non-Javadoc)
* @see org.dresdenocl.essentialocl.expressions.util.ExpressionsSwitch
* #caseRealLiteralExp
* (org.dresdenocl.essentialocl.expressions.RealLiteralExp)
*/
public ICode caseRealLiteralExp(RealLiteralExp aRealLiteralExp) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseRealLiteralExp(RealLiteralExp) - start");
}
// no else.
IComplexCode template;
template =
new Code("literal_real",mySettings);
// parameterize the template engine
template.addCode("value",
new CodeString(new Float(aRealLiteralExp.getRealSymbol()).toString()));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseRealLiteralExp(RealLiteralExp)"
+ " - end - return value=" + template.toString());
}
// no else.
return template;
}
/*
* (non-Javadoc)
* @see org.dresdenocl.essentialocl.expressions.util.ExpressionsSwitch
* #caseStringLiteralExp
* (org.dresdenocl.essentialocl.expressions.StringLiteralExp)
*/
public ICode caseStringLiteralExp(StringLiteralExp aStringLiteralExp) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseStringLiteralExp(StringLiteralExp) - start");
}
// no else.
IComplexCode template =
new Code("literal_string",mySettings);
// parameterize the template engine
template.addCode("value",
new CodeString(aStringLiteralExp.getStringSymbol()));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseStringLiteralExp(StringLiteralExp)"
+ " - end - return value=" + template.toString());
}
// no else.
return template;
}
/*
* (non-Javadoc)
* @see org.dresdenocl.essentialocl.expressions.util.ExpressionsSwitch#
* caseTypeLiteralExp
* (org.dresdenocl.essentialocl.expressions.TypeLiteralExp)
*/
public ICode caseTypeLiteralExp(TypeLiteralExp anTypeLiteralExp) {
assignClassGuide(anTypeLiteralExp, anTypeLiteralExp.getReferredType());
return new CodeString(anTypeLiteralExp.getReferredType().getName());
}
/*
* (non-Javadoc)
* @see org.dresdenocl.essentialocl.expressions.util.ExpressionsSwitch
* #caseVariableExp
* (org.dresdenocl.essentialocl.expressions.VariableExp)
*/
public ICode caseVariableExp(VariableExp aVariableExp) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseVariableExp(VariableExp) - start - Variable:"
+ aVariableExp);
}
// no else.
IComplexCode template =
new Code("literal_variable",mySettings);
template.addCode("value", createObjectValue(variableMap.get(aVariableExp
.getReferredVariable().getName())));
if (aVariableExp.getType() instanceof Type
&& !(aVariableExp.getType() instanceof PrimitiveType)) {
List<Guide> guides = new LinkedList<Guide>();
guides.add(assignClassGuide(aVariableExp, aVariableExp.getType()));
navigationMap.put(aVariableExp, guides);
}
else {
navigationMap.put(aVariableExp, assignGuides(aVariableExp));
}
if (aVariableExp.getReferredVariable().getName().equals("self"))
navigationMap.get(aVariableExp).get(0).setAlias("self");
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("caseVariableExp(VariableExp)" + " - end - return value="
+ template.toString());
}
// no else.
return template;
}
/**
* Generates a code fragment for an arithmetic operation.
*
* @param name
* the name of the arithmetic operation (can be div, minus, mult and
* plus)
* @param sourceCode
* the code of the source expression (argument 1)
* @param firstArg
* the code of the argument expression (argument 2)
* @return declarative code fragment for the arithmetic operation
*/
protected ICode handleArithmeticOperation(String name,
ICode sourceCode, ICode firstArg) {
return createTwoOperandOperation("arithmetic_expression_" + name,
sourceCode, firstArg);
}
/**
* Generates a code fragement for all operations.
*
* @param operationName
* the name of the operation
* @param type
* the type of operation
* @param sourceExp
* the source of operation
* @param sourceCode
* the generated code of the source
* @param args
* the generated code of the arguments
* @param arguments
* the arguments of the operation
* @return the generated code
*/
protected ICode handleAllOperations(String operationName, Type type,
OclExpression sourceExp, ICode sourceCode, List<ICode> args,
List<OclExpression> arguments) {
ICode resultExp = null;
ICode firstArg = null;
if (args.size() > 0) {
firstArg = args.get(0);
}
if (operationName.equals("=")) {
resultExp =
handleRelExpression("equals", sourceExp, sourceCode, firstArg);
}
else if (operationName.equals("<>")) {
resultExp =
handleRelExpression("nequals", sourceExp, sourceCode, firstArg);
}
else if (operationName.equals(">")) {
resultExp =
handleRelExpression("greater", sourceExp, sourceCode, firstArg);
}
else if (operationName.equals(">=")) {
resultExp =
handleRelExpression("greaterequal", sourceExp, sourceCode, firstArg);
}
else if (operationName.equals("<")) {
resultExp =
handleRelExpression("lesser", sourceExp, sourceCode, firstArg);
}
else if (operationName.equals("<=")) {
resultExp =
handleRelExpression("lesserequal", sourceExp, sourceCode, firstArg);
}
// arithmetic expressions
else if (operationName.equals("+")) {
resultExp = handleArithmeticOperation("plus", sourceCode, firstArg);
}
else if (operationName.equals("*")) {
resultExp = handleArithmeticOperation("mult", sourceCode, firstArg);
}
else if (operationName.equals("/")) {
resultExp = handleArithmeticOperation("div", sourceCode, firstArg);
}
else if (operationName.equals("-")) {
if (args.isEmpty()) { // unary minus special case
resultExp = handleUnaryMinus(sourceCode);
}
else {
resultExp = handleArithmeticOperation("minus", sourceCode, firstArg);
}
}
// unary expressions (unary minus special case above)
else if (operationName.equals("not")) {
resultExp = handleUnaryNot(sourceCode);
}
// logical expression
else if (operationName.equals("and")) {
resultExp = handleLogicalExpression("and", sourceCode, firstArg);
}
else if (operationName.equals("or")) {
resultExp = handleLogicalExpression("or", sourceCode, firstArg);
}
else if (operationName.equals("xor")) {
resultExp = handleLogicalExpression("xor", sourceCode, firstArg);
}
else if (operationName.equals("implies")) {
resultExp = handleLogicalExpression("implies", sourceCode, firstArg);
}
// collection related operations - BASIC VALUE
else if (operationName.equals("count")) {
resultExp = handleCollCount((IComplexCode) sourceCode, firstArg);
}
else if ((operationName.equals("size") && !(sourceExp.getType() instanceof PrimitiveType))) {
resultExp = handleCollObjectChange("size", (IComplexCode) sourceCode);
}
else if (operationName.equals("sum")) {
resultExp = handleCollObjectChange("sum", (IComplexCode) sourceCode);
}
// collection related operations - COMPLEX PREDICATE
else if (operationName.equals("includes")) {
resultExp = handleCollIncludes(sourceCode, firstArg);
}
else if (operationName.equals("excludes")) {
resultExp = handleCollExcludes(sourceCode, firstArg);
}
else if (operationName.equals("includesAll")) {
resultExp = handleCollIncludesAll(sourceCode, firstArg);
}
else if (operationName.equals("excludesAll")) {
resultExp = handleCollExcludesAll(sourceCode, firstArg);
}
else if (operationName.equals("isEmpty")) {
resultExp = handleCollIsEmpty(sourceCode);
}
else if (operationName.equals("notEmpty")) {
resultExp = handleCollNotEmpty(sourceCode);
}
else if (operationName.equals("intersection")) {
resultExp =
handleCollIntersection(sourceCode, firstArg,
(CollectionType) sourceExp.getType());
}
else if (operationName.equals("including")) {
resultExp =
handleCollIncluding(sourceCode, firstArg,
(CollectionType) sourceExp.getType());
}
else if (operationName.equals("excluding")) {
resultExp =
handleCollExcluding(sourceCode, firstArg,
(CollectionType) sourceExp.getType());
}
else if (operationName.equals("union")) {
resultExp =
handleCollUnion(sourceCode, firstArg,
(CollectionType) sourceExp.getType(), navigationMap
.get(sourceExp).get(0));
}
else if (operationName.equals("symmetricDifference")) {
resultExp = handleCollSymmetricDifference(sourceCode, firstArg);
}
// collection related operations - MODEL TYPE QUERY
else if (operationName.equals("allInstances")) {
resultExp = handleAllInstances(navigationMap.get(sourceExp).get(0));
}
// BASIC TYPE - String operations
else if (operationName.equals("size")) {
resultExp = handleStringSize(sourceCode);
}
else if (operationName.equals("concat")) {
resultExp = handleStringConcat(sourceCode, firstArg);
}
else if (operationName.equals("toUpperCase")) {
resultExp = handleStringToUpper(sourceCode);
}
else if (operationName.equals("toLowerCase")) {
resultExp = handleStringToLower(sourceCode);
}
else if (operationName.equals("substring")) {
resultExp = handleStringSubstring(sourceCode, firstArg, args.get(1));
}
else if (operationName.equals("matches")) {
resultExp = handleStringMatches(sourceCode, firstArg);
}
// BASIC TYPE - Real and Integer operations
else if (operationName.equals("abs")) {
resultExp = handleIntExpression("abs", sourceCode, null);
}
else if (operationName.equals("floor")) {
resultExp = handleIntExpression("floor", sourceCode, null);
}
else if (operationName.equals("max")) {
if (sourceExp.getType() instanceof CollectionType && firstArg == null) {
resultExp = handleCollObjectChange("max", (IComplexCode) sourceCode);
}
else {
resultExp = handleIntExpression("max", sourceCode, firstArg);
}
}
else if (operationName.equals("min")) {
if (sourceExp.getType() instanceof CollectionType && firstArg == null) {
resultExp = handleCollObjectChange("min", (IComplexCode) sourceCode);
}
else {
resultExp = handleIntExpression("min", sourceCode, firstArg);
}
}
else if (operationName.equals("round")) {
resultExp = handleIntExpression("round", sourceCode, null);
}
else if (operationName.equals("div")) {
resultExp = handleIntExpression("div", sourceCode, firstArg);
}
else if (operationName.equals("mod")) {
resultExp = handleIntExpression("mod", sourceCode, firstArg);
}
else if (operationName.equals("asSet")) {
resultExp = sourceCode;
}
else if (operationName.equals("asSequence")) {
resultExp = sourceCode;
}
else if (operationName.equals("oclIsTypeOf")) {
Guide guide = navigationMap.get(arguments.get(0)).get(0);
resultExp = handleOclIsTypeOf(guide, sourceCode);
}
else if (operationName.equals("oclIsKindOf")) {
List<Type> parents = query_Supertypes(type);
if (parents.size() != 1) {
throw new IllegalStateException(
"Illegal number of supertypes for type: " + (type).getName() + " !");
}
resultExp =
handleOclIsKindOf(
getSettings().getMappedModel().getClass(firstArg.getResult())
.getClassGuide(),
getSettings().getMappedModel().getClass(parents.get(0).getName())
.getClassGuide());
}
else {
return resultExp;
// throw new UnsupportedOperationException("The operation " +
// operationName + "is not supported.");
}
return resultExp;
}
/**
* Generates a code fragment for an allInstances operation.
*
* @return declarative code fragment for the allInstances operation
*/
protected ICode handleAllInstances(Guide guide) {
useVariable = true;
// return null;
return createSelectStatement(Arrays.asList(guide));
}
/**
* Generates a code fragment for a count operation.
*
* @param sourceCode
* the declarative code fragment representing the source collection
* @param guide
* the guide to the source expression
* @param firstArg
* argument passed to the feature call which is used as reference
* object
* @return declarative code fragment for the count operation
*/
protected ICode handleCollCount(IComplexCode sourceCode, ICode firstArg) {
// ICode select = createObjectValue(guide);
if (sourceCode.getCode("select") != null) {
String tempName = sourceCode.getComplexCode("select").getTemplateName();
if ("feature_call_count".equals(tempName)
|| "feature_call_sum".equals(tempName)
|| "feature_call_size".equals(tempName)) {
sourceCode.changeCode("groupby", null);
IComplexCode code =
new Code(tempName + "_select",mySettings);
code.addCode("select",
sourceCode.getComplexCode("select").getCode("select"));
sourceCode.changeCode("select", code);
}
}
IComplexCode sqlCode =
new Code("feature_call_count",mySettings);
sqlCode.addCode("select", sourceCode.getCode("select"));
ICode where1 =
createTwoOperandOperation("relational_expression_equals_any",
sourceCode.getCode("select"), firstArg);
changeWhereStatement(sourceCode, where1);
sourceCode.changeCode("select", sqlCode);
return sourceCode;
}
/**
* Generates a code fragment for an excludes operation.
*
* @param sourceCode
* the declarative code fragment representing the source collection
* @param firstArg
* argument passed to the feature call which is used as reference
* object
* @return declarative code fragment for the excludes operation
*/
protected ICode handleCollExcludes(ICode sourceCode, ICode firstArg) {
IComplexCode template =
new Code("feature_call_excludes",mySettings);
template.addCode("operand1", sourceCode);
template.changeCode("operand2", firstArg);
return template;
}
/**
* Generates a code fragment for an excludesAll operation.
*
* @param sourceCode
* the declarative code fragment representing the source collection
* @param firstArg
* argument passed to the feature call which is used as reference
* collection
* @return declarative code fragment for the excludesAll operation
*/
protected ICode handleCollExcludesAll(ICode sourceCode,
ICode firstArg) {
return createTwoOperandOperation("feature_call_excludesall", sourceCode,
firstArg);
}
/**
* Generates a code fragment for an excluding operation.
*
* @param sourceCode
* the declarative code fragment representing the source collection
* @param firstArg
* argument passed to the feature call which is used as reference
* object
* @param collType
* collection type to determine the template to use (BagType,
* SequenceType, SetType)
* @return declarative code fragment for the excluding operation
*/
protected ICode handleCollExcluding(ICode sourceCode,
ICode firstArg, CollectionType collType) {
assert (collType != null) : "including() collType may not be null";
String template = null;
if (collType instanceof BagType) {
template = "bag";
}
else if (collType instanceof SequenceType) {
template = "sequence";
}
else if (collType instanceof SetType) {
template = "set";
}
else {
throw new IllegalStateException(
"Unhandled collection type for excluding operation!");
}
IComplexCode returnValue = new Code("feature_call_excluding_"+template,mySettings);
Guide guide =
mySettings.getMappedModel()
.getClass(collType.getElementType().getName()).getClassGuide();
guide.reset();
returnValue.addCode("operand2", firstArg);
returnValue.addCode("element", new CodeString(guide.getSelect().get(0)));
returnValue.addCode("operand1", sourceCode);
return returnValue;
}
/**
* Generates a code fragment for an includes operation.
*
* @param sourceCode
* the declarative code fragment representing the source collection
* @param firstArg
* argument passed to the feature call which is used as reference
* object
* @return declarative code fragment for the includes operation
*/
protected ICode handleCollIncludes(ICode sourceCode, ICode firstArg) {
IComplexCode template =
new Code("feature_call_includes",mySettings);
template.addCode("operand1", sourceCode);
template.addCode("operand2", firstArg);
return template;
}
/**
* Generates a code fragment for an includesAll operation.
*
* @param sourceCode
* the declarative code fragment representing the source collection
* @param firstArg
* argument passed to the feature call which is used as reference
* collection
* @return declarative code fragment for the includesAll operation
*/
protected ICode handleCollIncludesAll(ICode sourceCode,
ICode firstArg) {
return createTwoOperandOperation("feature_call_includesall", sourceCode,
firstArg);
}
/**
* Generates a code fragment for an including operation.
*
* @param sourceCode
* the declarative code fragment representing the source collection
* @param firstArg
* argument passed to the feature call which is used as reference
* object
* @param collType
* collection type to determine the template to use (BagType,
* SequenceType, SetType)
* @return declarative code fragment for the including operation
*/
protected ICode handleCollIncluding(ICode sourceCode,
ICode firstArg, CollectionType collType) {
assert (collType != null) : "including() collType may not be null";
String template = null;
if (collType instanceof BagType) {
template ="bag";
}
else if (collType instanceof SequenceType) {
template ="sequence";
}
else if (collType instanceof SetType) {
template ="set";
}
else {
throw new IllegalStateException(
"Unhandled collection type for including operation!");
}
IComplexCode result = new Code("feature_call_including_"+template,mySettings);
result.addCode("operand2", firstArg);
result.addCode("operand1", sourceCode);
return result;
}
/**
* Generates a code fragment for a intersection operation.
*
* @param sourceCode
* the declarative code fragment representing the source collection
* @param firstArg
* argument passed to the feature call which is used as reference
* collection
* @param collType
* collection type to determine the template to use (BagType,
* SetType)
* @return declarative code fragment for the intersection operation
*/
protected ICode handleCollIntersection(ICode sourceCode,
ICode firstArg, CollectionType collType) {
assert (collType != null) : "intersection() collType may not be null";
String template = null;
if (collType instanceof BagType) {
template = "feature_call_intersection_bag";
}
else if (collType instanceof SetType) {
template = "feature_call_intersection_set";
}
else {
throw new IllegalStateException(
"Unhandled collection type for intesection operation!");
}
return createTwoOperandOperation(template, sourceCode, firstArg);
}
/**
* Generates a code fragment for a isEmpty operation
*
* @param sourceCode
* the declarative code fragment representing the source collection
* @return declarative code fragment for the isEmpty operation
*/
protected ICode handleCollIsEmpty(ICode sourceCode) {
return createOperandOperation("feature_call_isempty", sourceCode);
}
/**
* Generates a code fragment for a notEmpty operation.
*
* @param sourceCode
* the declarative code fragment representing the source collection
* @return declarative code fragment for the notEmpty operation
*/
protected ICode handleCollNotEmpty(ICode sourceCode) {
return createOperandOperation("feature_call_notempty", sourceCode);
}
/**
* Generates a code fragment for a collection operation.
*
* @param sourceCode
* the declarative code fragment representing the source collection
* @return declarative code fragment for the collection operation
*/
protected ICode handleCollObjectChange(String name, IComplexCode sourceCode) {
assert (sourceCode != null) : "handleCollObjectChange(): sourceCode may not be null";
if (LOGGER.isDebugEnabled()) {
LOGGER
.debug("handleCollObjectChange(String name, ICode sourceCode) - start - Type:"
+ name + ", Code:" + sourceCode);
}
if (sourceCode.getCode("select") != null) {
String tempName = sourceCode.getComplexCode("select").getTemplateName();
if ((name.equals("sum") || name.equals("size"))
&& ("feature_call_count".equals(tempName)
|| "feature_call_sum".equals(tempName) || "feature_call_size"
.equals(tempName))) {
IComplexCode code =
new Code(tempName + "_select",mySettings);
code.addCode("select",
sourceCode.getComplexCode("select").getCode("select"));
sourceCode.changeCode("select", code);
}
}
if (sourceCode.getCode("select") != null) {
changeObjectVariable("feature_call_" + name, sourceCode);
return sourceCode;
}
else if (sourceCode.getCode("operand") != null) {
return createOperandOperation("feature_call_" + name, sourceCode);
}
else {
IComplexCode code =
new Code( "feature_call_" + name,mySettings);
code.addCode("select", sourceCode);
return code;
}
}
/**
* Generates a code fragment for a symmetricDifference operation.
*
* @param sourceCode
* the declarative code fragment representing the source collection
* @param firstArg
* the declarative code fragment representing the collection passed
* to the feature call which is used to build the symmetric
* difference
* @return declarative code fragment for the symmetricDifference operation
*/
protected ICode handleCollSymmetricDifference(ICode sourceCode,
ICode firstArg) {
return createTwoOperandOperation("feature_call_symmetricdifference",
sourceCode, firstArg);
}
/**
* Generates a declarative code fragment for an union operation.
*
* @param sourceCode
* the declarative code fragment representing the source collection
* @param firstArg
* the declarative code fragment representing the collection passed
* to the feature call which is used to build the union of the two
* collections
* @param collType
* collection type to determine the template to use (BagType,
* SequenceType, SetType)
* @return declarative code fragment for the union operation
*/
protected ICode handleCollUnion(ICode sourceCode, ICode firstArg,
CollectionType collType, Guide guide) {
assert (collType != null) : "including() collType may not be null";
guide.reset();
String template = "feature_call_union_";
if (collType instanceof BagType) {
template += "bag";
}
else if (collType instanceof SequenceType) {
template += "sequence";
}
else if (collType instanceof SetType) {
template += "set";
}
else {
throw new IllegalStateException(
"Unhandled collection type for union operation!");
}
IComplexCode result = createTwoOperandOperation(template, sourceCode, firstArg);
ICode object = createObjectValue(guide);
result.addCode("select", object);
return result;
}
/**
* Generate for int operations
*
* @param name
* the last part of template name
* @param sourceCode
* the first code operand
* @param firstArg
* the second code operand
* @return generated code for the int operations.
*/
protected ICode handleIntExpression(String name, ICode sourceCode,
ICode firstArg) {
return createTwoOperandOperation("feature_call_int_" + name, sourceCode,
firstArg);
}
/**
* Generates a declarative code fragment for a collect iterator.
*
* @param anIteratorExp
* the iterator expression
* @param bodyExp
* the body expression
* @param arg
* the generated body code
* @param guideSrc
* the source guide
* @param srcGuides
* the source guides
* @param sourceCode
* the generated source code
* @return declarative code fragment for the collect iterator
*/
protected ICode handleIterCollect(IteratorExp anIteratorExp,
OclExpression bodyExp, IComplexCode arg, Guide guideSrc,
List<Guide> srcGuides, IComplexCode sourceCode) {
// TODO: optimize collect for the optimize way
List<Guide> nav = new LinkedList<Guide>();
nav.addAll(navigationMap.get(bodyExp));
nav.addAll(srcGuides);
navigationMap.put(anIteratorExp, nav);
Guide guideBody = navigationMap.get(bodyExp).get(0);
guideBody.reset();
guideSrc.reset();
if (srcGuides.size() == 1 && !guideSrc.isNavigation()
&& guideSrc.getSelect().equals(guideSrc.getWhere())) {
sourceCode = null;
}
boolean temp =
Boolean.valueOf(mySettings.getTemplateGroup()
.getTemplate("check_database_references").toString());
if (temp && guideSrc.getAlias().equals(guideBody.getAlias())
&& !guideSrc.getFrom().equals(guideBody.getFrom())) {
guideBody.setAlias(getUniqueAlias());
arg = createSelectStatement(navigationMap.get(bodyExp));
arg.changeCode("select", doSwitch(bodyExp));
}
else if (!temp) {
guideSrc = srcGuides.get(0);
}
return createCollectStatement(arg, sourceCode, guideSrc, bodyExp);
}
/**
* Generates a declarative code fragment for a forAll or exists iterator.
*
* @param operationName
* the name of the operation
* @param srcCode
* the generated source code
* @param where
* the generated body code
* @param srcGuides
* the source guides
* @param variables
* all iteratpr variables
* @return declarative code fragment for the collect iterator
*/
protected ICode handleIterForAllExits(String operationName,
IComplexCode srcCode, ICode where, List<Guide> srcGuides,
List<Variable> variables) {
where = handleIterOperation(operationName + "_where", where);
IComplexCode join = srcCode.getComplexCode("join");
if (variables.size() > 1) {
for (int i = 1; i < variables.size(); i++) {
if (join != null) {
IComplexCode newJoin =
createJoinStatement(variableMap.get(variables.get(i).getName()),
srcGuides.get(1));
newJoin.changeCode("join", join.getCode("join"));
join.changeCode("join", newJoin);
join = newJoin;
}
else {
IComplexCode newJoin;
if (srcGuides.size() > 1) {
newJoin = createJoinStatement(variableMap.get(variables.get(i).getName()),
srcGuides.get(1));
} else {
newJoin = createJoinStatement(variableMap.get(variables.get(i).getName()),
null);
}
srcCode.changeCode("join", newJoin);
join = newJoin;
}
}
}
changeWhereStatement(srcCode, where);
return handleIterOperation(operationName, srcCode);
}
/**
* Generates a declarative code fragment for a select or reject iterator.
*
* @param operationName
* the name of the operation
* @param sourceCode
* the generation source code
* @param where
* the generated body code
* @param anIteratorExp
* the iterator expression
* @param bodyExp
* the body expression
* @return declarative code fragment for the collect iterator
*/
protected ICode handleIterSelectReject(String operationName,
IComplexCode sourceCode, ICode where, IteratorExp anIteratorExp,
OclExpression bodyExp) {
ICode expression = handleIterOperation(operationName, where);
navigationMap.put(anIteratorExp, navigationMap.get(bodyExp));
changeWhereStatement(sourceCode, expression);
return sourceCode;
}
/**
* Generates a declarative code fragment for a closure iterator.
*
* @param anIteratorExp
* the iterator expression
* @param bodyExp
* the body expression
* @param guideSrc
* the source guide
* @param srcGuides
* the source guides
* @return declarative code fragment for the collect iterator
*/
protected ICode handleIterClosure(IteratorExp anIteratorExp,
OclExpression bodyExp, Guide guideSrc, List<Guide> srcGuides) {
String alias = guideSrc.getAlias();
guideSrc.setAlias(getUniqueAlias());
closure = true;
IComplexCode code =
new Code("common_table_expression",mySettings);
commonTableExpressions.add(code);
ICode cteName = new CodeString(constraintName + "_" + cteNumber++);
Guide closureGuide =
new Guide(false, getUniqueAlias());
closureGuide.add("variable2", cteName.getResult(), "variable1");
closureGuide.reset();
boolean saveAllInstances = useVariable;
useVariable = true;
Map<OclExpression, List<Guide>> navMap =
new HashMap<OclExpression, List<Guide>>();
navMap.putAll(navigationMap);
for (Variable v : anIteratorExp.getIterator()) {
variableMap.put(v.getName(), guideSrc);
}
IComplexCode arg1 = (IComplexCode)doSwitch(bodyExp);
if (arg1.getCode("select") == null) {
arg1 = createSelectStatement(Arrays.asList(guideSrc));
}
arg1.changeCode("select",
createObjectValue(navigationMap.get(bodyExp).get(0), guideSrc));
navigationMap.clear();
navigationMap.putAll(navMap);
for (Variable v : anIteratorExp.getIterator()) {
variableMap.remove(v.getName());
}
for (Variable v : anIteratorExp.getIterator()) {
variableMap.put(v.getName(), closureGuide);
}
IComplexCode arg2 = (IComplexCode) doSwitch(bodyExp);
closureGuide.reset();
Guide closureGuide1 = new Guide(false, closureGuide.getAlias());
closureGuide1.add("variable1", cteName.getResult(), "variable2");
closureGuide1.reset();
arg2.changeCode("select", this.createObjectValue(
navigationMap.get(bodyExp).get(0), closureGuide1));
useVariable = saveAllInstances;
guideSrc.setAlias(alias);
navMap.clear();
code.addCode("constraint_name", cteName);
code.addCode("recursive", arg2);
code.addCode("non_recursive", arg1);
LinkedList<Guide> guides = new LinkedList<Guide>();
guides.add(closureGuide);
guides.addAll(srcGuides);
closure = false;
navigationMap.put(anIteratorExp, guides);
return createSelectStatement(navigationMap.get(anIteratorExp));
}
/**
* Generates a declarative code fragment for a select iterator
*
* @param name
* the name of the iter operation
* @param guide
* the Guide to the source expression
* @param arg
* argument passed to the iterator
* @return declarative code fragment for the select iterator
*/
protected ICode handleIterOperation(String name, ICode arg) {
return createOperandOperation("feature_call_" + name, arg);
}
/**
* Generates a declarative code fragment for a logical expression.
*
* @param name
* name of the logical expression (and, or, xor, implies)
* @param sourceCode
* declarative code fragment of the first expression
* @param firstArg
* declarative code fragment of the second expression
* @return declarative code fragment for the logical expression
*/
protected ICode handleLogicalExpression(String name, ICode sourceCode,
ICode firstArg) {
return createTwoOperandOperation("logical_expression_" + name, sourceCode,
firstArg);
}
/**
* Generates a declarative code fragment for a oclIsKindOf feature call.
*
* @param guide
* the guide to the classifier type
* @return declarative code fragment for the oclIsKindOf feature call
*/
protected ICode handleOclIsTypeOf(Guide guide, ICode sourceCode) {
guide.reset();
IComplexCode template =
new Code("feature_call_oclistypeof",mySettings);
template.addCode("from", new CodeString(guide.getFrom()));
template.addCode("select", new CodeString(guide.getSelect().get(0)));
template.addCode("object2", sourceCode);
template.addCode("alias", new CodeString(guide.getAlias()));
return template;
}
/**
* Generates a declarative code fragment for a oclIsTypeOf feature call.
*
* @param typeGuide
* the guide to the classifier type
* @param supertypeGuide
* the guide to the classifiers supertype
* @return declarative code fragment for the oclIsTypeOf feature call
*/
protected ICode handleOclIsKindOf(Guide typeGuide, Guide supertypeGuide) {
typeGuide.reset();
if (supertypeGuide != null)
supertypeGuide.reset();
IComplexCode template =
new Code("feature_call_ocliskindof",mySettings);
template.addCode("from", new CodeString(typeGuide.getFrom()));
template.addCode("select", new CodeString(typeGuide.getSelect().get(0)));;
template.addCode("alias", new CodeString(typeGuide.getAlias()));
template.addCode("from2", (supertypeGuide != null) ? new CodeString(
supertypeGuide.getFrom()) : null);
return template;
}
/**
* Generates a declarative code fragment for a relational expression.
*
* @param name
* name of the relational expression (equal, nequal, greater, lesser,
* greaterequal, lesserequal)
* @param srcExp
* the OclExpression representing the first argument used to
* determine the operand types
* @param operand1
* declarative code fragment of the first operand
* @param operand2
* declarative code fragment of the second operand
* @return declarative code fragment for the equals operation
*/
protected ICode handleRelExpression(String name, OclExpression srcExp,
ICode operand1, ICode operand2) {
StringBuffer templateName = new StringBuffer("relational_expression_");
Type attrType = null;
templateName.append(name);
templateName.append("_");
if (srcExp instanceof OperationCallExp) {
attrType = srcExp.getType();
}
else if (srcExp instanceof PropertyCallExp) {
attrType = ((PropertyCallExp) srcExp).getReferredProperty().getType();
}
else if (srcExp instanceof PrimitiveLiteralExp) {
attrType = ((PrimitiveLiteralExp) srcExp).getType();
}
else if (srcExp instanceof VariableExp) {
attrType = ((VariableExp) srcExp).getType();
}
else {
throw new IllegalStateException(
"Unhandled attribute type for relational expression: "
+ srcExp.getClass().getName() + "!");
}
if (attrType instanceof PrimitiveType) {
templateName.append(((PrimitiveType) attrType).getKind().getName().toLowerCase());
}
/*
* No different between CollectionTypes and any else if (attrType instanceof
* CollectionType) { if (attrType instanceof SetType) {
* templateName.append("set"); } else if (attrType instanceof SequenceType)
* { templateName.append("sequence"); } else if (attrType instanceof
* BagType) { templateName.append("bag"); } else if (attrType instanceof
* OrderedSetType) { templateName.append("orderedset"); } else { throw new
* IllegalStateException(
* "Unhandled collection type for relational expression!"); } }
*/
else {
templateName.append("any");
}
return createTwoOperandOperation(templateName.toString(), operand1,
operand2);
}
/**
* Generates a declarative code fragment for a concat operation on strings.
*
* @param sourceCode
* declarative code fragment of the first argument (usually a simple
* string)
* @param firstArg
* declarative code fragment of the second argument (usually a simple
* string)
* @return declarative code fragment for the concat operation
*/
protected ICode handleStringConcat(ICode sourceCode, ICode firstArg) {
return createTwoOperandOperation("feature_call_string_concat", sourceCode,
firstArg);
}
/**
* Generates a declarative code fragment for a size operation on strings.
*
* @param sourceCode
* declarative code fragment of the operand (the string to get the
* size from)
* @return declarative code fragment for the size operation
*/
protected ICode handleStringSize(ICode sourceCode) {
return createOperandOperation("feature_call_string_size", sourceCode);
}
/**
* Generates a declarative code fragment for a substring operation.
*
* @param sourceCode
* declarative code fragment of the operand (the string to build the
* substring from)
* @param firstArg
* the start of the substring
* @param ICode
* the end of the substring
* @return declarative code fragment for the substring operation
*/
protected ICode handleStringSubstring(ICode sourceCode,
ICode firstArg, ICode ICode) {
IComplexCode template =
createOperandOperation("feature_call_string_substring", sourceCode);
template.addCode("start", firstArg);
template.addCode("end", ICode);
return template;
}
/**
* Generates a declarative code fragment for a matches operation.
*
* @param sourceCode
* declarative code fragment of the operand (the string to build the
* substring from)
* @param firstArg
* the regular Expression
* @return declarative code fragment for the substring operation
*/
protected ICode handleStringMatches(ICode sourceCode,
ICode firstArg) {
return this.createTwoOperandOperation("feature_call_string_matches", sourceCode, firstArg);
}
/**
* Generates a declarative code fragment for a toLower operation on strings.
*
* @param sourceCode
* declarative code fragment of the operand
* @return declarative code fragment for the toLower operation
*/
protected ICode handleStringToLower(ICode sourceCode) {
return createOperandOperation("feature_call_string_tolower", sourceCode);
}
/**
* Generates a declarative code fragment for a toUpper operation on strings.
*
* @param sourceCode
* declarative code fragment of the operand
* @return declarative code fragment for the toUpper operation
*/
protected ICode handleStringToUpper(ICode sourceCode) {
return createOperandOperation("feature_call_string_toupper", sourceCode);
}
/**
* Generates a declarative code fragment for a unary minus operation.
*
* @param sourceCode
* declarative code fragment of the operand
* @return declarative code fragment for the unary minus operation
*/
protected ICode handleUnaryMinus(ICode sourceCode) {
return createOperandOperation("unary_expression_minus", sourceCode);
}
/**
* Generates a declarative code fragment for a unary not operation.
*
* @param sourceCode
* declarative code fragment of the operand
* @return declarative code fragment for the unary not operation
*/
protected ICode handleUnaryNot(ICode sourceCode) {
return createOperandOperation("unary_expression_not", sourceCode);
}
/**
* Generate code fragment for property
*
* @param property
* the property
* @param guides
* the guides for the property
* @return the generated code
*/
protected ICode handlePropProperty(Property property, List<Guide> guides) {
Guide guide = guides.get(0);
guide.reset();
// attribute access without navigation
if (guides.size() == 1) {
IComplexCode template = createObjectValue(guide);
// special case for Boolean attributes: e.g. expand 'attribute' to
// 'attribute = 1' in SQL
if (property.getType() instanceof PrimitiveType && ((PrimitiveType) property.getType()).getKind() == PrimitiveTypeKind.BOOLEAN) {
ICode attr = template;
template =
new Code("feature_call_attribute_boolean",mySettings);
template.addCode("attribute", attr);
}
return template;
}
// attribute access with navigation
else {
return createSelectStatement(guides);
}
}
/**
* Resets the DeclarativeCodeGenerator to initial values. Must be used, if
* multiple invariants will be translated by one code generator object.
*/
public void reset() {
resetUniqueAlias();
navigationMap.clear();
variableMap.clear();
useVariable = false;
commonTableExpressions.clear();
constraintName = "";
cteNumber = 1;
closure = false;
}
/**
* Returns all super types of the type
*
* @param type
* the type
* @return a list of all supertypes
*/
private List<Type> query_Supertypes(Type type) {
List<Type> parents = new ArrayList<Type>();
for (Type t : type.getSuperType()) {
if (t instanceof AnyType)
continue;
parents.add(t);
parents.addAll(query_Supertypes(t));
}
return parents;
}
/**
* Assigns a class guide to the given Type which are used during the code
* generation process.
*
* @param exp
* the OclExpression to reaccess the generated guide
* @param type
* the type to assign the Guide
* @returm the class guide
*/
protected Guide assignClassGuide(OclExpression exp, Type type) {
if (LOGGER.isDebugEnabled()) {
LOGGER
.debug("assignClassGuide(OclExpression exp, Type type) - start - Expression:"
+ exp + ", Type:" + type);
}
Guide guide;
if (type instanceof CollectionType) {
guide =
mySettings.getMappedModel()
.getClass(((CollectionType) type).getElementType().getName())
.getClassGuide();
}
else {
guide =
mySettings.getMappedModel().getClass(type.getName()).getClassGuide();
}
String saveAlias = null;
try {
saveAlias = guide.getAlias();
} catch (NullPointerException e) {
}
guide.setAlias(getUniqueAlias());
Guide guide1 = new Guide(guide);
guide.setAlias(saveAlias);
List<Guide> guides = new LinkedList<Guide>();
guides.add(guide1);
navigationMap.put(exp, guides);
if (LOGGER.isDebugEnabled()) {
LOGGER
.debug("assignClassGuide(OclExpression exp, Type type) - end - Guide:"
+ guide1);
}
return guide1;
}
/**
* Change the where part of the select code
*
* @param select
* the select code
* @param where
* the extra where code
*/
protected void changeWhereStatement(IComplexCode select, ICode where) {
select.changeCode("where",
combinedWhereStatement(where, select.getCode("where")));
}
/**
* Generate a where statement
*
* @param guide1
* the first argument
* @param guide2
* the second argument
* @return the where statement
*/
protected ICode createWhereStatement(Guide guide1, Guide guide2) {
IComplexCode where = null;
if (guide2.getWhere().size()== 1 && guide1.getSelect().size() == 1) {
where =new Code("feature_call_navigation_where",mySettings);
where.addCode("alias", new CodeString(guide2.getAlias()));
where.addCode("alias2", new CodeString(guide1.getAlias()));
where.addCode("where", new CodeString(guide2.getWhere().get(0)));
where.addCode("select", new CodeString(guide1.getSelect().get(0)));
} else {
for (String s : guide2.getWhere()) {
if (guide1.getSelect().contains(s)) {
IComplexCode where2 =
new Code("feature_call_navigation_where",mySettings);
where2.addCode("alias", new CodeString(guide2.getAlias()));
where2.addCode("alias2", new CodeString(guide1.getAlias()));
where2.addCode("where", new CodeString(s));
where2.addCode("select", new CodeString(s));
if (where == null) where = where2;
else combinedWhereStatement(where,where2);
}
}
}
return where;
}
/**
* Generates a where clause with two operands.
*
* @param where1
* the new operand
* @param where2
* the operand which will be exists
* @return the new where clause
*/
protected ICode combinedWhereStatement(ICode where1, ICode where2) {
if (where2 != null) {
return handleLogicalExpression("and", where2, where1);
}
else {
return where1;
}
}
/**
* Generate a join statement.
*
* @param from
* the guide for the new view
* @param where
* the guide to bind the two tables
* @return the join statement
*/
protected IComplexCode createJoinStatement(Guide from, Guide where) {
IComplexCode template =
new Code("feature_call_navigation_join",mySettings);
IComplexCode fromCode =
new Code("feature_call_navigation_from",mySettings);
fromCode.addCode("from", new CodeString(from.getFrom()));
fromCode.addCode("select", new CodeString(from.getSelect().get(0)));
if (!from.getWhere().equals(from.getSelect())) {
fromCode.addCode("where", new CodeString(from.getWhere().get(0)));
}
template.addCode("alias", new CodeString(from.getAlias()));
template.addCode("from", fromCode);
if (where != null) template.addCode("where", createWhereStatement(from, where));
return template;
}
/**
* Generate a join statement with sub joins for the guides
*
* @param guides
* the guides
* @return the join statement from guides.get(0) with the subjoins
*/
protected ICode createJoinStatements(List<Guide> guides) {
ICode joinTemplate = null;
for (int i = guides.size() - 1; i > 0; i--) {
Guide guide = guides.get(i);
guide.reset();
IComplexCode template = createJoinStatement(guide, guides.get(i - 1));
if (joinTemplate != null) {
template.addCode("join", joinTemplate);
}
joinTemplate = template;
}
return joinTemplate;
}
/**
* Generate the object value.
*
* @param guide
* the guide for object
* @return the code fragment.
*/
protected IComplexCode createObjectValue(Guide guide) {
guide.reset();
IComplexCode select =
new Code("feature_call_attribute_context",mySettings);
select.addCode("alias", new CodeString(guide.getAlias()));
select.addCode("attribute", new CodeString(guide.getSelect().get(0)));
return select;
}
/**
* Generate the object value.
*
* @param guide1
* the guide for object
* @param guide2
* the guide for object
* @return the code fragment.
*/
protected ICode createObjectValue(Guide guide1, Guide guide2) {
guide1.reset();
IComplexCode select = createObjectValue(guide2);
select.addCode("alias2", new CodeString(guide1.getAlias()));
select.addCode("attribute2", new CodeString(guide1.getSelect().get(0)));
return select;
}
/**
* Creates a declarative code fragment for a navigation described by the Guide
* objects in the guides parameter.
*
* @param guides
* the guides which are describing the navigation
* @return declarative code fragment for a navigation in the target model
*/
protected IComplexCode createSelectStatement(List<Guide> guides) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("createNavigation(List<Guide> guides) - start - Guides:"
+ guides);
}
IComplexCode template;
LinkedList<Guide> steps = new LinkedList<Guide>();
LinkedList<String> aliase = new LinkedList<String>();
aliase.add(guides.get(0).getAlias());
if (guides.size() > 1
&& aliase.contains(guides.get(guides.size() - 1).getAlias())) {
guides.get(guides.size() - 1).setAlias(
getUniqueAlias());
}
aliase.add(guides.get(guides.size() - 1).getAlias());
for (Guide guide : guides) {
guide.reset();
if (aliase.contains(guide.getAlias()) && guides.indexOf(guide) != 0
&& guides.indexOf(guide) != guides.size() - 1) {
guide.setAlias(getUniqueAlias());
}
aliase.add(guide.getAlias());
for (int k = 0; k < guide.numberOfSteps(); k++, guide.next()) {
Guide newGuide = new Guide(guide.isNavigation(), guide.getAlias());
newGuide.add(guide.getSelect(), guide.getFrom(), guide.getWhere());
newGuide.reset();
steps.add(newGuide);
}
}
Guide guide = steps.get(0);
guide.reset();
LinkedList<Guide> joinGuides = new LinkedList<Guide>();
joinGuides.addAll(steps);
if (!closure)
joinGuides.removeLast();
template =
new Code("feature_call_navigation_select",mySettings);
template.addCode("select", createObjectValue(guide));
template.addCode("alias", new CodeString(guide.getAlias()));
template.addCode("join", createJoinStatements(joinGuides));
template.addCode("from", new CodeString(guide.getFrom()));
if (!useVariable && steps.size() >= 2) {
template.addCode(
"where",
createWhereStatement(steps.get(steps.size() - 1),
steps.get(steps.size() - 2)));
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("createNavigation(List<Guide> guides) - end - Navigation:"
+ template);
}
return template;
}
/**
* Assigns guides to the given OclExpression which are used during the code
* generation process.
*
* @param exp
* the OclExpression to assign the Guides for.
*/
protected List<Guide> assignGuides(OclExpression exp) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("assignGuides(OclExpression exp) - start - Expression:"
+ exp);
}
if (navigationMap.containsKey(exp)) {
return navigationMap.get(exp);
}
Guide guide;
LinkedList<Guide> guides = new LinkedList<Guide>();
String featureName; // used for attribute/association end names
if (exp instanceof PropertyCallExp) {
PropertyCallExp propertyExp = (PropertyCallExp) exp;
featureName = propertyExp.getReferredProperty().getName();
OclExpression sourceExp = propertyExp.getSource();
Type sourceType = propertyExp.getSourceType();
IMappedClass mc =
mySettings.getMappedModel().getClass(sourceType.getName());
boolean findAssociation = false;
if (propertyExp.getReferredProperty() instanceof AssociationProperty) {
findAssociation = true;
}
else if (propertyExp.getReferredProperty().getType() instanceof CollectionType) {
findAssociation =
mySettings.getMappedModel().isClass(
((CollectionType) propertyExp.getReferredProperty().getType())
.getElementType().getName());
}
else {
findAssociation =
mySettings.getMappedModel().isClass(
propertyExp.getReferredProperty().getType().getName());
}
if (findAssociation) {
guide = mc.getAssociationEndGuide(featureName);
}
else {
guide = mc.getAttributeGuide(featureName);
}
guide.setAlias("");
guide = new Guide(guide);
guides.add(guide);
guides.addAll(assignGuides(sourceExp));
if (sourceExp instanceof VariableExp) {
/*
* if (!guide.isNavigation()) { guide.reset(); Guide varGuide =
* guides.getLast(); varGuide.reset();
* guide.setAlias(getUniqueAlias());
* //guides.getLast().reset();
* //guide.setAlias(guides.removeLast().getAlias()); } else {
*/
guide.reset();
Guide varGuide = guides.getLast();
varGuide.reset();
if (guide.getWhere().equals(varGuide.getSelect())
&& guide.getWhere().equals(varGuide.getWhere())) {
guide.setAlias(guides.removeLast().getAlias());
}
else {
guide.setAlias(getUniqueAlias());
}
// }
}
else {
guide.setAlias(getUniqueAlias());
}
}
else if (exp instanceof VariableExp) {
guides.add(variableMap.get(((VariableExp) exp).getReferredVariable()
.getName()));
}
navigationMap.put(exp, guides);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("assignGuides(OclExpression exp) - end - Guides:" + guides);
}
return guides;
}
/**
* Generate the fragment code of a two operand operation.
*
* @param templateName
* the name of the template
* @param operand1
* the first argument
* @param operand2
* the second argument
* @return the fragment code
*/
private IComplexCode createTwoOperandOperation(String templateName,
ICode operand1, ICode operand2) {
IComplexCode code = new Code(templateName,mySettings);
code.addCode("operand1", operand1);
if (operand2 != null) {
code.addCode("operand2", operand2);
}
return code;
}
/**
* Generate the fragment code of a single operand operation.
*
* @param templateName
* the name of the template
* @param operand
* the argument
* @return the fragment code
*/
private IComplexCode createOperandOperation(String templateName, ICode operand) {
IComplexCode code = new Code(templateName,mySettings);
code.addCode("operand", operand);
return code;
}
/**
* Generate a Select statement for the operation collect.
*
* @param sourceCode
* the sourceCode of the statement
* @param bodyCode
* the body of the collect statement
* @return the fragment code
*/
private ICode createCollectStatement(IComplexCode sourceCode,
IComplexCode bodyCode, Guide srcGuide, Guide bodyGuide) {
IComplexCode result = null;
boolean temp =
Boolean.valueOf(mySettings.getTemplateGroup()
.getTemplate("check_database_references").toString());
if (bodyCode != null && bodyCode.getCode("from") != null) {
result = bodyCode;
IComplexCode join = result;
while (join.getComplexCode("join") != null) {
join = join.getComplexCode("join");
}
if (result.getComplexCode("where") != null) {
if (result.getComplexCode("where").getCode("operand1") != null) {
result.changeCode("where",
result.getComplexCode("where").getCode("operand2"));
}
else {
result.changeCode("where", null);
}
}
if (sourceCode != null) {
srcGuide.reset();
bodyGuide.reset();
if (temp) {
if (srcGuide.equals(bodyGuide)) {
join.changeCode("join", createJoinStatement(srcGuide, bodyGuide));
join = join.getComplexCode("join");
}
else {
if (sourceCode.getComplexCode("join") != null
&& srcGuide.getSelect().equals(bodyGuide.getSelect())) {
sourceCode.getComplexCode("join").getComplexCode("where")
.changeCode("alias", join.getCode("alias"));
}
else {
join.changeCode("join",
createJoinStatement(srcGuide, bodyGuide));
join = join.getComplexCode("join");
}
}
}
else {
if (!srcGuide.getAlias().equals(bodyGuide.getAlias())
&& srcGuide.numberOfSteps() > 1) {
while (bodyGuide.hasNext()) {
bodyGuide.next();
}
join.changeCode("join", createJoinStatement(srcGuide, bodyGuide));
join = join.getComplexCode("join");
}
else {
sourceCode.getComplexCode("join").getComplexCode("where")
.changeCode("alias", join.getCode("alias"));
}
}
join.changeCode("join", sourceCode.getCode("join"));
changeWhereStatement(result, sourceCode.getCode("where"));
}
}
else {
sourceCode.changeCode("select", bodyCode);
result = sourceCode;
}
return result;
}
/**
* Generate a new object value of the code
*
* @param templateName
* the name of the template for editing the object
* @param code
* the select code with the object
*/
private void changeObjectVariable(String templateName, IComplexCode code) {
IComplexCode sqlCode;
if (templateName != null) {
sqlCode =
new Code(templateName,mySettings);
sqlCode.addCode("select", code.getCode("select"));
}
else {
sqlCode = code;
}
code.changeCode("select", sqlCode);
}
/**
* Generate a new select statement
*
* @param arg
* the body code of the collect statement
* @param sourceCode
* the source code of the collect statement
* @param guideSrc
* the guide of the source
* @param bodyExp
* the body expression
* @return the fragment code
*/
protected ICode createCollectStatement(IComplexCode arg, IComplexCode sourceCode,
Guide guideSrc, OclExpression bodyExp) {
ICode result = null;
Guide guideBody;
if (navigationMap.get(bodyExp).size() >= 2) {
guideBody =
navigationMap.get(bodyExp).get(navigationMap.get(bodyExp).size() - 2);
}
else {
guideBody = navigationMap.get(bodyExp).get(0);
}
result = createCollectStatement(sourceCode, arg, guideSrc, guideBody);
return result;
}
/**
* Returns a unique alias which may be used in the declarative target language
*
* @return unique alias which may be used in the declarative target language
*/
public String getUniqueAlias() {
uniqueAlias++;
if (uniqueAlias == 1) {
return "self";
}
return "alias" + uniqueAlias;
}
public void resetUniqueAlias() {
uniqueAlias = 0;
}
}