/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.deployment; import java.io.File; import java.io.FileFilter; import java.net.JarURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.Arrays; import java.util.Enumeration; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.jboss.util.Strings; /** * This deployer exists to prevent deployment of packages whose deployers are not yet * deployed. It will accept only jar/zip format files or directories that don't * have a META-INF directory, or if they do, don't have any .xml files there. It * assumes any package with a META-INF/*.xml file needs a specialized deployer. * * @todo find a way to scan just the META-INF files, not the whole jar. * * @author <a href="mailto:scott.stark@jboss.org">Scott Stark</a> * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a> * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a> * @version $Revision: 81033 $ */ public class JARDeployer extends SubDeployerSupport implements JARDeployerMBean { /** * The suffixes we accept, along with their relative order. * * For JARDeployer, this is only used to populate the MainDeployer's * SuffixOrder list, it is not used to actually match deployment suffixes */ private static final String[] DEFAULT_ENHANCED_SUFFIXES = new String[] { "700:.jar", // normal .jar "750:.zip", // normal .zip "900:.last" // make content of .last dirs/archives deploy last }; private String[] descriptorNames = { ".xml" }; /** * Default CTOR */ public JARDeployer() { super.setEnhancedSuffixes(DEFAULT_ENHANCED_SUFFIXES); } public String[] getDescriptorNames() { return descriptorNames; } public void setDescriptorNames(String[] descriptorNames) { this.descriptorNames = descriptorNames; } // ServiceMBeanSupport methods protected void stopService() { // This can't be run right now since the JARDeployer is started before the MainDeployer, // so the MainDeployer is stopped first... so the JARDeployer can't unregister. // super.stopService(); } // SubDeployer implementation /** * The <code>accepts</code> method is called by MainDeployer to * determine which deployer is suitable for a DeploymentInfo. * * @todo find a way to scan just the META-INF files, not the whole jar. * * @param di a <code>DeploymentInfo</code> value * @return a <code>boolean</code> value */ public boolean accepts(DeploymentInfo di) { boolean trace = log.isTraceEnabled(); try { // Reject extensions not configured in this subdeployer // but do consider accepting non-dotted deployments, // like deploy-hasingleton if (di.shortName.indexOf('.') != -1 && super.accepts(di) == false) { return false; } // Reject deployments with a WEB-INF/ directory URL wdDir = di.localCl.findResource("WEB-INF/"); if (wdDir != null) { return false; } // Since a META-INF directory exists within rt.jar, we can't just do a // getResource (it will always return rt.jar's version). // The method we want is findResource, but it is marked protected in // ClassLoader. Fortunately, URLClassLoader exposes it which makes // this hack possible. Anybody have a better way to check a URL // for the existance of a META-INF?? URL ddDir; try { ddDir = di.localCl.findResource("META-INF/"); if (ddDir == null) { log.debug("No META-INF or WEB-INF resource found, assuming it if for us"); return true; } } catch (ClassCastException e) { // assume there is a META-INF... ddDir = new URL(di.url, "META-INF/"); } if (ddDir.getProtocol().equals("file")) { log.trace("File protocol: "+ddDir); File file = new File(ddDir.getFile()); if (!file.exists()) { log.warn("File not found: " + file); return true; } // Scan for any xml files in the META-INF dir File[] entries = file.listFiles( new FileFilter() { public boolean accept(File pathname) { boolean accept = false; String name = pathname.getName(); for(int n = 0; accept == false && n < descriptorNames.length; n ++) { String d = descriptorNames[n]; accept = name.endsWith(d); } return accept; } } ); log.debug("XML entries found: " + entries.length); return entries.length == 0; } // end of if () else if (ddDir.getProtocol().equals("jar") == true) { log.trace("jar protocol: " + ddDir); JarFile jarFile = null; try { URLConnection con = ddDir.openConnection(); JarURLConnection jarConn = (JarURLConnection) con; /* Need to set caching to false otherwise closing the jarfile ends up conflicting with other users of the cached jar. */ jarConn.setUseCaches(false); jarFile = jarConn.getJarFile(); // Scan for any xml files in the META-INF dir if (trace) log.trace("Descriptor names=" + Arrays.asList(descriptorNames)); for (Enumeration e = jarFile.entries(); e.hasMoreElements();) { JarEntry entry = (JarEntry)e.nextElement(); String name = entry.getName(); if (trace) log.trace("Looking at entry: '" + name + "'"); // JBAS-2949 - Look for xml descriptors directly // under META-INF/, not in META-INF/ subdirectories if (name.startsWith("META-INF/") && Strings.count(name, "/") == 1) { for (int n = 0; n < descriptorNames.length; n ++) { if (name.endsWith(descriptorNames[n])) { log.debug("Found entry: '" + name + "', matching: '" + descriptorNames[n] + "', rejecting jar"); // Do not accept this as jar file return false; } } } } } catch (Exception e) { log.warn("Looking inside jar failed; ignoring", e); return false; } finally { if (jarFile != null) jarFile.close(); jarFile = null; } log.debug("No xml files found"); return true; } else { log.debug("Unrecognized protocol: " + ddDir.getProtocol()); } return false; } catch (Exception e) { log.trace("Ignored error", e); return false; } } }