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

net.ericaro.diezel.core.builder.DiezelLanguageBuilder Maven / Gradle / Ivy

The newest version!
package net.ericaro.diezel.core.builder;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import net.ericaro.diezel.core.DiezelException;
import net.ericaro.diezel.core.InconsistentTypePathException;
import net.ericaro.diezel.core.exceptions.UndefinedTransitionException;
import net.ericaro.diezel.core.parser.Graph;
import net.ericaro.diezel.core.parser.Graph.S;
import net.ericaro.diezel.core.parser.Graph.T;
import net.ericaro.diezel.core.parser.GraphBuilder;
import net.ericaro.diezel.core.parser.ParseException;
import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
import edu.uci.ics.jung.graph.util.Graphs;

/**
 * built by a parser, and compiled, ready to be a DiezelLanguage instance
 * 
 * @author eric
 * 
 */
public class DiezelLanguageBuilder implements DiezelBuilder {

	private String header = "*   _________________________________\n"
			+ "*   ))                              (( \n"
			+ "*  ((   __    o     ___        _     ))\n"
			+ "*   ))  ))\\   _   __  ))   __  ))   (( \n"
			+ "*  ((  ((_/  ((  ((- ((__ ((- ((     ))\n"
			+ "*   ))        )) ((__     ((__ ))__  (( \n"
			+ "*  ((                                ))\n"
			+ "*   ))______________________________(( \n"
			+ "*        Diezel 2.0.0 Generated.\n*";
	private String expression; // the regexp defining the workfow
	private String packageName; // global conf: the target package name
	private String guideBaseName = "Guide";
	private List rootTypes = new ArrayList(); // the root
																// state
																// generics,
																// always
																// usefull to
																// start with
	private List transitions = new ArrayList();
	private Map states = new HashMap();

	// result of compilation
	transient DirectedGraph graph; // graph computed
																// from the
																// expression
																// expression
	transient State start, end;

	public DiezelLanguage build() throws ParseException, DiezelException {
		buildGraph(); // parses the expression, build a graph from it,
						// associated the State and Transition objects
		nameStates();
		solveStates();

		// and copy
		DiezelLanguage that = new DiezelLanguage();
		that.header = this.header;
		that.expression = this.expression;
		that.packageName = this.packageName;
		that.guideBaseName = this.guideBaseName;
		that.rootTypes = Collections.unmodifiableList(this.rootTypes);
		that.transitions = Collections.unmodifiableList(this.transitions);
		// that.states = Collections.unmodifiableList(this.states );
		that.graph = Graphs.unmodifiableDirectedGraph(this.graph);
		that.start = this.start;
		that.end = this.end;

		return that;

	}

	/**
	 * build a jung graph based on the expression
	 * 
	 * @param expression
	 * @return
	 * @throws ParseException
	 * @throws UndefinedTransitionException
	 */
	public void buildGraph() throws ParseException,
			UndefinedTransitionException {

		Graph g = GraphBuilder.build(expression);
		graph = new DirectedSparseMultigraph();
		// build a faster index for transition by name
		HashMap index = new HashMap();
		for (Transition t : transitions)
			index.put(t.getAlias(), t);

		{
			// check if transitions are the sames
			Set gTransitions = new HashSet(); // transitions
																// from the
																// graph
			for (T t : g.transitions)
				gTransitions.add(t.name);

			// transitions from the XML definition
			Set xTransitions = new HashSet(index.keySet()); 
			if (!xTransitions.containsAll(gTransitions)) {
				// removed known transition, leaving only the undefined ones
				gTransitions.removeAll(xTransitions); 
				throw new UndefinedTransitionException(gTransitions);
			}
			
			if (!gTransitions.containsAll(xTransitions)) {
				xTransitions.removeAll(gTransitions);  // xtransition contains "extra transitions
				System.out.println(StringUtils.toString(xTransitions , ", ","Warning: the following transition(s) defined in the Transitions element are not used in the expression: ", ""  ) );
			}

		}

		// build a map for states, and append vertices
		Map stateTypes = new HashMap();
		int i = 0;
		for (S s : g.states) {
			State state = new State(graph, guideBaseName + (++i),
					s.equals(g.in), s.equals(g.out));
			if (s.equals(g.out))
				end = state;
			if (s.equals(g.in))
				start = state;

			stateTypes.put(s.id, state);
			graph.addVertex(state);
		}
		// now append transitions
		for (S s : g.states)
			for (T t : s.outs)
				graph.addEdge(index.get(t.name).newInstance(graph),
						stateTypes.get(t.in.id), stateTypes.get(t.out.id));

	}

	/**
	 * parse the graph, and set a unique name for each state.
	 * 
	 */
	private void nameStates() {

		start.name = guideBaseName;

		for (Entry e : states.entrySet()) {
			State state = getStateByPath(e.getKey());
			state.name = e.getValue();
		}

		end.name = "Out";
	}

	private State getStateByPath(String key) {
		String[] elements = key.split("\\.");
		State current = start;
		for (String next : elements) {
			for (TransitionInstance t : graph.getOutEdges(current)) {
				if (next.equals(t.getAlias())) {
					current = graph.getDest(t);
					break; // get out of the transition loop
				}
			}
		}
		// now the whole path has been parsed, and current is our goal
		return current;
	}

	private String generateName(int i) {
		if (i >= 0 && i < states.size())
			return states.get(i);
		return guideBaseName + i;
	}

	private void solveStates() throws InconsistentTypePathException {
		// fill the root state with the default states
		start.generics.addAll(rootTypes);
		// compute every state generics
		Set knownStates = new HashSet();
		knownStates.add(start);

		int stateNumber = graph.getVertexCount();
		while (knownStates.size() != stateNumber)
			for (State source : new ArrayList(knownStates))
				for (TransitionInstance trans : graph.getOutEdges(source)) {
					State target = graph.getOpposite(source, trans);
					List types = new ArrayList(
							source.generics);// clone the source
					types.addAll(trans.getPush());
					types.removeAll(trans.getPull());
					// types contains the generics target should have
					if (!knownStates.contains(target)) {
						// it's a new, unknown state from a known one.
						target.generics = types;
						knownStates.add(target);
					} else if (!target.generics.equals(types)) // check for
																// states
						throw new InconsistentTypePathException("State "
								+ target.getName() + " has generic types "
								+ target.generics + " but from the transition "
								+ trans.getAlias()
								+ " it should have generic types " + types);
				}
	}

	public String getExpression() {
		return expression;
	}

	public void setExpression(String expression) {
		this.expression = expression;
	}

	public void setPackageName(String packageName) {
		this.packageName = packageName;
	}

	public String getPackageName() {
		return packageName;
	}

	public String getGuideName() {
		return guideBaseName;
	}

	public String getQualifiedName() {
		return getPackageName() + "." + getGuideName();
	}

	public void setGuideName(String guideBaseName) {
		this.guideBaseName = guideBaseName;
	}

	public String getHeader() {
		return header;
	}

	public void setHeader(String header) {
		this.header = header;
	}

	public boolean addRootType(Generic e) {
		return rootTypes.add(e);
	}

	public boolean addTransition(Transition e) {
		return transitions.add(e);
	}

	public void addStatePath(String path, String name) {
		this.states.put(path, name);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy