package org.uncertweb.ps.handler.soap; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import org.jdom.Attribute; import org.jdom.Content; import org.jdom.Element; import org.uncertweb.ps.data.DataDescription; import org.uncertweb.ps.data.DataReference; import org.uncertweb.ps.data.Input; import org.uncertweb.ps.data.MultipleInput; import org.uncertweb.ps.data.ProcessInputs; import org.uncertweb.ps.data.Request; import org.uncertweb.ps.data.RequestedOutput; import org.uncertweb.ps.data.SingleInput; import org.uncertweb.ps.encoding.EncodingRepository; import org.uncertweb.ps.encoding.ParseException; import org.uncertweb.ps.encoding.xml.AbstractXMLEncoding; import org.uncertweb.ps.handler.RequestParseException; import org.uncertweb.ps.handler.data.DataReferenceParser; import org.uncertweb.ps.process.AbstractProcess; import org.uncertweb.ps.process.ProcessRepository; import org.uncertweb.xml.Namespaces; public class XMLRequestParser { private static final Logger logger = Logger.getLogger(XMLRequestParser.class); public static Request parse(Element requestElement) throws RequestParseException { // check if process or description request if (requestElement == null || !requestElement.getNamespace().equals(Namespaces.PS) || !requestElement.getName().endsWith("Request")) { throw new RequestParseException("No request element found."); } // extract process id String processIdentifier = requestElement.getName().substring(0, requestElement.getName().length() - "Request".length()); // create request object Request request = new Request(processIdentifier); // get process AbstractProcess process = ProcessRepository.getInstance().getProcess(processIdentifier); // if we can't find process if (process == null) { throw new RequestParseException("Process with identifier " + processIdentifier + " could not be found."); } // parse inputs ProcessInputs inputs = request.getInputs(); List<Input> parsedInputs = parseInputs(requestElement, process); for (Input input : parsedInputs) { inputs.add(input); } // parse requested outputs request.setRequestedOutputs(parseRequestedOutputs(requestElement)); return request; } private static List<Input> parseInputs(Element baseElement, AbstractProcess process) throws RequestParseException { // list of parsed inputs List<Input> inputs = new ArrayList<Input>(); // lookup inputs for process name for (String inputIdentifier : process.getInputIdentifiers()) { // get data class for type from process DataDescription dataDescription = process.getInputDataDescription(inputIdentifier); if (dataDescription == null) { // FIXME: not a client problem throw new RequestParseException("Couldn't find description for input " + inputIdentifier + "."); } Class<?> type = dataDescription.getType(); // get input element List<?> inputElements = baseElement.getChildren(inputIdentifier, Namespaces.PS); // parse if present if (inputElements.size() > 0) { // hold data List<Object> dataList = new ArrayList<Object>(); // get each element for (Object o : inputElements) { // cast to element Element inputElement = (Element) o; // parse try { dataList.add(parseData(inputElement, type)); } catch (ParseException e) { throw new RequestParseException("Couldn't parse data for " + inputIdentifier + ".", e); } // add to request if (dataDescription.getMaxOccurs() > 1) { inputs.add(new MultipleInput(inputIdentifier, dataList)); } else { inputs.add(new SingleInput(inputIdentifier, dataList.get(0))); } } } } // all done return inputs; } private static <T> T parseData(Element element, Class<T> type) throws ParseException, RequestParseException { // get the content // workaround for whitespace Content content = element.getContent(0); if (element.getContentSize() > 1) { for (Object object : element.getContent()) { if (object instanceof Element) { content = (Element)object; break; } } } // special case for reference if (content instanceof Element && ((Element)content).getName().equals("DataReference")) { return parseDataReference((Element)content, type); } else { // get xml encoding EncodingRepository encodingRepo = EncodingRepository.getInstance(); AbstractXMLEncoding encoding = encodingRepo.getXMLEncoding(type); // couldn't find suitable encoding if (encoding == null) { // FIXME: not a client problem throw new RequestParseException("No encoding found for type " + type.getName() + "."); } return encoding.parse(content, type); } } private static <T> T parseDataReference(Element element, Class<T> type) throws ParseException, RequestParseException { // get attributes String href = element.getAttributeValue("href"); String mimeType = element.getAttributeValue("mimeType"); String compressedString = element.getAttributeValue("compressed"); boolean compressed = false; if (compressedString != null) { compressed = (compressedString.equalsIgnoreCase("true") || compressedString.equals("1")); } // parse DataReferenceParser refParser = new DataReferenceParser(); try { DataReference ref = new DataReference(new URL(href), mimeType, compressed); return refParser.parse(ref, type); } catch (MalformedURLException e) { throw new RequestParseException("Malformed data reference URL.", e); } } private static List<RequestedOutput> parseRequestedOutputs(Element requestElement) { // create list List<RequestedOutput> reqOutputs = new ArrayList<RequestedOutput>(); // get element Element reqOutputsElement = requestElement.getChild("RequestedOutputs", Namespaces.PS); if (reqOutputsElement != null) { for (Object o : reqOutputsElement.getChildren()) { Element reqOutputElement = (Element)o; String name = reqOutputElement.getName(); boolean reference = false; Attribute refAttr = reqOutputElement.getAttribute("reference"); if (refAttr != null && (refAttr.getValue().equals("true") || refAttr.equals("1"))) { reference = true; } reqOutputs.add(new RequestedOutput(name, reference)); } } else { reqOutputs = null; } // all done return reqOutputs; } }