package org.yamcs.api;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.net.URISyntaxException;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yamcs.ConfigurationException;
import org.yamcs.api.YamcsConnectionProperties.Protocol;
import org.yamcs.api.artemis.ArtemisEventProducer;
import org.yamcs.protobuf.Yamcs.Event;
import org.yaml.snakeyaml.Yaml;
public class EventProducerFactory {
/**
* set to true from the unit tests
*/
private static boolean mockup=false;
private static Queue<Event>mockupQueue;
static Logger log = LoggerFactory.getLogger(EventProducerFactory.class);
/**
* Configure the factory to produce mockup objects, optionally queuing the events in a queue
* @param queue - if true then queue all messages in the mockupQueue queue.
*/
public static void setMockup(boolean queue) {
mockup=true;
if(queue) {
mockupQueue=new LinkedList<Event>();
}
}
public static Queue<Event> getMockupQueue() {
return mockupQueue;
}
/**
* Creates an event producer based on the event-producer.yaml properties loaded from the classpath.
* The yamcsURL in the file has to contain the yamcs instance.
* If the event-producer.yaml is not found, then a console event producer is created that just
* prints the messages on console.
* @return the created event producer
* @throws RuntimeException in case the config files is found but contains errors
*/
static public EventProducer getEventProducer() throws RuntimeException {
return getEventProducer(null);
}
/**
*
* The instance passed as parameter will overwrite the instance in the config file if any.
*
* If the event-producer.yml config file is not found on the classpath, returns a ConsoleEventProducer when called outside yamcs or an StreamEventProducer when called inside.
* @param instance - instance for which the producer is to be returned
*
* @return an EventProducer
* @throws RuntimeException
*/
public static EventProducer getEventProducer(String instance) throws RuntimeException {
if(mockup) {
log.debug("Creating a ConsoleEventProducer with mockupQueue: "+mockupQueue);
return new MockupEventProducer(mockupQueue);
}
String configFile = "/event-producer.yaml";
InputStream is = EventProducerFactory.class.getResourceAsStream(configFile);
if(is==null) {
EventProducer producer = getStreamEventProducer(instance);
if(producer!=null) {
return producer;
}
log.debug("Could not find {} in the classpath, and not running inside Yamcs, returning a ConsoleEventProducer", configFile);
return new ConsoleEventProducer();
}
Yaml yaml = new Yaml();
Object o = yaml.load(is);
if(!(o instanceof Map<?,?>)) {
throw new ConfigurationException("event-producer.yaml does not contain a map but a "+o.getClass());
}
@SuppressWarnings("unchecked")
Map<String,String> m=(Map<String, String>)o;
if(!m.containsKey("yamcsURL")) {
throw new ConfigurationException("event-producer.yaml does not contain a property yamcsURL");
}
String url=m.get("yamcsURL");
YamcsConnectionProperties ycd;
try {
log.debug("Parsing a URL for an YamcsEventProducer: '{}'", url);
ycd = YamcsConnectionProperties.parse(url);
} catch (URISyntaxException e) {
throw new IllegalArgumentException("cannot parse yamcsURL", e);
}
if(instance==null) {
if (ycd.getInstance()==null) {
throw new IllegalArgumentException("yamcs instance has to be part of the URL");
}
} else {
ycd.setInstance(instance);
}
EventProducer producer;
if(ycd.getProtocol()==Protocol.artemis) {
log.debug("Creating an Artemis Yamcs event producer connected to {}", ycd.getUrl());
producer = new ArtemisEventProducer(ycd);
} else {
log.debug("Creating a REST Yamcs event producer connected to {}", ycd.getUrl());
producer = new RestEventProducer(ycd);
}
return producer;
}
private static EventProducer getStreamEventProducer(String instance) {
try {
//try to load the stream event producer from yamcs core because probably we are running inside the yamcs server
@SuppressWarnings("unchecked")
Class<EventProducer> ic=(Class<EventProducer>) Class.forName("org.yamcs.StreamEventProducer");
Constructor<EventProducer> constructor = ic.getConstructor(String.class);
return constructor.newInstance(instance);
} catch (Exception e) {
return null;
}
}
}