oms3.dsl.Model Maven / Gradle / Ivy
package oms3.dsl;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import oms3.ComponentException;
import oms3.annotations.Name;
import oms3.annotations.Role;
import oms3.compiler.ModelCompiler;
import oms3.io.CSProperties;
import oms3.io.CSTable;
import oms3.io.DataIO;
import oms3.util.Components;
public class Model implements Buildable {
protected static final Logger log = Logger.getLogger("oms3.sim");
//
String classname;
Resource res;
List params = new ArrayList();
Logging l = new Logging();
//
KVPContainer comps = new KVPContainer();
KVPContainer out2in = new KVPContainer();
KVPContainer feedback = new KVPContainer();
//
String control = null;
String controlClass = "oms3.Compound";
//
URLClassLoader modelClassLoader;
@Override
public Buildable create(Object name, Object value) {
if (name.equals("parameter")) {
Params p = new Params();
params.add(p);
return p;
} else if (name.equals("resource")) {
res.addResource(value);
return LEAF;
} else if (name.equals("logging")) {
return l;
} else if (name.equals("components")) {
return comps;
} else if (name.equals("connect")) {
return out2in;
} else if (name.equals("feedback")) {
return feedback;
}
throw new ComponentException("Unknown element: '" + name.toString() + "'");
}
KVPContainer getComponents() {
return comps;
}
KVPContainer getConnects() {
return out2in;
}
Logging getComponentLogging() {
return l;
}
Resource getRes() {
return res;
}
void setRes(Resource res) {
this.res = res;
}
public List getParams() {
return params;
}
@Deprecated
public void setIter(String c) {
setWhile(c);
}
public void setWhile(String c) {
control = c;
controlClass = "oms3.control.While";
}
public void setUntil(String c) {
control = c;
controlClass = "oms3.control.Until";
}
public void setIf(String c) {
control = c;
controlClass = "oms3.control.If";
}
public void setClassname(String classname) {
this.classname = classname;
}
public String getLibpath() {
List f = res.filterDirectories();
StringBuilder b = new StringBuilder();
for (int i = 0; i < f.size(); i++) {
b.append(f.get(i));
if (i < f.size() - 1) {
b.append(File.pathSeparatorChar);
}
}
return b.toString();
}
private static List getExtraResources() {
List sc = new ArrayList();
String simPath = System.getProperty("oms.sim.resources");
if (log.isLoggable(Level.CONFIG)) {
log.config("oms.sim.resources '" + simPath + "'");
}
if (simPath != null && !simPath.isEmpty()) {
simPath = simPath.replaceAll("\"", "");
for (String s : simPath.split("\\s*" + File.pathSeparator + "\\s*")) {
sc.add(new File(s));
}
}
return sc;
}
/** get the URL class loader for all the resources (just for jar files
*
* @return
* @throws Exception
*/
private synchronized URLClassLoader getClassLoader() {
if (modelClassLoader == null) {
List jars = res.filterFiles("jar"); // jars as defined in
List cli_jars = getExtraResources(); // cli extra jars
List dirs = res.filterDirectories(); // testing
List urls = new ArrayList();
try {
for (int i = 0; i < jars.size(); i++) {
urls.add(jars.get(i).toURI().toURL());
if (log.isLoggable(Level.CONFIG)) {
log.config("classpath entry from simulation: " + jars.get(i));
}
}
for (int i = 0; i < dirs.size(); i++) {
urls.add(dirs.get(i).toURI().toURL());
if (log.isLoggable(Level.CONFIG)) {
log.config("dir entry: " + dirs.get(i));
}
}
for (int i = 0; i < cli_jars.size(); i++) {
urls.add(cli_jars.get(i).toURI().toURL());
if (log.isLoggable(Level.CONFIG)) {
log.config("classpath entry from CLI: " + cli_jars.get(i));
}
}
urls.add(new URL("file:" + System.getProperty("oms.prj") + "/dist/"));
if (log.isLoggable(Level.CONFIG)) {
log.config("Sim loading classpath : " + "file:" + System.getProperty("oms.prj") + "/dist/");
}
} catch (MalformedURLException ex) {
throw new ComponentException("Illegal resource:" + ex.getMessage());
}
modelClassLoader = new URLClassLoader(urls.toArray(new URL[0]),
Thread.currentThread().getContextClassLoader());
}
return modelClassLoader;
}
public Object getComponent() throws Exception {
URLClassLoader loader = getClassLoader();
Class c = null;
if (classname == null) {
// return getGeneratedComponent(loader);
// classname = getGeneratedComponent(loader);
c = getGeneratedComponent(loader);
} else {
try {
c = loader.loadClass(getComponentClassName(classname));
} catch (ClassNotFoundException E) {
throw new IllegalArgumentException("Component/Model not found '" + classname + "'");
}
}
return c.newInstance();
}
public List getParam() {
List parameter = new ArrayList();
for (Params paras : getParams()) {
parameter.addAll(paras.getParam());
}
return parameter;
}
public CSProperties getParameter() throws IOException {
CSProperties p = DataIO.properties();
for (Params paras : getParams()) {
String f = paras.getFile();
if (f != null) {
// original properties.
p.putAll(DataIO.properties(new FileReader(new File(f)), "Parameter"));
// check for tables in the file.
List tables = DataIO.tables(new File(f));
if (!tables.isEmpty()) {
for (String name : tables) {
CSTable t = DataIO.table(new File(f), name);
// convert them to Properties.
CSProperties prop = DataIO.fromTable(t);
p.putAll(prop);
}
}
}
for (Param param : paras.getParam()) {
p.put(param.getName(), param.getValue());
}
}
return p;
}
static Object get(Map inst, String key) {
Object val = inst.get(key);
if (val == null) {
throw new IllegalArgumentException("No such component name '" + key + "'");
}
return val;
}
// @Name alias -> class name
Map nameClassMap;
private Map getName_ClassMap() {
if (nameClassMap == null) {
nameClassMap = new HashMap();
for (URL url : getClassLoader().getURLs()) {
try {
if(url.toString().startsWith("file:null"))
continue;
List> componentClasses = Components.getComponentClasses(url);
for (Class> class1 : componentClasses) {
Name name = class1.getAnnotation(Name.class);
if (name != null && !name.value().isEmpty()) {
if (name.value().indexOf(".") > -1) {
log.warning("@Name cannot contain '.' character : " + name.value() + " in " + class1.getName());
continue;
}
String prev = nameClassMap.put(name.value(), class1.getName());
if (prev != null) {
log.warning("duplicate @Name: " + name.value() + " for " + prev + " and " + class1.getName());
}
if (log.isLoggable(Level.CONFIG)) {
log.config("Added '@Name' alias '" + name.value() + "' for class: " + class1.getName());
}
}
}
} catch (IOException E) {
throw new ComponentException("Cannot access: " + url);
}
}
}
return nameClassMap;
}
private String getComponentClassName(String id) {
if (id.indexOf('.') == -1) {
String cn = getName_ClassMap().get(id);
if (cn == null) {
throw new ComponentException("Unknown component name: " + id);
}
return cn;
}
return id;
}
private Class> getGeneratedComponent(URLClassLoader loader) {
try {
// TODO Generate Digest instead of UUID.
String name = "Comp_" + UUID.randomUUID().toString().replace('-', '_');
String source = generateSource(name);
if (log.isLoggable(Level.FINE)) {
log.fine("Generated Class :" + name);
log.fine("Generated Source:\n" + source);
}
ModelCompiler mc = ModelCompiler.create(System.getProperty("oms.modelcompiler"));
Class jc = mc.compile(log, loader, name, source);
// TODO refactor for more generic use (internal, external compiler).
// oms3.compiler.Compiler.compile1(log, name, source); // This is external javac
// Class jc = loader.loadClass(name);
// oms3.compiler.Compiler tc = oms3.compiler.Compiler.singleton(loader);
// Class jc = tc.compileSource(name, source);
return jc;
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
private String generateSource(String cname) throws Exception {
if (control != null) {
if (control.indexOf('.') == -1) {
throw new IllegalArgumentException("Not a valid control reference (object.field): '" + control + "'");
}
}
StringBuilder b = new StringBuilder();
b.append("import java.util.*;\n");
b.append("import oms3.*;\n");
b.append("import oms3.annotations.*;\n");
b.append("public class " + cname + " extends " + controlClass + " {\n");
b.append("\n");
// Fields
for (Param param : getParam()) {
String p = param.getName();
if (p.indexOf('.') == -1) {
throw new IllegalArgumentException("Not a valid parameter reference (object.field): '" + p + "'");
}
String[] name = p.split("\\.");
String type = getClassForParameter(name[0], name[1], true);
String role = getClassForParameter(name[0], name[1], false);
b.append(" // " + p + "\n");
b.append(" @Role(\"" + role + "\")\n");
b.append(" @In public " + type + " " + name[0] + "_" + name[1] + ";\n");
b.append("\n");
}
// Components
for (KVP def : comps.entries) {
String compClass = def.getValue().toString();
compClass = getComponentClassName(compClass); // name -> class
b.append(" public " + compClass + " " + def.getKey() + " = new " + compClass + "();\n");
}
b.append("\n\n");
// init version.
b.append(" @Initialize\n");
b.append(" public void init() {\n");
if (control != null) {
String[] it = control.split("\\.");
b.append(" conditional(" + it[0] + ", \"" + it[1] + "\");\n");
}
// in2in
for (Param param : getParam()) {
String[] name = param.getName().split("\\.");
b.append(" in2in(\"" + name[0] + '_' + name[1] + "\", " + name[0] + ", \"" + name[1] + "\");\n");
}
// out2in
kvpExpand(b, out2in.entries, "out2in");
// feedback
kvpExpand(b, feedback.entries, "feedback");
b.append(" initializeComponents();\n");
b.append(" }\n");
b.append("}\n");
return b.toString();
}
void kvpExpand(StringBuilder b, List l, String method) {
for (KVP c : l) {
String[] from = c.getKey().split("\\.");
String tos = c.getValue().toString().trim();
String[] t = tos.split("\\s+"); // multiple @In
for (String kvp : t) {
String to_obj = kvp; // default target is just object name
String to_field = from[1]; // same as @Out
if (kvp.indexOf('.') > 0) {
String[] to = kvp.split("\\.");
to_obj = to[0];
to_field = to[1];
}
b.append(" " + method + "(" + from[0] + ", \"" + from[1] + "\", " + to_obj + ", \"" + to_field + "\");\n");
}
}
}
String getClassForParameter(String object, String field, boolean type) {
for (KVP def : comps.entries) {
if (object.equals(def.getKey())) {
String clname = def.getValue().toString();
clname = getComponentClassName(clname);
Class c;
try {
c = getClassLoader().loadClass(clname);
} catch (ClassNotFoundException ex) {
throw new ComponentException("Class not found: '" + clname + "'");
}
try {
if (type) {
String canName = c.getField(field).getType().getCanonicalName();
if (canName == null) {
throw new ComponentException("No canonical type name for : " + field);
}
return canName;
} else {
Role r = c.getField(field).getAnnotation(Role.class);
if (r != null) {
return r.value();
}
return Role.VARIABLE;
}
} catch (NoSuchFieldException ex) {
throw new ComponentException("No such field: " + field);
} catch (SecurityException ex) {
throw new ComponentException("Cannot access : " + field);
}
}
}
throw new ComponentException("Cannot find component '" + object + "'. in '" + object + "." + field + "'");
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy