/*
* Copyright 2013, 2014 Deutsche Nationalbibliothek
*
* Licensed under the Apache License, Version 2.0 the "License";
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.culturegraph.mf.flux.parser;
import java.io.IOException;
import java.io.PrintStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.culturegraph.mf.commons.ResourceUtil;
import org.culturegraph.mf.commons.reflection.ConfigurableClass;
import org.culturegraph.mf.commons.reflection.ObjectFactory;
import org.culturegraph.mf.commons.reflection.ReflectionUtil;
import org.culturegraph.mf.flux.FluxParseException;
import org.culturegraph.mf.flux.HelpPrinter;
import org.culturegraph.mf.framework.Receiver;
/**
* @author Markus Michael Geipel
*
*/
public final class FluxProgramm {
private static final ObjectFactory<Receiver> COMMAND_FACTORY = new ObjectFactory<Receiver>();
private static final String PROPERTIES_LOCATION = "flux-commands.properties";
static {
try {
final Enumeration<URL> enumeration = Thread.currentThread().getContextClassLoader()
.getResources(PROPERTIES_LOCATION);
while (enumeration.hasMoreElements()) {
final URL url = enumeration.nextElement();
COMMAND_FACTORY.loadClassesFromMap(ResourceUtil.loadProperties(url), Receiver.class);
}
} catch (final IOException e) {
throw new FluxParseException("unable to load properties.", e);
}
}
private Flow currentFlow = new Flow();
private final List<Flow> initialFlows = new ArrayList<Flow>();
private final Map<String, Wormhole> wormholeNameMapping = new HashMap<String, Wormhole>();
private final Map<Flow, Wormhole> wormholeInFlowMapping = new Hashtable<Flow, Wormhole>();
private static Receiver createElement(final String name, final Map<String, String> namedArgs,
final List<Object> cArgs) {
final Receiver newElement;
if (COMMAND_FACTORY.containsKey(name)) {
newElement = COMMAND_FACTORY.newInstance(name, namedArgs, cArgs.toArray());
} else {
final ConfigurableClass<? extends Receiver> elementClass =
ReflectionUtil.loadClass(name, Receiver.class);
newElement = elementClass.newInstance(namedArgs, cArgs.toArray());
}
return newElement;
}
protected void addElement(final String name, final Map<String, String> namedArgs, final List<Object> cArgs) {
currentFlow.addElement(createElement(name, namedArgs, cArgs));
}
protected void startTee() {
currentFlow.startTee();
}
protected void endTee() {
currentFlow.endTee();
}
protected void endSubFlow() {
currentFlow.endSubFlow();
}
protected void setStringStart(final String string) {
currentFlow.setStringStart(string);
if (!initialFlows.contains(currentFlow)) {
initialFlows.add(currentFlow);
}
}
protected void setStdInStart() {
currentFlow.setStdInStart();
if (!initialFlows.contains(currentFlow)) {
initialFlows.add(currentFlow);
}
}
protected void setWormholeEnd(final String name) {
Wormhole wormhole = wormholeNameMapping.get(name);
if (wormhole == null) {
wormhole = new Wormhole(name);
wormholeNameMapping.put(name, wormhole);
}
wormhole.addIn(currentFlow);
wormholeInFlowMapping.put(currentFlow, wormhole);
}
protected void setWormholeStart(final String name) {
if (initialFlows.contains(currentFlow)) {
initialFlows.remove(currentFlow);
}
Wormhole wormhole = wormholeNameMapping.get(name);
if (wormhole == null) {
wormhole = new Wormhole(name);
wormholeNameMapping.put(name, wormhole);
}
wormhole.setOut(currentFlow);
}
protected void nextFlow() {
currentFlow = new Flow();
}
protected void compile() {
for (final Wormhole wormhole : wormholeNameMapping.values()) {
if (wormhole.getOut() == null) {
throw new FluxParseException("Wormhole " + wormhole.getName() + " is going nowhere");
}
for (final Flow flow : wormhole.getIns()) {
flow.addElement(wormhole.getOut().getFirst());
}
}
}
public void start() {
for (final Flow flow : initialFlows) {
flow.start();
if (!wormholeInFlowMapping.containsKey(flow)) {
flow.close();
} else {
wormholeInFlowMapping.get(flow).finished(flow);
}
}
}
public static void printHelp(final PrintStream out) {
HelpPrinter.print(COMMAND_FACTORY, out);
}
private static final class Wormhole {
private final Set<Flow> insReady = new HashSet<Flow>();
private final Set<Flow> insFinished = new HashSet<Flow>();
private Flow out;
private final String name;
public Wormhole(final String name) {
this.name = name;
}
public String getName() {
return name;
}
public Flow getOut() {
return out;
}
public Set<Flow> getIns() {
return insReady;
}
public void setOut(final Flow out) {
this.out = out;
}
public void addIn(final Flow flow) {
insReady.add(flow);
}
public void finished(final Flow flow) {
insReady.remove(flow);
insFinished.add(flow);
if (insReady.isEmpty()) {
for (final Flow finished : insFinished) {
finished.close();
}
}
}
}
}