001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.deployment;
023:
024: import java.io.File;
025: import java.io.FileFilter;
026: import java.net.JarURLConnection;
027: import java.net.URL;
028: import java.net.URLConnection;
029: import java.util.Arrays;
030: import java.util.Enumeration;
031: import java.util.jar.JarEntry;
032: import java.util.jar.JarFile;
033:
034: import org.jboss.util.Strings;
035:
036: /**
037: * This deployer exists to prevent deployment of packages whose deployers are not yet
038: * deployed. It will accept only jar/zip format files or directories that don't
039: * have a META-INF directory, or if they do, don't have any .xml files there. It
040: * assumes any package with a META-INF/*.xml file needs a specialized deployer.
041: *
042: * @todo find a way to scan just the META-INF files, not the whole jar.
043: *
044: * @author <a href="mailto:scott.stark@jboss.org">Scott Stark</a>
045: * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
046: * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
047: * @version $Revision: 57205 $
048: */
049: public class JARDeployer extends SubDeployerSupport implements
050: JARDeployerMBean {
051: /**
052: * The suffixes we accept, along with their relative order.
053: *
054: * For JARDeployer, this is only used to populate the MainDeployer's
055: * SuffixOrder list, it is not used to actually match deployment suffixes
056: */
057: private static final String[] DEFAULT_ENHANCED_SUFFIXES = new String[] {
058: "700:.jar", // normal .jar
059: "750:.zip", // normal .zip
060: "900:.last" // make content of .last dirs/archives deploy last
061: };
062:
063: private String[] descriptorNames = { ".xml" };
064:
065: /**
066: * Default CTOR
067: */
068: public JARDeployer() {
069: super .setEnhancedSuffixes(DEFAULT_ENHANCED_SUFFIXES);
070: }
071:
072: public String[] getDescriptorNames() {
073: return descriptorNames;
074: }
075:
076: public void setDescriptorNames(String[] descriptorNames) {
077: this .descriptorNames = descriptorNames;
078: }
079:
080: // ServiceMBeanSupport methods
081:
082: protected void stopService() {
083: // This can't be run right now since the JARDeployer is started before the MainDeployer,
084: // so the MainDeployer is stopped first... so the JARDeployer can't unregister.
085:
086: // super.stopService();
087: }
088:
089: // SubDeployer implementation
090:
091: /**
092: * The <code>accepts</code> method is called by MainDeployer to
093: * determine which deployer is suitable for a DeploymentInfo.
094: *
095: * @todo find a way to scan just the META-INF files, not the whole jar.
096: *
097: * @param di a <code>DeploymentInfo</code> value
098: * @return a <code>boolean</code> value
099: */
100: public boolean accepts(DeploymentInfo di) {
101: boolean trace = log.isTraceEnabled();
102:
103: try {
104: // Reject extensions not configured in this subdeployer
105: // but do consider accepting non-dotted deployments,
106: // like deploy-hasingleton
107: if (di.shortName.indexOf('.') != -1
108: && super .accepts(di) == false) {
109: return false;
110: }
111:
112: // Reject deployments with a WEB-INF/ directory
113: URL wdDir = di.localCl.findResource("WEB-INF/");
114: if (wdDir != null) {
115: return false;
116: }
117:
118: // Since a META-INF directory exists within rt.jar, we can't just do a
119: // getResource (it will always return rt.jar's version).
120: // The method we want is findResource, but it is marked protected in
121: // ClassLoader. Fortunately, URLClassLoader exposes it which makes
122: // this hack possible. Anybody have a better way to check a URL
123: // for the existance of a META-INF??
124: URL ddDir;
125: try {
126: ddDir = di.localCl.findResource("META-INF/");
127: if (ddDir == null) {
128: log
129: .debug("No META-INF or WEB-INF resource found, assuming it if for us");
130: return true;
131: }
132: } catch (ClassCastException e) {
133: // assume there is a META-INF...
134: ddDir = new URL(di.url, "META-INF/");
135: }
136:
137: if (ddDir.getProtocol().equals("file")) {
138: log.trace("File protocol: " + ddDir);
139: File file = new File(ddDir.getFile());
140: if (!file.exists()) {
141: log.warn("File not found: " + file);
142: return true;
143: }
144:
145: // Scan for any xml files in the META-INF dir
146: File[] entries = file.listFiles(new FileFilter() {
147: public boolean accept(File pathname) {
148: boolean accept = false;
149: String name = pathname.getName();
150: for (int n = 0; accept == false
151: && n < descriptorNames.length; n++) {
152: String d = descriptorNames[n];
153: accept = name.endsWith(d);
154: }
155: return accept;
156: }
157: });
158: log.debug("XML entries found: " + entries.length);
159: return entries.length == 0;
160: } // end of if ()
161: else if (ddDir.getProtocol().equals("jar") == true) {
162: log.trace("jar protocol: " + ddDir);
163: JarFile jarFile = null;
164:
165: try {
166: URLConnection con = ddDir.openConnection();
167: JarURLConnection jarConn = (JarURLConnection) con;
168: /* Need to set caching to false otherwise closing the jarfile
169: ends up conflicting with other users of the cached jar.
170: */
171: jarConn.setUseCaches(false);
172: jarFile = jarConn.getJarFile();
173:
174: // Scan for any xml files in the META-INF dir
175: if (trace)
176: log.trace("Descriptor names="
177: + Arrays.asList(descriptorNames));
178: for (Enumeration e = jarFile.entries(); e
179: .hasMoreElements();) {
180: JarEntry entry = (JarEntry) e.nextElement();
181: String name = entry.getName();
182: if (trace)
183: log.trace("Looking at entry: '" + name
184: + "'");
185:
186: // JBAS-2949 - Look for xml descriptors directly
187: // under META-INF/, not in META-INF/ subdirectories
188: if (name.startsWith("META-INF/")
189: && Strings.count(name, "/") == 1) {
190: for (int n = 0; n < descriptorNames.length; n++) {
191: if (name.endsWith(descriptorNames[n])) {
192: log.debug("Found entry: '" + name
193: + "', matching: '"
194: + descriptorNames[n]
195: + "', rejecting jar");
196:
197: // Do not accept this as jar file
198: return false;
199: }
200: }
201: }
202: }
203: } catch (Exception e) {
204: log.warn("Looking inside jar failed; ignoring", e);
205: return false;
206: } finally {
207: if (jarFile != null)
208: jarFile.close();
209: jarFile = null;
210: }
211:
212: log.debug("No xml files found");
213: return true;
214: } else {
215: log.debug("Unrecognized protocol: "
216: + ddDir.getProtocol());
217: }
218:
219: return false;
220: } catch (Exception e) {
221: log.trace("Ignored error", e);
222: return false;
223: }
224: }
225: }
|