/*
* Visitor
*
*
* Copyright (c) 2003 Kansas State University, Laboratory for the Specification,
* Analysis, and Transformation of Software
*
* This software is licensed under the SAnToS Laboratory Open Academic License. You
* should have received a copy of the license with the distribution. A copy can be
* found at:
* http://www.cis.ksu.edu/santos/license.html
* or you can contact the lab at:
* SAnToS Laboratory
* 234 Nichols Hall
* Manhattan, KS 66506, USA
*/
package edu.ksu.cis.cadena.xmlgen;
import edu.ksu.cis.cadena.frontend.ComponentLibrary;
import edu.ksu.cis.cadena.frontend.cad.analysis.DefaultASTVisitor;
import edu.ksu.cis.cadena.frontend.cad.parser.BasicEventConnection;
import edu.ksu.cis.cadena.frontend.cad.parser.Connection;
import edu.ksu.cis.cadena.frontend.cad.parser.CorrelatedEventConnection;
import edu.ksu.cis.cadena.frontend.cad.parser.DataConnection;
import edu.ksu.cis.cadena.frontend.cad.parser.InstanceDecl;
import edu.ksu.cis.cadena.frontend.cad.parser.Location;
import edu.ksu.cis.cadena.frontend.cad.parser.Node;
import edu.ksu.cis.cadena.frontend.cad.parser.Scenario;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
/**
* This class generates the Java assembly code based on the scenario file
*
* @version 1.0.3 7.31.2003
* @author Shufeng Li
*
*/
public class Visitor extends DefaultASTVisitor {
/** package name for generated code*/
private String filePackage = "cadena";
/** class name for the generated file*/
private String filename = "Scenario";
/** the directory of the output file*/
private String outputDir;
/** the generated file*/
private File theFile;
/** the output file writer*/
private PrintWriter out;
/** array for the names of component servers*/
private String[] componentServerNames;
/** maps component server to a list*/
private Map comServerToHomeList = new HashMap();
/** the name of the project*/
private String projectName;
/** maps instance name to another map (which maps port name to eventID)*/
private Map instanceToPortID;
/** indicates whether generates the gateway parts in output file*/
private boolean forEventService = true;
/**
* initializes eventID and instancePorts map
* @post eventID == 1 && instancePorts != null;
*/
public Visitor() {
}
/**
* initializes eventID and instancePorts map, set outputDir, projectName
*
* @param dir the directory in which gluecode will be created
* @param name of the project
* @param instancePortID map instance name to port ID
* @pre instancePosrtID != null
* @post outputDir != null && projectName != null && eventID == 1
*/
public Visitor(String dir, String name, Map instancePortID) {
//pre-condition
assert dir != null;
assert name != null;
assert instancePortID != null;
outputDir = dir;
projectName = name;
this.instanceToPortID = instancePortID;;
}
/**
* get component server names based on the location names of the scenario
*
* @param node the scenario
* @post array componentServerNames != null
*/
private void getComponentServerNames(Scenario node) {
//pre condition
assert node != null;
componentServerNames = new String[node.getLocationList().size()];
int i = 0;
for (Iterator iterator = node.getLocationList().iterator();
iterator.hasNext();) {
Location location = (Location) iterator.next();
componentServerNames[i] = location.getLocation();
i++;
}
//post condition
assert i == node.getLocationList().size();
assert componentServerNames != null;
}
/**
* initializes the comServerToHomeList map,
* each component server name is the key, a LinkedList is the value
*
* @pre array componentServerNames != null
* @post map comServerToHomeList != null.
*/
private void initializeComServerToHomeListMap() {
//pre-condition
assert componentServerNames != null;
for (int i = 0; i < componentServerNames.length; i++) {
comServerToHomeList.put(componentServerNames[i], new LinkedList());
}
//post condition
assert comServerToHomeList != null;
}
/**
* visits Scenario
*
* @see edu.ksu.cis.cadena.frontend.cad.analysis.ASTVisitor#visit(Scenario, Object)
* @see setFile()
* @see getComponentServerNames(Scenario)
* @see initializeComServerToHomeListMap()
* @see initializeFile()
* @see createInstance(InstanceDecl)
* @see setInstanceName(InstanceDecl)
* @see instance.apply(InstanceDecl, Object)
* @see createGateWay(InstanceDecl)
* @see configurationComplete(InstanceDecl)
*
* @param node the current scenario
* @param input not used here
* @return null
*/
public Object visit(Scenario node, Object input) {
assert node != null;
setFile();
getComponentServerNames(node);
initializeComServerToHomeListMap();
initializeFile();
printMessage(
"\n\t\tSystem.out.println(\"Instantiating homes, components...\");");
for (Iterator iterator = node.getInstanceList().iterator();
iterator.hasNext();) {
InstanceDecl instance = (InstanceDecl) iterator.next();
createInstance(instance); //create component instances and assocated homes
}
printMessage("\n\t\tSystem.out.println(\"set instance names...\");");
for (Iterator iterator = node.getInstanceList().iterator();
iterator.hasNext();) {
InstanceDecl instance = (InstanceDecl) iterator.next();
setInstanceName(instance);
}
printMessage(
"\n\t\tSystem.out.println(\"Interconnecting components...\");");
for (Iterator iterator = node.getInstanceList().iterator();
iterator.hasNext();) {
InstanceDecl instance = (InstanceDecl) iterator.next();
instance.apply(this, "");
}
if (forEventService && (node.getLocationList().size() > 1)) {
printMessage("\n\t\tSystem.out.println(\"Create gateways...\");");
for (Iterator iterator = node.getInstanceList().iterator();
iterator.hasNext();) {
InstanceDecl instance = (InstanceDecl) iterator.next();
createGateWay(instance);
}
}
printMessage(
"\n\t\tSystem.out.println(\"Components configuration completion...\");");
for (Iterator iterator = node.getInstanceList().iterator();
iterator.hasNext();) {
InstanceDecl instance = (InstanceDecl) iterator.next();
configurationComplete(instance);
}
closeFile();
return null;
}
/**
* visits InstanceDecl, starts to visit Connection node
*
* @see edu.ksu.cis.cadena.frontend.cad.analysis.ASTVisitor#visit(InstanceDecl, Object)
* @see apply(DataConnection, Object)
* @see apply(BasicEventConnection, Object)
*
* @param node the instance is going to be visited
* @param input not used here
* @return null;
*/
public Object visit(InstanceDecl node, Object input) {
assert node != null;
for (Iterator iterator = node.getConnections().iterator();
iterator.hasNext();) {
Connection c = (Connection) iterator.next();
c.apply(this, node);
}
return null;
}
/**
* visits Data Connection, starts to create data connection
* @see edu.ksu.cis.cadena.frontend.cad.analysis.ASTVisitor#visit(DataConnection, Object)
* @see createDataConnection(DataConnection, InstanceDecl)
*
* @param node the DataConnection node
* @param input the owner instance of this DataConnection
* @return null;
*/
public Object visit(DataConnection node, Object input) {
assert node != null;
assert input instanceof InstanceDecl;
createDataConnection(node, ((InstanceDecl) input)); //create data connection
return null;
}
/**
* visits BasicEventConnection, starts to create event connection
* @see edu.ksu.cis.cadena.frontend.cad.analysis.ASTVisitor#visit(BasicEventConnection, Object)
* @see createEventConnection(BasicEventConnection, InstanceDecl)
* @param node the BasicEventConnection node
* @param input the owner instance of the BasicEventConnection
* @return null;
*/
public Object visit(BasicEventConnection node, Object input) {
assert node != null;
assert input instanceof InstanceDecl;
createEventConnection(node, ((InstanceDecl) input)); //create event connection
return null;
}
/**
* visits CorrelatedEventConnection, does nothing
* @see edu.ksu.cis.cadena.frontend.cad.analysis.ASTVisitor#visit(CorrelatedEventConnection, Object)
* @param node the CorrelatedEventConnection
* @param input the owner of the connection
* @return null;
*/
public Object visit(CorrelatedEventConnection node, Object input) {
return null;
}
/**
* writes the first part of file
* @see writeFileHeader()
* @see initialORB()
* @see initialRuntime()
* @see obtainNameServer()
* @see obtainComponentServer()
* @see obtainContainerHome()
* @see installArchives()
* @see getContainer()
*/
public void initializeFile() {
assert componentServerNames != null;
writeFileHeader();
initialORB();
initialRuntime();
obtainNameServer();
obtainComponentServer();
obtainContainerHome();
installArchives();
getContainer();
}
/**
* writes the generated file header, package, class name, main method
*/
private void writeFileHeader() {
out.println("package " + filePackage + ";");
out.println("\npublic class " + filename + "{");
out.println(
"\tpublic static void main(String[] args) throws Exception {");
out.println("\t\torg.omg.Components.CCMHome " + "ccmhome" + ";");
}
/**
* writes out the ORB comment
*/
private void initialORB() {
out.println("\t\t// Init the ORB.");
out.println("\t\tSystem.out.println(\"Initializing the ORB...\");");
}
/**
* write the initial ORB runtime
*/
private void initialRuntime() {
out.println("\t\t// Init the OpenCCM Components Runtime.");
out.println("\t\torg.omg.CORBA.ORB " + "corbaorb"
+ " = org.objectweb.ccm.Components.Runtime.init(args);");
}
/**
* writes the obtain Name Serve part of code
*/
private void obtainNameServer() {
out.println("\n\t\t// Obtain the Name Service.");
out.println(
"\t\tSystem.out.println(\"Obtaining the Name Service...\");");
out.println("\t\torg.omg.CORBA.Object " + "corbaobj" + " = "
+ "corbaorb" + ".resolve_initial_references(\"NameService\");");
out.println("\t\torg.omg.CosNaming.NamingContext " + "namingContext"
+ " = org.omg.CosNaming.NamingContextHelper.narrow(" + "corbaobj"
+ ");");
}
/**
* writes the obtain Component Server part of code
* @pre componentServerNames != null
*/
private void obtainComponentServer() {
assert componentServerNames != null;
out.println("\n\t\t// Obtain the component servers.");
out.println(
"\t\tSystem.out.println(\"Obtaining Component Servers...\");");
out.println("\t\torg.omg.CosNaming.NameComponent[] " + "nameComponent"
+ " = new org.omg.CosNaming.NameComponent[1];");
out.println("\t\t" + "nameComponent"
+ "[0] = new org.omg.CosNaming.NameComponent(\""
+ componentServerNames[0] + "\",\"\");");
out.println("\t\t" + "corbaobj" + " = " + "namingContext" + ".resolve("
+ "nameComponent" + ");");
out.println("\t\torg.objectweb.ccm.Deployment.Server "
+ componentServerNames[0].toLowerCase() + "_server" + " =");
out.println("\t\torg.objectweb.ccm.Deployment.ServerHelper.narrow("
+ "corbaobj" + ");\n");
for (int i = 1; i < componentServerNames.length; i++) {
out.println("\t\tnameComponent[0].id = \""
+ componentServerNames[i] + "\";");
out.println("\t\tcorbaobj = namingContext.resolve(nameComponent);");
out.println("\t\torg.objectweb.ccm.Deployment.Server "
+ componentServerNames[i].toLowerCase() + "_server" + " =");
out.println("\t\torg.objectweb.ccm.Deployment.ServerHelper.narrow("
+ "corbaobj" + ");\n");
}
}
/**
* writes the obtain Container Home part of code
* @pre componentServerNames != null
*/
private void obtainContainerHome() {
assert componentServerNames != null;
out.println("\n\t\t// Obtain the container homes.");
for (int i = 0; i < componentServerNames.length; i++) {
out.println("\t\torg.omg.Components.Deployment.ComponentServer "
+ componentServerNames[i].toLowerCase() + "_cs" + " = ");
out.println("\t\t" + componentServerNames[i].toLowerCase()
+ "_server" + ".provide_component_server();");
}
}
/**
* writes the install Archives part of code, the project jar file, and OpenCCM_Plugins.jar file
* @pre componentServerNames != null
*/
private void installArchives() {
assert componentServerNames != null;
out.println("\n\t\t//Install archives.");
out.println("\t\tSystem.out.println(\"Installing archives...\");");
for (int i = 0; i < componentServerNames.length; i++) {
out.println(
"\t\torg.omg.Components.Deployment.ComponentInstallation "
+ componentServerNames[i].toLowerCase() + "_inst" + " = ");
out.println("\t\t" + componentServerNames[i].toLowerCase()
+ "_server" + ".provide_install();");
out.println("\t\t" + componentServerNames[i].toLowerCase()
+ "_inst" + ".install(\"" + projectName + "\", \"./archives/"
+ projectName + ".jar\");");
out.println("\t\t" + componentServerNames[i].toLowerCase()
+ "_inst"
+ ".install(\"openccm_plugins\", \"./OpenCCM_Plugins.jar\");");
}
}
/**
* writes the get container part of code
* @pre componentServerNames != null
*/
public void getContainer() {
assert componentServerNames != null;
for (int i = 0; i < componentServerNames.length; i++) {
out.println("\n\t\torg.omg.Components.Deployment.Container "
+ componentServerNames[i].toLowerCase() + "_cont" + " =");
out.println("\t\t\t" + componentServerNames[i].toLowerCase()
+ "_cs"
+ ".create_container(new org.omg.Components.ConfigValue[0]);");
}
}
/**
* writes a message into generated file
* @param m the message to be written
*/
public void printMessage(String m) {
assert m != null;
out.println(m);
}
/**
* gets component server name based on some property file
* @param instanceName the name of the component instance
* @return the component server name of the component instance should be installed
*/
private String getComponentServerName(String instanceName) {
//somehow, get the name;
return "";
}
/**
* if a corresponding home has been created, then just create an instance from its home
* else installs a component home of this instance on corresponding componentServer,
* and put the home name into componentHome list
* @param instance the InstanceDecl to be instantiated
*/
public void createInstance(InstanceDecl instance) {
assert instance != null;
String serverName = instance.getLocation().getLocation();
String instanceType = instance.getBuildingBlock();
String postfix =
edu.ksu.cis.cadena.frontend.cad.parser.ImportLib
.convertCorbaNameToJava(instanceType.toLowerCase());
LinkedList homes = (LinkedList) comServerToHomeList.get(serverName);
if (!homes.contains(instanceType)) {
homes.add(instanceType);
out.println("\t\t" + "ccmhome" + " = " + serverName.toLowerCase()
+ "_cont.install_home(\"" + projectName + "\", \""
+ getPrefix(instanceType)
+ "HomeImpl.create_home\",\n \t\tnew org.omg.Components.ConfigValue[0]);\n\t\t"
+ getPrefix(instanceType) + "Home "
+ postfix.substring(postfix.lastIndexOf(".") + 1,
postfix.length()) + serverName + "Home = "
+ getPrefix(instanceType) + "HomeHelper.narrow(" + "ccmhome"
+ ");");
}
out.println("\t\t" + getPrefix(instanceType) + " "
+ edu.ksu.cis.cadena.frontend.cad.parser.ImportLib
.convertCorbaNameToJava(instance.getName().toLowerCase()) + " = "
+ postfix.substring(postfix.lastIndexOf(".") + 1, postfix.length())
+ serverName + "Home" + ".create();");
}
/**
* if the toInstance of this connection equals to the owner of this connection, creates a data connection
* else does nothing
*
* @param connection the connection node
* @param owner the owner of the connection node
* @pre two different instances for the connection
* @pre same port type of the two ports that are going to be connected
*/
public void createDataConnection(DataConnection connection,
InstanceDecl owner) {
//pre-condition
assert connection != null;
assert owner != null;
assert !connection.getFromInstance().getName().equals(connection.getToInstance()
.getName());
if (owner.equals(connection.getToInstance())) {
out.println("\t\t"
+ connection.getFromInstance().getName().toLowerCase()
+ ".connect_" + getLastToken(connection.getFromPort()) + "("
+ connection.getToInstance().getName().toLowerCase()
+ ".provide_" + getLastToken(connection.getToPort()) + "()"
+ ");");
}
}
/**
* if the toInstance of this connection equals to the owner of this connection, creates a basic event connection
* else does nothing
* @param connection the connection node
* @param owner the owner of the connection node
* @pre two different instances for the connection
* @pre same port type of the two ports that are going to be connected
*/
public void createEventConnection(BasicEventConnection connection,
InstanceDecl owner) {
//pre-condition
assert connection != null;
assert owner != null;
assert !connection.getFromInstance().getName().equals(connection.getToInstance()
.getName());
if (owner.equals(connection.getFromInstance())) {
out.println("\t\t"
+ connection.getFromInstance().getName().toLowerCase()
+ ".subscribe_" + getLastToken(connection.getFromPort()) + "("
+ connection.getToInstance().getName().toLowerCase()
+ ".get_consumer_" + getLastToken(connection.getToPort())
+ "());");
}
}
/**
* opens the output java file with the specified name
* @throws IOException
*/
public void setFile() {
try {
theFile = new File(outputDir + File.separator + filename + ".java");
out = new PrintWriter(new BufferedWriter(new FileWriter(theFile)));
} catch (Exception e) {
System.out.println(e);
}
}
/**
* writes the setName method for each instance
* @param instance the instance to be set name
*/
public void setInstanceName(InstanceDecl instance) {
assert instance != null;
out.println("\t\t" + instance.getName().toLowerCase() + ".name(\""
+ instance.getName().trim() + "\");");
}
/**
* writes configuration_complete method for each instance
* @param instance the instance to be completed
*/
public void configurationComplete(InstanceDecl instance) {
assert instance != null;
out.println("\t\t" + instance.getName().toLowerCase()
+ ".configuration_complete();");
}
/**
* makes prepares to do the createGateWays
* assigns a unique ID for the connection,
* groups the connection so that the connections have the same directions in a linkedList, the key is its board name
*
* @see createEventID(Connection, InstanceDecl)
* @see rearrangeConnections(String, Connection, InstanceDecl, Map)
* @param instance the component instance
* @pre instance != null
*/
public void createGateWay(InstanceDecl instance) {
assert instance != null;
Map boradToConnectionList = new HashMap();
String fromBoardName = instance.getLocationString();
for (Iterator it = instance.getConnections().iterator(); it.hasNext();) {
Connection c = (Connection) it.next();
if (c instanceof BasicEventConnection) {
if (((BasicEventConnection) c).getFromInstance().getName()
.equals(instance.getName())) {
//rearrange the connections based on the board locations
rearrangeConnections(fromBoardName, c, boradToConnectionList);
}
}
}
//create the gate ways
if (!boradToConnectionList.isEmpty()) {
for (Iterator it =
((Set) (boradToConnectionList.keySet())).iterator();
it.hasNext();) {
String toBoardName = (String) it.next();
LinkedList connectionList =
(LinkedList) boradToConnectionList.get(toBoardName);
createDependency(connectionList, fromBoardName, toBoardName);
}
}
}
/**
* groups the connection so that the connections have the same directions,
* from the fromBoard are grouped together, thus, the dependency could be created together
*
* @param instance the component instance
* @param c the connection to be rearranged
* @param fromBoardName the name of supplier board
* @param map maps connection list with the same board name
* @pre c instanceof BasicEventConnection && instance!=null
* @post eventID' == eventID || eventID' == eventID + 1
*/
private void rearrangeConnections(String fromBoardName, Connection c, Map map) {
assert fromBoardName != null;
assert (c != null) && (c instanceof BasicEventConnection);
assert map != null;
String board = ((BasicEventConnection) c).getToInstance().getLocationString();
if (!fromBoardName.equals(board)) {
if (map.containsKey(board)) {
((LinkedList) (map.get(board))).add(c);
} else {
LinkedList b = new LinkedList();
b.add(c);
map.put(board, b);
}
}
}
/**
* creates the dependency array, whose size is the length of the input LinkedList
* writes the create_gateway method in the output file
*
* @param connections the connections between two boards in one direction
* @param fromBoardName the supplier's board name
* @param toBoardName the consumer's board name
* @pre connections != null && fromBoardName != null && toBoardName != null
*/
private void createDependency(LinkedList connections, String fromBoardName,
String toBoardName) {
assert (connections != null) && (connections.size() != 0);
assert fromBoardName != null;
assert toBoardName != null;
out.println("\t\tedu.ksu.cis.EventChannelAdmin.Dependency "
+ toBoardName
+ "_"
+ fromBoardName
+ "_dependency[] = \n\t\t\tnew edu.ksu.cis.EventChannelAdmin.Dependency["
+ connections.size()
+ "];");
int i = 0;
for (Iterator it = connections.iterator(); it.hasNext();) {
BasicEventConnection c = (BasicEventConnection) it.next();
String fromInstanceName = c.getFromInstance().getName();
String fromPortName = c.getFromPort();
int eventid =
((PortEntryInformation) (((Map) instanceToPortID.get(fromInstanceName)).get(fromPortName)))
.getEventID();
out.println("\t\t"
+ toBoardName
+ "_"
+ fromBoardName
+ "_dependency["
+ i
+ "] = \n\t\t\tnew edu.ksu.cis.EventChannelAdmin.Dependency();");
out.println("\t\t"
+ toBoardName
+ "_"
+ fromBoardName
+ "_dependency["
+ i
+ "].header = \n\t\t\tnew edu.ksu.cis.EventComm.EventHeader("
+ eventid
+ ", 0);");
i++;
}
out.println("\t\tedu.ksu.cis.EventChannelAdmin.ConsumerQOS "
+ toBoardName
+ "_"
+ fromBoardName
+ "_cqos = \n\t\t\tnew edu.ksu.cis.EventChannelAdmin.ConsumerQOS("
+ toBoardName
+ "_"
+ fromBoardName
+ "_dependency);");
out.println("\t\t"
+ toBoardName.toLowerCase()
+ "_cs.create_gateway(\""
+ toBoardName
+ ".EventChannel\", \""
+ fromBoardName
+ ".EventChannel\", "
+ toBoardName
+ "_"
+ fromBoardName
+ "_cqos);\n");
}
/**
* writes the last part of the generated file, close the file
*/
public void closeFile() {
out.println("\t\tSystem.exit(0);\n\t}\n}");
out.close();
}
/**
* gets the last token of input string,
* @param s a string
* @return the last token of the input string
* @pre s != null
* @post return != null
*/
private String getLastToken(String s) {
assert s != null;
String name = "";
StringTokenizer st = new StringTokenizer(s);
while (st.hasMoreTokens()) {
name = st.nextToken();
}
assert name != null;
return name;
}
/**
* @see edu.ksu.cis.cadena.frontend.cad.analysis.DefaultASTVisitor#defaultCase(Node, Object)
*/
public Object defaultCase(Node node, Object input) {
assert false;
return null;
}
/**
* getPrefix ???
* @param name the string to be converted
* @return String the prefix of the name + the name whose "::" replaced by ".", if the prefix exists
* @else return the name with "::" replaced by "."
*/
private String getPrefix(String name) {
assert name != null;
int beginIndex = 0;
if (name.startsWith(":")) {
beginIndex = 2;
}
String modalName =
name.substring(beginIndex, name.indexOf(":", beginIndex));
ComponentLibrary comLib = ComponentLibrary.getComponentLibrary();
String prefix = comLib.getPrefix(modalName);
if (!prefix.trim().equals("")) {
if (prefix.startsWith(".")) {
return prefix
+ edu.ksu.cis.cadena.frontend.cad.parser.ImportLib
.convertCorbaNameToJava(name);
} else {
return prefix + "."
+ edu.ksu.cis.cadena.frontend.cad.parser.ImportLib
.convertCorbaNameToJava(name);
}
} else {
String temp =
edu.ksu.cis.cadena.frontend.cad.parser.ImportLib
.convertCorbaNameToJava(name);
return temp.substring(1);
}
}
/**
* sets the PrinteWriter pointer, only used by junit test
* @param out the output file handler
* @post this.out != null
*/
public void setOutName(PrintWriter out) {
try {
this.out = out;
} catch (Exception e) {
System.out.println(e);
}
}
}
syntax highlighted by Code2HTML, v. 0.9.1