Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* JBoss, Home of Professional Open Source.
* Copyright (c) 2011, Red Hat, Inc., 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.as.embedded.ejb3;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.DotName;
import org.jboss.jandex.Index;
import org.jboss.jandex.Indexer;
import org.jboss.logging.Logger;
import org.jboss.vfs.TempFileProvider;
import org.jboss.vfs.VFS;
import org.jboss.vfs.VirtualFile;
import javax.ejb.MessageDriven;
import javax.ejb.Singleton;
import javax.ejb.Stateful;
import javax.ejb.Stateless;
import javax.ejb.embeddable.EJBContainer;
import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import static java.security.AccessController.doPrivileged;
/**
* Implements JVM ClassPath scanning for EJB JARs as defined
* by EJB 3.1 Final Draft 22.2.1. This is a static utility
* class which is not to be instantiated.
*
* @author ALR
* @version $Revision: $
*/
class ClassPathEjbJarScanner {
//TODO
/*
* This is an intentionally naive implementation which essentially
* amounts to junkware. It gets us to the next phases of development,
* but isn't intended to be the final solution. For starters it's a static utility.
*
* Open issues:
*
* 1) Don't load all Classes to look for annotations. Vie for ASM or Javassist (or
* other bytecode analyzer). Or pass through an isolated VDF Deployer chain and let the
* deployers figure out what the eligible modules are
* 2) Define a configurable ScheduledExecutorService to back the TempFileProvider
* used to mount ZIP VFS roots. If we go the deployer chain route as noted by 1) this
* won't be necessary
*/
//-------------------------------------------------------------------------------------||
// Class Members ----------------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
/**
* Logger
*/
private static final Logger log = Logger.getLogger(ClassPathEjbJarScanner.class);
/**
* System property key denoting the JVM ClassPath
*/
private static final String SYS_PROP_KEY_CLASS_PATH = "java.class.path";
/**
* Dummy String array used in converting a {@link java.util.Collection} of {@link String} to a typed array
*/
private static final String[] DUMMY = new String[]{};
/**
* Path of the EJB Descriptor, relative to the root of a deployment
*/
private static final String PATH_EJB_JAR_XML = "META-INF/ejb-jar.xml";
/**
* .class Extension
*/
private static final String EXTENSION_CLASS = ".class";
/**
* .jar Extension
*/
private static final String EXTENSION_JAR = ".jar";
/**
* EJB Component-defining annotations
*/
@SuppressWarnings("unchecked")
private static final Class extends Annotation>[] EJB_COMPONENT_ANNOTATIONS = (Class extends Annotation>[]) new Class>[]
{Stateless.class, Stateful.class, Singleton.class, MessageDriven.class};
/**
* {@link java.util.concurrent.ScheduledExecutorService} to mount files to be scanned
*/
@Deprecated
//TODO Get some reusable, configurable real SES (as managed by the container) else we'll block on JVM shutdown;
// this one is never shut down cleanly
private static final ScheduledExecutorService ses = Executors.newScheduledThreadPool(Runtime.getRuntime()
.availableProcessors());
private static final String JAVA_HOME = getSystemProperty("java.home");
/**
* Configured exclusion filters
* TODO Shouldn't be hardcoded, but available via user configuration
*/
private static final List exclusionFilters;
static {
exclusionFilters = new ArrayList();
exclusionFilters.add(new BundleSymbolicNameExclusionFilter("org.eclipse", "org.junit"));
// scanning rt.jar leads to out of perm-gen
exclusionFilters.add(new ExclusionFilter() {
@Override
public boolean exclude(VirtualFile file) throws IllegalArgumentException {
final String pathName = file.getPathName();
return pathName.startsWith(JAVA_HOME);
}
});
}
//-------------------------------------------------------------------------------------||
// Constructor ------------------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
/**
* Internal Constructor, no instances permitted
*/
private ClassPathEjbJarScanner() {
throw new UnsupportedOperationException("No instances permitted");
}
//-------------------------------------------------------------------------------------||
// Functional Methods -----------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
/**
* Obtains all EJB JAR entries from the ClassPath
*/
public static String[] getEjbJars(Map, ?> properties) {
// Initialize
final Collection returnValue = new ArrayList();
// Get the full ClassPath
String classPath = getSystemProperty("surefire.test.class.path");
if (classPath == null || classPath.isEmpty())
classPath = getSystemProperty(SYS_PROP_KEY_CLASS_PATH);
if (log.isTraceEnabled()) {
log.tracef("Class Path: %s", classPath);
}
// Split by the path separator character
final String[] classPathEntries = classPath.split(File.pathSeparator);
final Object modules;
if (properties != null) {
modules = properties.get(EJBContainer.MODULES);
} else {
modules = null;
}
Set moduleNames = null;
if (modules != null) {
if (modules instanceof File[]) {
for (File file : (File[]) modules) {
returnValue.add(file.getAbsolutePath());
}
return returnValue.toArray(DUMMY);
} else if (modules instanceof File) {
returnValue.add(((File) modules).getAbsolutePath());
return returnValue.toArray(DUMMY);
} else if (modules instanceof String[]) {
moduleNames = new HashSet();
moduleNames.addAll(Arrays.asList((String[]) modules));
} else if (modules instanceof String) {
moduleNames = new HashSet();
moduleNames.add(modules.toString());
} else {
throw new RuntimeException(EJBContainer.MODULES + " was not of type File[], File, String[] or String, but of type " + modules.getClass());
}
}
// For each CP entry
for (final String classPathEntry : classPathEntries) {
// If this is an EJB JAR
final String moduleName = getEjbJar(classPathEntry);
if (moduleName != null) {
if (moduleNames == null) {
// Add to be returned
returnValue.add(classPathEntry);
} else if (moduleNames.contains(moduleName)) {
returnValue.add(classPathEntry);
}
}
}
// Return
if (log.isDebugEnabled()) {
log.debug("EJB Modules discovered on ClassPath: " + returnValue);
}
return returnValue.toArray(DUMMY);
}
private static ClassLoader getTccl() {
if (System.getSecurityManager() == null)
return Thread.currentThread().getContextClassLoader();
return doPrivileged(new PrivilegedAction() {
@Override
public ClassLoader run() {
return Thread.currentThread().getContextClassLoader();
}
});
}
private static String getSystemProperty(final String property) {
if (System.getSecurityManager() == null)
return System.getProperty(property);
return doPrivileged(new PrivilegedAction() {
@Override
public String run() {
return System.getProperty(property);
}
});
}
//-------------------------------------------------------------------------------------||
// Internal Helper Methods ------------------------------------------------------------||
//-------------------------------------------------------------------------------------||
/**
* Determines whether this entry from the ClassPath is an EJB JAR
*
* @return The module name, or null if this is not an EJB jar
*/
private static String getEjbJar(final String candidate) {
if (candidate == null || candidate.isEmpty())
return null;
/*
* EJB 3.1 22.2.1:
*
* A classpath entry is considered a matching entry if it meets one of the following criteria:
* - It is an ejb-jar according to the standard module-type identification rules defined by the Java
* EE platform specification
* - It is a directory containing a META-INF/ejb-jar.xml file or at least one .class with an enterprise
* bean component-defining annotation
*/
// Represent as VFS so we get a nice unified API
final VirtualFile file = VFS.getChild(candidate);
TempFileProvider provider = null;
/*
* See if we've been configured to skip this file
*/
for (final ExclusionFilter exclusionFilter : exclusionFilters) {
// If we should exclude this
if (exclusionFilter.exclude(file)) {
// Exclude from further processing
if (log.isTraceEnabled()) {
log.tracef("%s matched %s for exclusion; skipping", exclusionFilter, file);
}
return null;
}
}
Closeable handle;
try {
// If the file exists
if (file.exists()) {
// Mount Exploded dir
if (file.isDirectory()) {
handle = VFS.mountReal(file.getPhysicalFile(), file);
}
// Mount EJB JAR
else if (file.getName().endsWith(EXTENSION_JAR)) {
if (provider == null) {
provider = TempFileProvider.create("jbossejbmodulescanner", ses);
}
handle = VFS.mountZip(file.getPhysicalFile(), file, provider);
}
// No conditions met
else {
// So it's obvious if we've got something we didn't properly mount
log.warn("Encountered unknown file type, skipping: " + file);
return null;
}
}
// Not a real file
else {
log.warn("File on ClassPath could not be found: " + file);
return null;
}
try {
/*
* Directories and real JARs are handled the same way in VFS, so just do
* one check and skip logic to test isDirectory or not
*/
// Look for META-INF/ejb-jar.xml
final VirtualFile ejbJarXml = file.getChild(PATH_EJB_JAR_XML);
if (ejbJarXml.exists()) {
if (log.isTraceEnabled()) {
log.tracef("Found descriptor %s in %s", ejbJarXml.getPathNameRelativeTo(file), file);
}
return getModuleNameFromEjbJar(file, ejbJarXml);
}
// Look for at least one .class with an EJB annotation
if (containsEjbComponentClass(file)) {
return getModuleNameFromFileName(file);
}
// Return
return null;
} finally {
try {
handle.close();
} catch (final IOException e) {
// Ignore
log.warn("Could not close handle to mounted " + file, e);
}
}
} catch (final IOException e) {
throw new RuntimeException("Could not mount file '" + candidate + "'", e);
}
}
private static String getModuleNameFromEjbJar(final VirtualFile file, final VirtualFile ejbJarXml) {
//TODO: parse the xml file and get the module name
return getModuleNameFromFileName(file);
}
private static String getModuleNameFromFileName(final VirtualFile file) {
String moduleName = file.getName();
int index = moduleName.lastIndexOf('.');
if (index != -1) {
return moduleName.substring(0, index - 1);
}
return moduleName;
}
/**
* Determines if there is at least one .class in the given file
* with an EJB component-defining annotation (Stateless, Stateful,
* Singleton, MessageDriven)
*
* @param file
* @return
* @deprecated Use a real implementation scanner
*/
@Deprecated
private static boolean containsEjbComponentClass(final VirtualFile file) {
Indexer indexer = new Indexer();
indexClasses(file, file, indexer);
Index index = indexer.complete();
for (Class extends Annotation> annotation : EJB_COMPONENT_ANNOTATIONS) {
final DotName annotationName = DotName.createSimple(annotation.getName());
final List classes = index.getAnnotations(annotationName);
if (classes != null && !classes.isEmpty()) {
return true;
}
}
return false;
}
/**
* Determines if there is at least one .class in the given file
* with an EJB component-defining annotation (Stateless, Stateful,
* Singleton, MessageDriven).
*
* @param root The original root from which we started the search
* @param file
* @return
* @deprecated Use a real implementation scanner
*/
@Deprecated
private static void indexClasses(final VirtualFile root, final VirtualFile file, Indexer indexer) {
// Precondition check
assert file != null : "File must be specified";
// For all children
for (final VirtualFile child : file.getChildren()) {
if (child.isDirectory()) {
// Determine if there's one in the child
indexClasses(root, child, indexer);
}
// Get the Class for all .class files
final String childName = child.getPathNameRelativeTo(root);
if (childName.endsWith(EXTENSION_CLASS)) {
InputStream stream = null;
try {
try {
stream = child.openStream();
indexer.index(stream);
} catch (IOException e) {
log.warn("Could not load class file " + child, e);
}
} finally {
try {
if (stream != null) {
stream.close();
}
} catch (IOException e) {
log.warn("Exception closing file " + child, e);
}
}
}
}
}
}