You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by sc...@apache.org on 2007/01/09 23:30:39 UTC

svn commit: r494631 - in /incubator/uima/uimaj/trunk/uimaj-tools/src: main/java/org/apache/uima/tools/pear/merger/ test/java/org/apache/uima/tools/pear/merger/

Author: schor
Date: Tue Jan  9 14:30:39 2007
New Revision: 494631

URL: http://svn.apache.org/viewvc?view=rev&rev=494631
Log:
UIMA-94 remove -ae flag

Modified:
    incubator/uima/uimaj/trunk/uimaj-tools/src/main/java/org/apache/uima/tools/pear/merger/PMController.java
    incubator/uima/uimaj/trunk/uimaj-tools/src/main/java/org/apache/uima/tools/pear/merger/PMUimaAgent.java
    incubator/uima/uimaj/trunk/uimaj-tools/src/test/java/org/apache/uima/tools/pear/merger/PearMergerTest.java

Modified: incubator/uima/uimaj/trunk/uimaj-tools/src/main/java/org/apache/uima/tools/pear/merger/PMController.java
URL: http://svn.apache.org/viewvc/incubator/uima/uimaj/trunk/uimaj-tools/src/main/java/org/apache/uima/tools/pear/merger/PMController.java?view=diff&rev=494631&r1=494630&r2=494631
==============================================================================
--- incubator/uima/uimaj/trunk/uimaj-tools/src/main/java/org/apache/uima/tools/pear/merger/PMController.java (original)
+++ incubator/uima/uimaj/trunk/uimaj-tools/src/main/java/org/apache/uima/tools/pear/merger/PMController.java Tue Jan  9 14:30:39 2007
@@ -1,480 +1,458 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.apache.uima.tools.pear.merger;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.jar.JarFile;
-import java.util.logging.FileHandler;
-import java.util.logging.Handler;
-import java.util.logging.Level;
-import java.util.logging.LogRecord;
-import java.util.logging.Logger;
-import java.util.logging.SimpleFormatter;
-
-import org.apache.uima.analysis_engine.AnalysisEngineDescription;
-import org.apache.uima.pear.tools.InstallationDescriptor;
-import org.apache.uima.pear.tools.PackageBrowser;
-import org.apache.uima.pear.util.FileUtil;
-
-/**
- * The <code>PMController</code> class allows to merge several input PEAR files in one PEAR file
- * and generate an aggregate component from the components encapsulated in the input PEARs.
- * 
- * @see org.apache.uima.tools.pear.merger.PMControllerHelper
- * @see org.apache.uima.tools.pear.merger.PMUimaAgent
- */
-
-public class PMController {
-  // utility name
-  static final String PEAR_MERGER = "PEAR Merger";
-
-  // log file name
-  static final String LOG_FILE = "pm.log";
-
-  // command line argument names
-  static final String AGGREGATE_NAME_ARG = "-n";
-
-  static final String AGGREGATE_PEAR_FILE_ARG = "-f";
-
-  static final String AE_MODE_FLAG = "-ae";
-
-  // command line parameters
-  private static File[] __pearFiles = null;
-
-  private static String __aggregateName = null;
-
-  private static File __aggregatePearFile = null;
-
-  private static boolean __aeModeFlag = false;
-
-  /**
-   * The <code>PMLogFormatter</code> class formats messages for the log file.
-   */
-  static class PMLogFormatter extends SimpleFormatter {
-    private boolean _firstTime = true;
-
-    public String format(LogRecord record) {
-      if (_firstTime) {
-        // 1st time - print with header
-        _firstTime = false;
-        record.setSourceMethodName("");
-        return super.format(record);
-      } else {
-        // print level: message
-        StringBuffer buffer = new StringBuffer();
-        buffer.append(record.getLevel());
-        String message = record.getMessage();
-        // for multi-line msg - start msg in new line
-        if (message.indexOf('\n') >= 0)
-          buffer.append(": \n");
-        else
-          // for single line msg - start msg in the same line
-          buffer.append(": ");
-        buffer.append(record.getMessage());
-        buffer.append('\n');
-        return buffer.toString();
-      }
-    }
-  }
-
-  // static attributes
-  private static Logger __logger = null;
-
-  private static boolean __logFileEnabled = false;
-  // static Logger initialization
-  static {
-    // create default logger
-    __logger = Logger.getLogger(PMController.class.getName());
-    __logger.setUseParentHandlers(false);
-  }
-
-  // internal attributes
-  private File[] _inpPearFiles = null;
-
-  private String _outAggCompName = null;
-
-  private File _outAggPearFile = null;
-
-  private File _tempWorkDir = null;
-
-  private File _outAggRootDir = null;
-
-  private File[] _outDlgRootDirs = null;
-
-  private InstallationDescriptor[] _dlgInstDescs = null;
-
-  private InstallationDescriptor _outAggInstDesc = null;
-
-  private boolean _aeModeEnabled = false;
-
-  /**
-   * The command line application entry point. This method expects the following command line
-   * arguments:
-   * <ul>
-   * <li>pear_file_1 ... pear_file_n - input PEAR files (required)</li>
-   * <li>-n agg_name - a name of the output aggregate component (required) </li>
-   * <li>-f agg_pear_file - output aggregate PEAR file (optional). <br />
-   * If the output PEAR file is not specified, the default output PEAR file is created in the
-   * current working directory.</li>
-   * <li>-ae analysis engine mode flag (optional). If this flag is specified, the utility creates
-   * aggregate analysis engine descriptor, otherwise (by default) it creates more specific text
-   * analysis engine descriptor.</li>
-   * </ul>
-   * 
-   * @param args
-   *          pear_file_1 ... pear_file_n -n agg_name [-f agg_pear_file] [-ae]
-   */
-  public static void main(String[] args) {
-    // enable log file
-    setLogFileEnabled(true);
-    // parse and validate command line
-    if (!parseCommandLine(args)) {
-      logErrorMessage(PEAR_MERGER + " terminated: command line error");
-      return;
-    }
-    PMController controller = null;
-    try {
-      // create controller object
-      controller = new PMController(__pearFiles, __aggregateName, __aggregatePearFile);
-      controller.setAeModeEnabled(__aeModeFlag);
-      // merge input PEARs and create merged aggregate PEAR file
-      if (controller.mergePears()) {
-        logInfoMessage("[" + PEAR_MERGER + "]: " + "operation completed successfully");
-      } else
-        logInfoMessage("[" + PEAR_MERGER + "]: " + "operation failed");
-    } catch (Throwable err) {
-      logErrorMessage("Error in " + PEAR_MERGER + ": " + err.toString());
-    } finally {
-      if (controller != null) {
-        try {
-          controller.cleanUp();
-        } catch (Exception e) {
-        }
-      }
-    }
-  }
-
-  /**
-   * Returns the instance of the class-specific <code>Logger</code> object.
-   * 
-   * @return The instance of the class-specific <code>Logger</code> object.
-   */
-  public static Logger getLogger() {
-    return __logger;
-  }
-
-  /**
-   * Logs a given error message to the log file and prints it to the standard error console stream.
-   * 
-   * @param message
-   *          The given error message.
-   */
-  public static void logErrorMessage(String message) {
-    if (__logFileEnabled)
-      getLogger().severe(message);
-    System.err.println(message);
-  }
-
-  /**
-   * Logs a given info message to the log file and prints it to the standard output console stream.
-   * 
-   * @param message
-   *          The given info message.
-   */
-  public static void logInfoMessage(String message) {
-    if (__logFileEnabled)
-      getLogger().info(message);
-    System.out.println(message);
-  }
-
-  /**
-   * Logs a given warning message to the log file and prints it to the standard error console
-   * stream.
-   * 
-   * @param message
-   *          The given warning message.
-   */
-  public static void logWarningMessage(String message) {
-    if (__logFileEnabled)
-      getLogger().warning(message);
-    System.err.println(message);
-  }
-
-  /**
-   * Parses and validates the command line and initializes static attributes.
-   * 
-   * @param args
-   *          The given command line arguments.
-   * @return <code>true</code>, if the command line arguments are valid, <code>false</code>
-   *         otherwise.
-   */
-  private static boolean parseCommandLine(String[] args) {
-    // verify command line args (min 4 args: p_1 p_2 -n name)
-    if (args.length < 4) {
-      logErrorMessage(PEAR_MERGER + " args: " + "pear_file_1 ... pear_file_n -n agg_name "
-              + "[-f agg_pear_file] [-ae]");
-      return false;
-    }
-    ArrayList listOfPears = new ArrayList();
-    // parse command line
-    for (int i = 0; i < args.length; i++) {
-      if (args[i].equals(AGGREGATE_NAME_ARG)) {
-        // set aggregate name
-        if (++i < args.length)
-          __aggregateName = args[i];
-      } else if (args[i].equals(AGGREGATE_PEAR_FILE_ARG)) {
-        // set aggregate PEAR file
-        if (++i < args.length)
-          __aggregatePearFile = new File(args[i]);
-      } else if (args[i].equals(AE_MODE_FLAG)) {
-        __aeModeFlag = true;
-      } else {
-        // add next input PEAR file
-        File inPear = new File(args[i]);
-        if (inPear.isFile()) {
-          // make sure this is not duplicated input file
-          for (int n = 0; n < listOfPears.size(); n++) {
-            try {
-              String fPath = ((File) listOfPears.get(n)).getCanonicalPath();
-              String inPath = inPear.getCanonicalPath();
-              if (fPath.equals(inPath)) {
-                logErrorMessage(PEAR_MERGER + " error: " + "duplicated input file " + args[i]);
-                return false;
-              }
-            } catch (IOException e) {
-              logErrorMessage(PEAR_MERGER + " error: " + e.toString());
-              return false;
-            }
-          }
-          listOfPears.add(inPear);
-        } else {
-          logErrorMessage(PEAR_MERGER + " error: " + "cannot find input file " + args[i]);
-          return false;
-        }
-      }
-    }
-    // validate command line parameters and set input files
-    if (listOfPears.size() < 2) {
-      logErrorMessage(PEAR_MERGER + " error: " + "input PEAR files not specified");
-      return false;
-    } else {
-      __pearFiles = new File[listOfPears.size()];
-      listOfPears.toArray(__pearFiles);
-    }
-    if (__aggregateName == null) {
-      logErrorMessage(PEAR_MERGER + " error: " + "output aggregate name not specified");
-      return false;
-    }
-    return true;
-  }
-
-  /**
-   * Enables/disables PM log file. By default, the log file is disabled.
-   * 
-   * @param enable
-   *          if <code>true</code>, the log file is enabled, otherwise it is disabled.
-   */
-  public static void setLogFileEnabled(boolean enable) {
-    if (enable) {
-      Handler[] handlers = getLogger().getHandlers();
-      if (handlers == null || handlers.length == 0) {
-        // add default file handler
-        try {
-          FileHandler fileHandler = new FileHandler(LOG_FILE, false);
-          fileHandler.setLevel(Level.ALL);
-          fileHandler.setFormatter(new PMLogFormatter());
-          getLogger().addHandler(fileHandler);
-        } catch (Throwable err) {
-          System.err.println("Error initializing log file " + PMController.class.getName() + ": "
-                  + err.toString());
-        }
-      }
-    }
-    __logFileEnabled = enable;
-  }
-
-  /**
-   * Constructor that takes a given array of input PEAR files, a given output component name (ID)
-   * and a given output PEAR file.
-   * 
-   * @param inpPearFiles
-   *          The given array of input PEAR files.
-   * @param outCompName
-   *          The given output component name (ID).
-   * @param outPearFile
-   *          The given output PEAR file.
-   * @exception IOException
-   *              If any I/O exception occurred during initialization.
-   */
-  public PMController(File[] inpPearFiles, String outCompName, File outPearFile) throws IOException {
-    // initialize task attributes
-    _inpPearFiles = inpPearFiles;
-    _outAggCompName = outCompName;
-    _outAggPearFile = outPearFile;
-    initializeTaskAttributes();
-    // log PEAR Merger task parameters
-    logInfoMessage("[" + PEAR_MERGER + "]: task parameters =>");
-    logInfoMessage("> Input PEARs =>");
-    for (int i = 0; i < _inpPearFiles.length; i++)
-      logInfoMessage(">> " + _inpPearFiles[i].getAbsolutePath());
-    logInfoMessage("> Output PEAR =>");
-    logInfoMessage(">> Name = " + _outAggCompName);
-    logInfoMessage(">> File = " + _outAggPearFile.getAbsolutePath());
-    logInfoMessage("> Output root dir: " + _outAggRootDir.getAbsolutePath());
-  }
-
-  /**
-   * Deletes all temporary directories and files after the merging operation is completed.
-   * 
-   * @throws IOException
-   *           If an I/O exception occurred.
-   */
-  public void cleanUp() throws IOException {
-    logInfoMessage("[" + PEAR_MERGER + "]: " + "deleting temporary files");
-    FileUtil.deleteDirectory(_outAggRootDir);
-  }
-
-  /**
-   * Extracts all specified input PEARs to their corresponding folders inside the output root
-   * folder. Returns the total size (bytes) of extracted files.
-   * 
-   * @return The total size of extracted files.
-   * @throws IOException
-   *           If any I/O exception occurred during extraction.
-   */
-  private long extractInputPears() throws IOException {
-    long totalSize = 0;
-    for (int i = 0; i < _inpPearFiles.length; i++) {
-      JarFile pearFile = new JarFile(_inpPearFiles[i]);
-      totalSize += FileUtil.extractFilesFromJar(pearFile, _outDlgRootDirs[i]);
-    }
-    return totalSize;
-  }
-
-  /**
-   * Intializes the 'PEAR Merger' task attributes, based on the specified input.
-   * 
-   * @exception IOException
-   *              If any I/O exception occurred during initialization.
-   */
-  private void initializeTaskAttributes() throws IOException {
-    if (_outAggPearFile == null) // set default output file
-      _outAggPearFile = new File(_outAggCompName + ".pear");
-    // set temporary working directory
-    String userHomePath = System.getProperty("user.home");
-    _tempWorkDir = new File(userHomePath);
-    if (!_tempWorkDir.isDirectory())
-      throw new IOException(userHomePath + " directory not found");
-    // set output aggregate root directory
-    _outAggRootDir = new File(_tempWorkDir, _outAggCompName);
-    // if output aggregate root directory exists, remove it
-    if (_outAggRootDir.isDirectory()) {
-      if (!FileUtil.deleteDirectory(_outAggRootDir))
-        throw new IOException("cannot delete existing folder " + _outAggRootDir.getAbsolutePath());
-    } else if (_outAggRootDir.isFile()) {
-      if (!_outAggRootDir.delete())
-        throw new IOException("cannot delete existing file " + _outAggRootDir.getAbsolutePath());
-    }
-    // set output delegate root directories
-    _outDlgRootDirs = new File[_inpPearFiles.length];
-    for (int i = 0; i < _outDlgRootDirs.length; i++) {
-      String fileName = _inpPearFiles[i].getName();
-      String sdirName = fileName.substring(0, fileName.lastIndexOf('.'));
-      _outDlgRootDirs[i] = new File(_outAggRootDir, sdirName);
-    }
-    // prepare array for delegate installation descriptors
-    _dlgInstDescs = new InstallationDescriptor[_inpPearFiles.length];
-  }
-
-  /**
-   * Merges specified input PEARs into one PEAR, which encapsulates aggregate AE that refers to
-   * input components, as delegates. Returns <code>true</code>, if the merging operation
-   * completed successfully, <code>false</code> otherwise.
-   * 
-   * @return <code>true</code>, if the merge operation completed successfully, <code>false</code>
-   *         otherwise.
-   * @throws IOException
-   *           If an I/O exception occurred during the merging operation.
-   */
-  public boolean mergePears() throws IOException {
-    boolean done = false;
-    // 1st step: extract delegate PEARs to their target dirs
-    logInfoMessage("[" + PEAR_MERGER + "]: " + "extracting delegate PEARs ...");
-    long totalSize = extractInputPears();
-    logInfoMessage("[" + PEAR_MERGER + "]: " + totalSize + " bytes extracted successfully");
-    // 2nd step: process files in delegate packages and create InsD objs
-    for (int i = 0; i < _outDlgRootDirs.length; i++) {
-      _dlgInstDescs[i] = PMControllerHelper.processDescriptors(_outDlgRootDirs[i]);
-      if (_dlgInstDescs[i] == null) {
-        logErrorMessage("[" + PEAR_MERGER + "]: " + "failed to process input package in "
-                + _outDlgRootDirs[i] + "directory");
-        break;
-      }
-    }
-    // 3rd step: generate merged package directory structure
-    File pkgDescDir = new File(_outAggRootDir, PackageBrowser.DESCRIPTORS_DIR);
-    File pkgMetadataDir = new File(_outAggRootDir, PackageBrowser.METADATA_DIR);
-    if (pkgDescDir.mkdirs() && pkgMetadataDir.mkdirs())
-      logInfoMessage("[" + PEAR_MERGER + "]: " + "created merged package directory structure");
-    else
-      throw new IOException("cannot create merged package folders");
-    // 4th step: generate aggregate component descriptor
-    File aggDescFile = new File(pkgDescDir, _outAggCompName + ".xml");
-    AnalysisEngineDescription aggDescription = PMUimaAgent.createAggregateDescription(
-            _outAggCompName, _outAggRootDir, _dlgInstDescs, _aeModeEnabled);
-    if (aggDescription != null) {
-      PMUimaAgent.saveAggregateDescription(aggDescription, aggDescFile);
-      logInfoMessage("[" + PEAR_MERGER + "]: " + "generated aggregate component descriptor");
-      if (System.getProperty("DEBUG") != null)
-        logInfoMessage(PMUimaAgent.toXmlString(aggDescription));
-    } else
-      throw new IOException("cannot generate aggregate component descriptor");
-    // 5th step: generate merged installation descriptor
-    _outAggInstDesc = PMControllerHelper.generateMergedInstallationDescriptor(_outAggRootDir,
-            _outAggCompName, aggDescFile, _dlgInstDescs, _outDlgRootDirs);
-    if (_outAggInstDesc != null) {
-      logInfoMessage("[" + PEAR_MERGER + "]: "
-              + "generated aggregate package installation descriptor");
-      if (System.getProperty("DEBUG") != null)
-        logInfoMessage(_outAggInstDesc.toString());
-      // 6th step: create merged PEAR file
-      File outPearFile = FileUtil.zipDirectory(_outAggRootDir, _outAggPearFile);
-      logInfoMessage("[" + PEAR_MERGER + "]: " + "created output aggregate PEAR file - "
-              + outPearFile.getAbsolutePath());
-      done = true;
-    }
-    return done;
-  }
-
-  /**
-   * Enables or disables AE mode for the next merging operation. If the AE mode is enabled, the
-   * merger creates AE output descriptor, instead of a more specific TAE descriptor. <br />
-   * Note: by default, the TAE mode is used.
-   * 
-   * @param aeModeFlag
-   *          If <code>true</code>, the AE mode is enabled, otherwise the default (TAE) mode is
-   *          used.
-   */
-  public void setAeModeEnabled(boolean aeModeFlag) {
-    _aeModeEnabled = aeModeFlag;
-  }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.uima.tools.pear.merger;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.jar.JarFile;
+import java.util.logging.FileHandler;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
+import java.util.logging.Logger;
+import java.util.logging.SimpleFormatter;
+
+import org.apache.uima.analysis_engine.AnalysisEngineDescription;
+import org.apache.uima.pear.tools.InstallationDescriptor;
+import org.apache.uima.pear.tools.PackageBrowser;
+import org.apache.uima.pear.util.FileUtil;
+
+/**
+ * The <code>PMController</code> class allows to merge several input PEAR files in one PEAR file
+ * and generate an aggregate analysis engine from the components encapsulated in the input PEARs.
+ * 
+ * @see org.apache.uima.tools.pear.merger.PMControllerHelper
+ * @see org.apache.uima.tools.pear.merger.PMUimaAgent
+ */
+
+public class PMController {
+  // utility name
+  static final String PEAR_MERGER = "PEAR Merger";
+
+  // log file name
+  static final String LOG_FILE = "pm.log";
+
+  // command line argument names
+  static final String AGGREGATE_NAME_ARG = "-n";
+
+  static final String AGGREGATE_PEAR_FILE_ARG = "-f";
+  
+  // command line parameters
+  private static File[] __pearFiles = null;
+
+  private static String __aggregateName = null;
+
+  private static File __aggregatePearFile = null;
+
+  /**
+   * The <code>PMLogFormatter</code> class formats messages for the log file.
+   */
+  static class PMLogFormatter extends SimpleFormatter {
+    private boolean _firstTime = true;
+
+    public String format(LogRecord record) {
+      if (_firstTime) {
+        // 1st time - print with header
+        _firstTime = false;
+        record.setSourceMethodName("");
+        return super.format(record);
+      } else {
+        // print level: message
+        StringBuffer buffer = new StringBuffer();
+        buffer.append(record.getLevel());
+        String message = record.getMessage();
+        // for multi-line msg - start msg in new line
+        if (message.indexOf('\n') >= 0)
+          buffer.append(": \n");
+        else
+          // for single line msg - start msg in the same line
+          buffer.append(": ");
+        buffer.append(record.getMessage());
+        buffer.append('\n');
+        return buffer.toString();
+      }
+    }
+  }
+
+  // static attributes
+  private static Logger __logger = null;
+
+  private static boolean __logFileEnabled = false;
+  // static Logger initialization
+  static {
+    // create default logger
+    __logger = Logger.getLogger(PMController.class.getName());
+    __logger.setUseParentHandlers(false);
+  }
+
+  // internal attributes
+  private File[] _inpPearFiles = null;
+
+  private String _outAggCompName = null;
+
+  private File _outAggPearFile = null;
+
+  private File _tempWorkDir = null;
+
+  private File _outAggRootDir = null;
+
+  private File[] _outDlgRootDirs = null;
+
+  private InstallationDescriptor[] _dlgInstDescs = null;
+
+  private InstallationDescriptor _outAggInstDesc = null;
+
+  /**
+   * The command line application entry point. This method expects the following command line
+   * arguments:
+   * <ul>
+   * <li>pear_file_1 ... pear_file_n - input PEAR files (required)</li>
+   * <li>-n agg_name - a name of the output aggregate analysis engine (required) </li>
+   * <li>-f agg_pear_file - output aggregate PEAR file (optional). <br />
+   * If the output PEAR file is not specified, the default output PEAR file is created in the
+   * current working directory.</li>
+    * </ul>
+   * 
+   * @param args
+   *          pear_file_1 ... pear_file_n -n agg_name [-f agg_pear_file]
+   */
+  public static void main(String[] args) {
+    // enable log file
+    setLogFileEnabled(true);
+    // parse and validate command line
+    if (!parseCommandLine(args)) {
+      logErrorMessage(PEAR_MERGER + " terminated: command line error");
+      return;
+    }
+    PMController controller = null;
+    try {
+      // create controller object
+      controller = new PMController(__pearFiles, __aggregateName, __aggregatePearFile);
+      // merge input PEARs and create merged aggregate PEAR file
+      if (controller.mergePears()) {
+        logInfoMessage("[" + PEAR_MERGER + "]: " + "operation completed successfully");
+      } else
+        logInfoMessage("[" + PEAR_MERGER + "]: " + "operation failed");
+    } catch (Throwable err) {
+      logErrorMessage("Error in " + PEAR_MERGER + ": " + err.toString());
+    } finally {
+      if (controller != null) {
+        try {
+          controller.cleanUp();
+        } catch (Exception e) {
+        }
+      }
+    }
+  }
+
+  /**
+   * Returns the instance of the class-specific <code>Logger</code> object.
+   * 
+   * @return The instance of the class-specific <code>Logger</code> object.
+   */
+  public static Logger getLogger() {
+    return __logger;
+  }
+
+  /**
+   * Logs a given error message to the log file and prints it to the standard error console stream.
+   * 
+   * @param message
+   *          The given error message.
+   */
+  public static void logErrorMessage(String message) {
+    if (__logFileEnabled)
+      getLogger().severe(message);
+    System.err.println(message);
+  }
+
+  /**
+   * Logs a given info message to the log file and prints it to the standard output console stream.
+   * 
+   * @param message
+   *          The given info message.
+   */
+  public static void logInfoMessage(String message) {
+    if (__logFileEnabled)
+      getLogger().info(message);
+    System.out.println(message);
+  }
+
+  /**
+   * Logs a given warning message to the log file and prints it to the standard error console
+   * stream.
+   * 
+   * @param message
+   *          The given warning message.
+   */
+  public static void logWarningMessage(String message) {
+    if (__logFileEnabled)
+      getLogger().warning(message);
+    System.err.println(message);
+  }
+
+  /**
+   * Parses and validates the command line and initializes static attributes.
+   * 
+   * @param args
+   *          The given command line arguments.
+   * @return <code>true</code>, if the command line arguments are valid, <code>false</code>
+   *         otherwise.
+   */
+  private static boolean parseCommandLine(String[] args) {
+    // verify command line args (min 4 args: p_1 p_2 -n name)
+    if (args.length < 4) {
+      logErrorMessage(PEAR_MERGER + " args: " + "pear_file_1 ... pear_file_n -n agg_name "
+              + "[-f agg_pear_file]");
+      return false;
+    }
+    ArrayList listOfPears = new ArrayList();
+    // parse command line
+    for (int i = 0; i < args.length; i++) {
+      if (args[i].equals(AGGREGATE_NAME_ARG)) {
+        // set aggregate name
+        if (++i < args.length)
+          __aggregateName = args[i];
+      } else if (args[i].equals(AGGREGATE_PEAR_FILE_ARG)) {
+        // set aggregate PEAR file
+        if (++i < args.length)
+          __aggregatePearFile = new File(args[i]);
+      } else if (args[i].startsWith( "-" )) {
+        logErrorMessage(PEAR_MERGER + " error: " + "unknown flag '" + args[i] + "'");
+        return false;
+      } else {
+        // add next input PEAR file
+        File inPear = new File(args[i]);
+        if (inPear.isFile()) {
+          // make sure this is not duplicated input file
+          for (int n = 0; n < listOfPears.size(); n++) {
+            try {
+              String fPath = ((File) listOfPears.get(n)).getCanonicalPath();
+              String inPath = inPear.getCanonicalPath();
+              if (fPath.equals(inPath)) {
+                logErrorMessage(PEAR_MERGER + " error: " + "duplicated input file " + args[i]);
+                return false;
+              }
+            } catch (IOException e) {
+              logErrorMessage(PEAR_MERGER + " error: " + e.toString());
+              return false;
+            }
+          }
+          listOfPears.add(inPear);
+        } else {
+          logErrorMessage(PEAR_MERGER + " error: " + "cannot find input file " + args[i]);
+          return false;
+        }
+      }
+    }
+    // validate command line parameters and set input files
+    if (listOfPears.size() < 2) {
+      logErrorMessage(PEAR_MERGER + " error: " + "input PEAR files not specified");
+      return false;
+    } else {
+      __pearFiles = new File[listOfPears.size()];
+      listOfPears.toArray(__pearFiles);
+    }
+    if (__aggregateName == null) {
+      logErrorMessage(PEAR_MERGER + " error: " + "output aggregate name not specified");
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Enables/disables PM log file. By default, the log file is disabled.
+   * 
+   * @param enable
+   *          if <code>true</code>, the log file is enabled, otherwise it is disabled.
+   */
+  public static void setLogFileEnabled(boolean enable) {
+    if (enable) {
+      Handler[] handlers = getLogger().getHandlers();
+      if (handlers == null || handlers.length == 0) {
+        // add default file handler
+        try {
+          FileHandler fileHandler = new FileHandler(LOG_FILE, false);
+          fileHandler.setLevel(Level.ALL);
+          fileHandler.setFormatter(new PMLogFormatter());
+          getLogger().addHandler(fileHandler);
+        } catch (Throwable err) {
+          System.err.println("Error initializing log file " + PMController.class.getName() + ": "
+                  + err.toString());
+        }
+      }
+    }
+    __logFileEnabled = enable;
+  }
+
+  /**
+   * Constructor that takes a given array of input PEAR files, a given output component name (ID)
+   * and a given output PEAR file.
+   * 
+   * @param inpPearFiles
+   *          The given array of input PEAR files.
+   * @param outCompName
+   *          The given output component name (ID).
+   * @param outPearFile
+   *          The given output PEAR file.
+   * @exception IOException
+   *              If any I/O exception occurred during initialization.
+   */
+  public PMController(File[] inpPearFiles, String outCompName, File outPearFile) throws IOException {
+    // initialize task attributes
+    _inpPearFiles = inpPearFiles;
+    _outAggCompName = outCompName;
+    _outAggPearFile = outPearFile;
+    initializeTaskAttributes();
+    // log PEAR Merger task parameters
+    logInfoMessage("[" + PEAR_MERGER + "]: task parameters =>");
+    logInfoMessage("> Input PEARs =>");
+    for (int i = 0; i < _inpPearFiles.length; i++)
+      logInfoMessage(">> " + _inpPearFiles[i].getAbsolutePath());
+    logInfoMessage("> Output PEAR =>");
+    logInfoMessage(">> Name = " + _outAggCompName);
+    logInfoMessage(">> File = " + _outAggPearFile.getAbsolutePath());
+    logInfoMessage("> Output root dir: " + _outAggRootDir.getAbsolutePath());
+  }
+
+  /**
+   * Deletes all temporary directories and files after the merging operation is completed.
+   * 
+   * @throws IOException
+   *           If an I/O exception occurred.
+   */
+  public void cleanUp() throws IOException {
+    logInfoMessage("[" + PEAR_MERGER + "]: " + "deleting temporary files");
+    FileUtil.deleteDirectory(_outAggRootDir);
+  }
+
+  /**
+   * Extracts all specified input PEARs to their corresponding folders inside the output root
+   * folder. Returns the total size (bytes) of extracted files.
+   * 
+   * @return The total size of extracted files.
+   * @throws IOException
+   *           If any I/O exception occurred during extraction.
+   */
+  private long extractInputPears() throws IOException {
+    long totalSize = 0;
+    for (int i = 0; i < _inpPearFiles.length; i++) {
+      JarFile pearFile = new JarFile(_inpPearFiles[i]);
+      totalSize += FileUtil.extractFilesFromJar(pearFile, _outDlgRootDirs[i]);
+    }
+    return totalSize;
+  }
+
+  /**
+   * Intializes the 'PEAR Merger' task attributes, based on the specified input.
+   * 
+   * @exception IOException
+   *              If any I/O exception occurred during initialization.
+   */
+  private void initializeTaskAttributes() throws IOException {
+    if (_outAggPearFile == null) // set default output file
+      _outAggPearFile = new File(_outAggCompName + ".pear");
+    // set temporary working directory
+    String userHomePath = System.getProperty("user.home");
+    _tempWorkDir = new File(userHomePath);
+    if (!_tempWorkDir.isDirectory())
+      throw new IOException(userHomePath + " directory not found");
+    // set output aggregate root directory
+    _outAggRootDir = new File(_tempWorkDir, _outAggCompName);
+    // if output aggregate root directory exists, remove it
+    if (_outAggRootDir.isDirectory()) {
+      if (!FileUtil.deleteDirectory(_outAggRootDir))
+        throw new IOException("cannot delete existing folder " + _outAggRootDir.getAbsolutePath());
+    } else if (_outAggRootDir.isFile()) {
+      if (!_outAggRootDir.delete())
+        throw new IOException("cannot delete existing file " + _outAggRootDir.getAbsolutePath());
+    }
+    // set output delegate root directories
+    _outDlgRootDirs = new File[_inpPearFiles.length];
+    for (int i = 0; i < _outDlgRootDirs.length; i++) {
+      String fileName = _inpPearFiles[i].getName();
+      String sdirName = fileName.substring(0, fileName.lastIndexOf('.'));
+      _outDlgRootDirs[i] = new File(_outAggRootDir, sdirName);
+    }
+    // prepare array for delegate installation descriptors
+    _dlgInstDescs = new InstallationDescriptor[_inpPearFiles.length];
+  }
+
+  /**
+   * Merges specified input PEARs into one PEAR, which encapsulates aggregate AE that refers to
+   * input components, as delegates. Returns <code>true</code>, if the merging operation
+   * completed successfully, <code>false</code> otherwise.
+   * 
+   * @return <code>true</code>, if the merge operation completed successfully, <code>false</code>
+   *         otherwise.
+   * @throws IOException
+   *           If an I/O exception occurred during the merging operation.
+   */
+  public boolean mergePears() throws IOException {
+    boolean done = false;
+    // 1st step: extract delegate PEARs to their target dirs
+    logInfoMessage("[" + PEAR_MERGER + "]: " + "extracting delegate PEARs ...");
+    long totalSize = extractInputPears();
+    logInfoMessage("[" + PEAR_MERGER + "]: " + totalSize + " bytes extracted successfully");
+    // 2nd step: process files in delegate packages and create InsD objs
+    for (int i = 0; i < _outDlgRootDirs.length; i++) {
+      _dlgInstDescs[i] = PMControllerHelper.processDescriptors(_outDlgRootDirs[i]);
+      if (_dlgInstDescs[i] == null) {
+        logErrorMessage("[" + PEAR_MERGER + "]: " + "failed to process input package in "
+                + _outDlgRootDirs[i] + "directory");
+        break;
+      }
+    }
+    // 3rd step: generate merged package directory structure
+    File pkgDescDir = new File(_outAggRootDir, PackageBrowser.DESCRIPTORS_DIR);
+    File pkgMetadataDir = new File(_outAggRootDir, PackageBrowser.METADATA_DIR);
+    if (pkgDescDir.mkdirs() && pkgMetadataDir.mkdirs())
+      logInfoMessage("[" + PEAR_MERGER + "]: " + "created merged package directory structure");
+    else
+      throw new IOException("cannot create merged package folders");
+    // 4th step: generate aggregate component descriptor
+    File aggDescFile = new File(pkgDescDir, _outAggCompName + ".xml");
+    AnalysisEngineDescription aggDescription = PMUimaAgent.createAggregateDescription(
+            _outAggCompName, _outAggRootDir, _dlgInstDescs);
+    if (aggDescription != null) {
+      PMUimaAgent.saveAggregateDescription(aggDescription, aggDescFile);
+      logInfoMessage("[" + PEAR_MERGER + "]: " + "generated aggregate component descriptor");
+      if (System.getProperty("DEBUG") != null)
+        logInfoMessage(PMUimaAgent.toXmlString(aggDescription));
+    } else
+      throw new IOException("cannot generate aggregate component descriptor");
+    // 5th step: generate merged installation descriptor
+    _outAggInstDesc = PMControllerHelper.generateMergedInstallationDescriptor(_outAggRootDir,
+            _outAggCompName, aggDescFile, _dlgInstDescs, _outDlgRootDirs);
+    if (_outAggInstDesc != null) {
+      logInfoMessage("[" + PEAR_MERGER + "]: "
+              + "generated aggregate package installation descriptor");
+      if (System.getProperty("DEBUG") != null)
+        logInfoMessage(_outAggInstDesc.toString());
+      // 6th step: create merged PEAR file
+      File outPearFile = FileUtil.zipDirectory(_outAggRootDir, _outAggPearFile);
+      logInfoMessage("[" + PEAR_MERGER + "]: " + "created output aggregate PEAR file - "
+              + outPearFile.getAbsolutePath());
+      done = true;
+    }
+    return done;
+  }
+}

Modified: incubator/uima/uimaj/trunk/uimaj-tools/src/main/java/org/apache/uima/tools/pear/merger/PMUimaAgent.java
URL: http://svn.apache.org/viewvc/incubator/uima/uimaj/trunk/uimaj-tools/src/main/java/org/apache/uima/tools/pear/merger/PMUimaAgent.java?view=diff&rev=494631&r1=494630&r2=494631
==============================================================================
--- incubator/uima/uimaj/trunk/uimaj-tools/src/main/java/org/apache/uima/tools/pear/merger/PMUimaAgent.java (original)
+++ incubator/uima/uimaj/trunk/uimaj-tools/src/main/java/org/apache/uima/tools/pear/merger/PMUimaAgent.java Tue Jan  9 14:30:39 2007
@@ -1,384 +1,379 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.apache.uima.tools.pear.merger;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.Iterator;
-import java.util.Map;
-
-import org.apache.uima.ResourceSpecifierFactory;
-import org.apache.uima.UIMAFramework;
-import org.apache.uima.UIMA_IllegalStateException;
-import org.apache.uima.analysis_engine.AnalysisEngineDescription;
-import org.apache.uima.analysis_engine.TypeOrFeature;
-import org.apache.uima.analysis_engine.metadata.AnalysisEngineMetaData;
-import org.apache.uima.analysis_engine.metadata.FixedFlow;
-import org.apache.uima.collection.CasConsumerDescription;
-import org.apache.uima.pear.tools.InstallationDescriptor;
-import org.apache.uima.pear.util.StringUtil;
-import org.apache.uima.resource.ResourceSpecifier;
-import org.apache.uima.resource.metadata.Capability;
-import org.apache.uima.resource.metadata.Import;
-import org.apache.uima.resource.metadata.OperationalProperties;
-import org.apache.uima.resource.metadata.ProcessingResourceMetaData;
-import org.apache.uima.util.InvalidXMLException;
-import org.apache.uima.util.XMLInputSource;
-import org.apache.uima.util.XMLParser;
-import org.apache.uima.util.XMLizable;
-import org.xml.sax.SAXException;
-
-/**
- * The <code>PMUimaAgent</code> class implements UIMA-based utility methods utilized by the
- * <code>{@link PMController}</code> class. The class allows generating analysis engine descriptor
- * for output aggregate AE based on the specified input descriptors.
- */
-
-public class PMUimaAgent {
-  /**
-   * Creates UIMA aggregate component description object, based on given aggregate component name
-   * (ID), aggregate root directory and array of delegate installation descriptors. Returns the UIMA
-   * aggregate component description object. If the TAE mode is enabled, the method create TAE
-   * description object, otherwise it creates analysis engine description object.
-   * 
-   * @param aggCompName
-   *          The given aggregate component name (ID).
-   * @param aggRootDir
-   *          The given aggregate root directory.
-   * @param dlgInstDescs
-   *          The given array of delegate installation descriptors.
-   * @param aeModeEnabled
-   *          If <code>true</code>, the method creates AE description object, otherwise it
-   *          creates more specific TAE description object.
-   * @return The UIMA aggregate component description object.
-   */
-  static AnalysisEngineDescription createAggregateDescription(String aggCompName, File aggRootDir,
-          InstallationDescriptor[] dlgInstDescs, boolean aeModeEnabled) {
-    AnalysisEngineDescription aggDescription = null;
-    int lastInputNo = 0;
-    try {
-      // get UIMA resource specifier factory
-      ResourceSpecifierFactory rsFactory = UIMAFramework.getResourceSpecifierFactory();
-      // create aggregate AE description
-      aggDescription = aeModeEnabled ? rsFactory.createAnalysisEngineDescription() : rsFactory
-              .createTaeDescription();
-      aggDescription.setPrimitive(false);
-      // get Map of delegate specifiers with imports
-      Map delegatesMap = aggDescription.getDelegateAnalysisEngineSpecifiersWithImports();
-      // add delegate imports to the Map
-      for (int i = 0; i < dlgInstDescs.length; i++) {
-        // get delegate component attributes
-        InstallationDescriptor dlgInsD = dlgInstDescs[i];
-        String dlgName = dlgInsD.getMainComponentId();
-        String dlgDescPath = dlgInsD.getMainComponentDesc();
-        // create Import for delegate component
-        Import dlgImport = rsFactory.createImport();
-        // set relative delegate descriptor location
-        String dlgDescRelPath = dlgDescPath.replaceAll(PMControllerHelper.MAIN_ROOT_REGEX,
-                StringUtil.toRegExpReplacement(".."));
-        dlgImport.setLocation(dlgDescRelPath);
-        // add delegate Import to the Map
-        delegatesMap.put(dlgName, dlgImport);
-      }
-      // get AE metadata
-      AnalysisEngineMetaData aggMetadata = aggDescription.getAnalysisEngineMetaData();
-      // set AE name and textual description
-      aggMetadata.setName(aggCompName);
-      aggMetadata.setDescription("Merged aggregate component" + "(" + PMController.PEAR_MERGER
-              + ")");
-      // set fixed flow constraints
-      FixedFlow aggFixedFlow = rsFactory.createFixedFlow();
-      String[] aggFlowSpecs = new String[dlgInstDescs.length];
-      for (int i = 0; i < dlgInstDescs.length; i++)
-        aggFlowSpecs[i] = dlgInstDescs[i].getMainComponentId();
-      aggFixedFlow.setFixedFlow(aggFlowSpecs);
-      aggMetadata.setFlowConstraints(aggFixedFlow);
-      // collect capabilities & check operational props of delegates
-      ArrayList allCapabilities = new ArrayList();
-      boolean isMultipleDeploymentAllowed = true;
-      boolean modifiesCas = false;
-      for (int i = 0; i < dlgInstDescs.length; i++) {
-        lastInputNo = i + 1;
-        ResourceSpecifier dlgSpecifier = retrieveDelegateSpecifier(aggRootDir, dlgInstDescs[i]);
-        if (dlgSpecifier instanceof AnalysisEngineDescription) {
-          // get AE metadata
-          AnalysisEngineMetaData dlgAeMetadata = ((AnalysisEngineDescription) dlgSpecifier)
-                  .getAnalysisEngineMetaData();
-          // collect AE capabilities
-          Capability[] dlgCapabilities = dlgAeMetadata.getCapabilities();
-          if (dlgCapabilities != null)
-            for (int n = 0; n < dlgCapabilities.length; n++)
-              allCapabilities.add(dlgCapabilities[n]);
-          // check operational properties
-          OperationalProperties dlgOperProps = dlgAeMetadata.getOperationalProperties();
-          if (dlgOperProps != null) {
-            if (!dlgOperProps.isMultipleDeploymentAllowed())
-              isMultipleDeploymentAllowed = false;
-            if (dlgOperProps.getModifiesCas())
-              modifiesCas = true;
-          } else
-            // by default, AE modifies CAS
-            modifiesCas = true;
-        } else if (dlgSpecifier instanceof CasConsumerDescription) {
-          // get CC metadata
-          ProcessingResourceMetaData dlgCcMetadata = ((CasConsumerDescription) dlgSpecifier)
-                  .getCasConsumerMetaData();
-          // collect CC capabilities
-          Capability[] dlgCapabilities = dlgCcMetadata.getCapabilities();
-          if (dlgCapabilities != null)
-            for (int n = 0; n < dlgCapabilities.length; n++)
-              allCapabilities.add(dlgCapabilities[n]);
-          // check operational properties
-          OperationalProperties dlgOperProps = dlgCcMetadata.getOperationalProperties();
-          if (dlgOperProps != null) {
-            if (!dlgOperProps.isMultipleDeploymentAllowed())
-              isMultipleDeploymentAllowed = false;
-          }
-        } else
-          // other categories (CR, CI) are not allowed
-          throw new IllegalArgumentException("unsupported input component");
-      }
-      // merge capabilities, excluding duplicates
-      Capability[] mergedCapabilities = mergeCapabilities(allCapabilities, rsFactory);
-      // set aggregate capabilities
-      aggMetadata.setCapabilities(mergedCapabilities);
-      // set aggregate operational properties
-      OperationalProperties aggOperProps = aggMetadata.getOperationalProperties();
-      if (aggOperProps != null) {
-        aggOperProps.setMultipleDeploymentAllowed(isMultipleDeploymentAllowed);
-        aggOperProps.setModifiesCas(modifiesCas);
-      }
-    } catch (IllegalArgumentException exc) {
-      PMController.logErrorMessage("Invalid input component # " + lastInputNo);
-      PMController.logErrorMessage("IllegalArgumentException: " + exc.getMessage());
-      aggDescription = null;
-    } catch (Throwable err) {
-      if (lastInputNo > 0)
-        PMController.logErrorMessage("Error in input component # " + lastInputNo);
-      PMController.logErrorMessage(err.toString());
-      aggDescription = null;
-    } finally {
-    }
-    return aggDescription;
-  }
-
-  /**
-   * Merges source <code>Capability<code> objects specified in a given 
-   * <code>ArrayList</code>, creating one <code>Capability<code> object 
-   * that contains all non-duplicated inputs and outputs of the source 
-   * <code>Capability<code> objects. Returns an array of 
-   * <code>Capability<code> objects, containing the merged object.
-   * 
-   * @param allCapabilities The given <code>ArrayList</code> of the source 
-   * <code>Capability<code> objects.
-   * @param rsFactory The <code>ResourceSpecifierFactory</code> object 
-   * used to create new <code>Capability<code> object.
-   * @return Array of <code>Capability<code> objects, containing the merged 
-   * object.
-   */
-  private static Capability[] mergeCapabilities(ArrayList allCapabilities,
-          ResourceSpecifierFactory rsFactory) {
-    // collect all the inputs and all the outputs in 2 Hashtables
-    Hashtable mergedInputs = new Hashtable();
-    Hashtable mergedOutputs = new Hashtable();
-    Iterator allList = allCapabilities.iterator();
-    while (allList.hasNext()) {
-      Capability entry = (Capability) allList.next();
-      // get inputs/outputs for this entry
-      TypeOrFeature[] entryInps = entry.getInputs();
-      TypeOrFeature[] entryOuts = entry.getOutputs();
-      // add/merge inputs in Hashtable
-      for (int i = 0; i < entryInps.length; i++) {
-        TypeOrFeature nextTof = entryInps[i];
-        String name = nextTof.getName();
-        TypeOrFeature prevTof = (TypeOrFeature) mergedInputs.get(name);
-        if (prevTof != null) {
-          // choose next or prev, if it's 'type'
-          if (prevTof.isType()) {
-            // leave more general one
-            if (!prevTof.isAllAnnotatorFeatures() && nextTof.isAllAnnotatorFeatures())
-              mergedInputs.put(name, nextTof);
-          }
-        } else
-          // add next ToF
-          mergedInputs.put(name, nextTof);
-      }
-      // add/merge outputs in Hashtable
-      for (int i = 0; i < entryOuts.length; i++) {
-        TypeOrFeature nextTof = entryOuts[i];
-        String name = nextTof.getName();
-        TypeOrFeature prevTof = (TypeOrFeature) mergedOutputs.get(name);
-        if (prevTof != null) {
-          // choose next or prev, if it's 'type'
-          if (prevTof.isType()) {
-            // leave more general one
-            if (!prevTof.isAllAnnotatorFeatures() && nextTof.isAllAnnotatorFeatures())
-              mergedOutputs.put(name, nextTof);
-          }
-        } else
-          // add next ToF
-          mergedOutputs.put(name, nextTof);
-      }
-    }
-    // create merged Capability object and add merged inputs/outputs
-    Capability mergedCapability = rsFactory.createCapability();
-    // add merged inputs
-    Enumeration inpsList = mergedInputs.keys();
-    while (inpsList.hasMoreElements()) {
-      String name = (String) inpsList.nextElement();
-      TypeOrFeature tof = (TypeOrFeature) mergedInputs.get(name);
-      if (tof.isType())
-        mergedCapability.addInputType(name, tof.isAllAnnotatorFeatures());
-      else
-        mergedCapability.addInputFeature(name);
-    }
-    // add merged outputs
-    Enumeration outsList = mergedOutputs.keys();
-    while (outsList.hasMoreElements()) {
-      String name = (String) outsList.nextElement();
-      TypeOrFeature tof = (TypeOrFeature) mergedOutputs.get(name);
-      if (tof.isType())
-        mergedCapability.addOutputType(name, tof.isAllAnnotatorFeatures());
-      else
-        mergedCapability.addOutputFeature(name);
-    }
-    // put merged Capability in the array
-    Capability[] mergedArray = new Capability[1];
-    mergedArray[0] = mergedCapability;
-    return mergedArray;
-  }
-
-  /**
-   * Creates <code>ResourceSpecifier</code> object for a delegate component descriptor, specified
-   * by a given <code>InstallationDescriptor</code> object. Returns the delegate component
-   * <code>ResourceSpecifier</code> object.
-   * 
-   * @param aggRootDir
-   *          The given aggregate root directory.
-   * @param dlgInstDesc
-   *          The given delegate <code>InstallationDescriptor</code> object.
-   * @return The given delegate component <code>ResourceSpecifier</code> object.
-   * @throws IOException
-   *           If an I/O exception occurred while creating XML input source.
-   * @throws InvalidXMLException
-   *           If <code>ResourceSpecifier</code> object cannot be created from the specified
-   *           descriptor.
-   */
-  private static ResourceSpecifier retrieveDelegateSpecifier(File aggRootDir,
-          InstallationDescriptor dlgInstDesc) throws IOException, InvalidXMLException {
-    // get delegate desciptor path
-    String aggRootDirPath = aggRootDir.getAbsolutePath().replace('\\', '/');
-    String dlgDescPath = dlgInstDesc.getMainComponentDesc().replaceAll(
-            PMControllerHelper.MAIN_ROOT_REGEX, StringUtil.toRegExpReplacement(aggRootDirPath));
-    // parse component descriptor
-    XMLInputSource xmlSource = null;
-    ResourceSpecifier dlgSpecifier = null;
-    try {
-      xmlSource = new XMLInputSource(dlgDescPath);
-      XMLParser xmlParser = UIMAFramework.getXMLParser();
-      dlgSpecifier = xmlParser.parseResourceSpecifier(xmlSource);
-    } catch (InvalidXMLException xmlExc) {
-      String msgKey = xmlExc.getMessageKey();
-      // if msg key is INVALID_CLASS, this is TS or RR desc
-      if (InvalidXMLException.INVALID_CLASS.equals(msgKey))
-        throw new IllegalArgumentException(xmlExc.toString());
-      else
-        // otherwise, XML descriptor is not valid
-        throw xmlExc;
-    } catch (UIMA_IllegalStateException urtExc) {
-      String msgKey = urtExc.getMessageKey();
-      // if msg key is COULD_NOT_INSTANTIATE_XMLIZABLE, this is CPE desc
-      if (UIMA_IllegalStateException.COULD_NOT_INSTANTIATE_XMLIZABLE.equals(msgKey))
-        throw new IllegalArgumentException(urtExc.toString());
-      else
-        // otherwise, something is wrong
-        throw urtExc;
-    } finally {
-      if (xmlSource != null) {
-        try {
-          xmlSource.getInputStream().close();
-        } catch (Exception e) {
-        }
-      }
-    }
-    return dlgSpecifier;
-  }
-
-  /**
-   * Saves a given UIMA aggregate component desciption in a specified XML descriptor file.
-   * 
-   * @param aggDescription
-   *          The given UIMA aggregate component desciption.
-   * @param aggDescFile
-   *          The given XML descriptor file.
-   * @throws IOException
-   *           If an I/O exception occurrs.
-   */
-  static void saveAggregateDescription(AnalysisEngineDescription aggDescription, File aggDescFile)
-          throws IOException {
-    FileWriter fWriter = null;
-    try {
-      fWriter = new FileWriter(aggDescFile);
-      aggDescription.toXML(fWriter);
-    } catch (SAXException exc) {
-      throw new IOException(exc.toString());
-    } finally {
-      if (fWriter != null) {
-        try {
-          fWriter.close();
-        } catch (Exception e) {
-        }
-      }
-    }
-  }
-
-  /**
-   * Converts a given <code>XMLizable</code> object to String. This method is useful for
-   * debugging.
-   * 
-   * @param content
-   *          The given <code>XMLizable</code> object
-   * @return A String that represents the given <code>XMLizable</code> object.
-   */
-  static String toXmlString(XMLizable content) {
-    StringWriter sWriter = new StringWriter();
-    PrintWriter oWriter = null;
-    try {
-      oWriter = new PrintWriter(sWriter);
-      content.toXML(oWriter);
-      oWriter.flush();
-    } catch (Exception exc) {
-    } finally {
-      if (oWriter != null) {
-        try {
-          oWriter.close();
-        } catch (Exception e) {
-        }
-      }
-    }
-    return sWriter.toString();
-  }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.uima.tools.pear.merger;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.uima.ResourceSpecifierFactory;
+import org.apache.uima.UIMAFramework;
+import org.apache.uima.UIMA_IllegalStateException;
+import org.apache.uima.analysis_engine.AnalysisEngineDescription;
+import org.apache.uima.analysis_engine.TypeOrFeature;
+import org.apache.uima.analysis_engine.metadata.AnalysisEngineMetaData;
+import org.apache.uima.analysis_engine.metadata.FixedFlow;
+import org.apache.uima.collection.CasConsumerDescription;
+import org.apache.uima.pear.tools.InstallationDescriptor;
+import org.apache.uima.pear.util.StringUtil;
+import org.apache.uima.resource.ResourceSpecifier;
+import org.apache.uima.resource.metadata.Capability;
+import org.apache.uima.resource.metadata.Import;
+import org.apache.uima.resource.metadata.OperationalProperties;
+import org.apache.uima.resource.metadata.ProcessingResourceMetaData;
+import org.apache.uima.util.InvalidXMLException;
+import org.apache.uima.util.XMLInputSource;
+import org.apache.uima.util.XMLParser;
+import org.apache.uima.util.XMLizable;
+import org.xml.sax.SAXException;
+
+/**
+ * The <code>PMUimaAgent</code> class implements UIMA-based utility methods utilized by the
+ * <code>{@link PMController}</code> class. The class allows generating analysis engine descriptor
+ * for output aggregate AE based on the specified input descriptors.
+ */
+
+public class PMUimaAgent {
+  /**
+   * Creates UIMA aggregate analysis engine description object, based on given aggregate component name
+   * (ID), aggregate root directory and array of delegate installation descriptors. Returns the UIMA
+   * aggregate analysis engine description object. 
+   * 
+   * @param aggCompName
+   *          The given aggregate component name (ID).
+   * @param aggRootDir
+   *          The given aggregate root directory.
+   * @param dlgInstDescs
+   *          The given array of delegate installation descriptors.
+   * @return The UIMA aggregate analysis engine description object.
+   */
+  static AnalysisEngineDescription createAggregateDescription(String aggCompName, File aggRootDir,
+          InstallationDescriptor[] dlgInstDescs) {
+    AnalysisEngineDescription aggDescription = null;
+    int lastInputNo = 0;
+    try {
+      // get UIMA resource specifier factory
+      ResourceSpecifierFactory rsFactory = UIMAFramework.getResourceSpecifierFactory();
+      // create aggregate AE description
+      aggDescription = rsFactory.createAnalysisEngineDescription();
+      aggDescription.setPrimitive(false);
+      // get Map of delegate specifiers with imports
+      Map delegatesMap = aggDescription.getDelegateAnalysisEngineSpecifiersWithImports();
+      // add delegate imports to the Map
+      for (int i = 0; i < dlgInstDescs.length; i++) {
+        // get delegate component attributes
+        InstallationDescriptor dlgInsD = dlgInstDescs[i];
+        String dlgName = dlgInsD.getMainComponentId();
+        String dlgDescPath = dlgInsD.getMainComponentDesc();
+        // create Import for delegate component
+        Import dlgImport = rsFactory.createImport();
+        // set relative delegate descriptor location
+        String dlgDescRelPath = dlgDescPath.replaceAll(PMControllerHelper.MAIN_ROOT_REGEX,
+                StringUtil.toRegExpReplacement(".."));
+        dlgImport.setLocation(dlgDescRelPath);
+        // add delegate Import to the Map
+        delegatesMap.put(dlgName, dlgImport);
+      }
+      // get AE metadata
+      AnalysisEngineMetaData aggMetadata = aggDescription.getAnalysisEngineMetaData();
+      // set AE name and textual description
+      aggMetadata.setName(aggCompName);
+      aggMetadata.setDescription("Merged aggregate component" + "(" + PMController.PEAR_MERGER
+              + ")");
+      // set fixed flow constraints
+      FixedFlow aggFixedFlow = rsFactory.createFixedFlow();
+      String[] aggFlowSpecs = new String[dlgInstDescs.length];
+      for (int i = 0; i < dlgInstDescs.length; i++)
+        aggFlowSpecs[i] = dlgInstDescs[i].getMainComponentId();
+      aggFixedFlow.setFixedFlow(aggFlowSpecs);
+      aggMetadata.setFlowConstraints(aggFixedFlow);
+      // collect capabilities & check operational props of delegates
+      ArrayList allCapabilities = new ArrayList();
+      boolean isMultipleDeploymentAllowed = true;
+      boolean modifiesCas = false;
+      for (int i = 0; i < dlgInstDescs.length; i++) {
+        lastInputNo = i + 1;
+        ResourceSpecifier dlgSpecifier = retrieveDelegateSpecifier(aggRootDir, dlgInstDescs[i]);
+        if (dlgSpecifier instanceof AnalysisEngineDescription) {
+          // get AE metadata
+          AnalysisEngineMetaData dlgAeMetadata = ((AnalysisEngineDescription) dlgSpecifier)
+                  .getAnalysisEngineMetaData();
+          // collect AE capabilities
+          Capability[] dlgCapabilities = dlgAeMetadata.getCapabilities();
+          if (dlgCapabilities != null)
+            for (int n = 0; n < dlgCapabilities.length; n++)
+              allCapabilities.add(dlgCapabilities[n]);
+          // check operational properties
+          OperationalProperties dlgOperProps = dlgAeMetadata.getOperationalProperties();
+          if (dlgOperProps != null) {
+            if (!dlgOperProps.isMultipleDeploymentAllowed())
+              isMultipleDeploymentAllowed = false;
+            if (dlgOperProps.getModifiesCas())
+              modifiesCas = true;
+          } else
+            // by default, AE modifies CAS
+            modifiesCas = true;
+        } else if (dlgSpecifier instanceof CasConsumerDescription) {
+          // get CC metadata
+          ProcessingResourceMetaData dlgCcMetadata = ((CasConsumerDescription) dlgSpecifier)
+                  .getCasConsumerMetaData();
+          // collect CC capabilities
+          Capability[] dlgCapabilities = dlgCcMetadata.getCapabilities();
+          if (dlgCapabilities != null)
+            for (int n = 0; n < dlgCapabilities.length; n++)
+              allCapabilities.add(dlgCapabilities[n]);
+          // check operational properties
+          OperationalProperties dlgOperProps = dlgCcMetadata.getOperationalProperties();
+          if (dlgOperProps != null) {
+            if (!dlgOperProps.isMultipleDeploymentAllowed())
+              isMultipleDeploymentAllowed = false;
+          }
+        } else
+          // other categories (CR, CI) are not allowed
+          throw new IllegalArgumentException("unsupported input component");
+      }
+      // merge capabilities, excluding duplicates
+      Capability[] mergedCapabilities = mergeCapabilities(allCapabilities, rsFactory);
+      // set aggregate capabilities
+      aggMetadata.setCapabilities(mergedCapabilities);
+      // set aggregate operational properties
+      OperationalProperties aggOperProps = aggMetadata.getOperationalProperties();
+      if (aggOperProps != null) {
+        aggOperProps.setMultipleDeploymentAllowed(isMultipleDeploymentAllowed);
+        aggOperProps.setModifiesCas(modifiesCas);
+      }
+    } catch (IllegalArgumentException exc) {
+      PMController.logErrorMessage("Invalid input component # " + lastInputNo);
+      PMController.logErrorMessage("IllegalArgumentException: " + exc.getMessage());
+      aggDescription = null;
+    } catch (Throwable err) {
+      if (lastInputNo > 0)
+        PMController.logErrorMessage("Error in input component # " + lastInputNo);
+      PMController.logErrorMessage(err.toString());
+      aggDescription = null;
+    } finally {
+    }
+    return aggDescription;
+  }
+
+  /**
+   * Merges source <code>Capability<code> objects specified in a given 
+   * <code>ArrayList</code>, creating one <code>Capability<code> object 
+   * that contains all non-duplicated inputs and outputs of the source 
+   * <code>Capability<code> objects. Returns an array of 
+   * <code>Capability<code> objects, containing the merged object.
+   * 
+   * @param allCapabilities The given <code>ArrayList</code> of the source 
+   * <code>Capability<code> objects.
+   * @param rsFactory The <code>ResourceSpecifierFactory</code> object 
+   * used to create new <code>Capability<code> object.
+   * @return Array of <code>Capability<code> objects, containing the merged 
+   * object.
+   */
+  private static Capability[] mergeCapabilities(ArrayList allCapabilities,
+          ResourceSpecifierFactory rsFactory) {
+    // collect all the inputs and all the outputs in 2 Hashtables
+    Hashtable mergedInputs = new Hashtable();
+    Hashtable mergedOutputs = new Hashtable();
+    Iterator allList = allCapabilities.iterator();
+    while (allList.hasNext()) {
+      Capability entry = (Capability) allList.next();
+      // get inputs/outputs for this entry
+      TypeOrFeature[] entryInps = entry.getInputs();
+      TypeOrFeature[] entryOuts = entry.getOutputs();
+      // add/merge inputs in Hashtable
+      for (int i = 0; i < entryInps.length; i++) {
+        TypeOrFeature nextTof = entryInps[i];
+        String name = nextTof.getName();
+        TypeOrFeature prevTof = (TypeOrFeature) mergedInputs.get(name);
+        if (prevTof != null) {
+          // choose next or prev, if it's 'type'
+          if (prevTof.isType()) {
+            // leave more general one
+            if (!prevTof.isAllAnnotatorFeatures() && nextTof.isAllAnnotatorFeatures())
+              mergedInputs.put(name, nextTof);
+          }
+        } else
+          // add next ToF
+          mergedInputs.put(name, nextTof);
+      }
+      // add/merge outputs in Hashtable
+      for (int i = 0; i < entryOuts.length; i++) {
+        TypeOrFeature nextTof = entryOuts[i];
+        String name = nextTof.getName();
+        TypeOrFeature prevTof = (TypeOrFeature) mergedOutputs.get(name);
+        if (prevTof != null) {
+          // choose next or prev, if it's 'type'
+          if (prevTof.isType()) {
+            // leave more general one
+            if (!prevTof.isAllAnnotatorFeatures() && nextTof.isAllAnnotatorFeatures())
+              mergedOutputs.put(name, nextTof);
+          }
+        } else
+          // add next ToF
+          mergedOutputs.put(name, nextTof);
+      }
+    }
+    // create merged Capability object and add merged inputs/outputs
+    Capability mergedCapability = rsFactory.createCapability();
+    // add merged inputs
+    Enumeration inpsList = mergedInputs.keys();
+    while (inpsList.hasMoreElements()) {
+      String name = (String) inpsList.nextElement();
+      TypeOrFeature tof = (TypeOrFeature) mergedInputs.get(name);
+      if (tof.isType())
+        mergedCapability.addInputType(name, tof.isAllAnnotatorFeatures());
+      else
+        mergedCapability.addInputFeature(name);
+    }
+    // add merged outputs
+    Enumeration outsList = mergedOutputs.keys();
+    while (outsList.hasMoreElements()) {
+      String name = (String) outsList.nextElement();
+      TypeOrFeature tof = (TypeOrFeature) mergedOutputs.get(name);
+      if (tof.isType())
+        mergedCapability.addOutputType(name, tof.isAllAnnotatorFeatures());
+      else
+        mergedCapability.addOutputFeature(name);
+    }
+    // put merged Capability in the array
+    Capability[] mergedArray = new Capability[1];
+    mergedArray[0] = mergedCapability;
+    return mergedArray;
+  }
+
+  /**
+   * Creates <code>ResourceSpecifier</code> object for a delegate component descriptor, specified
+   * by a given <code>InstallationDescriptor</code> object. Returns the delegate component
+   * <code>ResourceSpecifier</code> object.
+   * 
+   * @param aggRootDir
+   *          The given aggregate root directory.
+   * @param dlgInstDesc
+   *          The given delegate <code>InstallationDescriptor</code> object.
+   * @return The given delegate component <code>ResourceSpecifier</code> object.
+   * @throws IOException
+   *           If an I/O exception occurred while creating XML input source.
+   * @throws InvalidXMLException
+   *           If <code>ResourceSpecifier</code> object cannot be created from the specified
+   *           descriptor.
+   */
+  private static ResourceSpecifier retrieveDelegateSpecifier(File aggRootDir,
+          InstallationDescriptor dlgInstDesc) throws IOException, InvalidXMLException {
+    // get delegate desciptor path
+    String aggRootDirPath = aggRootDir.getAbsolutePath().replace('\\', '/');
+    String dlgDescPath = dlgInstDesc.getMainComponentDesc().replaceAll(
+            PMControllerHelper.MAIN_ROOT_REGEX, StringUtil.toRegExpReplacement(aggRootDirPath));
+    // parse component descriptor
+    XMLInputSource xmlSource = null;
+    ResourceSpecifier dlgSpecifier = null;
+    try {
+      xmlSource = new XMLInputSource(dlgDescPath);
+      XMLParser xmlParser = UIMAFramework.getXMLParser();
+      dlgSpecifier = xmlParser.parseResourceSpecifier(xmlSource);
+    } catch (InvalidXMLException xmlExc) {
+      String msgKey = xmlExc.getMessageKey();
+      // if msg key is INVALID_CLASS, this is TS or RR desc
+      if (InvalidXMLException.INVALID_CLASS.equals(msgKey))
+        throw new IllegalArgumentException(xmlExc.toString());
+      else
+        // otherwise, XML descriptor is not valid
+        throw xmlExc;
+    } catch (UIMA_IllegalStateException urtExc) {
+      String msgKey = urtExc.getMessageKey();
+      // if msg key is COULD_NOT_INSTANTIATE_XMLIZABLE, this is CPE desc
+      if (UIMA_IllegalStateException.COULD_NOT_INSTANTIATE_XMLIZABLE.equals(msgKey))
+        throw new IllegalArgumentException(urtExc.toString());
+      else
+        // otherwise, something is wrong
+        throw urtExc;
+    } finally {
+      if (xmlSource != null) {
+        try {
+          xmlSource.getInputStream().close();
+        } catch (Exception e) {
+        }
+      }
+    }
+    return dlgSpecifier;
+  }
+
+  /**
+   * Saves a given UIMA aggregate component desciption in a specified XML descriptor file.
+   * 
+   * @param aggDescription
+   *          The given UIMA aggregate component desciption.
+   * @param aggDescFile
+   *          The given XML descriptor file.
+   * @throws IOException
+   *           If an I/O exception occurrs.
+   */
+  static void saveAggregateDescription(AnalysisEngineDescription aggDescription, File aggDescFile)
+          throws IOException {
+    FileWriter fWriter = null;
+    try {
+      fWriter = new FileWriter(aggDescFile);
+      aggDescription.toXML(fWriter);
+    } catch (SAXException exc) {
+      throw new IOException(exc.toString());
+    } finally {
+      if (fWriter != null) {
+        try {
+          fWriter.close();
+        } catch (Exception e) {
+        }
+      }
+    }
+  }
+
+  /**
+   * Converts a given <code>XMLizable</code> object to String. This method is useful for
+   * debugging.
+   * 
+   * @param content
+   *          The given <code>XMLizable</code> object
+   * @return A String that represents the given <code>XMLizable</code> object.
+   */
+  static String toXmlString(XMLizable content) {
+    StringWriter sWriter = new StringWriter();
+    PrintWriter oWriter = null;
+    try {
+      oWriter = new PrintWriter(sWriter);
+      content.toXML(oWriter);
+      oWriter.flush();
+    } catch (Exception exc) {
+    } finally {
+      if (oWriter != null) {
+        try {
+          oWriter.close();
+        } catch (Exception e) {
+        }
+      }
+    }
+    return sWriter.toString();
+  }
+}

Modified: incubator/uima/uimaj/trunk/uimaj-tools/src/test/java/org/apache/uima/tools/pear/merger/PearMergerTest.java
URL: http://svn.apache.org/viewvc/incubator/uima/uimaj/trunk/uimaj-tools/src/test/java/org/apache/uima/tools/pear/merger/PearMergerTest.java?view=diff&rev=494631&r1=494630&r2=494631
==============================================================================
--- incubator/uima/uimaj/trunk/uimaj-tools/src/test/java/org/apache/uima/tools/pear/merger/PearMergerTest.java (original)
+++ incubator/uima/uimaj/trunk/uimaj-tools/src/test/java/org/apache/uima/tools/pear/merger/PearMergerTest.java Tue Jan  9 14:30:39 2007
@@ -1,137 +1,137 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.apache.uima.tools.pear.merger;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-
-import junit.framework.Assert;
-import junit.framework.TestCase;
-
-import org.apache.uima.UIMAFramework;
-import org.apache.uima.analysis_engine.TaeDescription;
-import org.apache.uima.analysis_engine.TextAnalysisEngine;
-import org.apache.uima.cas.text.TCAS;
-import org.apache.uima.pear.tools.InstallationController;
-import org.apache.uima.pear.tools.InstallationDescriptor;
-import org.apache.uima.pear.util.FileUtil;
-import org.apache.uima.resource.ResourceManager;
-import org.apache.uima.test.junit_extension.JUnitExtension;
-import org.apache.uima.util.XMLInputSource;
-import org.apache.uima.util.XMLParser;
-
-/**
- * The <code>PearMergerTest</code> class provides JUnit test cases for the jedii_pear_merger
- * component. The test cases are based on the sample input PEARs located in the
- * 'pearTests/pearMergerTests' folder.
- * 
- * @author LK
- */
-public class PearMergerTest extends TestCase {
-  // relative location of sample PEARs
-  private static String TEST_FOLDER = "pearTests/pearMergerTests";
-
-  // sample input PEAR files
-  private static String INP_PEAR_1_FILE = "uima.example.DateTime.pear";
-
-  private static String INP_PEAR_2_FILE = "uima.example.RoomNumber.pear";
-
-  // output aggregate PEAR file
-  private static String OUT_PEAR_ID = "uima.example.RoomDateTimeAggregate";
-
-  // Temporary working directory
-  private File _tempWorkingDir = null;
-
-  /**
-   * @see junit.framework.TestCase#setUp()
-   */
-  protected void setUp() throws Exception {
-    
-    // create temporary working directory
-    File tempFile = File.createTempFile("pear_merger_test_", "~tmp");
-    if (tempFile.delete()) {
-      File tempDir = tempFile;
-      if (tempDir.mkdirs())
-        _tempWorkingDir = tempDir;
-    }
-  }
-
-  /**
-   * @see junit.framework.TestCase#tearDown()
-   */
-  protected void tearDown() throws Exception {
-    if (_tempWorkingDir != null) {
-      FileUtil.deleteDirectory(_tempWorkingDir);
-    }
-  }
-  
-  /**
-   * Runs test for org.apache.uima.pear.merger.PMController class by merging 2 sample input PEARs
-   * into the output aggregate PEAR. Then, the output PEAR is installed by using
-   * org.apache.uima.pear.tools.InstallationController, and the installed component is verified by
-   * instantiating the aggregate TAE and creating TCAS object.
-   */
-  public void testPearMerger() throws Exception {
-    // check temporary working directory
-    if (_tempWorkingDir == null)
-      throw new FileNotFoundException("temp directory not found");
-    // check sample PEAR files
-    File[] inpPearFiles = new File[2];
-    inpPearFiles[0] = JUnitExtension.getFile(TEST_FOLDER + File.separator + INP_PEAR_1_FILE);
-    if (!inpPearFiles[0].isFile())
-      throw new FileNotFoundException("sample PEAR 1 not found");
-    inpPearFiles[1] = JUnitExtension.getFile(TEST_FOLDER + File.separator + INP_PEAR_2_FILE);
-    if (!inpPearFiles[1].isFile())
-      throw new FileNotFoundException("sample PEAR 2 not found");
-    // specify output aggregate PEAR file
-    File outPearFile = new File(_tempWorkingDir, OUT_PEAR_ID + ".pear");
-    // create PMController instance and perform merging operation
-    PMController.setLogFileEnabled(false);
-    PMController pmController = new PMController(inpPearFiles, OUT_PEAR_ID, outPearFile);
-    boolean done = pmController.mergePears();
-    // check merging results
-    Assert.assertTrue(done);
-    Assert.assertTrue(outPearFile.isFile());
-    // install the output PEAR file and check the results
-    InstallationController insController = new InstallationController(OUT_PEAR_ID, outPearFile,
-            _tempWorkingDir);
-    InstallationDescriptor insDesc = insController.installComponent();
-    Assert.assertTrue(insDesc != null);
-    Assert.assertTrue(OUT_PEAR_ID.equals(insDesc.getMainComponentId()));
-    // verify the installed component
-    // customize ResourceManager by adding component CLASSPATH
-    ResourceManager resMngr = UIMAFramework.newDefaultResourceManager();
-    String compClassPath = InstallationController.buildComponentClassPath(insDesc
-            .getMainComponentRoot(), insDesc);
-    // instantiate the aggregate TAE
-    resMngr.setExtensionClassPath(compClassPath, true);
-    String compDescFilePath = insDesc.getMainComponentDesc();
-    XMLParser xmlPaser = UIMAFramework.getXMLParser();
-    XMLInputSource xmlInput = new XMLInputSource(compDescFilePath);
-    TaeDescription taeSpec = xmlPaser.parseTaeDescription(xmlInput);
-    TextAnalysisEngine tae = UIMAFramework.produceTAE(taeSpec, resMngr, null);
-    Assert.assertTrue(tae != null);
-    // create TCAS object
-    TCAS tCas = tae.newTCAS();
-    Assert.assertTrue(tCas != null);
-    // clean-up the results
-    pmController.cleanUp();
-  }
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.uima.tools.pear.merger;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.uima.UIMAFramework;
+import org.apache.uima.analysis_engine.AnalysisEngine;
+import org.apache.uima.analysis_engine.AnalysisEngineDescription;
+import org.apache.uima.cas.text.TCAS;
+import org.apache.uima.pear.tools.InstallationController;
+import org.apache.uima.pear.tools.InstallationDescriptor;
+import org.apache.uima.pear.util.FileUtil;
+import org.apache.uima.resource.ResourceManager;
+import org.apache.uima.test.junit_extension.JUnitExtension;
+import org.apache.uima.util.XMLInputSource;
+import org.apache.uima.util.XMLParser;
+
+/**
+ * The <code>PearMergerTest</code> class provides JUnit test cases for the jedii_pear_merger
+ * component. The test cases are based on the sample input PEARs located in the
+ * 'pearTests/pearMergerTests' folder.
+ * 
+ * @author LK
+ */
+public class PearMergerTest extends TestCase {
+  // relative location of sample PEARs
+  private static String TEST_FOLDER = "pearTests/pearMergerTests";
+
+  // sample input PEAR files
+  private static String INP_PEAR_1_FILE = "uima.example.DateTime.pear";
+
+  private static String INP_PEAR_2_FILE = "uima.example.RoomNumber.pear";
+
+  // output aggregate PEAR file
+  private static String OUT_PEAR_ID = "uima.example.RoomDateTimeAggregate";
+
+  // Temporary working directory
+  private File _tempWorkingDir = null;
+
+  /**
+   * @see junit.framework.TestCase#setUp()
+   */
+  protected void setUp() throws Exception {
+    
+    // create temporary working directory
+    File tempFile = File.createTempFile("pear_merger_test_", "~tmp");
+    if (tempFile.delete()) {
+      File tempDir = tempFile;
+      if (tempDir.mkdirs())
+        _tempWorkingDir = tempDir;
+    }
+  }
+
+  /**
+   * @see junit.framework.TestCase#tearDown()
+   */
+  protected void tearDown() throws Exception {
+    if (_tempWorkingDir != null) {
+      FileUtil.deleteDirectory(_tempWorkingDir);
+    }
+  }
+  
+  /**
+   * Runs test for org.apache.uima.pear.merger.PMController class by merging 2 sample input PEARs
+   * into the output aggregate PEAR. Then, the output PEAR is installed by using
+   * org.apache.uima.pear.tools.InstallationController, and the installed component is verified by
+   * instantiating the aggregate TAE and creating TCAS object.
+   */
+  public void testPearMerger() throws Exception {
+    // check temporary working directory
+    if (_tempWorkingDir == null)
+      throw new FileNotFoundException("temp directory not found");
+    // check sample PEAR files
+    File[] inpPearFiles = new File[2];
+    inpPearFiles[0] = JUnitExtension.getFile(TEST_FOLDER + File.separator + INP_PEAR_1_FILE);
+    if (!inpPearFiles[0].isFile())
+      throw new FileNotFoundException("sample PEAR 1 not found");
+    inpPearFiles[1] = JUnitExtension.getFile(TEST_FOLDER + File.separator + INP_PEAR_2_FILE);
+    if (!inpPearFiles[1].isFile())
+      throw new FileNotFoundException("sample PEAR 2 not found");
+    // specify output aggregate PEAR file
+    File outPearFile = new File(_tempWorkingDir, OUT_PEAR_ID + ".pear");
+    // create PMController instance and perform merging operation
+    PMController.setLogFileEnabled(false);
+    PMController pmController = new PMController(inpPearFiles, OUT_PEAR_ID, outPearFile);
+    boolean done = pmController.mergePears();
+    // check merging results
+    Assert.assertTrue(done);
+    Assert.assertTrue(outPearFile.isFile());
+    // install the output PEAR file and check the results
+    InstallationController insController = new InstallationController(OUT_PEAR_ID, outPearFile,
+            _tempWorkingDir);
+    InstallationDescriptor insDesc = insController.installComponent();
+    Assert.assertTrue(insDesc != null);
+    Assert.assertTrue(OUT_PEAR_ID.equals(insDesc.getMainComponentId()));
+    // verify the installed component
+    // customize ResourceManager by adding component CLASSPATH
+    ResourceManager resMngr = UIMAFramework.newDefaultResourceManager();
+    String compClassPath = InstallationController.buildComponentClassPath(insDesc
+            .getMainComponentRoot(), insDesc);
+    // instantiate the aggregate AE
+    resMngr.setExtensionClassPath(compClassPath, true);
+    String compDescFilePath = insDesc.getMainComponentDesc();
+    XMLParser xmlPaser = UIMAFramework.getXMLParser();
+    XMLInputSource xmlInput = new XMLInputSource(compDescFilePath);
+    AnalysisEngineDescription aeSpec = xmlPaser.parseAnalysisEngineDescription(xmlInput);
+    AnalysisEngine ae = UIMAFramework.produceAnalysisEngine(aeSpec, resMngr, null);
+    Assert.assertTrue(ae != null);
+    // create TCAS object
+    TCAS tCas = ae.newTCAS();
+    Assert.assertTrue(tCas != null);
+    // clean-up the results
+    pmController.cleanUp();
+  }
+}