package i5.las2peer.services.ocd.utils;
import i5.las2peer.services.ocd.adapters.AdapterException;
import i5.las2peer.services.ocd.adapters.coverInput.CoverInputAdapter;
import i5.las2peer.services.ocd.adapters.coverInput.CoverInputAdapterFactory;
import i5.las2peer.services.ocd.adapters.coverInput.CoverInputFormat;
import i5.las2peer.services.ocd.adapters.coverOutput.CoverOutputAdapter;
import i5.las2peer.services.ocd.adapters.coverOutput.CoverOutputAdapterFactory;
import i5.las2peer.services.ocd.adapters.coverOutput.CoverOutputFormat;
import i5.las2peer.services.ocd.adapters.graphInput.GraphInputAdapter;
import i5.las2peer.services.ocd.adapters.graphInput.GraphInputAdapterFactory;
import i5.las2peer.services.ocd.adapters.graphInput.GraphInputFormat;
import i5.las2peer.services.ocd.adapters.graphOutput.GraphOutputAdapter;
import i5.las2peer.services.ocd.adapters.graphOutput.GraphOutputAdapterFactory;
import i5.las2peer.services.ocd.adapters.graphOutput.GraphOutputFormat;
import i5.las2peer.services.ocd.graphs.Cover;
import i5.las2peer.services.ocd.graphs.CustomGraph;
import i5.las2peer.services.ocd.metrics.OcdMetricLog;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.text.ParseException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSSerializer;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Manages different request-related tasks for the Service Class.
* Mainly in charge of simple IO tasks and of creating entity managers for persistence purposes.
* @author Sebastian
*
*/
public class RequestHandler {
/**
* Default name of the persistence unit used for the creation of entity managers.
*/
private static final String defaultPersistenceUnitName = "ocd";
/**
* The factory used for the creation of entity managers.
*/
private static EntityManagerFactory emf = Persistence.createEntityManagerFactory(defaultPersistenceUnitName);
/**
* The factory used for the creation of document builders.
*/
private static final DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
/**
* The logger used for request logging.
*/
private static final Logger log = Logger.getLogger("Service API");
/**
* The factory used for creating cover output adapters.
*/
private static CoverOutputAdapterFactory coverOutputAdapterFactory = new CoverOutputAdapterFactory();
/**
* The factory used for creating graph output adapters.
*/
private static GraphOutputAdapterFactory graphOutputAdapterFactory = new GraphOutputAdapterFactory();
/**
* The factory used for creating cover input adapters.
*/
private static CoverInputAdapterFactory coverInputAdapterFactory = new CoverInputAdapterFactory();
/**
* The factory used for creating graph input adapters.
*/
private static GraphInputAdapterFactory graphInputAdapterFactory = new GraphInputAdapterFactory();
/**
* Sets the persistence unit for entity managers produced by any request handler.
* @param persistenceUnitName The name of the persistence unit.
*/
public static void setPersistenceUnit(String persistenceUnitName) {
emf = Persistence.createEntityManagerFactory(persistenceUnitName);
}
/**
* Creates a new instance.
* Also initiates the database connection.
*/
public RequestHandler() {
/*
* Init database connection
*/
EntityManager em = emf.createEntityManager();
em.close();
}
/**
* Creates a new log entry based on an exception.
* @param level The level of the entry.
* @param message The entry message.
* @param e The exception.
*/
public synchronized void log(Level level, String message, Exception e) {
log.log(level, message, e);
}
/**
* Creates a new log entry.
* @param level The entry message.
* @param message The entry message.
*/
public synchronized void log(Level level, String message) {
log.log(level, message);
}
/**
* Creates a new entity manager.
* @return The entity manager.
*/
public EntityManager getEntityManager() {
return emf.createEntityManager();
}
/**
* Returns an error in xml format.
* @param error The error.
* @param errorMessage An error Message
* @return The xml error.
*/
/*
* Note that this XML document is created "manually" in order to omit any additional exceptions.
*/
public String writeError(Error error, String errorMessage) {
if(errorMessage == null) {
errorMessage = "";
}
return "<?xml version=\"1.0\" encoding=\"UTF-16\"?>"
+ "<Error>"
+ "<Id>"+ error.getId() +"</Id>"
+ "<Name>"+ error.toString() +"</Name>"
+ "<Message>"+ errorMessage +"</Message>"
+ "</Error>";
}
/**
* Transforms a parameter xml into a parameter map.
* @param content A parameter xml.
* @return The corresponding parameter map.
* @throws SAXException
* @throws IOException
* @throws ParserConfigurationException
*/
public Map<String, String> parseParameters(String content) throws SAXException, IOException, ParserConfigurationException {
Map<String, String> parameters = new HashMap<String, String>();
Document doc = this.parseDocument(content);
NodeList parameterElts = doc.getElementsByTagName("Parameter");
for(int i=0; i<parameterElts.getLength(); i++) {
Node node = parameterElts.item(i);
if(node.getNodeType() == Node.ELEMENT_NODE) {
Element elt = (Element) node;
String name = elt.getElementsByTagName("Name").item(0).getTextContent();
String value = elt.getElementsByTagName("Value").item(0).getTextContent();
parameters.put(name, value);
}
}
return parameters;
}
/**
* Transforms a parameter map into a parameter xml.
* @param parameters A parameter mapping from the name of each parameter to the corresponding value.
* @return The corresponding parameter xml.
* @throws ParserConfigurationException
*/
public String writeParameters(Map<String, String> parameters) throws ParserConfigurationException {
Document doc = getDocument();
Element paramsElt = doc.createElement("Parameters");
for(Map.Entry<String, String> entry: parameters.entrySet()) {
Element paramElt = doc.createElement("Parameter");
Element paramNameElt = doc.createElement("Name");
paramNameElt.appendChild(doc.createTextNode(entry.getKey()));
paramElt.appendChild(paramNameElt);
Element paramValueElt = doc.createElement("Value");
paramValueElt.appendChild(doc.createTextNode(entry.getValue()));
paramElt.appendChild(paramValueElt);
paramsElt.appendChild(paramElt);
}
doc.appendChild(paramsElt);
return this.writeDoc(doc);
}
/**
* Creates a standard XML document used for confirmation responses.
* @return The document.
* @throws ParserConfigurationException
*/
public String writeConfirmationXml() throws ParserConfigurationException {
Document doc = getDocument();
doc.appendChild(doc.createElement("Confirmation"));
return writeDoc(doc);
}
/**
* Creates an XML document containing multiple graph ids.
* @param graphs The graphs.
* @return The document.
* @throws ParserConfigurationException
*/
public String writeGraphIds(List<CustomGraph> graphs) throws ParserConfigurationException {
Document doc = getDocument();
Element graphsElt = doc.createElement("Graphs");
for(int i=0; i<graphs.size(); i++) {
graphsElt.appendChild(getIdElt(graphs.get(i), doc));
}
doc.appendChild(graphsElt);
return writeDoc(doc);
}
/**
* Creates an XML document containing multiple cover ids.
* @param covers The covers.
* @return The document.
* @throws ParserConfigurationException
*/
public String writeCoverIds(List<Cover> covers) throws ParserConfigurationException {
Document doc = getDocument();
Element coversElt = doc.createElement("Covers");
for(int i=0; i<covers.size(); i++) {
coversElt.appendChild(getIdElt(covers.get(i), doc));
}
doc.appendChild(coversElt);
return writeDoc(doc);
}
/**
* Creates an XML document containing meta information about multiple graphs.
* @param graphs The graphs.
* @return The document.
* @throws AdapterException
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
* @throws InstantiationException
* @throws IllegalAccessException
*/
public String writeGraphMetas(List<CustomGraph> graphs) throws AdapterException, ParserConfigurationException, IOException, SAXException, InstantiationException, IllegalAccessException {
Document doc = getDocument();
Element graphsElt = doc.createElement("Graphs");
for(CustomGraph graph : graphs) {
String metaDocStr = writeGraph(graph, GraphOutputFormat.META_XML);
Node metaDocNode = parseDocumentToNode(metaDocStr);
Node importNode = doc.importNode(metaDocNode, true);
graphsElt.appendChild(importNode);
}
doc.appendChild(graphsElt);
return writeDoc(doc);
}
/**
* Creates an XML document containing meta information about multiple covers.
* @param covers The covers.
* @return The document.
* @throws AdapterException
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
* @throws InstantiationException
* @throws IllegalAccessException
*/
public String writeCoverMetas(List<Cover> covers) throws AdapterException, ParserConfigurationException, IOException, SAXException, InstantiationException, IllegalAccessException {
Document doc = getDocument();
Element coversElt = doc.createElement("Covers");
for(Cover cover : covers) {
String metaDocStr = writeCover(cover, CoverOutputFormat.META_XML);
Node metaDocNode = parseDocumentToNode(metaDocStr);
Node importNode = doc.importNode(metaDocNode, true);
coversElt.appendChild(importNode);
}
doc.appendChild(coversElt);
return writeDoc(doc);
}
/**
* Creates an XML document containing the id of a single graph.
* @param graph The graph.
* @return The document.
* @throws ParserConfigurationException
*/
public String writeId(CustomGraph graph) throws ParserConfigurationException {
Document doc = getDocument();
doc.appendChild(getIdElt(graph, doc));
return writeDoc(doc);
}
/**
* Creates an XML document containing the id of a single cover.
* @param cover The cover.
* @return The document.
* @throws ParserConfigurationException
*/
public String writeId(Cover cover) throws ParserConfigurationException {
Document doc = getDocument();
doc.appendChild(getIdElt(cover, doc));
return writeDoc(doc);
}
/**
* Creates an XML document containing the id of a single metric log.
* @param metricLog The metric log.
* @return The document.
* @throws ParserConfigurationException
*/
public String writeId(OcdMetricLog metricLog) throws ParserConfigurationException {
Document doc = getDocument();
doc.appendChild(getIdElt(metricLog, doc));
return writeDoc(doc);
}
/**
* Creates a graph output in a specified format.
* @param graph The graph.
* @param outputFormat The format.
* @return The graph output.
* @throws AdapterException
* @throws InstantiationException
* @throws IllegalAccessException
*/
public String writeGraph(CustomGraph graph, GraphOutputFormat outputFormat) throws AdapterException, InstantiationException, IllegalAccessException {
GraphOutputAdapter adapter = graphOutputAdapterFactory.getInstance(outputFormat);
Writer writer = new StringWriter();
adapter.setWriter(writer);
adapter.writeGraph(graph);
return writer.toString();
}
/**
* Creates a cover output in a specified format.
* @param cover The cover.
* @param outputFormat The format.
* @return The cover output.
* @throws AdapterException
* @throws InstantiationException
* @throws IllegalAccessException
*/
public String writeCover(Cover cover, CoverOutputFormat outputFormat) throws AdapterException, InstantiationException, IllegalAccessException {
Writer writer = new StringWriter();
CoverOutputAdapter adapter = coverOutputAdapterFactory.getInstance(outputFormat);
adapter.setWriter(writer);
adapter.writeCover(cover);
return writer.toString();
}
/**
* Parses a graph input using a specified format.
* @param contentStr The graph input.
* @param inputFormat The format.
* @return The graph.
* @throws AdapterException
* @throws InstantiationException
* @throws IllegalAccessException
*/
public CustomGraph parseGraph(String contentStr, GraphInputFormat inputFormat) throws AdapterException, InstantiationException, IllegalAccessException {
GraphInputAdapter adapter = graphInputAdapterFactory.getInstance(inputFormat);
Reader reader = new StringReader(contentStr);
adapter.setReader(reader);
return adapter.readGraph();
}
/**
* Parses a graph input using a specified format.
* @param contentStr The graph input.
* @param inputFormat The format.
* @param param Parametes that are passed to the adapters.
* @return The graph.
* @throws AdapterException
* @throws InstantiationException
* @throws IllegalAccessException
* @throws ParseException
* @throws IllegalArgumentException
*/
public CustomGraph parseGraph(String contentStr, GraphInputFormat inputFormat, Map<String, String> param) throws AdapterException, InstantiationException, IllegalAccessException, IllegalArgumentException, ParseException {
GraphInputAdapter adapter = graphInputAdapterFactory.getInstance(inputFormat);
Reader reader = new StringReader(contentStr);
adapter.setReader(reader);
adapter.setParameter(param);
return adapter.readGraph();
}
/**
* Parses a cover input using a specified format.
* @param contentStr The cover input.
* @param graph The graph that the cover is based on.
* @param inputFormat The format.
* @return The cover.
* @throws AdapterException
* @throws InstantiationException
* @throws IllegalAccessException
*/
public Cover parseCover(String contentStr, CustomGraph graph, CoverInputFormat inputFormat) throws AdapterException, InstantiationException, IllegalAccessException {
CoverInputAdapter adapter = coverInputAdapterFactory.getInstance(inputFormat);
Reader reader = new StringReader(contentStr);
adapter.setReader(reader);
return adapter.readCover(graph);
}
/**
* Returns an XML element node representing the id of a graph.
* @param graph The graph.
* @param doc The document to create the element node for.
* @return The element node.
*/
protected Node getIdElt(CustomGraph graph, Document doc) {
Element graphElt = doc.createElement("Graph");
Element graphIdElt = doc.createElement("Id");
graphIdElt.appendChild(doc.createTextNode(Long.toString(graph.getId())));
graphElt.appendChild(graphIdElt);
return graphElt;
}
/**
* Returns an XML element node representing the id of a cover.
* @param cover The cover.
* @param doc The document to create the element node for.
* @return The element node.
*/
protected Node getIdElt(Cover cover, Document doc) {
Element coverElt = doc.createElement("Cover");
Element idElt = doc.createElement("Id");
Element coverIdElt = doc.createElement("CoverId");
coverIdElt.appendChild(doc.createTextNode(Long.toString(cover.getId())));
idElt.appendChild(coverIdElt);
Element graphIdElt = doc.createElement("GraphId");
graphIdElt.appendChild(doc.createTextNode(Long.toString(cover.getGraph().getId())));
idElt.appendChild(graphIdElt);
coverElt.appendChild(idElt);
return coverElt;
}
/**
* Returns an XML element node representing the id of a metric log.
* @param metricLog The metric log.
* @param doc The document to create the element node for.
* @return The element node.
*/
protected Node getIdElt(OcdMetricLog metricLog, Document doc) {
Element metricElt = doc.createElement("Metric");
Element idElt = doc.createElement("Id");
Element metricIdElt = doc.createElement("MetricId");
metricIdElt.appendChild(doc.createTextNode(Long.toString(metricLog.getId())));
idElt.appendChild(metricIdElt);
Element coverIdElt = doc.createElement("CoverId");
coverIdElt.appendChild(doc.createTextNode(Long.toString(metricLog.getCover().getId())));
idElt.appendChild(coverIdElt);
Element graphIdElt = doc.createElement("GraphId");
graphIdElt.appendChild(doc.createTextNode(Long.toString(metricLog.getCover().getGraph().getId())));
idElt.appendChild(graphIdElt);
metricElt.appendChild(idElt);
return metricElt;
}
/**
* Transforms a document into a string.
* @param doc The document.
* @return The document string.
*/
protected String writeDoc(Document doc) {
DOMImplementationLS domImplementation = (DOMImplementationLS) doc.getImplementation();
LSSerializer lsSerializer = domImplementation.createLSSerializer();
return lsSerializer.writeToString(doc);
}
/**
* Creates an empty document.
* @return The document.
* @throws ParserConfigurationException
*/
protected Document getDocument() throws ParserConfigurationException {
DocumentBuilder builder = builderFactory.newDocumentBuilder();
return builder.newDocument();
}
/**
* Transforms an XML document in string form into an actual XML node.
* @param docString The document string.
* @return The node.
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
*/
protected Node parseDocumentToNode(String docString) throws ParserConfigurationException, IOException, SAXException {
Document doc = parseDocument(docString);
return doc.getDocumentElement();
}
/**
* Parses an XML document in string form into an actual XML document.
* @param docString The document string.
* @return The document.
* @throws SAXException
* @throws IOException
* @throws ParserConfigurationException
*/
protected Document parseDocument(String docString) throws SAXException, IOException, ParserConfigurationException {
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Reader reader = new StringReader(docString);
Document doc = builder.parse(new InputSource(reader));
return doc;
}
/**
* Parses a string into a boolean value. Only the words TRUE and FALSE are accepted, ignoring the letter cases though.
* @param valueStr The value in string format.
* @return The boolean value.
*/
public boolean parseBoolean(String valueStr) {
boolean value = Boolean.parseBoolean(valueStr);
if(!value) {
if(!(valueStr).matches("(?iu)false")) {
throw new IllegalArgumentException();
}
}
return value;
}
/**
* Creates an XML document containing all enum constant names of a given enum class.
* @param enumClass The class object of the corresponding enum class.
* @param <E> An enum subclass type.
* @return The document.
* @throws ParserConfigurationException
*/
public <E extends Enum<E>> String writeEnumNames(final Class<E> enumClass) throws ParserConfigurationException {
Document doc = getDocument();
Element namesElt = doc.createElement("Names");
for(E e : enumClass.getEnumConstants()) {
Element nameElt = doc.createElement("Name");
nameElt.appendChild(doc.createTextNode(e.name()));
namesElt.appendChild(nameElt);
}
doc.appendChild(namesElt);
return writeDoc(doc);
}
/**
* Parses a single string into a list of strings by splitting on the "-" delimiter.
* Intended for parsing multiple values passed as single request query parameter.
* @param paramStr A string (possibly containing) "-" delimiters.
* @return The string list.
*/
public List<String> parseQueryMultiParam(String paramStr) {
return Arrays.asList(paramStr.split("-"));
}
}