All Downloads are FREE. Search and download functionalities are using the official Maven repository.

oms3.dsl.Model Maven / Gradle / Ivy

There is a newer version: 0.8.1
Show newest version
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