/* * Copyright (C) 2010 Brockmann Consult GmbH (info@brockmann-consult.de) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package com.bc.ceres.deploy; import com.bc.ceres.core.CoreException; import static com.bc.ceres.core.runtime.Constants.MODULE_MANIFEST_NAME; import com.bc.ceres.core.runtime.Module; import com.bc.ceres.core.runtime.internal.JarFilenameFilter; import com.bc.ceres.core.runtime.internal.ModuleReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; import java.util.logging.Logger; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; /** * Converts all module files (ZIPs and JARs) found in a given modules source directory to deployable * modules in a repository output directory. * <p/>The deployable modules are written to the repository output directory * in the following form: * <pre> * `- <repositoryDir> * `- <manifest.symbolicName>-<manifest.version>/ * |- <manifest.symbolicName>-<manifest.version>.jar * |- module.xml * |- about.html (optional) * `- LICENSE.txt (optional) * </pre> * Output modules files are named after the manifest information, * independently of the name of the source modules. */ public class DeployMain { private String[] mandatoryFilePaths = new String[]{ MODULE_MANIFEST_NAME, }; private String[] optionalFilePaths = new String[]{ "about.html", "LICENSE.txt" }; private Logger logger; private int warningCount; private int errorCount; /** * Deploys a module to a target repository directory. * * @param args {@code args[0]} is a module directory or JAR file, * {@code args[1]} is the target repository directory. */ public static void main(String[] args) { if (args.length != 2) { System.err.println("Usage: deploy <modules-dir>|<module-jar> <repository-dir>"); return; } File modulesFile = new File(args[0]); File repositoryDir = new File(args[1]); new DeployMain().run(modulesFile, repositoryDir); } private void run(File modulesFile, File repositoryDir) { logger = Logger.getLogger(System.getProperty("ceres.context", "ceres")); File[] moduleFiles; if (modulesFile.isDirectory()) { moduleFiles = modulesFile.listFiles(); if (moduleFiles == null) { String msg = "No files found in " + modulesFile; warn(msg); return; } info(String.format("Deploying modules of [%s] to [%s]...", modulesFile, repositoryDir)); } else { moduleFiles = new File[]{modulesFile}; info(String.format("Deploying module [%s] to [%s]...", modulesFile, repositoryDir)); } repositoryDir.mkdirs(); int deployedModuleCount = 0; for (File moduleFile : moduleFiles) { if (moduleFile.isDirectory() || JarFilenameFilter.isJarName(moduleFile.getName())) { try { deployModuleFile(moduleFile, repositoryDir); deployedModuleCount++; } catch (Exception e) { error("Failed to deploy " + moduleFile.getName() + ": " + e.getMessage()); } } else { warn("Cannot deploy file of unknown type: " + moduleFile.getName()); } } info(String.format("Deploying completed with %d error(s), %d warning(s).", errorCount, warningCount)); info(String.format("%d module(s) deployed", deployedModuleCount)); } private void info(String msg) { logger.info(msg); } private void error(String msg) { logger.severe(msg); errorCount++; } private void warn(String msg) { logger.warning(msg); warningCount++; } private void deployModuleFile(File moduleFile, File repositoryDir) throws CoreException, IOException { ModuleReader moduleReader = new ModuleReader(logger); Module module = moduleReader.readFromLocation(moduleFile); String moduleFileNameNE = module.getSymbolicName() + "-" + module.getVersion(); File moduleRepositoryDir = new File(repositoryDir, moduleFileNameNE); String moduleFileName = moduleFile.getName(); info("Deploying " + moduleFileName + " to " + moduleRepositoryDir); moduleRepositoryDir.mkdirs(); if (!moduleRepositoryDir.isDirectory()) { throw new IOException("Failed to create " + moduleRepositoryDir.getPath()); } if (moduleFile.isDirectory()) { copyFiles(moduleFile, moduleRepositoryDir); jarIntoDir(moduleFile, moduleRepositoryDir, moduleFileNameNE + ".jar"); } else { extractFiles(moduleFile, moduleRepositoryDir); copyIntoDir(moduleFile, true, moduleRepositoryDir, moduleFileNameNE + getExtension(moduleFileName)); } } private void jarIntoDir(File moduleDir, File moduleRepositoryDir, String jarName) throws IOException { File jarFile = new File(moduleRepositoryDir, jarName); JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream(jarFile)); try { copyIntoJar(moduleDir, "", jarOutputStream); } finally { jarOutputStream.close(); } } private void copyIntoJar(File baseDir, String basePath, JarOutputStream jarOutputStream) throws IOException { String[] fileNames = baseDir.list(); if (fileNames != null) { for (String fileName : fileNames) { String entryName = basePath + (basePath.length() > 0 ? "/" : "") + fileName; File file = new File(baseDir, fileName); if (file.isDirectory()) { copyIntoJar(file, entryName, jarOutputStream); } else { FileInputStream fileInputStream = new FileInputStream(file); try { JarEntry jarEntry = new JarEntry(entryName); jarOutputStream.putNextEntry(jarEntry); copy(fileInputStream, jarOutputStream); jarOutputStream.closeEntry(); } finally { fileInputStream.close(); } } } } } private String getExtension(String name) { return name.substring(name.lastIndexOf('.')); } private void extractFiles(File moduleFile, File moduleRepositoryDir) throws IOException { ZipFile zip = new ZipFile(moduleFile); try { for (String mandatoryFilePath : mandatoryFilePaths) { extractToDir(zip, mandatoryFilePath, true, moduleRepositoryDir); } for (String optionalFilePath : optionalFilePaths) { extractToDir(zip, optionalFilePath, false, moduleRepositoryDir); } } finally { zip.close(); } } private void copyFiles(File moduleDir, File moduleRepositoryDir) throws IOException { for (String mandatoryFilePath : mandatoryFilePaths) { copyIntoDir(new File(moduleDir, mandatoryFilePath), true, moduleRepositoryDir); } for (String optionalFilePath : optionalFilePaths) { copyIntoDir(new File(moduleDir, optionalFilePath), false, moduleRepositoryDir); } } private void extractToDir(ZipFile zip, String entryName, boolean mustExists, File targetDir) throws IOException { File targetFile = new File(targetDir, entryName); targetFile.getParentFile().mkdirs(); ZipEntry entry = zip.getEntry(entryName); if (entry == null) { String message = "ZIP entry not found: " + entryName; if (mustExists) { throw new IOException(message); } else { warn(message); return; } } InputStream inputStream = null; OutputStream outputStream = null; try { inputStream = zip.getInputStream(entry); outputStream = new FileOutputStream(targetFile); copy(inputStream, outputStream); } finally { closeBoth(inputStream, outputStream); } } private boolean copyIntoDir(File sourceFile, boolean mustExist, File targetDir) throws IOException { return copyIntoDir(sourceFile, mustExist, targetDir, sourceFile.getName()); } private boolean copyIntoDir(File sourceFile, boolean mustExist, File targetDir, String targetName) throws IOException { InputStream inputStream = null; try { inputStream = new FileInputStream(sourceFile); } catch (FileNotFoundException e) { if (mustExist) { throw e; } else { return false; } } OutputStream outputStream = null; try { inputStream = new FileInputStream(sourceFile); outputStream = new FileOutputStream(new File(targetDir, targetName)); copy(inputStream, outputStream); } finally { closeBoth(inputStream, outputStream); } return true; } private void copy(InputStream inputStream, OutputStream outputStream) throws IOException { byte[] buffer = new byte[64 * 1024]; int numBytes; do { numBytes = inputStream.read(buffer); if (numBytes != -1) { outputStream.write(buffer, 0, numBytes); } } while (numBytes > 0); } private void closeBoth(InputStream inputStream, OutputStream outputStream) { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { // ignore } } if (outputStream != null) { try { outputStream.close(); } catch (IOException e) { // ignore } } } }