/* | |
* 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.pear.tools; | |
import java.io.BufferedInputStream; | |
import java.io.BufferedOutputStream; | |
import java.io.File; | |
import java.io.FileInputStream; | |
import java.io.FileNotFoundException; | |
import java.io.FileOutputStream; | |
import java.io.IOException; | |
import java.util.Enumeration; | |
import java.util.Properties; | |
import java.util.zip.ZipEntry; | |
import java.util.zip.ZipOutputStream; | |
import org.apache.uima.UIMAFramework; | |
import org.apache.uima.internal.util.I18nUtil; | |
import org.apache.uima.resource.RelativePathResolver; | |
import org.apache.uima.util.Level; | |
/** | |
* Utility class to generate a pear package. | |
* | |
*/ | |
public class PackageCreator { | |
private static final String PEAR_MESSAGE_RESOURCE_BUNDLE = "org.apache.uima.pear.pear_messages"; | |
/** | |
* Default method to generate a pear package. With the given information first the installation | |
* descriptor is created and then the pear package is built. | |
* | |
* @param componentID | |
* Specify a componentID for this component | |
* | |
* @param mainComponentDesc | |
* Specify the main component descriptor path that is used to start the component. The | |
* path must be specified relative to the <code>mainComponentDir</code> parameter. | |
* | |
* @param classpath | |
* Specify the classpath for this component. Use macros like <code>$main_root</code> to | |
* specify the classpath entries. | |
* | |
* @param datapath | |
* Specify the datapath for this component. Use macros like <code>$main_root</code> to | |
* specify the datapath entiies. | |
* | |
* @param mainComponentDir | |
* Specify the main component root directory that contains all the resources for the | |
* component. The mainComponentDir is packaged to the pear file. | |
* | |
* @param targetDir | |
* Specify the target directory where the generated pear file is written to. | |
* | |
* @param envVars | |
* Specify additional environment variables for the pear component. May also use macros | |
* like <code>$main_root</code> to specify the key values if necessary. | |
* | |
* @throws PackageCreatorException | |
* if an error occurs while create the pear package | |
*/ | |
public static void generatePearPackage(String componentID, String mainComponentDesc, | |
String classpath, String datapath, String mainComponentDir, String targetDir, | |
Properties envVars) throws PackageCreatorException { | |
// create installation descriptor | |
createInstallDescriptor(componentID, mainComponentDesc, classpath, datapath, mainComponentDir, | |
envVars); | |
// packagee pear file | |
createPearPackage(componentID, mainComponentDir, targetDir); | |
} | |
/** | |
* Creates the installation descriptor with the given information and save it in the metadata | |
* folder of the <code>mainComponentDir</code>. | |
* | |
* @param componentID | |
* Specify a componentID for this component | |
* | |
* @param mainComponentDesc | |
* Specify the main component descriptor path that is used to start the component. The | |
* path must be specified relative to the <code>mainComponentDir</code> parameter. | |
* | |
* @param classpath | |
* Specify the classpath for this component. Use macros like <code>$main_root</code> to | |
* specify the classpath entries. | |
* | |
* @param datapath | |
* Specify the datapath for this component. Use macros like <code>$main_root</code> to | |
* specify the datapath entiies. | |
* | |
* @param mainComponentDir | |
* Specify the main component root directory that contains all the resources for the | |
* component. The mainComponentDir is packaged to the pear file. | |
* | |
* @param envVars | |
* Specify additional environment variables for the pear component. May also use macros | |
* like <code>$main_root</code> to specify the key values if necessary. | |
* | |
* @throws PackageCreatorException | |
* if an error occurs while creating the installation descriptor | |
* | |
* @return Path to the created installation descriptor. | |
*/ | |
public static String createInstallDescriptor(String componentID, String mainComponentDesc, | |
String classpath, String datapath, String mainComponentDir, Properties envVars) | |
throws PackageCreatorException { | |
//installation descriptor file path | |
String installationDesc = null; | |
// create new install descriptor | |
InstallationDescriptor insd = new InstallationDescriptor(); | |
// set main component ID | |
insd.setMainComponent(componentID); | |
// set main component descriptor and add $main_root macro | |
insd.setMainComponentDesc(addMacro(mainComponentDesc)); | |
// set Operation system where it was packaged | |
insd.clearOSSpecs(); | |
insd.addOSSpec(InstallationDescriptorHandler.NAME_TAG, System.getProperty("os.name")); | |
// set Java version where is was packaged | |
insd.clearToolkitsSpecs(); | |
insd.addToolkitsSpec(InstallationDescriptorHandler.JDK_VERSION_TAG, System | |
.getProperty("java.version")); | |
// add classpath setting to the installation descriptor | |
if (classpath != null) { | |
// classpath setting should use ";" as separator | |
if (classpath.indexOf(":") != -1) { | |
// log warning that ";" as separator should be used. | |
UIMAFramework.getLogger(PackageCreator.class).logrb(Level.WARNING, "PackageCreator", | |
"createInstallDescriptor", PEAR_MESSAGE_RESOURCE_BUNDLE, | |
"package_creator_classpath_not_valid_warning"); | |
} | |
InstallationDescriptor.ActionInfo actionInfo = new InstallationDescriptor.ActionInfo( | |
InstallationDescriptor.ActionInfo.SET_ENV_VARIABLE_ACT); | |
actionInfo.params.put(InstallationDescriptorHandler.VAR_NAME_TAG, | |
InstallationController.CLASSPATH_VAR); | |
actionInfo.params.put(InstallationDescriptorHandler.VAR_VALUE_TAG, classpath); | |
String commentMessage = I18nUtil.localizeMessage(PEAR_MESSAGE_RESOURCE_BUNDLE, | |
"package_creator_env_setting", new Object[] { InstallationController.CLASSPATH_VAR }); | |
actionInfo.params.put(InstallationDescriptorHandler.COMMENTS_TAG, commentMessage); | |
insd.addInstallationAction(actionInfo); | |
} | |
// add datapath settings to the installation descriptor | |
if (datapath != null) { | |
// datapath setting should use ";" as separator | |
if (datapath.indexOf(":") != -1) { | |
// log warning that ";" as separator should be used. | |
UIMAFramework.getLogger(PackageCreator.class).logrb(Level.WARNING, "PackageCreator", | |
"createInstallDescriptor", PEAR_MESSAGE_RESOURCE_BUNDLE, | |
"package_creator_datapath_not_valid_warning"); | |
} | |
InstallationDescriptor.ActionInfo actionInfo = new InstallationDescriptor.ActionInfo( | |
InstallationDescriptor.ActionInfo.SET_ENV_VARIABLE_ACT); | |
actionInfo.params.put(InstallationDescriptorHandler.VAR_NAME_TAG, | |
RelativePathResolver.UIMA_DATAPATH_PROP); | |
actionInfo.params.put(InstallationDescriptorHandler.VAR_VALUE_TAG, datapath); | |
String commentMessage = I18nUtil.localizeMessage(PEAR_MESSAGE_RESOURCE_BUNDLE, | |
"package_creator_env_setting", | |
new Object[] { RelativePathResolver.UIMA_DATAPATH_PROP }); | |
actionInfo.params.put(InstallationDescriptorHandler.COMMENTS_TAG, commentMessage); | |
insd.addInstallationAction(actionInfo); | |
} | |
// set additional environment variables | |
if (envVars != null) { | |
Enumeration keys = envVars.keys(); | |
while (keys.hasMoreElements()) { | |
InstallationDescriptor.ActionInfo actionInfo = new InstallationDescriptor.ActionInfo( | |
InstallationDescriptor.ActionInfo.SET_ENV_VARIABLE_ACT); | |
String key = (String) keys.nextElement(); | |
actionInfo.params.put(InstallationDescriptorHandler.VAR_NAME_TAG, key); | |
actionInfo.params | |
.put(InstallationDescriptorHandler.VAR_VALUE_TAG, envVars.getProperty(key)); | |
String commentMessage = I18nUtil.localizeMessage(PEAR_MESSAGE_RESOURCE_BUNDLE, | |
"package_creator_env_setting", new Object[] { key }); | |
actionInfo.params.put(InstallationDescriptorHandler.COMMENTS_TAG, commentMessage); | |
insd.addInstallationAction(actionInfo); | |
} | |
} | |
// save descriptor to metadata directory in the file system | |
try { | |
File metaDataDir = new File(mainComponentDir, InstallationController.PACKAGE_METADATA_DIR); | |
if (!metaDataDir.exists()) { | |
metaDataDir.mkdir(); | |
} | |
File installDesc = new File(mainComponentDir, InstallationProcessor.INSD_FILE_PATH); | |
InstallationDescriptorHandler.saveInstallationDescriptor(insd, installDesc); | |
UIMAFramework.getLogger(PackageCreator.class).logrb(Level.INFO, "PackageCreator", | |
"createInstallDescriptor", PEAR_MESSAGE_RESOURCE_BUNDLE, | |
"package_creator_install_desc_created_info", new Object[] {installDesc}); | |
//set installation descriptor file path | |
installationDesc = installDesc.getAbsolutePath(); | |
} catch (IOException ex) { | |
throw new PackageCreatorException(PEAR_MESSAGE_RESOURCE_BUNDLE, | |
"error_package_creator_creating_pear_package", new Object[] { componentID }, ex); | |
} | |
return installationDesc; | |
} | |
/** | |
* create pear package based on the given information. This method can be called if a installation | |
* descriptor is already available or generated. The method will not generate the installation | |
* descriptor if it is not present. | |
* | |
* @param componentID | |
* Specify a componentID for this component | |
* | |
* @param mainComponentDir | |
* Specify the main component root directory that contains all the resources for the | |
* component. The mainComponentDir is packaged to the pear file. | |
* | |
* @param targetDir | |
* Specify the target directory where the generated pear file is written to. | |
* | |
* @throws PackageCreatorException | |
* if the pear package can not be created successfully. | |
* | |
* @return Retuns path absolute path to the created pear package. | |
*/ | |
public static String createPearPackage(String componentID, String mainComponentDir, String targetDir) | |
throws PackageCreatorException { | |
// package pear file with all data from the mainComponentDir | |
ZipOutputStream zipFile; | |
File pearFile; | |
try { | |
pearFile = new File(targetDir, componentID + ".pear"); | |
zipFile = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(pearFile))); | |
File mainDir = new File(mainComponentDir); | |
zipDirectory(componentID, mainDir.getAbsolutePath(), mainDir, zipFile); | |
zipFile.close(); | |
UIMAFramework.getLogger(PackageCreator.class).logrb(Level.INFO, "PackageCreator", | |
"createInstallDescriptor", PEAR_MESSAGE_RESOURCE_BUNDLE, | |
"package_creator_pear_created_info", new Object[] {pearFile}); | |
} catch (FileNotFoundException ex) { | |
throw new PackageCreatorException(PEAR_MESSAGE_RESOURCE_BUNDLE, | |
"error_package_creator_creating_pear_package", new Object[] { componentID }, ex); | |
} catch (IOException ex) { | |
throw new PackageCreatorException(PEAR_MESSAGE_RESOURCE_BUNDLE, | |
"error_package_creator_creating_pear_package", new Object[] { componentID }, ex); | |
} | |
return pearFile.getAbsolutePath(); | |
} | |
/** | |
* adds the $main_root/ macro as a prefix to the given string | |
* | |
* @param s | |
* a String representing a relative path to the project root | |
* @return The String with the macro | |
*/ | |
private static String addMacro(String s) { | |
String macro = "$main_root"; | |
if (s == null || s.length() == 0) | |
return ""; | |
else { | |
if (s.startsWith("/") || s.startsWith("\\")) | |
s = macro + s; | |
else | |
s = macro + File.separator + s; | |
return s; | |
} | |
} | |
/** | |
* returns a postfix path of the <code>currendPath</code> based on the <code>mainDir</code> | |
* prefix. | |
* | |
* @param mainDir | |
* Main directory - this prefix is cut from the <code>currentPath</code> | |
* | |
* @param currentPath | |
* a Path element that has the <code>mainDir</code> as prefix. | |
* | |
* @return returns the postfix of the <code>currendPath</code> based on the <code>mainDir</code> | |
* prefix. | |
*/ | |
private static String getRelativePath(String mainDir, File currentPath) { | |
int prefixLength = mainDir.length(); | |
return currentPath.getAbsolutePath().substring(prefixLength + 1); | |
} | |
/** | |
* adds recursivly all files and directories based on the source directory to the | |
* <code>ZipOutputStream</code>. | |
* | |
* @param componentID | |
* componentID of the pear package. | |
* | |
* @param mainDir | |
* Main directory path that should be zipped. | |
* | |
* @param sourceDir | |
* Source directory that should be zipped. | |
* | |
* @param zipOut | |
* zip file output stream | |
* | |
* @throws PackageCreatorException | |
* if an error occurs while adding the file and directories to the zip file. | |
*/ | |
private static void zipDirectory(String componentID, String mainDir, File sourceDir, | |
ZipOutputStream zipOut) throws PackageCreatorException { | |
if (!sourceDir.isDirectory()) { | |
throw new PackageCreatorException(PEAR_MESSAGE_RESOURCE_BUNDLE, | |
"error_package_creator_invalid_directory", | |
new Object[] { sourceDir.getAbsolutePath() }); | |
} | |
try { | |
// get all files and directories of the sourceDir | |
String[] fileList = sourceDir.list(); | |
byte[] buffer = new byte[5120]; | |
File current = null; | |
ZipEntry currentEntry = null; | |
BufferedInputStream bufIn = null; | |
// loop over all enties and zip them in case of files, for directories, recursivly call | |
// zipDirectory() | |
for (int i = 0; i < fileList.length; i++) { | |
current = new File(sourceDir, fileList[i]); | |
if (current.isDirectory()) { | |
// if the current file is a directory, recursivly call zipDirectory() | |
zipDirectory(componentID, mainDir, current, zipOut); | |
continue; | |
} else { | |
// crate zip entry | |
String path = getRelativePath(mainDir, current); | |
path = path.replaceAll("\\\\", "/"); | |
currentEntry = new ZipEntry(path); | |
zipOut.putNextEntry(currentEntry); | |
// add file content to zip | |
bufIn = new BufferedInputStream(new FileInputStream(current)); | |
int bytesRead = -1; | |
while ((bytesRead = bufIn.read(buffer)) != -1) { | |
zipOut.write(buffer, 0, bytesRead); | |
} | |
bufIn.close(); | |
zipOut.closeEntry(); | |
} | |
} | |
} catch (IOException ex) { | |
throw new PackageCreatorException(PEAR_MESSAGE_RESOURCE_BUNDLE, | |
"error_package_creator_creating_pear_package", new Object[] { componentID }, ex); | |
} | |
} | |
} |