Java tutorial
/** * Copyright 2009 Humboldt-Universitt zu Berlin, INRIA. * * 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.corpus_tools.pepper.cli; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Vector; import org.apache.commons.lang3.StringUtils; import org.corpus_tools.pepper.common.FormatDesc; import org.corpus_tools.pepper.common.MODULE_TYPE; import org.corpus_tools.pepper.common.Pepper; import org.corpus_tools.pepper.common.PepperJob; import org.corpus_tools.pepper.common.PepperModuleDesc; import org.corpus_tools.pepper.common.PepperUtil; import org.corpus_tools.pepper.common.StepDesc; import org.corpus_tools.pepper.modules.PepperModuleProperties; import org.corpus_tools.pepper.modules.PepperModuleProperty; import org.eclipse.emf.common.util.URI; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class represents a console to realize a kind of an interactive wizard to * guide the user through the workflow configuration. This is a step by step * wizard in which the the user needs to make an input for each step: * <ol> * <li>Import phase * <ol> * <li>choose source corpus</li> * <li>choose importer (if possible show a list of recommended importers and the * rest)</li> * <li>choose configuration properties (wizard presents a list of possible * properties)</li> * <li>another importer? press enter for no, corpus path for yes</li> * </ol> * </li> * <li>Manipulation phase * <ol> * <li>choose manipulator (enter for non)</li> * <li>choose configuration properties (wizard presents a list of possible * properties)</li> * <li>another manipulator? press enter for no</li> * </ol> * </li> * <li>Export phase * <ol> * <li>choose target path for corpus</li> * <li>choose configuration properties (wizard presents a list of possible * properties)</li> * <li>another exporter? press enter for no, corpus path for yes</li> * </ol> * </li> * * </ol> * * @author Florian Zipser * */ public class ConvertWizardConsole { private static final Logger logger = LoggerFactory.getLogger(PepperStarter.class); private static final String PROMPT = "wizard"; private static final String MSG_IM = "\tPlease enter the number or the name of the importer you want to use. "; private static final String MSG_IMPORT_CORPUS = "\tPlease enter a (further) path to corpus you want to import or press enter to skip. When you use a relative path make the relative to:'" + new File("").getAbsolutePath() + "/'. "; private static final String MSG_PROP = "\tTo use a customization property, please enter it's number or name, the '=' and a value (e.g. 'name=value', or 'number=value'). To skip the customiazation, press enter. "; private static final String MSG_MAN = "\tIf you want to use a manipulator, please enter it's number or name, or press enter to skip. "; private static final String MSG_NO_PROPS = "\tNo customization properties available."; private static final String MSG_NO_VALID_MODULE = "\tSorry could not match the input, please enter the number or the name of the module again. "; private static final String MSG_NO_VALID_PROP = "\tSorry could not match the input, please enter the number or the name of the property followed by '=' and the value again. "; private static final String MSG_EX = "\tPlease enter the number or the name of the exporter you want to use. "; private static final String MSG_EX_CORPUS = "\tPlease enter a (further) path to which you want to export the corpus or press enter to skip. When you use a relative path make the relative to:'" + new File("").getAbsolutePath() + "/'. "; private static final String MSG_ABORTED = "Creating of Pepper workflow aborted by user's input. "; /** Determines if debug mode is on or off **/ public Boolean isDebug = false; public enum COMMAND { // SAVE("save", "s", "path to file", "Stores the Pepper workflow description to passed file location. "), // CONVERT("convert", "c", null, "Starts the conversion process of the created Pepper workflow. "); private String name = null; private String abbreviation = null; private String parameters = null; private String description = null; private COMMAND(String name, String abbreviation, String parameters, String description) { this.name = name; this.abbreviation = abbreviation; this.parameters = parameters; this.description = description; } public String getName() { return (name); } public String getAbbreviation() { return (abbreviation); } public String getParameters() { return (parameters); } public String getDescription() { return (description); } } private String prompt = null; /** * Initializes an object. * * @param prefixPrompt * the prefix prompt to be displayed, before the prompt of this * console. */ public ConvertWizardConsole(String prefixPrompt) { prompt = prefixPrompt + "/" + PROMPT; } /** The Pepper object, which shall create and run the job **/ private Pepper pepper = null; /** * @return The Pepper object, which shall create and run the job */ public Pepper getPepper() { return pepper; } /** * @param pepper * The Pepper object, which shall create and run the job */ public void setPepper(Pepper pepper) { this.pepper = pepper; } /** * Starts this console, using std in and std out. */ public void start() { start(new BufferedReader(new InputStreamReader(System.in)), System.out); } /** Input stream to be used for this session to get the users input. **/ private BufferedReader in = null; /** Output stream to be used for this session to give feedback. **/ private PrintStream out = null; /** * Starts the wizard for a 'session'. A wizard can only be started as * singleton. That means it needs to be quit before it can be started again. * <ol> * <li>startes wizard for import phase {@link #importPhase(PepperJob)}</li> * <li>startes wizard for manipulation phase * {@link #manipulationPhase(PepperJob)}</li> * <li>startes wizard for export phase {@link #exportPhase(PepperJob)}</li> * <li>requests user input {@value COMMAND#SAVE} to store workflow * description or {@value COMMAND#CONVERT} to start conversion</li> * </ol> * * @param in * @param out */ public synchronized PepperJob start(BufferedReader in, PrintStream out) { this.in = in; this.out = out; String jobId = pepper.createJob(); PepperJob pepperJob = pepper.getJob(jobId); try { String promptOld = prompt; prompt = prompt + "/importer"; if (!importPhase(pepperJob)) { out.println(MSG_ABORTED); return (null); } prompt = promptOld + "/manipulator"; manipulationPhase(pepperJob); prompt = promptOld + "/exporter"; if (!exportPhase(pepperJob)) { out.println(MSG_ABORTED); return (null); } prompt = promptOld; out.println( "Type 'convert' to start the conversion, 'save' to save the workflow description and 'exit' to exit. "); String input = null; while ((input = getUserInput(in, out)) != null) { String[] parts = input.split(" "); String command = parts[0]; List<String> params = new Vector<String>(); int i = 0; for (String part : parts) { if (i > 0) { params.add(part); } i++; } if ((COMMAND.SAVE.getName().equalsIgnoreCase(command)) || (COMMAND.SAVE.getAbbreviation().equalsIgnoreCase(command))) { File outputFile = null; if (parts.length == 1) { // path to workflow description wasn't given and needs // to be // requested out.println("Please enter the file location to store Pepper workflow description. "); while ((input = getUserInput(in, out)) != null) { outputFile = new File(input); break; } } else { // path to store workflow description was given outputFile = new File(params.get(params.size() - 1)); } if (outputFile != null) { try { deresolveURIs(outputFile, pepperJob); URI workflowURI = pepperJob.save(URI.createFileURI(outputFile.getAbsolutePath())); out.println("Stored Pepper workflow description at '" + outputFile.getAbsolutePath() + "'. "); // because of the deresolving of the URI, the // relative // path now is incompatible with current working // location, to fix this, the Pepper workflow file // needs // to be stored and reloaded again pepperJob.load(workflowURI); } catch (Exception e) { out.println("Could not store Pepper workflow to '" + outputFile.getAbsolutePath() + "', because of: " + e.getMessage()); if (isDebug) { e.printStackTrace(out); } } } } else if ((COMMAND.CONVERT.getName().equalsIgnoreCase(command)) || (COMMAND.CONVERT.getAbbreviation().equalsIgnoreCase(command))) { return (pepperJob); } out.println( "Type 'convert' to start the conversion, 'save' to save the workflow description and enter to exit. "); } } catch (ExitWizardException e) { out.println(MSG_ABORTED); return (null); } return (null); } /** * Before saving, create relative URIs for Pepper job. Create a base URI to * deresolve relative URIs * * @param outputFile * @param pepperJob * @throws IOException */ public static void deresolveURIs(File outputFile, PepperJob pepperJob) throws IOException { URI base; if (outputFile.isDirectory()) { base = URI.createFileURI(outputFile.getCanonicalPath() + "/"); } else { base = URI.createFileURI(outputFile.getCanonicalFile().getParentFile().getCanonicalPath() + "/"); } for (StepDesc stepDesc : pepperJob.getStepDescs()) { if ((stepDesc.getCorpusDesc() != null) && (stepDesc.getCorpusDesc().getCorpusPath() != null)) { URI before = stepDesc.getCorpusDesc().getCorpusPath(); stepDesc.getCorpusDesc() .setCorpusPath(stepDesc.getCorpusDesc().getCorpusPath().deresolve(base, true, true, true)); if (!stepDesc.getCorpusDesc().getCorpusPath().equals(before)) { // creates a leading './' if URI is relative stepDesc.getCorpusDesc() .setCorpusPath(URI.createFileURI("./" + stepDesc.getCorpusDesc().getCorpusPath())); } } } } /** * A sub wizard to manage the import phase. Asks all importers from the * user. * <ol> * <li>state 0: reads corpus path, empty input leads to exit import phase * </li> * <li>state 1: choose importer</li> * <li>state 2: choose properties, empty input leads to state 0</li> * </ol> * * @param pepperJob * the {@link PepperJob} object to be filled. * @return true if an importer was chosen, false if phase was aborted */ public boolean importPhase(PepperJob pepperJob) { int state = 0; String input = null; StepDesc stepDesc = null; out.println(MSG_IMPORT_CORPUS.replace("(further) ", "")); // a map containing each registered module and a corresponding number, // to make selection easier (key= number, value= module desc) Map<Integer, PepperModuleDesc> number2Module = null; // a map containing each registered module and a corresponding name, // to make selection easier (key= name, value= module desc) Map<String, PepperModuleDesc> name2Module = null; // the String containing the map to be presented to the user String legend = null; // a map containing a number corresponding to a customization property // for the current module Map<Integer, String> number2PropName = null; // stores the legend of the customization properties for the current // module String propLegend = null; // the module description which was selected by the user PepperModuleDesc moduleDesc = null; String promptOld = prompt; while (((input = getUserInput(in, out)) != null) || (state == 2)) { if (state == 0) { if (!input.isEmpty()) { // read corpus path File corpusPath = new File(input); if (!corpusPath.exists()) { out.println("\tThe path to corpus does not exist '" + corpusPath.getAbsolutePath() + "' please type in another one. "); } else { stepDesc = pepperJob.createStepDesc(); stepDesc.setModuleType(MODULE_TYPE.IMPORTER); String path; try { path = corpusPath.getCanonicalPath(); } catch (IOException e) { path = corpusPath.getAbsolutePath(); } if ((corpusPath.isDirectory()) && (!path.endsWith("/"))) { path = path + "/"; } out.println("import corpus from: " + path); stepDesc.getCorpusDesc().setCorpusPath(URI.createFileURI(path)); if ((number2Module == null) || (name2Module == null)) { number2Module = new HashMap<Integer, PepperModuleDesc>(); name2Module = new HashMap<String, PepperModuleDesc>(); legend = createModuleLegend(stepDesc.getCorpusDesc().getCorpusPath(), number2Module, name2Module, MODULE_TYPE.IMPORTER); } out.println(legend); out.println(MSG_IM); state++; } } else { // empty input return if (stepDesc != null) { // at least one importer was created return (true); } else { return (false); } } } else if (state == 1) { // choose importer try { Integer num = Integer.valueOf(input); moduleDesc = number2Module.get(num); } catch (NumberFormatException e) { moduleDesc = name2Module.get(input); } if (moduleDesc == null) { out.println(legend); out.println(MSG_NO_VALID_MODULE); } else { out.println("\tchoosed importer: '" + moduleDesc + "'. \n"); stepDesc.setName(moduleDesc.getName()); pepperJob.addStepDesc(stepDesc); if (moduleDesc.getProperties() != null) { // module takes customization properties state = 2; prompt = promptOld + "/prop"; number2PropName = new HashMap<Integer, String>(); propLegend = createPropertyLegend(moduleDesc.getProperties(), number2PropName); out.println(propLegend); out.println(MSG_PROP); } else { // module does not take customization properties out.println(MSG_NO_PROPS); out.println(MSG_IMPORT_CORPUS); propLegend = null; state = 0; } } } else if (state == 2) { // choose properties if (!readProp(number2PropName, input, stepDesc)) { state = 0; prompt = promptOld; out.println(MSG_IMPORT_CORPUS); } } } // end: while return (true); } /** * A sub wizard to manage the manipulation phase. Asks for all manipulators * from the user. * <ol> * <li>state 1: reads name of manipulator, empty input leads to exit import * phase</li> * <li>state 2: asks for properties, input leads to state 1</li> * </ol> * * @param pepperJob * the {@link PepperJob} object to be filled. * @return */ public void manipulationPhase(PepperJob pepperJob) { int state = 1; String input = null; StepDesc stepDesc = null; String promptOld = prompt; // a map containing each registered module and a corresponding number, // to make selection easier (key= number, value= module desc) Map<Integer, PepperModuleDesc> number2Module = new HashMap<Integer, PepperModuleDesc>(); // a map containing each registered module and a corresponding name, // to make selection easier (key= name, value= module desc) Map<String, PepperModuleDesc> name2Module = new HashMap<String, PepperModuleDesc>(); // the String containing the map to be presented to the user String legend = createModuleLegend(null, number2Module, name2Module, MODULE_TYPE.MANIPULATOR); out.println(legend); out.println(MSG_MAN); // a map containing a number corresponding to a customization property // for the current module Map<Integer, String> number2PropName = null; // stores the legend of the customization properties for the current // module String propLegend = null; // the module description which was selected by the user PepperModuleDesc moduleDesc = null; while (((input = getUserInput(in, out)) != null) || (state == 2)) { if (state == 1) { // choose manipulator if (input.isEmpty()) { return; } stepDesc = pepperJob.createStepDesc(); stepDesc.setModuleType(MODULE_TYPE.MANIPULATOR); try { Integer num = Integer.valueOf(input); moduleDesc = number2Module.get(num); } catch (NumberFormatException e) { moduleDesc = name2Module.get(input); } if (moduleDesc == null) { out.println(legend); out.println(MSG_NO_VALID_MODULE); } else { out.println("\tchoosed manipulator: '" + moduleDesc + "'. \n"); stepDesc.setName(moduleDesc.getName()); pepperJob.addStepDesc(stepDesc); if (moduleDesc.getProperties() != null) { // module takes customization properties state = 2; prompt = promptOld + "/prop"; number2PropName = new HashMap<Integer, String>(); propLegend = createPropertyLegend(moduleDesc.getProperties(), number2PropName); out.println(propLegend); out.println(MSG_PROP); } else { // module does not take customization properties out.println(MSG_NO_PROPS); out.println(MSG_IMPORT_CORPUS); propLegend = null; state = 0; } } } else if (state == 2) { if (!readProp(number2PropName, input, stepDesc)) { state = 1; prompt = promptOld; out.println(legend); out.println(MSG_MAN); } } } // end while prompt = promptOld; } /** * A sub wizard to manage the import phase. Asks all importers from the * user. * <ol> * <li>state 0: choose output path, empty input leads to exit of export * phase</li> * <li>state 1: choose exporter</li> * <li>state 2: choose property, empty input leads to state 0</li> * </ol> * * @param pepperJob * the {@link PepperJob} object to be filled. * @return if an exporter was set, false otherwise */ public boolean exportPhase(PepperJob pepperJob) { int state = 0; String input = null; StepDesc stepDesc = null; out.println(MSG_EX_CORPUS.replace("(further) ", "")); // a map containing each registered module and a corresponding number, // to make selection easier (key= number, value= module desc) Map<Integer, PepperModuleDesc> number2Module = null; // a map containing each registered module and a corresponding name, // to make selection easier (key= name, value= module desc) Map<String, PepperModuleDesc> name2Module = null; // the String containing the map to be presented to the user String legend = null; // a map containing a number corresponding to a customization property // for the current module Map<Integer, String> number2PropName = null; // stores the legend of the customization properties for the current // module String propLegend = null; // the module description which was selected by the user PepperModuleDesc moduleDesc = null; String promptOld = prompt; while (((input = getUserInput(in, out)) != null) || (state == 2)) { if (state == 0) { if (!input.isEmpty()) { // read corpus path File corpusPath = new File(input); if (!corpusPath.exists()) { if (!corpusPath.mkdirs()) { logger.warn("Cannot create folder for corpus path '{}'. ", corpusPath.getAbsolutePath()); } } String path; try { path = corpusPath.getCanonicalPath(); } catch (IOException e) { path = corpusPath.getAbsolutePath(); } if (!path.endsWith("/")) { path = path + "/"; } out.println("export corpus to: " + path); stepDesc = pepperJob.createStepDesc(); stepDesc.setModuleType(MODULE_TYPE.EXPORTER); stepDesc.getCorpusDesc().setCorpusPath(URI.createFileURI(path)); if ((number2Module == null) || (name2Module == null)) { number2Module = new HashMap<Integer, PepperModuleDesc>(); name2Module = new HashMap<String, PepperModuleDesc>(); legend = createModuleLegend(null, number2Module, name2Module, MODULE_TYPE.EXPORTER); } out.println(legend); out.println(MSG_EX); state++; } else { // empty input return if (stepDesc != null) { // at least one importer was created return (true); } else { return (false); } } } else if (state == 1) { // choose exporter try { Integer num = Integer.valueOf(input); moduleDesc = number2Module.get(num); } catch (NumberFormatException e) { moduleDesc = name2Module.get(input); } if (moduleDesc == null) { out.println(legend); out.println(MSG_NO_VALID_MODULE); } else { out.println("\tchoosed exporter: '" + moduleDesc + "'. \n"); stepDesc.setName(moduleDesc.getName()); pepperJob.addStepDesc(stepDesc); if (moduleDesc.getProperties() != null) { // module takes customization properties state = 2; prompt = promptOld + "/prop"; number2PropName = new HashMap<Integer, String>(); propLegend = createPropertyLegend(moduleDesc.getProperties(), number2PropName); out.println(propLegend); out.println(MSG_PROP); } else { // module does not take customization properties out.println(MSG_NO_PROPS); out.println(MSG_EX_CORPUS); propLegend = null; state = 0; } } } else if (state == 2) { // choose properties if (!readProp(number2PropName, input, stepDesc)) { state = 0; prompt = promptOld; out.println(MSG_IMPORT_CORPUS); } } } // end: while return (true); } public static class ImporterModuleDesc implements Comparable<ImporterModuleDesc> { public Double probability = null; public PepperModuleDesc moduleDesc = null; public ImporterModuleDesc(PepperModuleDesc moduleDesc, Double probability) { this.probability = probability; this.moduleDesc = moduleDesc; } @Override public int compareTo(ImporterModuleDesc arg0) { if (this.probability == null) { this.probability = 0.0; } if (arg0.probability == null) { arg0.probability = 0.0; } return (Double.compare(this.probability, arg0.probability)); } /** * This method is here to satisfy findbugs. */ @Override public boolean equals(Object obj) { return (super.equals(obj)); } /** * This method is here to satisfy findbugs. */ @Override public int hashCode() { return super.hashCode(); } public String toString() { return (probability + " " + moduleDesc.getName()); } } /** * Fills a map containing each registered module and a corresponding number, * to make selection easier (key= number, value= module desc). Fills a map * containing each registered module and a corresponding name, to make * selection easier (key= name, value= module desc). * * @param number2Module * @param name2Module * @return legend for the map to be printed */ private String createModuleLegend(URI corpusPath, Map<Integer, PepperModuleDesc> number2Module, Map<String, PepperModuleDesc> name2Module, MODULE_TYPE moduleType) { ArrayList<PepperModuleDesc> modules = new ArrayList<PepperModuleDesc>(); int numOfRecommended = 0; // if module is importer, call isImportable if (MODULE_TYPE.IMPORTER.equals(moduleType)) { List<ImporterModuleDesc> importerModuleDescs = new ArrayList<ConvertWizardConsole.ImporterModuleDesc>(); for (PepperModuleDesc moduleDesc : getPepper().getRegisteredModules()) { if (MODULE_TYPE.IMPORTER.equals(moduleDesc.getModuleType())) { Double isImportable = getPepper().isImportable(corpusPath, moduleDesc); if ((isImportable != null) && (isImportable > 0.0)) { numOfRecommended++; } importerModuleDescs.add(new ImporterModuleDesc(moduleDesc, isImportable)); } } Collections.reverse(importerModuleDescs); for (ImporterModuleDesc moduleDesc : importerModuleDescs) { modules.add(moduleDesc.moduleDesc); } } else { for (PepperModuleDesc moduleDesc : getPepper().getRegisteredModules()) { if (moduleType.equals(moduleDesc.getModuleType())) { modules.add(moduleDesc); } } } String retStr = null; String[][] map = new String[modules.size() + 1][3]; map[0][0] = "no"; map[0][1] = "module name"; if ((MODULE_TYPE.IMPORTER.equals(moduleType)) || (MODULE_TYPE.EXPORTER.equals(moduleType))) { map[0][2] = "format"; } else { map[0][2] = "description"; } Integer[] length = { 5, 30, 40 }; Integer num = 1; for (PepperModuleDesc moduleDesc : modules) { number2Module.put(num, moduleDesc); name2Module.put(moduleDesc.getName(), moduleDesc); String prefix = ""; if (numOfRecommended > num) { prefix = "* "; } else { prefix = " "; } map[num][0] = prefix + num; map[num][1] = moduleDesc.getName(); if ((MODULE_TYPE.IMPORTER.equals(moduleType)) || (MODULE_TYPE.EXPORTER.equals(moduleType))) { // module is an importer or exporter if (moduleDesc.getSupportedFormats().size() > 0) { int i = 0; StringBuilder str = new StringBuilder(); str.append("("); for (FormatDesc format : moduleDesc.getSupportedFormats()) { if (i > 0) { str.append("; "); } str.append(format.getFormatName()); str.append(", "); str.append(format.getFormatVersion()); i++; } str.append(")"); map[num][2] = str.toString(); } } else { // module is a manipulator map[num][2] = moduleDesc.getDesc(); } num++; } retStr = PepperUtil.createTable(length, map, true, true, true); return (retStr); } /** * Fills a map containing each {@link PepperModuleProperty} and a * corresponding number, to make selection easier (key= number, value= * property). Fills a map containing each {@link PepperModuleProperty} and a * corresponding name, to make selection easier (key= name, value= * property). * * @param number2Module * @param name2Module * @return legend for the map to be printed */ private String createPropertyLegend(PepperModuleProperties props, Map<Integer, String> number2propName) { String retStr = null; if (props != null) { String[][] map = new String[props.getPropertyDesctriptions().size() + 1][3]; map[0][0] = "no"; map[0][1] = "property name"; map[0][2] = "description"; Integer[] length = { 3, 30, 40 }; int i = 1; for (PepperModuleProperty<?> prop : props.getPropertyDesctriptions()) { map[i][0] = String.valueOf(i); map[i][1] = prop.getName(); map[i][2] = prop.getDescription(); number2propName.put(i, prop.getName()); i++; } retStr = PepperUtil.createTable(length, map, true, true, true); } return (retStr); } /** * Waits for a user input from passed input stream and returns it. If the * command "exit" was entered. null is returned. * * @param in * @param out * @return */ private String getUserInput(BufferedReader in, PrintStream out) { String userInput = ""; try { out.println(); out.print(prompt); out.print(">"); userInput = in.readLine(); if (userInput != null) { userInput = userInput.trim(); } } catch (IOException ioe) { out.println("Cannot read command."); } if (("exit".equalsIgnoreCase(userInput))) { throw new ExitWizardException(); } return (userInput); } @SuppressWarnings("serial") public static class ExitWizardException extends RuntimeException { } /** * Reads a property from the given inpu and returns true, if the input was * not empty and false otherwise. * * @param input * the user input * @param stepDesc * the {@link StepDesc} object to which the property should be * added * @return true if input was not empty */ private boolean readProp(Map<Integer, String> number2propName, String input, StepDesc stepDesc) { if ((input != null) && (!input.isEmpty())) { int eqPosition = StringUtils.indexOf(input, "="); if (eqPosition > 0) { String qualifier = input.substring(0, eqPosition); try { Integer num = Integer.valueOf(qualifier); qualifier = number2propName.get(num); } catch (NumberFormatException e) { // do nothing } String value = input.substring(eqPosition + 1, input.length()); if (stepDesc.getProps() == null) { stepDesc.setProps(new Properties()); } stepDesc.getProps().put(qualifier, value); out.println("\tAdded property: " + qualifier + " = " + value); } else { out.println(MSG_NO_VALID_PROP); } return (true); } else { return (false); } } }