Java tutorial
/******************************************************************************* * Copyright (C) 2007 The University of Manchester * * Modifications to the initial code base are copyright of their * respective authors, or their employers as appropriate. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 ******************************************************************************/ package net.sf.taverna.t2.commandline.data; import java.io.File; import java.io.IOException; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import net.sf.taverna.t2.commandline.exceptions.InputMismatchException; import net.sf.taverna.t2.commandline.exceptions.InvalidOptionException; import net.sf.taverna.t2.commandline.exceptions.ReadInputException; import net.sf.taverna.t2.commandline.options.CommandLineOptions; import net.sf.taverna.t2.invocation.InvocationContext; import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; import org.jdom.JDOMException; import org.purl.wf4ever.robundle.Bundle; import uk.org.taverna.databundle.DataBundles; import uk.org.taverna.scufl2.api.port.InputWorkflowPort; /** * Handles the reading, or processing, or input values according to arguments provided to the * commandline. * The may be either as direct values, from a file, or from a Baclava document. * Also handles registering the input values with the Data Service, ready to initiate * the workflow run. * * @author Stuart Owen */ public class InputsHandler { private static Logger logger = Logger.getLogger(InputsHandler.class); public void checkProvidedInputs(Map<String, InputWorkflowPort> portMap, CommandLineOptions options) throws InputMismatchException { // we dont check for the document Set<String> providedInputNames = new HashSet<String>(); for (int i = 0; i < options.getInputFiles().length; i += 2) { // If it already contains a value for the input port, e.g // two inputs are provided for the same port if (providedInputNames.contains(options.getInputFiles()[i])) { throw new InputMismatchException("Two input values were provided for the same input port " + options.getInputFiles()[i] + ".", null, null); } providedInputNames.add(options.getInputFiles()[i]); } for (int i = 0; i < options.getInputValues().length; i += 2) { // If it already contains a value for the input port, e.g // two inputs are provided for the same port if (providedInputNames.contains(options.getInputValues()[i])) { throw new InputMismatchException("Two input values were provided for the same input port " + options.getInputValues()[i] + ".", null, null); } providedInputNames.add(options.getInputValues()[i]); } if (portMap.size() * 2 != (options.getInputFiles().length + options.getInputValues().length)) { throw new InputMismatchException( "The number of inputs provided does not match the number of input ports.", portMap.keySet(), providedInputNames); } for (String portName : portMap.keySet()) { if (!providedInputNames.contains(portName)) { throw new InputMismatchException( "The provided inputs does not contain an input for the port '" + portName + "'", portMap.keySet(), providedInputNames); } } } public Bundle registerInputs(Map<String, InputWorkflowPort> portMap, CommandLineOptions options, InvocationContext context) throws InvalidOptionException, ReadInputException, IOException { Bundle inputDataBundle; inputDataBundle = DataBundles.createBundle(); inputDataBundle.setDeleteOnClose(false); System.out.println("Bundle: " + inputDataBundle.getSource()); Path inputs = DataBundles.getInputs(inputDataBundle); URL url; try { url = new URL("file:"); } catch (MalformedURLException e1) { // Should never happen, but just in case: throw new ReadInputException( "The was an internal error setting up the URL to open the inputs. You should contact Taverna support.", e1); } if (options.hasInputFiles()) { regesterInputsFromFiles(portMap, options, inputs, url); } if (options.hasInputValues()) { registerInputsFromValues(portMap, options, inputs); } return inputDataBundle; } private void registerInputsFromValues(Map<String, InputWorkflowPort> portMap, CommandLineOptions options, Path inputs) throws InvalidOptionException { String[] inputParams = options.getInputValues(); for (int i = 0; i < inputParams.length; i = i + 2) { String inputName = inputParams[i]; try { String inputValue = inputParams[i + 1]; InputWorkflowPort port = portMap.get(inputName); if (port == null) { throw new InvalidOptionException("Cannot find an input port named '" + inputName + "'"); } Path portPath = DataBundles.getPort(inputs, inputName); if (options.hasDelimiterFor(inputName)) { String delimiter = options.inputDelimiter(inputName); Object value = checkForDepthMismatch(1, port.getDepth(), inputName, inputValue.split(delimiter)); setValue(portPath, value); } else { Object value = checkForDepthMismatch(0, port.getDepth(), inputName, inputValue); setValue(portPath, value); } } catch (IndexOutOfBoundsException e) { throw new InvalidOptionException("Missing input value for input " + inputName); } catch (IOException e) { throw new InvalidOptionException("Error creating value for input " + inputName); } } } private void regesterInputsFromFiles(Map<String, InputWorkflowPort> portMap, CommandLineOptions options, Path inputs, URL url) throws InvalidOptionException { String[] inputParams = options.getInputFiles(); for (int i = 0; i < inputParams.length; i = i + 2) { String inputName = inputParams[i]; try { URL inputURL = new URL(url, inputParams[i + 1]); InputWorkflowPort port = portMap.get(inputName); if (port == null) { throw new InvalidOptionException("Cannot find an input port named '" + inputName + "'"); } Path portPath = DataBundles.getPort(inputs, inputName); if (options.hasDelimiterFor(inputName)) { String delimiter = options.inputDelimiter(inputName); Object value = IOUtils.toString(inputURL.openStream()).split(delimiter); value = checkForDepthMismatch(1, port.getDepth(), inputName, value); setValue(portPath, value); } else { Object value = IOUtils.toByteArray(inputURL.openStream()); value = checkForDepthMismatch(0, port.getDepth(), inputName, value); setValue(portPath, value); } } catch (IndexOutOfBoundsException e) { throw new InvalidOptionException("Missing input filename for input " + inputName); } catch (IOException e) { throw new InvalidOptionException("Could not read input " + inputName + ": " + e.getMessage()); } } } private void setValue(Path port, Object userInput) throws IOException { if (userInput instanceof File) { DataBundles.setReference(port, ((File) userInput).toURI()); } else if (userInput instanceof URL) { try { DataBundles.setReference(port, ((URL) userInput).toURI()); } catch (URISyntaxException e) { logger.warn(String.format("Error converting %1$s to URI", userInput), e); } } else if (userInput instanceof String) { DataBundles.setStringValue(port, (String) userInput); } else if (userInput instanceof byte[]) { Files.write(port, (byte[]) userInput, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE); } else if (userInput instanceof List<?>) { DataBundles.createList(port); List<?> list = (List<?>) userInput; for (Object object : list) { setValue(DataBundles.newListItem(port), object); } } else { logger.warn("Unknown input type : " + userInput.getClass().getName()); } } private Object checkForDepthMismatch(int inputDepth, int portDepth, String inputName, Object inputValue) throws InvalidOptionException { if (inputDepth != portDepth) { if (inputDepth < portDepth) { logger.warn("Wrapping input for '" + inputName + "' from a depth of " + inputDepth + " to the required depth of " + portDepth); while (inputDepth < portDepth) { List<Object> l = new ArrayList<Object>(); l.add(inputValue); inputValue = l; inputDepth++; } } else { String msg = "There is a mismatch between depth of the list for the input port '" + inputName + "' and the data presented. The input port requires a " + depthToString(portDepth) + " and the data presented is a " + depthToString(inputDepth); throw new InvalidOptionException(msg); } } return inputValue; } private String depthToString(int depth) { switch (depth) { case 0: return "single item"; case 1: return "list"; case 2: return "list of lists"; default: return "list of depth " + depth; } } private int getObjectDepth(Object o) { int result = 0; if (o instanceof Iterable) { result++; Iterator i = ((Iterable) o).iterator(); if (i.hasNext()) { Object child = i.next(); result = result + getObjectDepth(child); } } return result; } }