Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
eu.mihosoft.vrl.lang.visual.SessionClassUtils Maven / Gradle / Ivy
/*
* SessionClassUtils.java
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2009–2015 Steinbeis Forschungszentrum (STZ Ölbronn),
* Copyright (c) 2007–2017 by Michael Hoffer
*
* This file is part of Visual Reflection Library (VRL).
*
* VRL is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* as published by the Free Software Foundation.
*
* see: http://opensource.org/licenses/LGPL-3.0
* file://path/to/VRL/src/eu/mihosoft/vrl/resources/license/lgplv3.txt
*
* VRL 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.
*
* This version of VRL includes copyright notice and attribution requirements.
* According to the LGPL this information must be displayed even if you modify
* the source code of VRL. Neither the VRL Canvas attribution icon nor any
* copyright statement/attribution may be removed.
*
* Attribution Requirements:
*
* If you create derived work you must do three things regarding copyright
* notice and author attribution.
*
* First, the following text must be displayed on the Canvas:
* "based on VRL source code". In this case the VRL canvas icon must be removed.
*
* Second, the copyright notice must remain. It must be reproduced in any
* program that uses VRL.
*
* Third, add an additional notice, stating that you modified VRL. A suitable
* notice might read
* "VRL source code modified by YourName 2012".
*
* Note, that these requirements are in full accordance with the LGPL v3
* (see 7. Additional Terms, b).
*
* Please cite the publication(s) listed below.
*
* Publications:
*
* M. Hoffer, C. Poliwoda, & G. Wittum. (2013). Visual reflection library:
* a framework for declarative GUI programming on the Java platform.
* Computing and Visualization in Science, 2013, 16(4),
* 181–192. http://doi.org/10.1007/s00791-014-0230-y
*/
package eu.mihosoft.vrl.lang.visual;
import eu.mihosoft.vrl.annotation.ParamInfo;
import eu.mihosoft.vrl.io.vrlx.AbstractCode;
import eu.mihosoft.vrl.lang.CodeBuilder;
import eu.mihosoft.vrl.lang.VLangUtils;
import eu.mihosoft.vrl.lang.groovy.GroovyCompiler;
import eu.mihosoft.vrl.reflection.DefaultMethodRepresentation;
import eu.mihosoft.vrl.reflection.DefaultObjectRepresentation;
import eu.mihosoft.vrl.reflection.MethodDescription;
import eu.mihosoft.vrl.reflection.TypeRepresentationBase;
import eu.mihosoft.vrl.reflection.TypeRepresentationContainer;
import eu.mihosoft.vrl.reflection.VisualCanvas;
import eu.mihosoft.vrl.system.VClassLoaderUtil;
import eu.mihosoft.vrl.types.ArrayBaseType;
import eu.mihosoft.vrl.types.MultipleOutputType;
import eu.mihosoft.vrl.visual.Connection;
import eu.mihosoft.vrl.visual.Connections;
import eu.mihosoft.vrl.visual.Connector;
import eu.mihosoft.vrl.visual.ConnectorType;
import eu.mihosoft.vrl.visual.MessageType;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Converts an opened session to valid Java/Groovy source code.
*
* @author Michael Hoffer <[email protected] >
*/
public class SessionClassUtils {
// no instanciation allowed
private SessionClassUtils() {
throw new AssertionError(); // not in this class either!
}
/**
* Analyzes the specified canvas and converts its content to source code.
*
* @param canvas canvas to analyze
* @return source code
*/
public static AbstractCode createSessionClassCode(VisualCanvas canvas) {
return createSessionClassCode(canvas, null);
}
/**
* Analyzes the specified canvas and converts its content to source code.
*
* @param canvas canvas to analyze
* @param info
* @return source code
*/
public static AbstractCode createSessionClassCode(VisualCanvas canvas,
ClassInfoObject info) {
boolean pulseEffectState = canvas.getEffectPane().isPulseEffect();
canvas.getEffectPane().enablePulseEffect(false);
if (!validateSession(canvas)) {
return null;
}
invokeInputsAndOutputs(canvas);
ClassInfoObject classInfo = info;
if (classInfo == null) {
classInfo = getClassInfo(canvas);
invokeInfoObject(canvas);
}
CodeBuilder code = new CodeBuilder();
// add imports
Iterable imports = new GroovyCompiler().getImports();
for (String imp : imports) {
code.append(imp);
}
code.newLine().newLine();
code.addLine("@ComponentInfo(" + classInfo.getComponentInfo() + ")").
addLine("@ObjectInfo(" + classInfo.getObjectInfo() + ")").
addLine("public class " + classInfo.getClassName()
+ " implements Serializable {").
incIndentation().
addLine("private static final long serialVersionUID=1L;").
addLine(
getMethodHeaderCode(getOutputParameter(canvas),
classInfo.getMethodInfo(),
classInfo.getMethodName(),
getInputParameter(canvas),
code.getIndentString())
+ " {").
incIndentation().
addLine("").
addLine(getBodyCode(canvas, code.getIndentString())).
decIndentation().
addLine("}").
decIndentation().
addLine("}");
AbstractCode result = new AbstractCode();
result.setPackageName(classInfo.getPackageName());
StringBuilder builder = new StringBuilder(code.getCode());
for (AbstractCode c : canvas.getCodes()) {
builder.append("\n\n").append(c.getCode());
}
result.setCode(builder.toString());
canvas.getEffectPane().enablePulseEffect(pulseEffectState);
return result;
}
/**
* Validates the session.
*
* @param canvas
* @return
* true
if the specified canvas session is valid;
* false
otherwise
*/
private static boolean validateSession(VisualCanvas canvas) {
if (!ControlFlowUtils.validateSession(canvas)) {
return false;
}
return true;
}
/**
* Returns a collection containing all input objects of the specified
* canvas.
*
* @param canvas canvas
* @return a collection containing all input objects of the specified canvas
*/
private static Collection getInputs(VisualCanvas canvas) {
Collection inputs
= canvas.getInspector().
getObjectsByClassName(InputObject.class.getName());
ArrayList result = new ArrayList();
for (Object o : inputs) {
result.add((InputObject) o);
}
return result;
}
/**
* Returns a collection containing all output objects of the specified
* canvas.
*
* @param canvas canvas
* @return a collection containing all output objects of the specified
* canvas
*/
private static OutputObject getOutput(VisualCanvas canvas) {
Collection outputs
= canvas.getInspector().
getObjectsByClassName(OutputObject.class.getName());
if (!outputs.isEmpty()) {
return (OutputObject) outputs.iterator().next();
}
return null;
}
/**
* Indicates whether an output object exists.
*
* @param canvas canvas
* @return
* true
if an output object exists;
* false
otherwise
*/
private static boolean outputExists(VisualCanvas canvas) {
return getOutput(canvas) != null;
}
/**
* Returns the class info object of the specified canvas.
*
* @param canvas canvas
* @return the class info object of the specified canvas or
* null
if no such object exists
*/
private static ClassInfoObject getClassInfo(VisualCanvas canvas) {
Collection classInfoObjects
= canvas.getInspector().
getObjectsByClassName(ClassInfoObject.class.getName());
if (!classInfoObjects.isEmpty()) {
return (ClassInfoObject) classInfoObjects.iterator().next();
}
return null;
}
/**
* Indicates whether a class info object exists.
*
* @param canvas canvas
* @return
* true
if an class info object exists;
* false
otherwise
*/
private static boolean classInfoExists(VisualCanvas canvas) {
return getClassInfo(canvas) != null;
}
/**
* Invokes the methods of all input and output objects. This ensures that
* the objects use the data the user has entered in the text fields of the
* type representations.
*
* @param canvas canvas
*/
private static void invokeInputsAndOutputs(VisualCanvas canvas) {
// invoke inputs
for (InputObject o : getInputs(canvas)) {
// multiple views false, thus we can savely use get(0)
DefaultObjectRepresentation oRep
= canvas.getInspector().
getObjectRepresentationsByReference(o).get(0);
DefaultMethodRepresentation m
= oRep.getMethodBySignature(
"info", new Class>[]{String.class});
if (m != null) {
try {
m.automaticInvocation(canvas.getInspector());
} catch (InvocationTargetException ex) {
Logger.getLogger(SessionClassUtils.class.getName()).
log(Level.SEVERE, null, ex);
}
}
}
if (outputExists(canvas)) {
// output
// multiple views false, thus we can savely use get(0)
DefaultObjectRepresentation oRep
= canvas.getInspector().
getObjectRepresentationsByReference(
getOutput(canvas)).get(0);
DefaultMethodRepresentation m1
= oRep.getMethodBySignature(
"info",
new Class>[]{String.class, OutputValue.class});
try {
m1.automaticInvocation(canvas.getInspector());
} catch (InvocationTargetException ex) {
Logger.getLogger(SessionClassUtils.class.getName()).
log(Level.SEVERE, null, ex);
}
}
}
/**
* Invokes the methods of the class info object. This ensures that the
* objects use the data the user has entered in the text fields of the type
* representations.
*
* @param canvas canvas
*/
public static void invokeInfoObject(VisualCanvas canvas) {
if (classInfoExists(canvas)) {
// class-info
// multiple views false, thus we can savely use get(0)
DefaultObjectRepresentation oRep
= canvas.getInspector().
getObjectRepresentationsByReference(
getClassInfo(canvas)).get(0);
// DefaultMethodRepresentation m1 =
// oRep.getMethodBySignature(
// "info", new Class>[]{
// String.class, String.class, String.class});
DefaultMethodRepresentation m2
= oRep.getMethodBySignature(
"additionalInfo",
new Class>[]{
String.class, String.class,
String.class, String.class, String.class});
try {
// m1.automaticInvocation(canvas.getInspector());
m2.automaticInvocation(canvas.getInspector());
} catch (InvocationTargetException ex) {
Logger.getLogger(SessionClassUtils.class.getName()).
log(Level.SEVERE, null, ex);
}
}
}
/**
* Returns the type of the input connector the specified input object is
* connected to.
*
* @param canvas canvas
* @param input input object to check
* @return the type of the input connector the specified input object is
* connected to or
* void.class
if it is not connected
*/
private static Class> getInputType(VisualCanvas canvas,
InputObject input) {
Class> result = void.class;
Connection connection = getInputConnection(canvas, input);
// if connection exist add the receiver to the result collection
if (connection != null) {
// we can use first one because we only allow one connection
result = connection.getReceiver().
getValueObject().getType();
}
return result;
}
/**
* Returns the connection of the specified input object.
*
* @param canvas canvas
* @param input input object
* @return the connection of the specified input object or
* null
if no such connection exists
*/
private static Connection getInputConnection(VisualCanvas canvas,
InputObject input) {
Connection result = null;
// multiple views false, thus we can savely use get(0)
DefaultObjectRepresentation oRep
= canvas.getInspector().
getObjectRepresentationsByReference(input).get(0);
// get the method representation
DefaultMethodRepresentation m
= oRep.getMethodBySignature(
"info", new Class>[]{String.class});
// take the return value connector and get the connections
Connector c = m.getReturnValue().getConnector();
Collection connections
= canvas.getDataConnections().getAllWith(c);
// if connection exist return it
if (!connections.isEmpty()) {
// we can use first one because we only allow one connection
result = connections.iterator().next();
}
return result;
}
/**
* Returns the parameter object of the specified input object.
*
* @param canvas canvas
* @return the parameter object of the specified input object
*/
private static Collection getInputParameter(
VisualCanvas canvas) {
ArrayList result = new ArrayList();
Collection inputs = getInputs(canvas);
int paramIndex = 0;
for (InputObject iO : inputs) {
Class> infoType = getInputType(canvas, iO);
if (!infoType.equals(void.class)) {
result.add(new Parameter(
infoType, "p" + paramIndex,
iO.getParamInfo(), getInputConnection(canvas, iO)));
paramIndex++;
}
}
return result;
}
/**
* Returns the parameter object of the specified output object
*
* @param canvas canvas
* @return the parameter object of the specified output object
*/
private static Parameter getOutputParameter(VisualCanvas canvas) {
Connector outputSender = getOutputSender(canvas);
if (!outputExists(canvas) || outputSender == null) {
return new Parameter(void.class, "", "", null);
}
Class> type = outputSender.getValueObject().getType();
OutputObject output = getOutput(canvas);
String paramInfo = output.getParamInfo();
// we use the method info from the sender if no custom info is defined
if (paramInfo == null || paramInfo.trim().equals("")) {
paramInfo = "";
TypeRepresentationBase tRep = ((TypeRepresentationContainer) outputSender.getValueObject()).getTypeRepresentation();
MethodDescription mDesc = tRep.getParentMethod().getDescription();
if (mDesc.getMethodInfo() != null) {
String valueName = mDesc.getMethodInfo().valueName();
String valueStyle = mDesc.getMethodInfo().valueStyle();
String valueOptions = mDesc.getMethodInfo().valueOptions();
paramInfo = "valueName=\""
+ VLangUtils.addEscapeCharsToCode(valueName) + "\", ";
paramInfo += "valueStyle=\""
+ VLangUtils.addEscapeCharsToCode(valueStyle) + "\", ";
paramInfo += "valueOptions=\""
+ VLangUtils.addEscapeCharsToCode(valueOptions) + "\"";
}
}
// get(0) is save because only one connection is allowed
Connection connection
= canvas.getDataConnections().
getAllWith(getOutputReceiver(canvas)).get(0);
return new Parameter(
type, "", paramInfo, connection);
}
/**
* Returns the sender connector of the connection to the output object.
*
* @param canvas canvas
* @return the sender connector of the connection to the output object or
* null
if no such connection exists
*/
private static Connector getOutputSender(
VisualCanvas canvas) {
Connector result = null;
Connector c = getOutputReceiver(canvas);
Collection connections
= canvas.getDataConnections().getAllWith(c);
// if connection exist return the sender as result
if (!connections.isEmpty()) {
// we can use 0 because we only allow one connection
result = connections.iterator().next().getSender();
}
return result;
}
/**
* Returns the input connector of the output object.
*
* @param canvas canvas
* @return the input connector of the output object or
* null
if the specified canvas does not contain an output
* object
*/
private static Connector getOutputReceiver(
VisualCanvas canvas) {
// if no outputs exist we can exit
if (!outputExists(canvas)) {
return null;
}
// invoke inputs
OutputObject o = getOutput(canvas);
// multiple views false, thus we can savely use get(0)
DefaultObjectRepresentation oRep
= canvas.getInspector().
getObjectRepresentationsByReference(o).get(0);
// get the method representation
DefaultMethodRepresentation m
= oRep.getMethodBySignature(
"info",
new Class>[]{String.class, OutputValue.class});
// take the input value connector and get the connections
// connector of outputvalue (see OutputObject)
return m.getConnectorByKey(DefaultMethodRepresentation.KEY_INPUT_CONNECTOR_PREFIX+1);
}
/**
* Returns the code of the specified method header.
*
* @param output output parameter
* @param methodInfo method info string without enclosing
* @MethodInfo()
* @param methodName method name without left and right parenthesis
* @param params input paramter list
* @param indent indent to use (necessary for correct code formatting)
* @return the code of the specified method header
*/
private static String getMethodHeaderCode(Parameter output,
String methodInfo, String methodName,
Collection params, String indent) {
StringBuilder builder = new StringBuilder();
boolean methodInfoNeedsComma = methodInfo.length() > 0
&& output.paramInfo.length() > 0;
builder. // methodInfo
append("@MethodInfo(").append(methodInfo);
if (methodInfoNeedsComma) {
builder.append(", ");
}
String returnTypeString = "void";
if (output.getType().isArray()) {
// returnTypeString = output.type.getComponentType().getName() + "[]";
returnTypeString = VClassLoaderUtil.arrayClass2Code(output.type.getName());
} else {
returnTypeString = output.type.getName();
}
builder.append(output.paramInfo).append(")\n").
// return type
append(indent).append("public ").append(returnTypeString).
// method name
append(" ").append(methodName);
builder.append("( ");
boolean firstRun = true;
// method parameters
for (Parameter p : params) {
System.out.println("P: ");
System.out.println(">> p-info: " + p.getParamInfo());
if (firstRun) {
firstRun = false;
} else {
builder.append(",");
}
builder.append("\n").append(indent).append(" ");
String paramTypeString = "";
if (p.getType().isArray()) {
// paramTypeString = p.type.getComponentType().getName() + "[]";
paramTypeString = VClassLoaderUtil.arrayClass2Code(p.type.getName());
} else {
paramTypeString = p.type.getName();
}
builder.append("@ParamInfo(").append(p.getParamInfo()).append(") ").
append(paramTypeString).append(" ").
append(p.getName());
}
builder.append(" )");
return builder.toString();
}
/**
Returns the code that is resposible for object instanciation.
@param canvas where the object is visualized on
@param controlFlowMethods are methods which are in the controlflow
@param indent is the indentation for the automatic generated groovy code
@return the code that is resposible for object instanciation
*/
private static String getObjectInstanciationCodeViaControlFlowMethods(
VisualCanvas canvas,
Collection controlFlowMethods,
String indent) {
StringBuilder builder = new StringBuilder("// instances\n");
Set addedObjects = new HashSet();
String objName = null;
for (DefaultMethodRepresentation dmr : controlFlowMethods) {
objName = getObjectInstanciationCodeVariableName(dmr);
//if we already have an instance of the object we do not want to add/create it again
//e.g. in case an object invokes to methods in the controllflow
if (addedObjects.contains(objName)) {
continue;
}
addedObjects.add(objName);
int objID = dmr.getDescription().getObjectID();
String className = canvas.getInspector().getObject(objID).getClass().getName();
builder.append(indent).append(" ").append(className).append(" ").
append(objName).
append(" = new ").append(className).append("();\n");
}
return builder.toString();
}
/**Returns an unique variable name for the return value of a method.
@param controlFlowMethod a method in the control flow
@return a unique variable name
*/
private static String getObjectInstanciationCodeVariableName(
DefaultMethodRepresentation controlFlowMethod) {
StringBuilder builder = new StringBuilder();
int objID = controlFlowMethod.getDescription().getObjectID();
builder.append("obj").append(objID);
return builder.toString();
}
/**
* Returns a unique variable name for the specified connection.
*
* @param canvas canvas
* @param connections data connections of the canvas
* @param con connection
* @return a unique variable name for the specified connection
*/
private static String getVariableName(VisualCanvas canvas,
Collection connections, Connection con) {
return getVariableName(canvas, connections, con.getSender());
}
/**
* Returns a unique variable name for the specified connector.
* Warning: this method does not indicate if the specified arguments
* are illegal. This may cause wrong results.
*
* @param canvas canvas
* @param connections data connections of the canvas
* @param receiver connector (Input)
* @return a unique variable name for the specified connector
*/
private static String getVariableName(VisualCanvas canvas,
Collection connections, Connector receiver) {
if (receiver.getType() != ConnectorType.OUTPUT) {
throw new IllegalArgumentException(
"only output connectors supported!");
}
int varIndex = 0;
// if we are connected to an input parameter use it instead
// of an automatically generated variable name
for (Parameter p : getInputParameter(canvas)) {
if (p.getConnection().contains(receiver)) {
return p.getName();
}
}
for (Connection c : connections) {
if (c.getSender().equals(receiver)) {
break;
}
varIndex++;
}
return "v" + varIndex;
}
private static String getMultiOutputVariableName(DefaultMethodRepresentation method) {
return "multiOut_Obj" + method.getDescription().getObjectID() + "m" + method.getDescription().getMethodID();
}
/**
Helper method to check in methods with a multioutput return vale if there subelements are used
as return values.
@param connections data connections of the canvas
@param method a multiOutput method which should be check if there subelements have connections
@return a list with all connected subelements, list is empty if none subelement is connected
*/
private static ArrayList checkAndCollectSubelementContainersOfMultiOutputs(Connections connections, DefaultMethodRepresentation method) {
ArrayList connectedSubTypes = new ArrayList();
MultipleOutputType mot = (MultipleOutputType) method.getReturnValue();
ArrayList typeContainers = mot.getTypeContainers();
//go over all subelements of the multioutput
for (int i = 0; i < typeContainers.size(); i++) {
TypeRepresentationContainer trepContainer = (TypeRepresentationContainer) typeContainers.get(i);
TypeRepresentationBase trep = trepContainer.getTypeRepresentation();
//check the subConnection if it is used
boolean isConnected = connections.alreadyConnected(trep.getConnector());
if (isConnected) {
connectedSubTypes.add(trepContainer);
}
}
return connectedSubTypes;
}
/**
* Returns the variable declaration code. All variables are initialized with
* null
*
* @param canvas canvas
* @param connections data connections of the canvas
* @param methods all methods that are part of the controlflow of the canvas
* @param indent indent to use (necessary for correct code formatting)
* @return returns the variable declaration code
*/
private static String getVariableDeclarationCode(VisualCanvas canvas,
Connections connections,
Collection methods, String indent) {
StringBuilder builder
= new StringBuilder(indent);
builder.append("// variable declarations\n").append(indent);
for (DefaultMethodRepresentation method : methods) {
boolean notVoid = !method.getReturnValue().getType().equals(void.class);
boolean connected = connections.alreadyConnected(method.getReturnValue().getConnector());
boolean checkForMultipleOutput = method.getReturnValue().getClass().equals(MultipleOutputType.class);
boolean arraySubElementsAreConnected = false;
ArrayList connectedSubTypes = new ArrayList();
// check if one or more of the multiple ouput elements are connected
// and save the connected ones in a list
if (checkForMultipleOutput) {
connectedSubTypes = checkAndCollectSubelementContainersOfMultiOutputs(connections, method);
//if connectedSubTypes is empty no connection are used inside the multioutput
arraySubElementsAreConnected = !connectedSubTypes.isEmpty();
}// if checkForMultipleOutput
boolean methodReturnsData = notVoid && (connected || arraySubElementsAreConnected);
// we only need to declare a variable if this method
// returns something
if (methodReturnsData) {
String returnValueType = "";
if (method.getReturnValue().getType().isArray()) {
returnValueType = VClassLoaderUtil.arrayClass2Code(
method.getReturnValue().getType().getName());
// if subelements of multiple outputs are connected we need
// create variable for them too
if (arraySubElementsAreConnected) {
for (int i = 0; i < connectedSubTypes.size(); i++) {
//get the right format for the variable typ
if (connectedSubTypes.get(i).getType().isArray()) {
returnValueType = VClassLoaderUtil.arrayClass2Code(connectedSubTypes.get(i).getType().getName());
} else {
returnValueType = connectedSubTypes.get(i).getType().getName();
}
TypeRepresentationBase trep = connectedSubTypes.get(i).getTypeRepresentation();
Connector subConnector = trep.getConnector();
//write the variable declaration for multiOuput variables
builder.append(returnValueType).
append(" ").
append(getVariableName(canvas, connections, subConnector)).
append(" = null; // multi-out-var : ").
append("obj").append(method.getDescription().getObjectID()).
append("m").append(method.getDescription().getMethodID()).
append("\n").append(indent);
}
}//if (arraySubElementsAreConnected) end
else {
builder.append(returnValueType).
append(" ").
append(getVariableName(canvas, connections,
method.getReturnValue().getConnector())).
append(" = null; // single-out-var (array) : ").
append("obj").append(method.getDescription().getObjectID()).
append("m").append(method.getDescription().getMethodID()).
append("\n").append(indent);
}
} else {
returnValueType = method.getReturnValue().getType().getName();
builder.append(returnValueType).
append(" ").
append(getVariableName(canvas, connections,
method.getReturnValue().getConnector())).
append(" = null; // single-out-var : ").
append("obj").append(method.getDescription().getObjectID()).
append("m").append(method.getDescription().getMethodID()).
append("\n").append(indent);
}
}
}
return builder.toString();
}
/**
* Returns the method invocation code. Return values of connected methods
* are stored in the previously defined variables (see
* {@link #getVariableDeclarationCode(
* eu.mihosoft.vrl.reflection.VisualCanvas,
* eu.mihosoft.vrl.visual.Connections,
* java.util.Collection, java.lang.String)} )
*
* @param method method to invoke
* @param indent indent to use (necessary for correct code formatting)
* @return method invocation code
*/
private static String getMethodInvocationCode(
DefaultMethodRepresentation method, String indent) {
StringBuilder builder
= new StringBuilder(indent);
VisualCanvas canvas = (VisualCanvas) method.getMainCanvas();
Connections connections = canvas.getDataConnections();
// controlflow statements
if (ControlFlowUtils.isMethodControlFlowStatement(method)) {
try {
method.automaticInvocation(canvas.getInspector());
} catch (InvocationTargetException ex) {
Logger.getLogger(SessionClassUtils.class.getName()).
log(Level.SEVERE, null, ex);
}
ControlFlowStatement statement
= ControlFlowUtils.getControlFlowStatement(
method);
builder.append(statement.getCode()).append("\n");
return builder.toString();
}
// if we are a reference method we only add our instance name and return
// examples:
// 1) if method's return value is assigned to a variable:
// v0 = o2;
// 2) if method's return value is not assigned to a variable:
// o1 = o2;
// 3) if method's input and output are connected:
// v1 = o1; o1 = o2;
if (method.isReferenceMethod()) {
boolean returnValueConnected
= method.getMainCanvas().getDataConnections().
alreadyConnected(method.getReturnValue().getConnector());
boolean inputValuesConnected = method.getMainCanvas().
getDataConnections().
alreadyConnected(method.getParameter(0).getConnector());
if (inputValuesConnected) {
builder.append(getObjectInstanciationCodeVariableName(method))
.append(" = ");
// only one connection allowed. thus, get(0) is save
Connection c
= connections.getAllWith(
method.getParameter(0).
getConnector()).get(0);
builder.append(
getVariableName(canvas, connections, c)).
append(";");
}
// we add a newline if no code for input value assignment has to
// be added
if (inputValuesConnected && !returnValueConnected) {
builder.append("\n");
}
if (returnValueConnected) {
// only one connection allowed. thus, get(0) is save
Connection c
= connections.getAllWith(
method.getReturnValue().
getConnector()).get(0);
builder.append(getVariableName(canvas, connections, c)).
append(" = ");
builder.append(getObjectInstanciationCodeVariableName(method))
.append(";\n");
}
if (inputValuesConnected || returnValueConnected) {
return builder.toString();
} else {
return "";
}
}
//
// we are no reference method and thus we are still in this method
//
boolean notVoid = !method.getReturnValue().getType().equals(void.class);
boolean connected = connections.alreadyConnected(method.getReturnValue().getConnector());
boolean checkForMultipleOutput = method.getReturnValue().getClass().equals(MultipleOutputType.class);
boolean arraySubElementsAreConnected = false;
ArrayList connectedSubTypes = new ArrayList();
// check if one or more of the multiple ouput elements are connected
// and save the connected ones in a list
if (checkForMultipleOutput) {
connectedSubTypes = checkAndCollectSubelementContainersOfMultiOutputs(connections, method);
//if connectedSubTypes is empty no connection are used inside the multioutput
arraySubElementsAreConnected = !connectedSubTypes.isEmpty();
}// if checkForMultipleOutput
boolean methodReturnsData = notVoid && (connected || arraySubElementsAreConnected);
//
// we only need to declare a variable if this method returns something
// or has a multioutput where at least one suboutput returns something
if (methodReturnsData) {
//the method has a multiOutput and at least one subOutput is connected
if (arraySubElementsAreConnected) {
builder.append("\n").append(indent)
.append("Object[] ").append(getMultiOutputVariableName(method)).append(" = ");
} else {
builder.append(getVariableName(canvas, connections,
method.getReturnValue().getConnector())).append(" = ");
}
}
String methodName = getObjectInstanciationCodeVariableName(method)
+ "." + method.getDescription().getMethodName();
builder.append(methodName).append("( ");
ArrayList doNotSupportCodeGeneration
= new ArrayList();
// now we add the parameter values to the method
boolean firstRun = true;
for (TypeRepresentationBase tRep : method.getParameters()) {
if (firstRun) {
firstRun = false;
} else {
builder.append(", ");
}
boolean paramConnected
= connections.alreadyConnected(tRep.getConnector());
if (paramConnected) {
// only one connection allowed. thus, get(0) is save
Connection c
= connections.getAllWith(tRep.getConnector()).get(0);
builder.append(getVariableName(canvas, connections, c));
} else if (tRep instanceof ArrayBaseType) {
// check whether using ArrayBaseType because arrays are handled
// differently (array connectors are never connected). We only
// operate on the type representations of the array elements
generateArrayBaseClassCode(builder,
canvas, connections,
doNotSupportCodeGeneration,
(ArrayBaseType) tRep);
} else {
String code = null;
try {
code = tRep.getValueAsCode();
} catch (Exception ex) {
ex.printStackTrace(System.err);
}
if (code == null) {
code = "null as "
+ VClassLoaderUtil.arrayClass2Code(
tRep.getType().getName());
if (tRep.isWarningIfNoCodeGeneration()) {
doNotSupportCodeGeneration.add(tRep.getConnector());
}
}
builder.append(code);
}
// }
} // end for
builder.append(" );\n");
//the method has a multiOutput and at least one subOutput is connected
if (arraySubElementsAreConnected) {
builder.append(indent).append("// multioutput variable initialization \n");
//for each variable that is declared because of a subOutput connection
//we initialize those variables now
MultipleOutputType mot = (MultipleOutputType) method.getReturnValue();
ArrayList typeContainers = mot.getTypeContainers();
//go over all subelements of the multioutput
for (int i = 0; i < typeContainers.size(); i++) {
TypeRepresentationContainer trepContainer = (TypeRepresentationContainer) typeContainers.get(i);
TypeRepresentationBase trep = trepContainer.getTypeRepresentation();
//check the subConnection if it is used
boolean isConnected = connections.alreadyConnected(trep.getConnector());
if (isConnected) {
Connector subConnector = trepContainer.getConnector();
//at the index of the subElement of the mutiOutput
builder.append(indent)
.append(getVariableName(canvas, connections, subConnector))
.append(" = ")
.append(getMultiOutputVariableName(method))
.append("[").append(i).append("];\n");
}
}
builder.append("\n");
}
if (!doNotSupportCodeGeneration.isEmpty()) {
for (Connector c : doNotSupportCodeGeneration) {
canvas.getMessageBox().addMessage("Warning: code-generation"
+ " may be broken", "This type representation does not"
+ " support code-generation! \"null \" is used"
+ " instead. Thus, only values that are"
+ " connected will work in automatically generated code!",
c, MessageType.WARNING);
}
}
return builder.toString();
}
/**
* Generates param code for array type representations that delegate element
* code generation to their clid representations.
*
* @param arrayType array type representation
*/
private static void generateArrayBaseClassCode(
StringBuilder builder,
VisualCanvas canvas,
Connections connections,
ArrayList doNotSupportCodeGeneration,
ArrayBaseType arrayType) {
builder.append("[");
boolean firstSubElementRun = true;
for (TypeRepresentationContainer tCont : arrayType.getTypeContainers()) {
if (firstSubElementRun) {
firstSubElementRun = false;
} else {
builder.append(", ");
}
boolean paramConnected
= connections.alreadyConnected(tCont.getConnector());
if (paramConnected) {
// only one connection allowed. thus, get(0) is save
Connection c
= connections.getAllWith(
tCont.getConnector()).get(0);
builder.append(getVariableName(canvas, connections, c));
} else {
String code
= tCont.getTypeRepresentation().getValueAsCode();
if (code == null) {
code = "null as "
+ tCont.getTypeRepresentation().getType().getName();
doNotSupportCodeGeneration.add(tCont.getConnector());
}
builder.append(code);
}
} // end for
builder.append("] as ").
append(arrayType.getType().getComponentType().getName()).append("[]");
}
/**
* Returns the code of the method body. This includes object instanciation,
* variable declarations and method invocation code.
*
* @param canvas canvas
* @param indent indent to use (necessary for correct code formatting)
* @return code of the method body
*/
private static String getBodyCode(VisualCanvas canvas, String indent) {
// methods for controlflow
Collection controlFlowMethods
= ControlFlowUtils.getInvocationList(canvas);
StringBuilder builder = new StringBuilder();
// get object instances for groovy code
builder.append(getObjectInstanciationCodeViaControlFlowMethods(canvas, controlFlowMethods, indent)).
append("\n\n");
//get variable declarations for groovy code
builder.append(getVariableDeclarationCode(canvas,
canvas.getDataConnections(),
controlFlowMethods, indent + " ")).
append("\n\n");
builder.append("\n");
builder.append(indent).append(" // method calls\n");
for (DefaultMethodRepresentation mRep : controlFlowMethods) {
builder.append(getMethodInvocationCode(mRep, indent + " "));
}
builder.append("\n");
// return value
Connector c = getOutputSender(canvas);
if (c != null) {
builder.append(indent).append(" ").append("return ").
append(getVariableName(
canvas, canvas.getDataConnections(), c)).append(";\n");
}
return builder.toString();
}
/**
* Parameter class.
*/
private static class Parameter {
private Class> type;
private String name;
private String paramInfo;
private Connection connection;
public Parameter(Class> type, String name,
String paramInfo, Connection connection) {
this.type = type;
this.name = name;
this.paramInfo = paramInfo;
this.connection = connection;
}
public String getParamInfo() {
// if no custom param info has been defined use the param info of
// the corresponding type representation
// (from the receiver connector)
if (paramInfo == null || paramInfo.trim().equals("")) {
paramInfo = "";
TypeRepresentationContainer tCont
= (TypeRepresentationContainer) getConnection().
getReceiver().getValueObject();
TypeRepresentationBase tRep = tCont.getTypeRepresentation();
ArrayList params
= tCont.getTypeRepresentation().getParentMethod().
getParameters();
int id = params.indexOf(tRep);
ParamInfo info = null;
if (id >= 0 && id < tCont.getTypeRepresentation().
getParentMethod().getDescription().getParamInfos().length) {
info = tCont.getTypeRepresentation().
getParentMethod().getDescription().getParamInfos()[id];
}
if (info != null) {
paramInfo = "name=\"" + VLangUtils.addEscapeCharsToCode(
info.name()) + "\", style=\""
+ VLangUtils.addEscapeCharsToCode(info.style())
+ "\", options=\""
+ VLangUtils.addEscapeCharsToCode(
info.options()) + "\"";
} else {
System.err.println("ParamInfo not found!");
}
}
return paramInfo;
}
public String getName() {
return name;
}
public Class> getType() {
return type;
}
public Connection getConnection() {
return connection;
}
}
}