/** * * Copyright 2003-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.geronimo.deployment.cli; import java.io.*; import java.util.jar.JarFile; import java.util.jar.JarEntry; import java.util.Collection; import java.util.List; import java.util.LinkedList; import org.apache.geronimo.common.DeploymentException; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.Attributes; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.SAXParserFactory; import javax.xml.parsers.SAXParser; import javax.xml.parsers.ParserConfigurationException; import javax.enterprise.deploy.spi.TargetModuleID; /** * Various helpers for deployment. * * @version $Rev$ $Date$ */ public class DeployUtils { /** * Split up an output line so it indents at beginning and end (to fit in a * typical terminal) and doesn't break in the middle of a word. * @param source The unformatted String * @param indent The number of characters to indent on the left * @param endCol The maximum width of the entire line in characters, * including indent (indent 10 with endCol 70 results * in 60 "usable" characters). */ public static String reformat(String source, int indent, int endCol) { if(endCol-indent < 10) { throw new IllegalArgumentException("This is ridiculous!"); } StringBuffer buf = new StringBuffer((int)(source.length()*1.1)); String prefix = indent == 0 ? "" : buildIndent(indent); try { BufferedReader in = new BufferedReader(new StringReader(source)); String line; int pos; while((line = in.readLine()) != null) { if(buf.length() > 0) { buf.append('\n'); } while(line.length() > 0) { line = prefix + line; if(line.length() > endCol) { pos = line.lastIndexOf(' ', endCol); if(pos < indent) { pos = line.indexOf(' ', endCol); if(pos < indent) { pos = line.length(); } } buf.append(line.substring(0, pos)).append('\n'); if(pos < line.length()-1) { line = line.substring(pos+1); } else { break; } } else { buf.append(line).append("\n"); break; } } } } catch (IOException e) { throw new AssertionError("This should be impossible"); } return buf.toString(); } private static String buildIndent(int indent) { StringBuffer buf = new StringBuffer(indent); for(int i=0; i<indent; i++) { buf.append(' '); } return buf.toString(); } /** * Given a list of all available TargetModuleIDs and the name of a module, * find the TargetModuleIDs that represent that module. * @throws DeploymentException If no TargetModuleIDs have that module. */ public static Collection identifyTargetModuleIDs(TargetModuleID[] allModules, String name) throws DeploymentException { List list = new LinkedList(); int pos; if((pos = name.indexOf('|')) > -1) { String target = name.substring(0, pos); String module = name.substring(pos+1); // First pass: exact match for(int i=0; i<allModules.length; i++) { if(allModules[i].getTarget().getName().equals(target) && allModules[i].getModuleID().equals(module)) { list.add(allModules[i]); } } } if(!list.isEmpty()) { return list; } // second pass: module matches for(int i = 0; i < allModules.length; i++) { if(allModules[i].getModuleID().equals(name)) { list.add(allModules[i]); } } if(list.isEmpty()) { throw new DeploymentException(name+" does not appear to be a the name of a module " + "available on the selected server. Perhaps it has already been " + "stopped or undeployed? If you're trying to specify a " + "TargetModuleID, use the syntax TargetName|ModuleName instead. " + "If you're not sure what's running, try the list-modules command."); } return list; } /** * Try to determine whether a file is a JAR File (or, at least, a ZIP file). */ public static boolean isJarFile(File file) throws DeploymentException { if(file.isDirectory()) { return false; } if(!file.canRead()) { throw new DeploymentException("Cannot read file "+file.getAbsolutePath()); } if(file.length() < 4) { return false; } try { DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(file))); int test = in.readInt(); in.close(); return test == 0x504b0304; } catch(IOException e) { throw new DeploymentException("Cannot read from file "+file.getAbsolutePath(), e); } } /** * Attempt to calculate the Geronimo ModuleID for a J2EE application * module. * * Given a File representing an archive (which may be a JAR file or a * directory laid out like a JAR file), identify it's J2EE module type * based on which (if any) deployment descriptor is present, and then look * for a Geronimo deployment plan in the usual place, and if one is found, * retrieve the configId from the Geronimo deployment plan. * * todo: Handle Spring and other weird deployment types? * * @param module A Jar file or directory representing a J2EE module * @return The configId in the Geronimo deployment plan for this module, * or null if no Geronimo deployment plan was identified. */ public static String extractModuleIdFromArchive(File module) throws IOException, DeploymentException { if(!module.canRead()) { throw new DeploymentException("Not a readable file ("+module.getAbsolutePath()+")"); } if(module.isDirectory()) { File target = null; if(new File(module, "WEB-INF/web.xml").canRead()) { target = new File(module, "WEB-INF/geronimo-web.xml"); } else if(new File(module, "META-INF/application.xml").canRead()) { target = new File(module, "META-INF/geronimo-application.xml"); } else if(new File(module, "META-INF/ejb-jar.xml").canRead()) { target = new File(module, "META-INF/openejb-jar.xml"); } else if(new File(module, "META-INF/ra.xml").canRead()) { target = new File(module, "META-INF/geronimo-ra.xml"); } else if(new File(module, "META-INF/application-client.xml").canRead()) { target = new File(module, "META-INF/geronimo-application-client.xml"); } if(target != null && target.canRead()) { Reader in = new BufferedReader(new FileReader(target)); return extractModuleIdFromPlan(in); } } else { if(!isJarFile(module)) { throw new DeploymentException(module.getAbsolutePath()+" is neither a JAR file nor a directory!"); } JarFile input = new JarFile(module); //todo: instead of looking for specific file names here, do something generic. // Perhaps load a DConfigBeanRoot and look for a configId property on the first child, // though that would probably be a little heavyweight. try { JarEntry entry = null; if(input.getJarEntry("WEB-INF/web.xml") != null) { entry = input.getJarEntry("WEB-INF/geronimo-web.xml"); } else if(input.getJarEntry("META-INF/application.xml") != null) { entry = input.getJarEntry("META-INF/geronimo-application.xml"); } else if(input.getJarEntry("META-INF/ejb-jar.xml") != null) { entry = input.getJarEntry("META-INF/openejb-jar.xml"); } else if(input.getJarEntry("META-INF/ra.xml") != null) { entry = input.getJarEntry("META-INF/geronimo-ra.xml"); } else if(input.getJarEntry("META-INF/application-client.xml") != null) { entry = input.getJarEntry("META-INF/geronimo-application-client.xml"); } if(entry != null) { Reader in = new BufferedReader(new InputStreamReader(input.getInputStream(entry))); return extractModuleIdFromPlan(in); } } finally { input.close(); } } return null; } /** * Attempt to calculate the Geronimo ModuleID for a Geronimo deployment * plan. * * @param plan A Geronimo deployment plan (which must be an XML file). * @return The configId in the Geronimo deployment plan for this module. */ public static String extractModuleIdFromPlan(File plan) throws IOException { if(plan.isDirectory() || !plan.canRead()) { throw new IllegalArgumentException(plan.getAbsolutePath()+" is not a readable XML file!"); } Reader in = new BufferedReader(new FileReader(plan)); return extractModuleIdFromPlan(in); } private static String extractModuleIdFromPlan(Reader plan) throws IOException { SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(true); factory.setValidating(false); try { SAXParser parser = factory.newSAXParser(); ConfigIdHandler handler = new ConfigIdHandler(); parser.parse(new InputSource(plan), handler); return handler.configId; } catch (ParserConfigurationException e) { throw new IOException("Unable to read plan: "+e.getMessage()); } catch (SAXException e) { throw new IOException("Unable to read plan: "+e.getMessage()); } finally { plan.close(); } } private static class ConfigIdHandler extends DefaultHandler { private String configId; public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if(configId == null) { configId = attributes.getValue("configId"); } } } }