blob: cbdb33547c06b93512ba78f3d6ff1668ba47b8e1 [file] [log] [blame]
/*
* 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<Object> 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);
}
}
}