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

org.coos.actorframe.ActorSpecParser Maven / Gradle / Ivy

/**
 * COOS - Connected Objects Operating System (www.connectedobjects.org).
 *
 * Copyright (C) 2009 Telenor ASA and Tellu AS. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * 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 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 program.  If not, see .
 *
 * You may also contact one of the following for additional information:
 * Telenor ASA, Snaroyveien 30, N-1331 Fornebu, Norway (www.telenor.no)
 * Tellu AS, Hagalokkveien 13, N-1383 Asker, Norway (www.tellu.no)
 */
package org.coos.actorframe;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.Vector;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.coos.actorframe.ActorPartSpec;
import org.coos.actorframe.ActorPortSpec;
import org.coos.actorframe.RoleSpec;
import org.coos.actorframe.application.Container;
import org.coos.actorframe.application.DomainSpec;
import org.coos.javaframe.ActorAddress;
import org.coos.javaframe.ActorSpec;
import org.coos.javaframe.ApplicationSpec;
import org.coos.javaframe.ConnectorSpec;
import org.coos.javaframe.PartSpec;
import org.coos.javaframe.SchedulerSpec;
import org.coos.javaframe.TraceConstants;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * @author Knut Eilif Husa, Tellu AS
 * @author Robert Bjarum, Tellu AS
 */
public class ActorSpecParser {
	/**
	 * Parse ApplicationSpec xml-file representation.
	 * 
	 * @param fileName
	 *            name of file
	 * @param container
	 *            that runs the application
	 * @return application specification
	 * @throws FileNotFoundException
	 *             when file not found
	 */
	public static ApplicationSpec parseXml(String fileName, Container container) throws ActorSpecException {
		ApplicationSpec spec = new ApplicationSpec();
		parseXml(fileName, spec, container);

		return spec;
	}

	/**
	 * Parse ApplicationSpec xml-file representation.
	 * 
	 * @param fileName
	 *            name of file
	 * @return application specification
	 * @throws FileNotFoundException
	 *             when file not found
	 */
	public static ApplicationSpec parseXml(String fileName) throws ActorSpecException {
		return parseXml(fileName, (Container) null);
	}

	public static ApplicationSpec parseXml(String fileName, ApplicationSpec spec) throws ActorSpecException {
		return parseXml(fileName, spec, null);
	}

	public static ApplicationSpec parseXml(String fileName, ApplicationSpec spec, Container container)
			throws ActorSpecException {
		InputStream is = null;

		/* First try file on disk */
		try {
			is = new FileInputStream(fileName);
		} catch (FileNotFoundException e) {
			is = null;
		}

		/* File not found. Try resource instead. */
		if (is == null) {
			is = ActorSpecParser.class.getResourceAsStream(fileName);
		}

		parseXml(is, spec, container);

		return spec;
	}

	/**
	 * This method create ApplicationSpec from XML resource file.
	 * 
	 * @param name name of application specification resource (XML)
	 * @param appName name of application
	 * @return instance of ApplicationSpec formed by reading resource file
	 */
	public static ApplicationSpec createApplicationSpec(String name, String appName) {
		return createApplicationSpec(name, appName, null);
	}

    /**
     * This method create ApplicationSpec from XML resource file.
     * A new instance of ApplicationSpec is created before createApplicationSpec(name, appSpec, container) is called.
     * 
     * @param name name of application specification resource (XML)
     * @param appName name of application
     * @param container instance of application container. If null, Java default Classloader if required.
     * @return instance of ApplicationSpec formed by reading resource file
     */
	public static ApplicationSpec createApplicationSpec(String name, String appName, Container container) {
		ApplicationSpec appSpec = new ApplicationSpec(appName);
		appSpec = createApplicationSpec(name, appSpec, container);

		return appSpec;
	}

	public static ApplicationSpec createApplicationSpec(String name, ApplicationSpec appSpec) {
		return createApplicationSpec(name, appSpec, null);
	}

	public static ApplicationSpec createApplicationSpec(String name, ApplicationSpec appSpec, Container container) {
		InputStream fi = ActorSpecParser.class.getResourceAsStream(name);
		parseXml(fi, appSpec, container);

		return appSpec;
	}

	public static void parseXml(InputStream is, ApplicationSpec spec) throws ActorSpecException {
		parseXml(is, spec, null);
	}

	public static void parseXml(InputStream is, ApplicationSpec spec, Container container) throws ActorSpecException {
		if (is == null) {
			throw new ActorSpecException("Inputstream cannot be null. Check name of application spec. (xml) resource.");
		}

		Document doc = null;

		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			dbf.setIgnoringElementContentWhitespace(true);

			DocumentBuilder builder = dbf.newDocumentBuilder();

			doc = builder.parse(is);
		} catch (Exception e) {
			throw new ActorSpecException("Failed to parse application spec. (xml). Check content.", e);
		}

		Element appElement = doc.getDocumentElement();

		/*
		 * Trace Tag, example: 
		 */
		Vector traces = getChildren(appElement, "trace");
		if (traces.size() > 0) {
			Element traceElement = (Element) traces.get(0);
			spec.setTraceEnabled(getAttrBoolean(traceElement, "trace", spec.isTraceEnabled()));
			String format = getAttrString(traceElement, "format", "text");
			if (format.equalsIgnoreCase("xml")) {
			    spec.setTraceFormat(ApplicationSpec.TRACE_FORMAT_XML);
			} else if (format.equalsIgnoreCase("text")) {
			    spec.setTraceFormat(ApplicationSpec.TRACE_FORMAT_TEXT);
			}
		}

        // read meta data about the application

		String name = getAttrString(appElement, "name", spec.getAppName());
		spec.setAppName(name);

		Vector descriptions = getChildren(appElement, "description");
		String description = null;

		if (descriptions.size() > 0) {
			description = ((Element) descriptions.get(0)).getFirstChild().getNodeValue();
		}

		// String description = getAttrString(appElement, "description", null);
		spec.setDescription(description);

		// parse the creation of the actor schedulerData
		Vector domains = getChildren(appElement, "domain");
		for (int x = 0; x < domains.size(); x++) {
			DomainSpec aps = parseDomainSpec((Element) domains.get(x), spec.getDomainSpec());
			spec.setDomainSpec(aps);
		}

		String extend = null;

		// parse the actors
		Vector actors = getChildren(appElement, "actor");

		for (int x = 0; x < actors.size(); x++) {
			Element e = (Element) actors.get(x);
			extend = getAttrString(e, "extends", null);

			String type = getAttrString(e, "name", null);

			if (type == null) {
				throw new ActorSpecException("Actor spec: No name defined in element " + e.getNodeName());
			}

			ActorSpec as = spec.getActorSpec(type);

			if (as == null) {
				as = new ActorSpec();
				as.setActorType(type);
			} else {
				if (extend == null) {
					throw new ActorSpecException("Actor spec: actor type <" + type
							+ "> already exist, illegal extension");
				}
			}

			// Get the class name
			as.setActorClassName(parseClassName(e, as, container));

			// Parse role spec
			Vector roleSpecs = as.getRoleDesc();
			Vector roleSpec = getChildren(e, "role");

			for (int i = 0; i < roleSpec.size(); i++) {
				RoleSpec aps = parseRoleSpec((Element) roleSpec.get(i), as);
				as.addRoleSpec(aps);
			}

			// Reads the Port spec for the actor
			Vector actorPortSpecs = as.getPortDesc();
			Vector actorPorts = getChildren(e, "port");

			for (int i = 0; i < actorPorts.size(); i++) {
				ActorPortSpec aps = parseActorPortSpec((Element) actorPorts.get(i), as);
				as.addPortSpec(aps);
			}

			// as.setPortDesc(actorPortSpecs);

			// reads the connector specs
			Vector connectors = as.getConnectorDesc();
			connectors = parseConnectors(e, connectors, as);
			as.setConnectorDesc(connectors);

			Vector actorPartSpecs = as.getPartDesc();
			Vector actorParts = getChildren(e, "part");

			for (int i = 0; i < actorParts.size(); i++) {
				ActorPartSpec aps = parseActorPartSpec((Element) actorParts.get(i), as);

				if (as.getPartSpec(aps.getRoleType()) != null) {
					as.deletePartSpec(aps.getRoleType());
				}

				actorPartSpecs.addElement(aps);
			}

			as.setPartDesc(actorPartSpecs);

			spec.addActorSpec(as);
		}
	}

	private static String parseClassName(Element e, ActorSpec as, Container container) {
		String className = getAttrString(e, "class", as.getActorClassName());

		try {
			if (container != null) {
				container.loadClass(className);
			} else {
				Class.forName(className);
			}

			return className;
		} catch (NullPointerException e1) {
		    throw new ActorSpecException("The attribute 'class' is mandatory and cannot be null. Actor type " + as.getActorType() + ".");
		} catch (ClassNotFoundException e1) {
			throw new ActorSpecException("Class <" + className + "> not found");
		}
	}

	/**
	 * Parse trace info
	 * 
	 * @param e
	 *            JDOM element for  tags.
	 * @param ps
	 *            Specification of the actor
	 */
	private static void parseTraceSpec(Element e, PartSpec ps) {
		ps.setTraceLev(TraceConstants.getTraceLevel(getAttrString(e, "trace", TraceConstants.getTraceLevel(ps
				.getTraceLev()))));
	}

	private static Vector parseConnectors(Element e, Vector connectors, ActorSpec as) {
		// add ports
		NodeList ic = e.getChildNodes(); // e.getElementsByTagName("connector");

		for (int x = 0; x < ic.getLength(); x++) {
			// 
			if (!ic.item(x).getNodeName().equals("connector"))
				continue;

			Element connector = (Element) ic.item(x);
			String name = getAttrString(connector, "name", null);

			if (name == null) {
				throw new ActorSpecException("Connector spec: no connector name");
			}

			ConnectorSpec cs = as.getConnectorDesc(name);

			if (cs == null) {
				cs = new ConnectorSpec();
				cs.setName(name);
			}

			cs.setIsBidirectional(getAttrBoolean(connector, "bidirectional", cs.isBidirectional()));

			// parse from port spec
			String fromString = getAttrString(connector, "from", null);

			if ((fromString == null) || fromString.equals("")) {
				throw new ActorSpecException("Connector spec: from address");
			}

			cs.setFrom(new ActorAddress(fromString)); // default port

			// parse to spec
			String toString = getAttrString(connector, "to", null);

			if ((toString == null) || fromString.equals("")) {
				throw new ActorSpecException("Connector spec: to address");
			}

			cs.setTo(new ActorAddress(toString)); // default port

			connectors.addElement(cs);
		}

		return connectors;
	}

	private static int getAttrInt(Element e, String name, int defaultValue) {
		String res = e.getAttribute(name);

		if ((res == null) || res.equals("")) {
			return defaultValue;
		}

		return Integer.parseInt(res.trim());
	}

	private static String getAttrString(Element e, String name, String defaultValue) {
		String res = e.getAttribute(name);

		if ((res == null) || res.equals("")) {
			return defaultValue;
		}

		return res.trim();
	}

	private static boolean getAttrBoolean(Element e, String name, boolean defaultValue) {
		String attr = e.getAttribute(name);
		boolean res;

		if (attr == null) {
			res = defaultValue;
		} else {
			res = Boolean.parseBoolean(attr);
		}

		return res;
	}

	private static Vector getChildren(Element e, String type) {
		Vector v = new Vector();

		NodeList nl = e.getChildNodes();
		for (int x = 0; x < nl.getLength(); x++) {
			if (nl.item(x).getNodeName().equals(type))
				v.add(nl.item(x));
		}

		return v;
	}

	private static RoleSpec parseRoleSpec(Element e, ActorSpec actorSpec) {
		String type;

		type = getAttrString(e, "type", null);

		if (type == null) {
			throw new ActorSpecException("Actor spec: illegal role type definition");
		}

		RoleSpec aps = actorSpec.getRoleSpec(type);

		if (aps == null) {
			aps = new RoleSpec();
			aps.setType(type);
		}

		aps.setRoleClass(getAttrString(e, "class", aps.getRoleClass()));
		aps.setInstance(getAttrString(e, "instance", aps.getInstance()));

		aps.setPersistent(getAttrBoolean(e, "persistent", aps.isPersistent()));

		return aps;
	}

	private static ActorPortSpec parseActorPortSpec(Element e, ActorSpec actorSpec) {
		String portName = getAttrString(e, "name", null);

		if (portName == null) {
			throw new ActorSpecException("Port name < " + portName + "> cannot be null");
		}

		ActorPortSpec portSpec = (ActorPortSpec) actorSpec.getPortSpec(portName);

		if (portSpec == null) {
			portSpec = new ActorPortSpec(portName);
		}

		portSpec.setPortType(getAttrString(e, "class", portSpec.getPortType()));
		portSpec.setBehavior(getAttrBoolean(e, "isbehavior", portSpec.isBehavior()));

		// boolean hideInner = getAttrBoolean(e, "hideinner", );
		// boolean sessionEnabled = getAttrBoolean(e, "sessionenabled", false);
		// ActorPortSpec aps = new ActorPortSpec(portName, className,
		// isBehavior);
		// aps.setSessionEnabled(sessionEnabled);
		// aps.setHideInner(hideInner);
		return portSpec;
	}

	/**
	 * Creates a PartSpec based on a JDOM element.
	 */
	private static ActorPartSpec parseActorPartSpec(Element e, ActorSpec spec) {
		// 
		String roleType = getAttrString(e, "actor", null);

		if (roleType == null) {
			throw new ActorSpecException("Part spec: illegal actor type definition");
		}

		ActorPartSpec apc = (ActorPartSpec) spec.getPartSpec(roleType);

		if (apc == null) {
			apc = new ActorPartSpec();
			apc.setRoleType(roleType);
		}

		apc.setVisible(getAttrBoolean(e, "visible", apc.isVisible()));

		apc.setLevel(getAttrInt(e, "level", apc.getLevel()));

		apc.setCredentialsRequired(getAttrBoolean(e, "credentialsrequired", apc.isCredentialsRequired()));

		String ad = getAttrString(e, "actordomain", null);

		if (ad != null) {
			// actordomain is by default set to null
			apc.setActorDomain(new ActorAddress(ad));
		}

		apc.setBind(getAttrString(e, "bind", apc.getBind()));

		// parse the set name , used to identyfy uniq sets
		apc.setSetId(getAttrString(e, "set", apc.getSetId()));

		apc.setLow(getAttrInt(e, "min", apc.getLow()));
		apc.setHigh(getAttrInt(e, "max", apc.getHigh()));

		// First check if one instance is defined as a property
		Vector rn = toVector(apc.getRoleNames());

		String instanceName = getAttrString(e, "instance", null);

		if (instanceName != null) {
			rn.add(instanceName);
		}

		// check properties for all instances
		Hashtable instanceProperties = null;

		Hashtable properties = readProperties(e);

		if (properties != null) {
			instanceProperties = new Hashtable();
			instanceProperties.put("default", properties);
		}

		Vector inst = getChildren(e, "instance");
		if (inst.size() > 0) {
			if (instanceProperties == null) {
				instanceProperties = new Hashtable();
			}

			for (int i = 0; i < inst.size(); i++) {
				Element ie = (Element) inst.get(i);
				String s = getAttrString(ie, "name", null);

				if (s != null) {
					rn.add(s);
					properties = readProperties(ie);

					if (properties != null) {
						instanceProperties.put(s, properties);
					}
				}
			}
		}

		// merge instance names
		apc.setActorProperties(instanceProperties);

		apc.setRoleNames(toStringArray(rn));

		// parse trace specification
		parseTraceSpec(e, apc);

		return apc;
	}

	private static String[] toStringArray(Vector v) {
		if (v == null) {
			return new String[0];
		}

		String[] sa = new String[v.size()];

		for (int i = 0; i < v.size(); i++) {
			sa[i] = (String) v.elementAt(i);
		}

		return sa;
	}

	private static Vector toVector(String[] sa) {
		Vector v = new Vector();

		if (sa == null) {
			return v;
		}

		for (int i = 0; i < sa.length; i++) {
			v.add(sa[i]);
		}

		return v;
	}

	/**
	 * Reads the properties for an instance
	 * 
	 * @param ie
	 *            the dom element that contains the property
	 * @return a hashtable of properties
	 */
	private static Hashtable readProperties(Element ie) {
		Vector itProps = getChildren(ie, "property");

		if (itProps.size() > 0) {
			Hashtable properties = new Hashtable();

			for (int x = 0; x < itProps.size(); x++) {
				Element ieProp = (Element) itProps.get(x);
				properties.put(getAttrString(ieProp, "name", null), getAttrString(ieProp, "value", null));
			}

			return properties;
		}

		return null;
	}

	/**
	 * Creates a DomainSpec based on a JDOM element.
	 */
	private static DomainSpec parseDomainSpec(Element e, DomainSpec domainSpec) {
		String actor = getAttrString(e, "actor", "ActorDomain");
		String name = getAttrString(e, "name", actor);

		boolean validated = getAttrBoolean(e, "validated", false);
		String extend = getAttrString(e, "extends", null);

		if (domainSpec == null) {
			domainSpec = new org.coos.actorframe.application.DomainSpec(name, actor);
		} else {
			if (extend == null) {
				// Domain spec already exists, no extentions is defined
				throw new ActorSpecException("Domain <" + domainSpec.getName()
						+ "> already exists, no extension is defined");
			}
		}

		domainSpec.setValidated(validated);

		// parse the scheduler of the actor schedulerData
		Vector scheduler = getChildren(e, "scheduler");

		if (scheduler.size() > 0) {
			for (int i = 0; i < scheduler.size(); i++) {
				// iterate over scheduler
				Element et = (Element) scheduler.get(i);
				String id = getAttrString(et, "name", "sched" + String.valueOf(i));

				if (id == null) {
					throw new ActorSpecException("Scheduler name not defined");
				}

				SchedulerSpec ss = domainSpec.getSchedulerSpec(id);

				if (ss == null) {
					ss = new SchedulerSpec();
					ss.setId(id);
				}

				String threads = getAttrString(et, "threads", String.valueOf(ss.getThreads()));
				ss.setThreads(Integer.parseInt(threads));

                String className = getAttrString(et, "class", null);
                ss.setClassName(className);

				Vector r = getChildren(et, "actor");

				for (int x = 0; x < r.size(); x++) {
					String actorType = getAttrString((Element) r.get(x), "type", null);
					SchedulerSpec spec = domainSpec.containsActorType(actorType);

					// if (ss.getActorType(actorType) == null) {
					if (spec == null) {
						ss.addActorType(actorType);
					} else {
						throw new ActorSpecException("Scheduler: actor: " + actorType + " is already defined in <"
								+ spec.getId() + ">");
					}
				}

				domainSpec.addSchedulerSpec(ss);
			}
		} else {
			SchedulerSpec ss = new SchedulerSpec();
			ss.setId("default");
			domainSpec.addSchedulerSpec(ss);
		}

		return domainSpec;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy