public static Object build( final Collection<ServiceInfo> services, final ServiceInfo info, final ObjectRecipe serviceRecipe) { if ("org.apache.openejb.config.sys.MapFactory".equals(info.className)) { return info.properties; } if (!info.properties.containsKey("properties")) { info.properties.put("properties", new UnsetPropertiesRecipe()); } // we can't ask for having a setter for existing code serviceRecipe.allow(Option.FIELD_INJECTION); serviceRecipe.allow(Option.PRIVATE_PROPERTIES); for (final Map.Entry<Object, Object> entry : info.properties.entrySet()) { // manage links final String key = entry.getKey().toString(); final Object value = entry.getValue(); if (value instanceof String) { final String valueStr = value.toString(); if (valueStr.startsWith("$")) { serviceRecipe.setProperty(key, resolve(services, valueStr.substring(1))); } else if (valueStr.startsWith("@")) { final Context jndiContext = SystemInstance.get().getComponent(ContainerSystem.class).getJNDIContext(); try { serviceRecipe.setProperty( key, jndiContext.lookup( JndiConstants.OPENEJB_RESOURCE_JNDI_PREFIX + valueStr.substring(1))); } catch (final NamingException e) { try { serviceRecipe.setProperty(key, jndiContext.lookup(valueStr.substring(1))); } catch (final NamingException e1) { Logger.getInstance(LogCategory.OPENEJB, ServiceInfos.class) .warning( "Value " + valueStr + " starting with @ but doesn't point to an existing resource, using raw value"); serviceRecipe.setProperty(key, value); } } } else { serviceRecipe.setProperty(key, value); } } else { serviceRecipe.setProperty(key, entry.getValue()); } } final Object service = serviceRecipe.create(); SystemInstance.get() .addObserver( service); // TODO: remove it? in all case the observer should remove itself when done Assembler.logUnusedProperties(serviceRecipe, info); return service; }
public class DynamicMBeanWrapper implements DynamicMBean, MBeanRegistration { public static final Logger logger = Logger.getInstance(LogCategory.OPENEJB_DEPLOY, DynamicMBeanWrapper.class); private static final Map<Class<?>, CacheInfo> CACHE = new HashMap<Class<?>, CacheInfo>(); private static final Map<Class<?>, Class<? extends Annotation>> OPENEJB_API_TO_JAVAX = new HashMap<Class<?>, Class<? extends Annotation>>(); static { final ClassLoader loader = DynamicMBeanWrapper.class.getClassLoader(); try { OPENEJB_API_TO_JAVAX.put( MBean.class, (Class<? extends Annotation>) loader.loadClass("javax.management.MBean")); OPENEJB_API_TO_JAVAX.put( Description.class, (Class<? extends Annotation>) loader.loadClass("javax.management.Description")); OPENEJB_API_TO_JAVAX.put( ManagedOperation.class, (Class<? extends Annotation>) loader.loadClass("javax.management.ManagedOperation")); OPENEJB_API_TO_JAVAX.put( ManagedAttribute.class, (Class<? extends Annotation>) loader.loadClass("javax.management.ManagedAttribute")); OPENEJB_API_TO_JAVAX.put( NotificationInfo.class, (Class<? extends Annotation>) loader.loadClass("javax.management.NotificationInfo")); OPENEJB_API_TO_JAVAX.put( NotificationInfos.class, (Class<? extends Annotation>) loader.loadClass("javax.management.NotificationInfos")); } catch (final ClassNotFoundException | NoClassDefFoundError cnfe) { // ignored } } private final MBeanInfo info; private final Map<String, Method> getters = new HashMap<String, Method>(); private final Map<String, Method> setters = new HashMap<String, Method>(); private final Map<String, Method> operations = new HashMap<String, Method>(); private final Object instance; private final ClassLoader classloader; public DynamicMBeanWrapper(final Object givenInstance) { this(null, givenInstance); } public DynamicMBeanWrapper(final WebBeansContext wc, final Object givenInstance) { Class<?> annotatedMBean = givenInstance.getClass(); // javaassist looses annotation so simply unwrap it if (wc != null) { if (givenInstance.getClass().getName().contains("$Owb")) { // isProxy annotatedMBean = annotatedMBean.getSuperclass(); } } classloader = annotatedMBean.getClassLoader(); instance = givenInstance; final CacheInfo cache = CACHE.get(annotatedMBean); if (cache == null) { final String description; final List<MBeanAttributeInfo> attributeInfos = new ArrayList<MBeanAttributeInfo>(); final List<MBeanOperationInfo> operationInfos = new ArrayList<MBeanOperationInfo>(); final List<MBeanNotificationInfo> notificationInfos = new ArrayList<MBeanNotificationInfo>(); // class final Description classDescription = findAnnotation(annotatedMBean, Description.class); description = getDescription(classDescription, "a MBean built by OpenEJB"); final NotificationInfo notification = findAnnotation(annotatedMBean, NotificationInfo.class); if (notification != null) { final MBeanNotificationInfo notificationInfo = getNotificationInfo(notification); notificationInfos.add(notificationInfo); } final NotificationInfos notifications = findAnnotation(annotatedMBean, NotificationInfos.class); if (notifications != null && notifications.value() != null) { for (final NotificationInfo n : notifications.value()) { final MBeanNotificationInfo notificationInfo = getNotificationInfo(n); notificationInfos.add(notificationInfo); } } // methods for (final Method m : annotatedMBean.getMethods()) { final int modifiers = m.getModifiers(); if (m.getDeclaringClass().equals(Object.class) || !Modifier.isPublic(modifiers) || Modifier.isAbstract(modifiers)) { continue; } if (findAnnotation(m, ManagedAttribute.class) != null) { final String methodName = m.getName(); String attrName = methodName; if ((attrName.startsWith("get") && m.getParameterTypes().length == 0 || attrName.startsWith("set") && m.getParameterTypes().length == 1) && attrName.length() > 3) { attrName = attrName.substring(3); if (attrName.length() > 1) { attrName = Character.toLowerCase(attrName.charAt(0)) + attrName.substring(1); } else { attrName = attrName.toLowerCase(); } } else { logger.warning( "ignoring attribute " + m.getName() + " for " + annotatedMBean.getName()); } if (methodName.startsWith("get")) { getters.put(attrName, m); } else if (methodName.startsWith("set")) { setters.put(attrName, m); } } else if (findAnnotation(m, ManagedOperation.class) != null) { operations.put(m.getName(), m); String operationDescr = ""; final Description descr = findAnnotation(m, Description.class); if (descr != null) { operationDescr = getDescription(descr, "-"); } operationInfos.add(newMethodDescriptor(operationDescr, m)); } } for (final Map.Entry<String, Method> e : getters.entrySet()) { final String key = e.getKey(); final Method mtd = e.getValue(); String attrDescr = ""; final Description descr = findAnnotation(mtd, Description.class); if (descr != null) { attrDescr = getDescription(descr, "-"); } try { attributeInfos.add(new MBeanAttributeInfo(key, attrDescr, mtd, setters.get(key))); } catch (final IntrospectionException ex) { logger.warning("can't manage " + key + " for " + mtd.getName(), ex); } } // for updatable but not readable attributes for (final Map.Entry<String, Method> e : setters.entrySet()) { final String key = e.getKey(); if (getters.get(key) != null) { continue; // already done } final Method mtd = e.getValue(); String attrDescr = ""; final Description descr = findAnnotation(mtd, Description.class); if (descr != null) { attrDescr = getDescription(descr, "-"); } try { attributeInfos.add(new MBeanAttributeInfo(key, attrDescr, null, setters.get(key))); } catch (final IntrospectionException ex) { logger.warning("can't manage " + key + " for " + mtd.getName(), ex); } } info = new MBeanInfo( annotatedMBean.getName(), description, attributeInfos.toArray(new MBeanAttributeInfo[attributeInfos.size()]), null, // default constructor is mandatory operationInfos.toArray(new MBeanOperationInfo[operationInfos.size()]), notificationInfos.toArray(new MBeanNotificationInfo[notificationInfos.size()])); if (annotatedMBean.getAnnotation(Internal.class) != null) { CACHE.put(annotatedMBean, new CacheInfo(info, getters, setters, operations)); } } else { info = cache.mBeanInfo; getters.putAll(cache.getters); setters.putAll(cache.setters); operations.putAll(cache.operations); } } private MBeanOperationInfo newMethodDescriptor(final String operationDescr, final Method m) { final MBeanOperationInfo jvmInfo = new MBeanOperationInfo(operationDescr, m); return new MBeanOperationInfo( m.getName(), operationDescr, methodSignature(jvmInfo, m), m.getReturnType().getName(), MBeanOperationInfo.UNKNOWN, jvmInfo.getDescriptor()); // avoid to copy the logic } private static MBeanParameterInfo[] methodSignature( final MBeanOperationInfo jvmInfo, final Method method) { final Class<?>[] classes = method.getParameterTypes(); final Annotation[][] annots = method.getParameterAnnotations(); return parameters(jvmInfo, classes, annots); } static MBeanParameterInfo[] parameters( final MBeanOperationInfo jvmInfo, final Class<?>[] classes, final Annotation[][] annots) { final MBeanParameterInfo[] params = new MBeanParameterInfo[classes.length]; assert classes.length == annots.length; String desc = ""; for (int i = 0; i < classes.length; i++) { final Descriptor d = jvmInfo.getSignature()[i].getDescriptor(); final String pn = "arg" + i; for (final Annotation a : annots[i]) { final Class<? extends Annotation> type = a.annotationType(); if (type.equals(Description.class) || type.equals(OPENEJB_API_TO_JAVAX.get(Description.class))) { desc = getDescription(annotationProxy(a, Description.class), desc); break; } } params[i] = new MBeanParameterInfo(pn, classes[i].getName(), desc, d); } return params; } private <T extends Annotation> T findAnnotation( final Method method, final Class<T> searchedAnnotation) { final T annotation = method.getAnnotation(searchedAnnotation); if (annotation != null) { return annotation; } if (OPENEJB_API_TO_JAVAX.containsKey(searchedAnnotation)) { final Class<? extends Annotation> clazz = OPENEJB_API_TO_JAVAX.get(searchedAnnotation); final Object javaxAnnotation = method.getAnnotation(clazz); if (javaxAnnotation != null) { return annotationProxy(javaxAnnotation, searchedAnnotation); } } return null; } private <T extends Annotation> T findAnnotation( final Class<?> annotatedMBean, final Class<T> searchedAnnotation) { final T annotation = annotatedMBean.getAnnotation(searchedAnnotation); if (annotation != null) { return annotation; } if (OPENEJB_API_TO_JAVAX.containsKey(searchedAnnotation)) { final Class<? extends Annotation> clazz = OPENEJB_API_TO_JAVAX.get(searchedAnnotation); final Object javaxAnnotation = annotatedMBean.getAnnotation(clazz); if (javaxAnnotation != null) { return annotationProxy(javaxAnnotation, searchedAnnotation); } } return null; } private static <T extends Annotation> T annotationProxy( final Object javaxAnnotation, final Class<T> clazz) { return (T) Proxy.newProxyInstance( DynamicMBeanWrapper.class.getClassLoader(), new Class<?>[] {clazz}, new AnnotationHandler(javaxAnnotation)); } private static MBeanNotificationInfo getNotificationInfo(final NotificationInfo n) { final String description = getDescription(n.description(), "-"); return new MBeanNotificationInfo( n.types(), n.notificationClass().getName(), description, new ImmutableDescriptor(n.descriptorFields())); } private static String getDescription(final Description d, final String defaultValue) { if (d != null) { if (d.bundleBaseName() != null && d.key() != null) { try { return ResourceBundle.getBundle(d.bundleBaseName()).getString(d.key()); } catch (final RuntimeException re) { return d.value(); } } else { return d.value(); } } return defaultValue; } @Override public MBeanInfo getMBeanInfo() { return info; } @Override public Object getAttribute(final String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { if (getters.containsKey(attribute)) { final ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(classloader); try { return getters.get(attribute).invoke(instance); } catch (final IllegalArgumentException | InvocationTargetException | IllegalAccessException e) { logger.error("can't get " + attribute + " value", e); } finally { Thread.currentThread().setContextClassLoader(oldCl); } } throw new AttributeNotFoundException(); } @Override public void setAttribute(final Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { if (setters.containsKey(attribute.getName())) { final ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(classloader); try { setters.get(attribute.getName()).invoke(instance, attribute.getValue()); } catch (final IllegalArgumentException | InvocationTargetException | IllegalAccessException e) { logger.error("can't set " + attribute + " value", e); } finally { Thread.currentThread().setContextClassLoader(oldCl); } } else { throw new AttributeNotFoundException(); } } @Override public AttributeList getAttributes(final String[] attributes) { final AttributeList list = new AttributeList(); for (final String n : attributes) { try { list.add(new Attribute(n, getAttribute(n))); } catch (final Exception ignore) { // no-op } } return list; } @Override public AttributeList setAttributes(final AttributeList attributes) { final AttributeList list = new AttributeList(); for (final Object o : attributes) { final Attribute attr = (Attribute) o; try { setAttribute(attr); list.add(attr); } catch (final Exception ignore) { // no-op } } return list; } @Override public Object invoke(final String actionName, final Object[] params, final String[] signature) throws MBeanException, ReflectionException { if (operations.containsKey(actionName)) { final ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(classloader); try { return operations.get(actionName).invoke(instance, params); } catch (final IllegalArgumentException | InvocationTargetException | IllegalAccessException e) { logger.error(actionName + "can't be invoked", e); } finally { Thread.currentThread().setContextClassLoader(oldCl); } } throw new MBeanException(new IllegalArgumentException(), actionName + " doesn't exist"); } @Override public ObjectName preRegister(final MBeanServer server, final ObjectName name) throws Exception { final Thread thread = Thread.currentThread(); final ClassLoader oldCl = thread.getContextClassLoader(); thread.setContextClassLoader(classloader); try { if (MBeanRegistration.class.isInstance(instance)) { return MBeanRegistration.class.cast(instance).preRegister(server, name); } return name; } finally { thread.setContextClassLoader(oldCl); } } @Override public void postRegister(final Boolean registrationDone) { final Thread thread = Thread.currentThread(); final ClassLoader oldCl = thread.getContextClassLoader(); thread.setContextClassLoader(classloader); try { if (MBeanRegistration.class.isInstance(instance)) { MBeanRegistration.class.cast(instance).postRegister(registrationDone); } } finally { thread.setContextClassLoader(oldCl); } } @Override public void preDeregister() throws Exception { final Thread thread = Thread.currentThread(); final ClassLoader oldCl = thread.getContextClassLoader(); thread.setContextClassLoader(classloader); try { if (MBeanRegistration.class.isInstance(instance)) { MBeanRegistration.class.cast(instance).preDeregister(); } } finally { thread.setContextClassLoader(oldCl); } } @Override public void postDeregister() { final Thread thread = Thread.currentThread(); final ClassLoader oldCl = thread.getContextClassLoader(); thread.setContextClassLoader(classloader); try { if (MBeanRegistration.class.isInstance(instance)) { MBeanRegistration.class.cast(instance).postDeregister(); } } finally { thread.setContextClassLoader(oldCl); } } private static class AnnotationHandler implements InvocationHandler { private final Object delegate; public AnnotationHandler(final Object javaxAnnotation) { delegate = javaxAnnotation; } @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { Object result = null; for (final Method mtd : delegate.getClass().getMethods()) { // simple heurisitc which should be enough if (mtd.getName().equals(method.getName())) { result = mtd.invoke(delegate, args); break; } } if (result == null) { return null; } if (result.getClass().isArray()) { final Object[] array = (Object[]) result; if (array.length == 0 || !OPENEJB_API_TO_JAVAX.containsValue(array[0].getClass())) { return array; } final Object[] translated = new Object[array.length]; for (int i = 0; i < translated.length; i++) { translated[i] = annotationProxy(array[i], OPENEJB_API_TO_JAVAX.get(array[i].getClass())); } } return result; } } private static final class CacheInfo { public final MBeanInfo mBeanInfo; public final Map<String, Method> getters; public final Map<String, Method> setters; public final Map<String, Method> operations; private CacheInfo( final MBeanInfo mBeanInfo, final Map<String, Method> getters, final Map<String, Method> setters, final Map<String, Method> operations) { this.mBeanInfo = mBeanInfo; this.getters = getters; this.setters = setters; this.operations = operations; } } }
public class DeployTimeEnhancer { private static final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB_DEPLOY, DeployTimeEnhancer.class); private static final String OPENEJB_JAR_ENHANCEMENT_INCLUDE = "openejb.jar.enhancement.include"; private static final String OPENEJB_JAR_ENHANCEMENT_EXCLUDE = "openejb.jar.enhancement.exclude"; private static final String CLASS_EXT = ".class"; private static final String PROPERTIES_FILE_PROP = "propertiesFile"; private static final String META_INF_PERSISTENCE_XML = "META-INF/persistence.xml"; private static final String TMP_ENHANCEMENT_SUFFIX = ".tmp-enhancement"; private final Method enhancerMethod; private final Constructor<?> optionsConstructor; public DeployTimeEnhancer() { Method mtd; Constructor<?> cstr; final ClassLoader cl = DeployTimeEnhancer.class.getClassLoader(); try { final Class<?> enhancerClass = cl.loadClass("org.apache.openjpa.enhance.PCEnhancer"); final Class<?> arg2 = cl.loadClass("org.apache.openjpa.lib.util.Options"); cstr = arg2.getConstructor(Properties.class); mtd = enhancerClass.getMethod("run", String[].class, arg2); } catch (Exception e) { LOGGER.warning("openjpa enhancer can't be found in the container, will be skipped"); mtd = null; cstr = null; } optionsConstructor = cstr; enhancerMethod = mtd; } public void enhance(@Observes final BeforeDeploymentEvent event) { if (enhancerMethod == null) { LOGGER.debug("OpenJPA is not available so no deploy-time enhancement will be done"); return; } // find persistence.xml final Map<String, List<String>> classesByPXml = new HashMap<String, List<String>>(); final List<URL> usedUrls = new ArrayList<URL>(); // for fake classloader for (URL url : event.getUrls()) { final File file = URLs.toFile(url); if (file.isDirectory()) { final String pXmls = getWarPersistenceXml(url); if (pXmls != null) { feed(classesByPXml, pXmls); } usedUrls.add(url); } else if (file.getName().endsWith(".jar")) { try { final JarFile jar = new JarFile(file); ZipEntry entry = jar.getEntry(META_INF_PERSISTENCE_XML); if (entry != null) { final String path = file.getAbsolutePath(); final File unpacked = new File(path.substring(0, path.length() - 4) + TMP_ENHANCEMENT_SUFFIX); JarExtractor.extract(file, unpacked); // replace jar by folder url since otherwise enhancement doesn't work usedUrls.add(unpacked.toURI().toURL()); feed(classesByPXml, new File(unpacked, META_INF_PERSISTENCE_XML).getAbsolutePath()); } } catch (IOException e) { // ignored } } else { usedUrls.add(url); } } // enhancement final ClassLoader tccl = Thread.currentThread().getContextClassLoader(); final ClassLoader fakeClassLoader = new URLClassLoaderFirst( usedUrls.toArray(new URL[usedUrls.size()]), event.getParentClassLoader()); Thread.currentThread().setContextClassLoader(fakeClassLoader); try { for (Map.Entry<String, List<String>> entry : classesByPXml.entrySet()) { final Properties opts = new Properties(); opts.setProperty(PROPERTIES_FILE_PROP, entry.getKey()); final Object optsArg; try { optsArg = optionsConstructor.newInstance(opts); } catch (Exception e) { LOGGER.debug("can't create options for enhancing"); return; } LOGGER.info("enhancing url(s): " + Arrays.asList(event.getUrls())); try { enhancerMethod.invoke(null, toFilePaths(entry.getValue()), optsArg); } catch (Exception e) { LOGGER.warning("can't enhanced at deploy-time entities", e); } } } finally { Thread.currentThread().setContextClassLoader(tccl); usedUrls.clear(); } // clean up extracted jars and replace jar to keep consistent classloading for (Map.Entry<String, List<String>> entry : classesByPXml.entrySet()) { final List<String> values = entry.getValue(); for (String rawPath : values) { if (rawPath.endsWith(TMP_ENHANCEMENT_SUFFIX + "/") || rawPath.endsWith(TMP_ENHANCEMENT_SUFFIX)) { final File dir = new File(rawPath); final File file = new File( rawPath.substring(0, rawPath.length() - TMP_ENHANCEMENT_SUFFIX.length() - 1) + ".jar"); if (file.exists()) { String name = dir.getName(); name = name.substring(0, name.length() - TMP_ENHANCEMENT_SUFFIX.length()) + ".jar"; final File target = new File(dir.getParentFile(), name); try { // override existing jar otherwise classloading is broken in tomee Files.delete(file); JarCreator.jarDir(dir, target); } catch (final IOException e) { LOGGER.error("can't repackage enhanced jar file " + file.getName()); } Files.delete(dir); } } } values.clear(); } classesByPXml.clear(); } private void feed(final Map<String, List<String>> classesByPXml, final String pXml) { final List<String> paths = new ArrayList<String>(); // first add the classes directory where is the persistence.xml if (pXml.endsWith(META_INF_PERSISTENCE_XML)) { paths.add(pXml.substring(0, pXml.length() - META_INF_PERSISTENCE_XML.length())); } else if (pXml.endsWith("/WEB-INF/persistence.xml")) { paths.add(pXml.substring(0, pXml.length() - 24)); } // then jar-file try { final SAXParser parser = Saxs.factory().newSAXParser(); final JarFileParser handler = new JarFileParser(); parser.parse(new File(pXml), handler); for (String path : handler.getPaths()) { paths.add(relative(paths.iterator().next(), path)); } } catch (Exception e) { LOGGER.error("can't parse '" + pXml + "'", e); } classesByPXml.put(pXml, paths); } // relativePath = relative path to the jar file containing the persistence.xml private String relative(final String relativePath, final String pXmlPath) { return new File(new File(pXmlPath).getParent(), relativePath).getAbsolutePath(); } private String getWarPersistenceXml(final URL url) { final File dir = URLs.toFile(url); if (dir.isDirectory() && (dir.getAbsolutePath().endsWith("/WEB-INF/classes") || dir.getAbsolutePath().endsWith("/WEB-INF/classes/"))) { final File pXmlStd = new File(dir.getParentFile(), "persistence.xml"); if (pXmlStd.exists()) { return pXmlStd.getAbsolutePath(); } final File pXml = new File(dir, META_INF_PERSISTENCE_XML); if (pXml.exists()) { return pXml.getAbsolutePath(); } } return null; } private String[] toFilePaths(final List<String> urls) { final List<String> files = new ArrayList<String>(); for (String url : urls) { final File dir = new File(url); if (!dir.isDirectory()) { continue; } for (File f : Files.collect(dir, new ClassFilter())) { files.add(f.getAbsolutePath()); } } return files.toArray(new String[files.size()]); } private static class ClassFilter implements FileFilter { private static final String DEFAULT_INCLUDE = "\\*"; private static final String DEFAULT_EXCLUDE = ""; private static final Pattern INCLUDE_PATTERN = Pattern.compile( SystemInstance.get() .getOptions() .get(OPENEJB_JAR_ENHANCEMENT_INCLUDE, DEFAULT_INCLUDE)); private static final Pattern EXCLUDE_PATTERN = Pattern.compile( SystemInstance.get() .getOptions() .get(OPENEJB_JAR_ENHANCEMENT_EXCLUDE, DEFAULT_EXCLUDE)); @Override public boolean accept(final File file) { boolean isClass = file.getName().endsWith(CLASS_EXT); if (DEFAULT_EXCLUDE.equals(EXCLUDE_PATTERN.pattern()) && DEFAULT_INCLUDE.equals(INCLUDE_PATTERN.pattern())) { return isClass; } final String path = file.getAbsolutePath(); return isClass && INCLUDE_PATTERN.matcher(path).matches() && !EXCLUDE_PATTERN.matcher(path).matches(); } } private static class JarFileParser extends DefaultHandler { private final List<String> paths = new ArrayList<String>(); private boolean getIt = false; @Override public void startElement( final String uri, final String localName, final String qName, final Attributes att) throws SAXException { if (!localName.endsWith("jar-file")) { return; } getIt = true; } @Override public void characters(final char ch[], final int start, final int length) throws SAXException { if (getIt) { paths.add(String.valueOf(ch, start, length)); } } @Override public void endElement(final String uri, final String localName, final String qName) throws SAXException { getIt = false; } public List<String> getPaths() { return paths; } } }
public final class ValidatorBuilder { public static final Logger logger = Logger.getInstance(LogCategory.OPENEJB_STARTUP, ValidatorBuilder.class); public static final String VALIDATION_PROVIDER_KEY = "openejb.bean-validation.provider"; private ValidatorBuilder() { // no-op } public static ValidatorFactory buildFactory( final ClassLoader classLoader, final ValidationInfo info) { // now we will not be polluted by log build return buildFactory(info, classLoader); } public static ValidationInfo getInfo(final ValidationConfigType config) { final ValidationInfo info = new ValidationInfo(); if (config != null) { info.version = config.getVersion(); info.providerClassName = config.getDefaultProvider(); info.constraintFactoryClass = config.getConstraintValidatorFactory(); info.traversableResolverClass = config.getTraversableResolver(); info.messageInterpolatorClass = config.getMessageInterpolator(); info.parameterNameProviderClass = config.getParameterNameProvider(); final ExecutableValidationType executableValidation = config.getExecutableValidation(); if (executableValidation != null) { info.executableValidationEnabled = executableValidation.getEnabled(); final DefaultValidatedExecutableTypesType executableTypes = executableValidation.getDefaultValidatedExecutableTypes(); if (executableTypes != null) { for (final ExecutableType type : executableTypes.getExecutableType()) { info.validatedTypes.add(type.name()); } } } for (final PropertyType p : config.getProperty()) { info.propertyTypes.put(p.getName(), p.getValue()); } for (final String element : config.getConstraintMapping()) { info.constraintMappings.add(element); } } return info; } public static ValidatorFactory buildFactory( final ValidationInfo config, final ClassLoader classLoader) { ValidatorFactory factory = null; final Thread thread = Thread.currentThread(); final ClassLoader oldContextLoader = thread.getContextClassLoader(); try { thread.setContextClassLoader(classLoader); if (config == null) { factory = Validation.buildDefaultValidatorFactory(); } else { final Configuration<?> configuration = getConfig(config); try { factory = configuration.buildValidatorFactory(); } catch (final ValidationException ve) { thread.setContextClassLoader(ValidatorBuilder.class.getClassLoader()); factory = Validation.buildDefaultValidatorFactory(); thread.setContextClassLoader(classLoader); logger.warning( "Unable create validator factory with config " + config + " (" + ve.getMessage() + ")." + " Default factory will be used."); } } } finally { thread.setContextClassLoader(oldContextLoader); } return factory; } @SuppressWarnings("unchecked") private static Configuration<?> getConfig(final ValidationInfo info) { Configuration<?> target = null; final Thread thread = Thread.currentThread(); final ClassLoader classLoader = thread.getContextClassLoader(); String providerClassName = info.providerClassName; if (providerClassName == null) { providerClassName = SystemInstance.get().getOptions().get(VALIDATION_PROVIDER_KEY, (String) null); } if (providerClassName != null) { try { @SuppressWarnings({"unchecked", "rawtypes"}) final Class clazz = classLoader.loadClass(providerClassName); target = Validation.byProvider(clazz).configure(); logger.info("Using " + providerClassName + " as validation provider."); } catch (final ClassNotFoundException e) { logger.warning("Unable to load provider class " + providerClassName, e); } catch (final ValidationException ve) { logger.warning( "Unable create validator factory with provider " + providerClassName + " (" + ve.getMessage() + ")." + " Default one will be used."); } } if (target == null) { // force to use container provider to ignore any conflicting configuration thread.setContextClassLoader(ValidatorBuilder.class.getClassLoader()); target = Validation.byDefaultProvider().configure(); thread.setContextClassLoader(classLoader); } final Set<ExecutableType> types = new HashSet<>(); for (final String type : info.validatedTypes) { types.add(ExecutableType.valueOf(type)); } final Map<String, String> props = new HashMap<>(); for (final Map.Entry<Object, Object> entry : info.propertyTypes.entrySet()) { final PropertyType property = new PropertyType(); property.setName((String) entry.getKey()); property.setValue((String) entry.getValue()); props.put(property.getName(), property.getValue()); if (logger.isDebugEnabled()) { logger.debug( "Found property '" + property.getName() + "' with value '" + property.getValue()); } target.addProperty(property.getName(), property.getValue()); } final OpenEjbBootstrapConfig bootstrapConfig = new OpenEjbBootstrapConfig( providerClassName, info.constraintFactoryClass, info.messageInterpolatorClass, info.traversableResolverClass, info.parameterNameProviderClass, new HashSet<>(info.constraintMappings), info.executableValidationEnabled, types, props); final OpenEjbConfig config = new OpenEjbConfig(bootstrapConfig, target); target.ignoreXmlConfiguration(); final String messageInterpolatorClass = info.messageInterpolatorClass; if (messageInterpolatorClass != null) { try { @SuppressWarnings("unchecked") final Class<MessageInterpolator> clazz = (Class<MessageInterpolator>) classLoader.loadClass(messageInterpolatorClass); target.messageInterpolator(newInstance(config, clazz)); } catch (final Exception e) { logger.warning( "Unable to set " + messageInterpolatorClass + " as message interpolator.", e); } logger.info("Using " + messageInterpolatorClass + " as message interpolator."); } final String traversableResolverClass = info.traversableResolverClass; if (traversableResolverClass != null) { try { @SuppressWarnings("unchecked") final Class<TraversableResolver> clazz = (Class<TraversableResolver>) classLoader.loadClass(traversableResolverClass); target.traversableResolver(newInstance(config, clazz)); } catch (final Exception e) { logger.warning( "Unable to set " + traversableResolverClass + " as traversable resolver.", e); } logger.info("Using " + traversableResolverClass + " as traversable resolver."); } final String constraintFactoryClass = info.constraintFactoryClass; if (constraintFactoryClass != null) { try { @SuppressWarnings("unchecked") final Class<ConstraintValidatorFactory> clazz = (Class<ConstraintValidatorFactory>) classLoader.loadClass(constraintFactoryClass); target.constraintValidatorFactory(newInstance(config, clazz)); } catch (final Exception e) { logger.warning("Unable to set " + constraintFactoryClass + " as constraint factory.", e); } logger.info("Using " + constraintFactoryClass + " as constraint factory."); } for (final String mappingFileName : info.constraintMappings) { if (logger.isDebugEnabled()) { logger.debug("Opening input stream for " + mappingFileName); } final InputStream in = classLoader.getResourceAsStream(mappingFileName); if (in == null) { logger.warning( "Unable to open input stream for mapping file " + mappingFileName + ". It will be ignored"); } else { target.addMapping(in); } } if (info.parameterNameProviderClass != null) { try { final Class<ParameterNameProvider> clazz = (Class<ParameterNameProvider>) classLoader.loadClass(info.parameterNameProviderClass); target.parameterNameProvider(newInstance(config, clazz)); } catch (final Exception e) { logger.warning( "Unable to set " + info.parameterNameProviderClass + " as parameter name provider.", e); } logger.info("Using " + info.parameterNameProviderClass + " as parameter name provider."); } return config; } private static <T> T newInstance(final OpenEjbConfig config, final Class<T> clazz) throws Exception { final WebBeansContext webBeansContext = WebBeansContext.currentInstance(); if (webBeansContext == null) { return clazz.newInstance(); } final BeanManagerImpl beanManager = webBeansContext.getBeanManagerImpl(); if (!beanManager.isInUse()) { return clazz.newInstance(); } final AnnotatedType<T> annotatedType = beanManager.createAnnotatedType(clazz); final InjectionTarget<T> it = beanManager.createInjectionTarget(annotatedType); final CreationalContext<T> context = beanManager.createCreationalContext(null); final T instance = it.produce(context); it.inject(instance, context); it.postConstruct(instance); config.releasables.add(new Releasable<T>(context, it, instance)); return instance; } private static final class OpenEjbBootstrapConfig implements BootstrapConfiguration, Serializable { private final String providerClassName; private final String constraintFactoryClass; private final String messageInterpolatorClass; private final String traversableResolverClass; private final String parameterNameProviderClass; private final Set<String> constraintMappings; private final boolean executableValidationEnabled; private final Set<ExecutableType> validatedTypes; private final Map<String, String> props; public OpenEjbBootstrapConfig( final String providerClassName, final String constraintFactoryClass, final String messageInterpolatorClass, final String traversableResolverClass, final String parameterNameProviderClass, final Set<String> constraintMappings, final boolean executableValidationEnabled, final Set<ExecutableType> validatedTypes, final Map<String, String> props) { this.providerClassName = providerClassName; this.constraintFactoryClass = constraintFactoryClass; this.messageInterpolatorClass = messageInterpolatorClass; this.traversableResolverClass = traversableResolverClass; this.parameterNameProviderClass = parameterNameProviderClass; this.constraintMappings = constraintMappings; this.executableValidationEnabled = executableValidationEnabled; this.validatedTypes = validatedTypes; this.props = props; } @Override public String getDefaultProviderClassName() { return providerClassName; } @Override public String getConstraintValidatorFactoryClassName() { return constraintFactoryClass; } @Override public String getMessageInterpolatorClassName() { return messageInterpolatorClass; } @Override public String getTraversableResolverClassName() { return traversableResolverClass; } @Override public String getParameterNameProviderClassName() { return parameterNameProviderClass; } @Override public Set<String> getConstraintMappingResourcePaths() { return constraintMappings; } @Override public boolean isExecutableValidationEnabled() { return executableValidationEnabled; } @Override public Set<ExecutableType> getDefaultValidatedExecutableTypes() { return validatedTypes; } @Override public Map<String, String> getProperties() { return props; } } private static final class OpenEjbConfig<T extends Configuration<T>> implements Configuration<T> { private final Collection<Releasable<?>> releasables = new LinkedList<>(); private final Configuration<T> delegate; private final BootstrapConfiguration bootstrap; public OpenEjbConfig( final BootstrapConfiguration bootstrapConfig, final Configuration<T> target) { bootstrap = bootstrapConfig; delegate = target; } @Override public T ignoreXmlConfiguration() { return delegate.ignoreXmlConfiguration(); } @Override public T messageInterpolator(final MessageInterpolator interpolator) { return delegate.messageInterpolator(interpolator); } @Override public T traversableResolver(final TraversableResolver resolver) { return delegate.traversableResolver(resolver); } @Override public T constraintValidatorFactory( final ConstraintValidatorFactory constraintValidatorFactory) { return delegate.constraintValidatorFactory(constraintValidatorFactory); } @Override public T addMapping(final InputStream stream) { return delegate.addMapping(stream); } @Override public T addProperty(final String name, final String value) { return delegate.addProperty(name, value); } @Override public MessageInterpolator getDefaultMessageInterpolator() { return delegate.getDefaultMessageInterpolator(); } @Override public TraversableResolver getDefaultTraversableResolver() { return delegate.getDefaultTraversableResolver(); } @Override public ConstraintValidatorFactory getDefaultConstraintValidatorFactory() { return delegate.getDefaultConstraintValidatorFactory(); } @Override public ValidatorFactory buildValidatorFactory() { return new OpenEJBValidatorFactory(delegate.buildValidatorFactory(), releasables); } @Override public T parameterNameProvider(ParameterNameProvider parameterNameProvider) { return delegate.parameterNameProvider(parameterNameProvider); } @Override public ParameterNameProvider getDefaultParameterNameProvider() { return delegate.getDefaultParameterNameProvider(); } @Override public BootstrapConfiguration getBootstrapConfiguration() { return bootstrap; } } private static final class OpenEJBValidatorFactory implements ValidatorFactory { private final ValidatorFactory delegate; private final Collection<Releasable<?>> toRelease; public OpenEJBValidatorFactory( final ValidatorFactory validatorFactory, final Collection<Releasable<?>> releasables) { delegate = validatorFactory; toRelease = releasables; } @Override public Validator getValidator() { return delegate.getValidator(); } @Override public ValidatorContext usingContext() { return delegate.usingContext(); } @Override public MessageInterpolator getMessageInterpolator() { return delegate.getMessageInterpolator(); } @Override public TraversableResolver getTraversableResolver() { return delegate.getTraversableResolver(); } @Override public ConstraintValidatorFactory getConstraintValidatorFactory() { return delegate.getConstraintValidatorFactory(); } @Override public <T> T unwrap(final Class<T> type) { return delegate.unwrap(type); } @Override public ParameterNameProvider getParameterNameProvider() { return delegate.getParameterNameProvider(); } @Override public void close() { delegate.close(); for (final Releasable<?> r : toRelease) { r.release(); } } } private static final class Releasable<T> { private final CreationalContext<T> context; private final InjectionTarget<T> injectionTarget; private final T instance; private Releasable( final CreationalContext<T> context, final InjectionTarget<T> injectionTarget, final T instance) { this.context = context; this.injectionTarget = injectionTarget; this.instance = instance; } private void release() { try { injectionTarget.preDestroy(instance); injectionTarget.dispose(instance); context.release(); } catch (final Exception | NoClassDefFoundError e) { // no-op } } } }
public class InitEjbDeployments implements DynamicDeployer { public static Messages messages = new Messages("org.apache.openejb.util.resources"); public static Logger logger = Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources"); private final StringTemplate deploymentIdTemplate; private static final String DEPLOYMENT_ID_FORMAT = "openejb.deploymentId.format"; public InitEjbDeployments() { final String format = SystemInstance.get().getOptions().get(DEPLOYMENT_ID_FORMAT, "{ejbName}"); this.deploymentIdTemplate = new StringTemplate(format); } public synchronized AppModule deploy(final AppModule appModule) throws OpenEJBException { final Set<String> abstractSchemaNames = new HashSet<String>(); for (final EjbModule ejbModule : appModule.getEjbModules()) { for (final EnterpriseBean bean : ejbModule.getEjbJar().getEnterpriseBeans()) { if (isCmpEntity(bean)) { final EntityBean entity = (EntityBean) bean; final String name = entity.getAbstractSchemaName(); if (name != null) { abstractSchemaNames.add(name); } } } } final Map<String, String> contextData = new HashMap<String, String>(); contextData.put("appId", appModule.getModuleId()); for (final EjbModule ejbModule : appModule.getEjbModules()) { contextData.put("ejbJarId", ejbModule.getModuleId()); deploy(ejbModule, contextData, abstractSchemaNames); } contextData.clear(); return appModule; } public EjbModule deploy(final EjbModule ejbModule) throws OpenEJBException { return deploy(ejbModule, new HashMap<String, String>(), new HashSet<String>()); } private EjbModule deploy( final EjbModule ejbModule, final Map<String, String> contextData, final Set<String> abstractSchemaNames) throws OpenEJBException { contextData.put("moduleId", ejbModule.getModuleId()); contextData.put("moduleUri", ejbModule.getModuleUri().toString()); final OpenejbJar openejbJar; if (ejbModule.getOpenejbJar() != null) { openejbJar = ejbModule.getOpenejbJar(); } else { openejbJar = new OpenejbJar(); ejbModule.setOpenejbJar(openejbJar); } StringTemplate deploymentIdTemplate = this.deploymentIdTemplate; if (openejbJar.getProperties().containsKey(DEPLOYMENT_ID_FORMAT)) { final String format = openejbJar.getProperties().getProperty(DEPLOYMENT_ID_FORMAT); logger.info("Using " + DEPLOYMENT_ID_FORMAT + " '" + format + "'"); deploymentIdTemplate = new StringTemplate(format); } for (final EnterpriseBean bean : ejbModule.getEjbJar().getEnterpriseBeans()) { StringTemplate template = deploymentIdTemplate; final org.apache.openejb.api.EjbDeployment annotation = getEjbDeploymentAnnotation(ejbModule, bean); EjbDeployment ejbDeployment = openejbJar.getDeploymentsByEjbName().get(bean.getEjbName()); if (ejbDeployment == null) { ejbDeployment = new EjbDeployment(); ejbDeployment.setEjbName(bean.getEjbName()); if (annotation != null && isDefined(annotation.id())) { template = new StringTemplate(annotation.id()); ejbDeployment.setDeploymentId(formatDeploymentId(bean, contextData, template)); } else { ejbDeployment.setDeploymentId(formatDeploymentId(bean, contextData, template)); if (!(bean instanceof ManagedBean) || !((ManagedBean) bean).isHidden()) { logger.info( "Auto-deploying ejb " + bean.getEjbName() + ": EjbDeployment(deployment-id=" + ejbDeployment.getDeploymentId() + ")"); } } openejbJar.getEjbDeployment().add(ejbDeployment); } else if (ejbDeployment.getDeploymentId() == null) { if (annotation != null && isDefined(annotation.id())) { template = new StringTemplate(annotation.id()); ejbDeployment.setDeploymentId(formatDeploymentId(bean, contextData, template)); } else { ejbDeployment.setDeploymentId(formatDeploymentId(bean, contextData, template)); logger.info( "Auto-assigning deployment-id for ejb " + bean.getEjbName() + ": EjbDeployment(deployment-id=" + ejbDeployment.getDeploymentId() + ")"); } } if (ejbDeployment.getContainerId() == null && annotation != null && isDefined(annotation.container())) { ejbDeployment.setContainerId(annotation.container()); } if (isCmpEntity(bean)) { final EntityBean entity = (EntityBean) bean; if (entity.getAbstractSchemaName() == null) { String abstractSchemaName = bean.getEjbName().trim().replaceAll("[ \\t\\n\\r-]+", "_"); // The AbstractSchemaName must be unique, we should check that it is if (abstractSchemaNames.contains(abstractSchemaName)) { int i = 2; while (abstractSchemaNames.contains(abstractSchemaName + i)) { i++; } abstractSchemaName = abstractSchemaName + i; } abstractSchemaNames.add(abstractSchemaName); entity.setAbstractSchemaName(abstractSchemaName); } } } return ejbModule; } private org.apache.openejb.api.EjbDeployment getEjbDeploymentAnnotation( final EjbModule ejbModule, final EnterpriseBean bean) { try { final Class<?> beanClass = ejbModule.getClassLoader().loadClass(bean.getEjbClass()); return beanClass.getAnnotation(org.apache.openejb.api.EjbDeployment.class); } catch (final ClassNotFoundException e) { // this should never happen, the class has already been loaded a ton of times by this point // unfortunately we have some unit tests that prevent us from throwing an exception just in // case // Those are OpenEjb2ConversionTest and SunCmpConversionTest return null; } } private boolean isDefined(final String s) { return s != null && !"".equals(s); } private static boolean isCmpEntity(final EnterpriseBean bean) { return bean instanceof EntityBean && ((EntityBean) bean).getPersistenceType() == PersistenceType.CONTAINER; } private String formatDeploymentId( final EnterpriseBean bean, final Map<String, String> contextData, final StringTemplate template) { contextData.put("ejbType", bean.getClass().getSimpleName()); contextData.put("ejbClass", bean.getEjbClass()); // we don't have the ejb class object (only the string name) so we have // to extract the simple name from the FQN of the class final int simpleNameIdx = bean.getEjbClass().lastIndexOf("."); contextData.put("ejbClass.simpleName", bean.getEjbClass().substring(simpleNameIdx + 1)); contextData.put("ejbName", bean.getEjbName()); final String name = template.apply(contextData); if (bean instanceof CompManagedBean) { // avoid conflict in ear between an ejbmodule and a war using the same // name return name + System.identityHashCode(bean); } return name; } }
public class ManagedContainer implements RpcContainer { private static final Logger logger = Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources"); private final Object containerID; private final SecurityService securityService; // todo this should be part of the constructor protected final JtaEntityManagerRegistry entityManagerRegistry = SystemInstance.get().getComponent(JtaEntityManagerRegistry.class); /** Index used for getDeployments() and getDeploymentInfo(deploymentId). */ protected final Map<Object, BeanContext> deploymentsById = new HashMap<Object, BeanContext>(); protected final Cache<Object, Instance> cache; private final ConcurrentHashMap<Object, Instance> checkedOutInstances = new ConcurrentHashMap<Object, Instance>(); private final SessionContext sessionContext; public ManagedContainer(Object id, SecurityService securityService) throws SystemException { this.cache = new SimpleCache<Object, Instance>( null, new SimplePassivater(), 1000, 50, new Duration("1 hour")); this.containerID = id; this.securityService = securityService; cache.setListener(new StatefulCacheListener()); sessionContext = new ManagedContext( securityService, new ManagedUserTransaction(new EjbUserTransaction(), entityManagerRegistry)); } private Map<Method, MethodType> getLifecycleMethodsOfInterface(BeanContext beanContext) { Map<Method, MethodType> methods = new HashMap<Method, MethodType>(); List<Method> removeMethods = beanContext.getRemoveMethods(); for (Method removeMethod : removeMethods) { methods.put(removeMethod, MethodType.REMOVE); for (Class businessLocal : beanContext.getBusinessLocalInterfaces()) { try { Method method = businessLocal.getMethod(removeMethod.getName()); methods.put(method, MethodType.REMOVE); } catch (NoSuchMethodException thatsFine) { } } for (Class businessRemote : beanContext.getBusinessRemoteInterfaces()) { try { Method method = businessRemote.getMethod(removeMethod.getName()); methods.put(method, MethodType.REMOVE); } catch (NoSuchMethodException thatsFine) { } } } Class legacyRemote = beanContext.getRemoteInterface(); if (legacyRemote != null) { try { Method method = legacyRemote.getMethod("remove"); methods.put(method, MethodType.REMOVE); } catch (NoSuchMethodException thatsFine) { } } Class legacyLocal = beanContext.getLocalInterface(); if (legacyLocal != null) { try { Method method = legacyLocal.getMethod("remove"); methods.put(method, MethodType.REMOVE); } catch (NoSuchMethodException thatsFine) { } } Class businessLocalHomeInterface = beanContext.getBusinessLocalInterface(); if (businessLocalHomeInterface != null) { for (Method method : BeanContext.BusinessLocalHome.class.getMethods()) { if (method.getName().startsWith("create")) { methods.put(method, MethodType.CREATE); } else if (method.getName().equals("remove")) { methods.put(method, MethodType.REMOVE); } } } Class businessLocalBeanHomeInterface = beanContext.getBusinessLocalBeanInterface(); if (businessLocalBeanHomeInterface != null) { for (Method method : BeanContext.BusinessLocalBeanHome.class.getMethods()) { if (method.getName().startsWith("create")) { methods.put(method, MethodType.CREATE); } else if (method.getName().equals("remove")) { methods.put(method, MethodType.REMOVE); } } } Class businessRemoteHomeInterface = beanContext.getBusinessRemoteInterface(); if (businessRemoteHomeInterface != null) { for (Method method : BeanContext.BusinessRemoteHome.class.getMethods()) { if (method.getName().startsWith("create")) { methods.put(method, MethodType.CREATE); } else if (method.getName().equals("remove")) { methods.put(method, MethodType.REMOVE); } } } Class homeInterface = beanContext.getHomeInterface(); if (homeInterface != null) { for (Method method : homeInterface.getMethods()) { if (method.getName().startsWith("create")) { methods.put(method, MethodType.CREATE); } else if (method.getName().equals("remove")) { methods.put(method, MethodType.REMOVE); } } } Class localHomeInterface = beanContext.getLocalHomeInterface(); if (localHomeInterface != null) { for (Method method : localHomeInterface.getMethods()) { if (method.getName().startsWith("create")) { methods.put(method, MethodType.CREATE); } else if (method.getName().equals("remove")) { methods.put(method, MethodType.REMOVE); } } } return methods; } public static enum MethodType { CREATE, REMOVE, BUSINESS } public ContainerType getContainerType() { return ContainerType.STATEFUL; } public Object getContainerID() { return containerID; } public synchronized BeanContext[] getBeanContexts() { return deploymentsById.values().toArray(new BeanContext[deploymentsById.size()]); } public synchronized BeanContext getBeanContext(Object deploymentID) { return deploymentsById.get(deploymentID); } public void start(BeanContext beanContext) throws OpenEJBException {} public void stop(BeanContext beanContext) throws OpenEJBException {} public synchronized void undeploy(final BeanContext bean) throws OpenEJBException { Data data = (Data) bean.getContainerData(); MBeanServer server = LocalMBeanServer.get(); for (ObjectName objectName : data.jmxNames) { try { server.unregisterMBean(objectName); } catch (Exception e) { logger.error("Unable to unregister MBean " + objectName); } } deploymentsById.remove(bean.getDeploymentID()); bean.setContainer(null); bean.setContainerData(null); cache.removeAll( new CacheFilter<Instance>() { public boolean matches(Instance instance) { return bean == instance.beanContext; } }); } public synchronized void deploy(BeanContext beanContext) throws OpenEJBException { Map<Method, MethodType> methods = getLifecycleMethodsOfInterface(beanContext); deploymentsById.put(beanContext.getDeploymentID(), beanContext); beanContext.setContainer(this); Data data = new Data(new Index<Method, MethodType>(methods)); beanContext.setContainerData(data); // Create stats interceptor StatsInterceptor stats = new StatsInterceptor(beanContext.getBeanClass()); beanContext.addSystemInterceptor(stats); MBeanServer server = LocalMBeanServer.get(); ObjectNameBuilder jmxName = new ObjectNameBuilder("openejb.management"); jmxName.set("J2EEServer", "openejb"); jmxName.set("J2EEApplication", null); jmxName.set("EJBModule", beanContext.getModuleID()); jmxName.set("StatelessSessionBean", beanContext.getEjbName()); jmxName.set("j2eeType", ""); jmxName.set("name", beanContext.getEjbName()); // register the invocation stats interceptor try { ObjectName objectName = jmxName.set("j2eeType", "Invocations").build(); server.registerMBean(new ManagedMBean(stats), objectName); data.jmxNames.add(objectName); } catch (Exception e) { logger.error("Unable to register MBean ", e); } try { final Context context = beanContext.getJndiEnc(); context.bind("comp/EJBContext", sessionContext); } catch (NamingException e) { throw new OpenEJBException("Failed to bind EJBContext", e); } beanContext.set(EJBContext.class, this.sessionContext); } /** @deprecated use invoke signature without 'securityIdentity' argument. */ public Object invoke( Object deployID, Method callMethod, Object[] args, Object primKey, Object securityIdentity) throws OpenEJBException { return invoke(deployID, null, callMethod.getDeclaringClass(), callMethod, args, primKey); } public Object invoke( Object deployID, Class callInterface, Method callMethod, Object[] args, Object primKey) throws OpenEJBException { return invoke(deployID, null, callInterface, callMethod, args, primKey); } public Object invoke( Object deployID, InterfaceType type, Class callInterface, Method callMethod, Object[] args, Object primKey) throws OpenEJBException { BeanContext beanContext = this.getBeanContext(deployID); if (beanContext == null) throw new OpenEJBException( "Deployment does not exist in this container. Deployment(id='" + deployID + "'), Container(id='" + containerID + "')"); // Use the backup way to determine call type if null was supplied. if (type == null) type = beanContext.getInterfaceType(callInterface); Data data = (Data) beanContext.getContainerData(); MethodType methodType = data.getMethodIndex().get(callMethod); methodType = (methodType != null) ? methodType : MethodType.BUSINESS; switch (methodType) { case CREATE: return createEJBObject(beanContext, callMethod, args, type); case REMOVE: return removeEJBObject(beanContext, primKey, callInterface, callMethod, args, type); default: return businessMethod(beanContext, primKey, callInterface, callMethod, args, type); } } protected ProxyInfo createEJBObject( BeanContext beanContext, Method callMethod, Object[] args, InterfaceType interfaceType) throws OpenEJBException { // generate a new primary key Object primaryKey = newPrimaryKey(); ThreadContext createContext = new ThreadContext(beanContext, primaryKey); ThreadContext oldCallContext = ThreadContext.enter(createContext); try { // Security check checkAuthorization(callMethod, interfaceType); // Create the extended entity managers for this instance Index<EntityManagerFactory, JtaEntityManagerRegistry.EntityManagerTracker> entityManagers = createEntityManagers(beanContext); // Register the newly created entity managers if (entityManagers != null) { try { entityManagerRegistry.addEntityManagers( (String) beanContext.getDeploymentID(), primaryKey, entityManagers); } catch (EntityManagerAlreadyRegisteredException e) { throw new EJBException(e); } } createContext.setCurrentOperation(Operation.CREATE); createContext.setCurrentAllowedStates(null); // Start transaction TransactionPolicy txPolicy = createTransactionPolicy( createContext.getBeanContext().getTransactionType(callMethod, interfaceType), createContext); Instance instance = null; try { // Create new instance try { final InstanceContext context = beanContext.newInstance(); // Wrap-up everthing into a object instance = new Instance( beanContext, primaryKey, context.getBean(), context.getInterceptors(), context.getCreationalContext(), entityManagers); } catch (Throwable throwable) { ThreadContext callContext = ThreadContext.getThreadContext(); handleSystemException(callContext.getTransactionPolicy(), throwable, callContext); throw new IllegalStateException(throwable); // should never be reached } // add to cache cache.add(primaryKey, instance); // instance starts checked-out checkedOutInstances.put(primaryKey, instance); // Register for synchronization callbacks registerSessionSynchronization(instance, createContext); // Invoke create for legacy beans if (!callMethod.getDeclaringClass().equals(BeanContext.BusinessLocalHome.class) && !callMethod.getDeclaringClass().equals(BeanContext.BusinessRemoteHome.class) && !callMethod.getDeclaringClass().equals(BeanContext.BusinessLocalBeanHome.class)) { // Setup for business invocation Method createOrInit = beanContext.getMatchingBeanMethod(callMethod); createContext.set(Method.class, createOrInit); // Initialize interceptor stack InterceptorStack interceptorStack = new InterceptorStack( instance.bean, createOrInit, Operation.CREATE, new ArrayList<InterceptorData>(), new HashMap<String, Object>()); // Invoke if (args == null) { interceptorStack.invoke(); } else { interceptorStack.invoke(args); } } } catch (Throwable e) { handleException(createContext, txPolicy, e); } finally { afterInvoke(createContext, txPolicy, instance); } return new ProxyInfo(beanContext, primaryKey); } finally { ThreadContext.exit(oldCallContext); } } protected Object newPrimaryKey() { return new VMID(); } protected Object removeEJBObject( BeanContext beanContext, Object primKey, Class callInterface, Method callMethod, Object[] args, InterfaceType interfaceType) throws OpenEJBException { if (primKey == null) throw new NullPointerException("primKey is null"); ThreadContext callContext = new ThreadContext(beanContext, primKey); ThreadContext oldCallContext = ThreadContext.enter(callContext); try { // Security check checkAuthorization(callMethod, interfaceType); // If a bean managed transaction is active, the bean can not be removed if (interfaceType.isComponent()) { Instance instance = checkedOutInstances.get(primKey); /** * According to EJB 3.0 "4.4.4 Restrictions for Transactions" any remove methods from home * or component interfaces must not be allowed if the bean instance is in a transaction. * Unfortunately, the Java EE 5 TCK has tests that ignore the restrictions in 4.4.4 and * expect beans in transactions can be removed via their home or component interface. The * test to see if the bean instance implements javax.ejb.SessionBean is a workaround for * passing the TCK while the tests in question can be challenged or the spec can be * changed/updated. */ if (instance != null && instance.bean instanceof javax.ejb.SessionBean) { throw new ApplicationException( new RemoveException("A stateful EJB enrolled in a transaction can not be removed")); } } // Start transaction TransactionPolicy txPolicy = createTransactionPolicy( callContext.getBeanContext().getTransactionType(callMethod, interfaceType), callContext); Object returnValue = null; boolean retain = false; Instance instance = null; Method runMethod = null; try { // Obtain instance instance = obtainInstance(primKey, callContext); // Resume previous Bean transaction if there was one if (txPolicy instanceof BeanTransactionPolicy) { // Resume previous Bean transaction if there was one SuspendedTransaction suspendedTransaction = instance.getBeanTransaction(); if (suspendedTransaction != null) { instance.setBeanTransaction(null); BeanTransactionPolicy beanTxEnv = (BeanTransactionPolicy) txPolicy; beanTxEnv.resumeUserTransaction(suspendedTransaction); } } // Register the entity managers registerEntityManagers(instance, callContext); // Register for synchronization callbacks registerSessionSynchronization(instance, callContext); // Setup for remove invocation callContext.setCurrentOperation(Operation.REMOVE); callContext.setCurrentAllowedStates(null); callContext.setInvokedInterface(callInterface); runMethod = beanContext.getMatchingBeanMethod(callMethod); callContext.set(Method.class, runMethod); // Do not pass arguments on home.remove(remote) calls Class<?> declaringClass = callMethod.getDeclaringClass(); if (declaringClass.equals(EJBHome.class) || declaringClass.equals(EJBLocalHome.class)) { args = new Object[] {}; } // Initialize interceptor stack List<InterceptorData> interceptors = beanContext.getMethodInterceptors(runMethod); InterceptorStack interceptorStack = new InterceptorStack( instance.bean, runMethod, Operation.REMOVE, interceptors, instance.interceptors); // Invoke if (args == null) { returnValue = interceptorStack.invoke(); } else { returnValue = interceptorStack.invoke(args); } } catch (InvalidateReferenceException e) { throw e; } catch (Throwable e) { if (interfaceType.isBusiness()) { retain = beanContext.retainIfExeption(runMethod); handleException(callContext, txPolicy, e); } else { try { handleException(callContext, txPolicy, e); } catch (ApplicationException ae) { // Don't throw application exceptions for non-business interface removes } } } finally { if (!retain) { try { callContext.setCurrentOperation(Operation.PRE_DESTROY); List<InterceptorData> callbackInterceptors = beanContext.getCallbackInterceptors(); InterceptorStack interceptorStack = new InterceptorStack( instance.bean, null, Operation.PRE_DESTROY, callbackInterceptors, instance.interceptors); interceptorStack.invoke(); } catch (Throwable callbackException) { String logMessage = "An unexpected exception occured while invoking the preDestroy method on the removed Stateful SessionBean instance; " + callbackException.getClass().getName() + " " + callbackException.getMessage(); /* [1] Log the exception or error */ logger.error(logMessage); } finally { callContext.setCurrentOperation(Operation.REMOVE); } // todo destroy extended persistence contexts discardInstance(callContext); } // Commit transaction afterInvoke(callContext, txPolicy, instance); } return returnValue; } finally { ThreadContext.exit(oldCallContext); } } protected Object businessMethod( BeanContext beanContext, Object primKey, Class callInterface, Method callMethod, Object[] args, InterfaceType interfaceType) throws OpenEJBException { ThreadContext callContext = new ThreadContext(beanContext, primKey); ThreadContext oldCallContext = ThreadContext.enter(callContext); try { // Security check checkAuthorization(callMethod, interfaceType); // Start transaction TransactionPolicy txPolicy = createTransactionPolicy( callContext.getBeanContext().getTransactionType(callMethod, interfaceType), callContext); Object returnValue = null; Instance instance = null; try { // Obtain instance instance = obtainInstance(primKey, callContext); // Resume previous Bean transaction if there was one if (txPolicy instanceof BeanTransactionPolicy) { SuspendedTransaction suspendedTransaction = instance.getBeanTransaction(); if (suspendedTransaction != null) { instance.setBeanTransaction(null); BeanTransactionPolicy beanTxEnv = (BeanTransactionPolicy) txPolicy; beanTxEnv.resumeUserTransaction(suspendedTransaction); } } // Register the entity managers registerEntityManagers(instance, callContext); // Register for synchronization callbacks registerSessionSynchronization(instance, callContext); // Setup for business invocation callContext.setCurrentOperation(Operation.BUSINESS); callContext.setCurrentAllowedStates(null); callContext.setInvokedInterface(callInterface); Method runMethod = beanContext.getMatchingBeanMethod(callMethod); callContext.set(Method.class, runMethod); // Initialize interceptor stack List<InterceptorData> interceptors = beanContext.getMethodInterceptors(runMethod); InterceptorStack interceptorStack = new InterceptorStack( instance.bean, runMethod, Operation.BUSINESS, interceptors, instance.interceptors); // Invoke returnValue = interceptorStack.invoke(args); } catch (Throwable e) { handleException(callContext, txPolicy, e); } finally { // Commit transaction afterInvoke(callContext, txPolicy, instance); } return returnValue; } finally { ThreadContext.exit(oldCallContext); } } private Instance obtainInstance(Object primaryKey, ThreadContext callContext) throws OpenEJBException { if (primaryKey == null) { throw new SystemException( new NullPointerException( "Cannot obtain an instance of the stateful session bean with a null session id")); } Transaction currentTransaction = getTransaction(callContext); // Find the instance Instance instance = checkedOutInstances.get(primaryKey); if (instance == null) { try { instance = cache.checkOut(primaryKey); } catch (OpenEJBException e) { throw e; } catch (Exception e) { throw new SystemException("Unexpected load exception", e); } // Did we find the instance? if (instance == null) { throw new InvalidateReferenceException(new NoSuchObjectException("Not Found")); } // remember instance until it is returned to the cache checkedOutInstances.put(primaryKey, instance); } synchronized (instance) { // Is the instance alreayd in use? if (instance.isInUse()) { // the bean is already being invoked; the only reentrant/concurrent operations allowed are // Session synchronization callbacks Operation currentOperation = callContext.getCurrentOperation(); if (currentOperation != Operation.AFTER_COMPLETION && currentOperation != Operation.BEFORE_COMPLETION) { throw new ApplicationException(new RemoteException("Concurrent calls not allowed.")); } } if (instance.getTransaction() != null) { if (!instance.getTransaction().equals(currentTransaction) && !instance.getLock().tryLock()) { throw new ApplicationException( new RemoteException( "Instance is in a transaction and cannot be invoked outside that transaction. See EJB 3.0 Section 4.4.4")); } } else { instance.setTransaction(currentTransaction); } // Mark the instance in use so we can detect reentrant calls instance.setInUse(true); return instance; } } private Transaction getTransaction(ThreadContext callContext) { TransactionPolicy policy = callContext.getTransactionPolicy(); Transaction currentTransaction = null; if (policy instanceof JtaTransactionPolicy) { JtaTransactionPolicy jtaPolicy = (JtaTransactionPolicy) policy; currentTransaction = jtaPolicy.getCurrentTransaction(); } return currentTransaction; } private void releaseInstance(Instance instance) { // Don't pool if the bean has been undeployed if (instance.beanContext.isDestroyed()) return; // verify the instance is not associated with a bean-managed transaction if (instance.getBeanTransaction() != null) { new IllegalStateException("Instance has an active bean-managed transaction"); } // no longer in use instance.setInUse(false); if (instance.getTransaction() == null) { // return to cache cache.checkIn(instance.primaryKey); // no longer checked out checkedOutInstances.remove(instance.primaryKey); } } private void discardInstance(ThreadContext threadContext) { Object primaryKey = threadContext.getPrimaryKey(); if (primaryKey == null) { return; } Instance instance = checkedOutInstances.remove(primaryKey); cache.remove(primaryKey); if (instance.creationalContext != null) { instance.creationalContext.release(); } } private void checkAuthorization(Method callMethod, InterfaceType interfaceType) throws ApplicationException { boolean authorized = securityService.isCallerAuthorized(callMethod, interfaceType); if (!authorized) { throw new ApplicationException( new EJBAccessException("Unauthorized Access by Principal Denied")); } } private void handleException(ThreadContext callContext, TransactionPolicy txPolicy, Throwable e) throws ApplicationException { if (e instanceof ApplicationException) { throw (ApplicationException) e; } ExceptionType type = callContext.getBeanContext().getExceptionType(e); if (type == SYSTEM) { discardInstance(callContext); handleSystemException(txPolicy, e, callContext); } else { handleApplicationException(txPolicy, e, type == APPLICATION_ROLLBACK); } } private void afterInvoke(ThreadContext callContext, TransactionPolicy txPolicy, Instance instance) throws OpenEJBException { try { unregisterEntityManagers(instance, callContext); if (instance != null && txPolicy instanceof BeanTransactionPolicy) { // suspend the currently running transaction if any SuspendedTransaction suspendedTransaction = null; try { BeanTransactionPolicy beanTxEnv = (BeanTransactionPolicy) txPolicy; suspendedTransaction = beanTxEnv.suspendUserTransaction(); } catch (SystemException e) { handleSystemException(txPolicy, e, callContext); } finally { instance.setBeanTransaction(suspendedTransaction); } } } finally { if (instance != null) { instance.setInUse(false); } EjbTransactionUtil.afterInvoke(txPolicy, callContext); } } private Index<EntityManagerFactory, JtaEntityManagerRegistry.EntityManagerTracker> createEntityManagers(BeanContext beanContext) { // create the extended entity managers Index<EntityManagerFactory, Map> factories = beanContext.getExtendedEntityManagerFactories(); Index<EntityManagerFactory, JtaEntityManagerRegistry.EntityManagerTracker> entityManagers = null; if (factories != null && factories.size() > 0) { entityManagers = new Index<EntityManagerFactory, JtaEntityManagerRegistry.EntityManagerTracker>( new ArrayList<EntityManagerFactory>(factories.keySet())); for (Map.Entry<EntityManagerFactory, Map> entry : factories.entrySet()) { EntityManagerFactory entityManagerFactory = entry.getKey(); Map properties = entry.getValue(); JtaEntityManagerRegistry.EntityManagerTracker entityManagerTracker = entityManagerRegistry.getInheritedEntityManager(entityManagerFactory); EntityManager entityManager; if (entityManagerTracker == null) { if (properties != null) { entityManager = entityManagerFactory.createEntityManager(properties); } else { entityManager = entityManagerFactory.createEntityManager(); } entityManagerTracker = new JtaEntityManagerRegistry.EntityManagerTracker(entityManager); } else { entityManagerTracker.incCounter(); } entityManagers.put(entityManagerFactory, entityManagerTracker); } } return entityManagers; } private void registerEntityManagers(Instance instance, ThreadContext callContext) throws OpenEJBException { if (entityManagerRegistry == null) return; BeanContext beanContext = callContext.getBeanContext(); // get the factories Index<EntityManagerFactory, Map> factories = beanContext.getExtendedEntityManagerFactories(); if (factories == null) return; // get the managers for the factories Map<EntityManagerFactory, JtaEntityManagerRegistry.EntityManagerTracker> entityManagers = instance.getEntityManagers(factories); if (entityManagers == null) return; // register them try { entityManagerRegistry.addEntityManagers( (String) beanContext.getDeploymentID(), instance.primaryKey, entityManagers); } catch (EntityManagerAlreadyRegisteredException e) { throw new EJBException(e); } } private void unregisterEntityManagers(Instance instance, ThreadContext callContext) { if (entityManagerRegistry == null) return; if (instance == null) return; BeanContext beanContext = callContext.getBeanContext(); // register them entityManagerRegistry.removeEntityManagers( (String) beanContext.getDeploymentID(), instance.primaryKey); } private void registerSessionSynchronization(Instance instance, ThreadContext callContext) { TransactionPolicy txPolicy = callContext.getTransactionPolicy(); if (txPolicy == null) { throw new IllegalStateException("ThreadContext does not contain a TransactionEnvironment"); } SessionSynchronizationCoordinator coordinator = (SessionSynchronizationCoordinator) txPolicy.getResource(SessionSynchronizationCoordinator.class); if (coordinator == null) { coordinator = new SessionSynchronizationCoordinator(txPolicy); txPolicy.registerSynchronization(coordinator); txPolicy.putResource(SessionSynchronizationCoordinator.class, coordinator); } // SessionSynchronization are only enabled for beans after CREATE that are not bean-managed and // implement the SessionSynchronization interface boolean synchronize = callContext.getCurrentOperation() != Operation.CREATE && callContext.getBeanContext().isSessionSynchronized() && txPolicy.isTransactionActive(); coordinator.registerSessionSynchronization( instance, callContext.getBeanContext(), callContext.getPrimaryKey(), synchronize); } /** * SessionSynchronizationCoordinator handles afterBegin, beforeCompletion and afterCompletion * callbacks. * * <p>This class also is responsible for calling releaseInstance after the transaction completes. */ private class SessionSynchronizationCoordinator implements TransactionSynchronization { private final Map<Object, Synchronization> registry = new HashMap<Object, Synchronization>(); private final TransactionPolicy txPolicy; private SessionSynchronizationCoordinator(TransactionPolicy txPolicy) { this.txPolicy = txPolicy; } public class Synchronization { private final Instance instance; private boolean callSessionSynchronization; public Synchronization(Instance instance) { this.instance = instance; } public synchronized boolean isCallSessionSynchronization() { return callSessionSynchronization; } public synchronized boolean setCallSessionSynchronization(boolean synchronize) { boolean oldValue = this.callSessionSynchronization; this.callSessionSynchronization = synchronize; return oldValue; } } private void registerSessionSynchronization( Instance instance, BeanContext beanContext, Object primaryKey, boolean synchronize) { Synchronization synchronization = registry.get(primaryKey); if (synchronization == null) { synchronization = new Synchronization(instance); registry.put(primaryKey, synchronization); } boolean wasSynchronized = synchronization.setCallSessionSynchronization(synchronize); // check if afterBegin has already been invoked or if this is not a session synchronization // bean if (wasSynchronized || !synchronize) { return; } // Invoke afterBegin ThreadContext callContext = new ThreadContext(instance.beanContext, instance.primaryKey, Operation.AFTER_BEGIN); callContext.setCurrentAllowedStates(null); ThreadContext oldCallContext = ThreadContext.enter(callContext); try { List<InterceptorData> interceptors = beanContext.getCallbackInterceptors(); InterceptorStack interceptorStack = new InterceptorStack( instance.bean, null, Operation.AFTER_BEGIN, interceptors, instance.interceptors); interceptorStack.invoke(); } catch (Exception e) { String message = "An unexpected system exception occured while invoking the afterBegin method on the SessionSynchronization object"; // [1] Log the exception or error logger.error(message, e); // Caller handles transaction rollback and discardInstance // [4] throw the java.rmi.RemoteException to the client throw new RuntimeException(message, e); } finally { ThreadContext.exit(oldCallContext); } } public void beforeCompletion() { for (Synchronization synchronization : registry.values()) { Instance instance = synchronization.instance; // don't call beforeCompletion when transaction is marked rollback only if (txPolicy.isRollbackOnly()) return; // only call beforeCompletion on beans with session synchronization if (!synchronization.isCallSessionSynchronization()) continue; // Invoke beforeCompletion ThreadContext callContext = new ThreadContext( instance.beanContext, instance.primaryKey, Operation.BEFORE_COMPLETION); callContext.setCurrentAllowedStates(null); ThreadContext oldCallContext = ThreadContext.enter(callContext); try { instance.setInUse(true); BeanContext beanContext = instance.beanContext; List<InterceptorData> interceptors = beanContext.getCallbackInterceptors(); InterceptorStack interceptorStack = new InterceptorStack( instance.bean, null, Operation.BEFORE_COMPLETION, interceptors, instance.interceptors); interceptorStack.invoke(); instance.setInUse(false); } catch (InvalidateReferenceException e) { // exception has alredy been handled } catch (Exception e) { String message = "An unexpected system exception occured while invoking the beforeCompletion method on the SessionSynchronization object"; // [1] Log the exception or error logger.error(message, e); // [2] Mark the transaction for rollback. txPolicy.setRollbackOnly(e); // [3] Discard the instance discardInstance(callContext); // [4] throw the java.rmi.RemoteException to the client throw new RuntimeException(message, e); } finally { ThreadContext.exit(oldCallContext); } } } public void afterCompletion(Status status) { Throwable firstException = null; for (Synchronization synchronization : registry.values()) { Instance instance = synchronization.instance; ThreadContext callContext = new ThreadContext( instance.beanContext, instance.primaryKey, Operation.AFTER_COMPLETION); callContext.setCurrentAllowedStates(null); ThreadContext oldCallContext = ThreadContext.enter(callContext); try { instance.setInUse(true); if (synchronization.isCallSessionSynchronization()) { BeanContext beanContext = instance.beanContext; List<InterceptorData> interceptors = beanContext.getCallbackInterceptors(); InterceptorStack interceptorStack = new InterceptorStack( instance.bean, null, Operation.AFTER_COMPLETION, interceptors, instance.interceptors); interceptorStack.invoke(status == Status.COMMITTED); } instance.setTransaction(null); releaseInstance(instance); } catch (InvalidateReferenceException inv) { // exception has alredy been handled } catch (Throwable e) { String message = "An unexpected system exception occured while invoking the afterCompletion method on the SessionSynchronization object"; // [1] Log the exception or error logger.error(message, e); // Transaction is complete so can not be rolled back // [3] Discard the instance discardInstance(callContext); // [4] throw throw first exception to the client if (firstException == null) firstException = e; } finally { ThreadContext.exit(oldCallContext); } } if (firstException != null) { throw new RuntimeException( "An unexpected system exception occured while invoking the afterCompletion method on the SessionSynchronization object", firstException); } } } public class StatefulCacheListener implements CacheListener<Instance> { public void afterLoad(Instance instance) throws SystemException, ApplicationException { BeanContext beanContext = instance.beanContext; ThreadContext threadContext = new ThreadContext(instance.beanContext, instance.primaryKey, Operation.ACTIVATE); ThreadContext oldContext = ThreadContext.enter(threadContext); try { Method remove = instance.bean instanceof SessionBean ? SessionBean.class.getMethod("ejbActivate") : null; List<InterceptorData> callbackInterceptors = beanContext.getCallbackInterceptors(); InterceptorStack interceptorStack = new InterceptorStack( instance.bean, remove, Operation.ACTIVATE, callbackInterceptors, instance.interceptors); interceptorStack.invoke(); } catch (Throwable callbackException) { discardInstance(threadContext); handleSystemException( threadContext.getTransactionPolicy(), callbackException, threadContext); } finally { ThreadContext.exit(oldContext); } } public void beforeStore(Instance instance) { BeanContext beanContext = instance.beanContext; ThreadContext threadContext = new ThreadContext(beanContext, instance.primaryKey, Operation.PASSIVATE); ThreadContext oldContext = ThreadContext.enter(threadContext); try { Method passivate = instance.bean instanceof SessionBean ? SessionBean.class.getMethod("ejbPassivate") : null; List<InterceptorData> callbackInterceptors = beanContext.getCallbackInterceptors(); InterceptorStack interceptorStack = new InterceptorStack( instance.bean, passivate, Operation.PASSIVATE, callbackInterceptors, instance.interceptors); interceptorStack.invoke(); } catch (Throwable e) { logger.error( "An unexpected exception occured while invoking the ejbPassivate method on the Stateful SessionBean instance", e); } finally { ThreadContext.exit(oldContext); } } public void timedOut(Instance instance) { BeanContext beanContext = instance.beanContext; ThreadContext threadContext = new ThreadContext(beanContext, instance.primaryKey, Operation.PRE_DESTROY); threadContext.setCurrentAllowedStates(null); ThreadContext oldContext = ThreadContext.enter(threadContext); try { Method remove = instance.bean instanceof SessionBean ? SessionBean.class.getMethod("ejbRemove") : null; List<InterceptorData> callbackInterceptors = beanContext.getCallbackInterceptors(); InterceptorStack interceptorStack = new InterceptorStack( instance.bean, remove, Operation.PRE_DESTROY, callbackInterceptors, instance.interceptors); interceptorStack.invoke(); } catch (Throwable e) { logger.error( "An unexpected exception occured while invoking the ejbRemove method on the timed-out Stateful SessionBean instance", e); } finally { logger.info("Removing the timed-out stateful session bean instance " + instance.primaryKey); ThreadContext.exit(oldContext); } } } private static class Data { private final Index<Method, MethodType> methodIndex; private final List<ObjectName> jmxNames = new ArrayList<ObjectName>(); private Data(Index<Method, MethodType> methodIndex) { this.methodIndex = methodIndex; } public Index<Method, MethodType> getMethodIndex() { return methodIndex; } } }
/** @version $Revision$ $Date$ */ public class EjbJarInfoBuilder { public static Messages messages = new Messages("org.apache.openejb.util.resources"); public static Logger logger = Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources"); private final List<String> deploymentIds = new ArrayList<>(); private final List<String> securityRoles = new ArrayList<>(); public EjbJarInfo buildInfo(final EjbModule jar) throws OpenEJBException { deploymentIds.clear(); securityRoles.clear(); final Map<String, EjbDeployment> ejbds = jar.getOpenejbJar().getDeploymentsByEjbName(); final int beansDeployed = jar.getOpenejbJar().getEjbDeploymentCount(); final int beansInEjbJar = jar.getEjbJar().getEnterpriseBeans().length; if (beansInEjbJar != beansDeployed) { for (final EnterpriseBean bean : jar.getEjbJar().getEnterpriseBeans()) { if (!ejbds.containsKey(bean.getEjbName())) { ConfigUtils.logger.warning("conf.0018", bean.getEjbName(), jar.getJarLocation()); } } final String message = messages.format( "conf.0008", jar.getJarLocation(), String.valueOf(beansInEjbJar), String.valueOf(beansDeployed)); logger.warning(message); throw new OpenEJBException(message); } final Map<String, EnterpriseBeanInfo> infos = new HashMap<String, EnterpriseBeanInfo>(); final Map<String, EnterpriseBean> items = new HashMap<String, EnterpriseBean>(); final EjbJarInfo ejbJar = new EjbJarInfo(); ejbJar.path = jar.getJarLocation(); ejbJar.moduleUri = jar.getModuleUri(); ejbJar.moduleId = jar.getModuleId(); if (jar.getEjbJar() != null && jar.getEjbJar().getModuleName() != null) { ejbJar.moduleName = jar.getEjbJar().getModuleName(); } else { ejbJar.moduleName = jar.getModuleId(); } ejbJar.watchedResources.addAll(jar.getWatchedResources()); ejbJar.properties.putAll(jar.getProperties()); ejbJar.properties.putAll(jar.getOpenejbJar().getProperties()); for (final EnterpriseBean bean : jar.getEjbJar().getEnterpriseBeans()) { final EnterpriseBeanInfo beanInfo; if (bean instanceof SessionBean) { beanInfo = initSessionBean((SessionBean) bean, ejbJar, ejbds); } else if (bean instanceof EntityBean) { beanInfo = initEntityBean((EntityBean) bean, ejbds); } else if (bean instanceof MessageDrivenBean) { beanInfo = initMessageBean((MessageDrivenBean) bean, ejbds); } else { throw new OpenEJBException("Unknown bean type: " + bean.getClass().getName()); } ejbJar.enterpriseBeans.add(beanInfo); if (deploymentIds.contains(beanInfo.ejbDeploymentId)) { final String message = messages.format( "conf.0100", beanInfo.ejbDeploymentId, jar.getJarLocation(), beanInfo.ejbName); logger.warning(message); throw new OpenEJBException(message); } deploymentIds.add(beanInfo.ejbDeploymentId); beanInfo.codebase = jar.getJarLocation(); infos.put(beanInfo.ejbName, beanInfo); items.put(beanInfo.ejbName, bean); if (bean.getSecurityIdentity() != null) { beanInfo.runAs = bean.getSecurityIdentity().getRunAs(); final EjbDeployment deployment = ejbds.get(beanInfo.ejbName); if (deployment != null) { for (final RoleMapping mapping : deployment.getRoleMapping()) { if (mapping.getRoleName().equals(beanInfo.runAs)) { beanInfo.runAsUser = mapping.getPrincipalName(); break; } } } } initJndiNames(ejbds, beanInfo); } if (jar.getEjbJar().getAssemblyDescriptor() != null) { initInterceptors(jar, ejbJar); initSecurityRoles(jar, ejbJar); initMethodPermissions(jar, ejbds, ejbJar); initExcludesList(jar, ejbds, ejbJar); initMethodTransactions(jar, ejbds, ejbJar); initMethodConcurrency(jar, ejbds, ejbJar); initApplicationExceptions(jar, ejbJar); for (final EnterpriseBeanInfo bean : ejbJar.enterpriseBeans) { resolveRoleLinks(bean, items.get(bean.ejbName)); } } if (jar.getEjbJar().getRelationships() != null) { initRelationships(jar, infos); } final Beans beans = jar.getBeans(); if (beans != null) { ejbJar.beans = new BeansInfo(); ejbJar.beans.version = beans.getVersion(); ejbJar.beans.discoveryMode = beans.getBeanDiscoveryMode(); if (beans.getScan() != null) { for (final Beans.Scan.Exclude exclude : beans.getScan().getExclude()) { final ExclusionInfo exclusionInfo = new ExclusionInfo(); for (final Object config : exclude.getIfClassAvailableOrIfClassNotAvailableOrIfSystemProperty()) { if (Beans.Scan.Exclude.IfAvailableClassCondition.class.isInstance(config)) { exclusionInfo.availableClasses.add( Beans.Scan.Exclude.ClassCondition.class.cast(config).getName()); } else if (Beans.Scan.Exclude.IfNotAvailableClassCondition.class.isInstance(config)) { exclusionInfo.notAvailableClasses.add( Beans.Scan.Exclude.ClassCondition.class.cast(config).getName()); } else if (Beans.Scan.Exclude.IfSystemProperty.class.isInstance(config)) { final Beans.Scan.Exclude.IfSystemProperty systemProperty = Beans.Scan.Exclude.IfSystemProperty.class.cast(config); if (systemProperty.getValue() == null) { exclusionInfo.systemPropertiesPresence.add(systemProperty.getName()); } else { exclusionInfo.systemProperties.put( systemProperty.getName(), systemProperty.getValue()); } } else { throw new IllegalArgumentException("Not supported: " + config); } } final BeansInfo.ExclusionEntryInfo exclusionEntryInfo = new BeansInfo.ExclusionEntryInfo(); exclusionEntryInfo.name = exclude.getName(); exclusionEntryInfo.exclusion = exclusionInfo; ejbJar.beans.excludes.add(exclusionEntryInfo); } } ejbJar.beans.interceptors.addAll(beans.getInterceptors()); ejbJar.beans.decorators.addAll(beans.getDecorators()); ejbJar.beans.alternativeClasses.addAll(beans.getAlternativeClasses()); ejbJar.beans.alternativeStereotypes.addAll(beans.getAlternativeStereotypes()); ejbJar.beans.duplicatedAlternativeClasses.addAll( beans.getDuplicatedAlternatives().getClasses()); ejbJar.beans.duplicatedAlternativeStereotypes.addAll( beans.getDuplicatedAlternatives().getStereotypes()); ejbJar.beans.duplicatedInterceptors.addAll(beans.getDuplicatedInterceptors()); ejbJar.beans.duplicatedDecorators.addAll(beans.getDuplicatedDecorators()); ejbJar.beans.startupClasses.addAll(beans.getStartupBeans()); final Map<URL, String> discoveryModeByUrl = new HashMap<>(); if (CompositeBeans.class.isInstance(beans)) { discoveryModeByUrl.putAll(CompositeBeans.class.cast(beans).getDiscoveryByUrl()); } else { discoveryModeByUrl.put(null, beans.getBeanDiscoveryMode()); } for (final Map.Entry<URL, List<String>> next : beans.getManagedClasses().entrySet()) { final URL key = next.getKey(); final BeansInfo.BDAInfo bdaInfo = new BeansInfo.BDAInfo(); bdaInfo.managedClasses.addAll(next.getValue()); bdaInfo.discoveryMode = discoveryModeByUrl.get(key); try { bdaInfo.uri = key == null ? null : key.toURI(); } catch (final URISyntaxException e) { bdaInfo.uri = null; } ejbJar.beans.bdas.add(bdaInfo); } } return ejbJar; } private void initJndiNames( final Map<String, EjbDeployment> ejbds, final EnterpriseBeanInfo info) { final EjbDeployment deployment = ejbds.get(info.ejbName); if (deployment != null) { for (final Jndi jndi : deployment.getJndi()) { final JndiNameInfo jndiNameInfo = new JndiNameInfo(); jndiNameInfo.intrface = jndi.getInterface(); jndiNameInfo.name = jndi.getName(); info.jndiNamess.add(jndiNameInfo); } } } private void initRelationships(final EjbModule jar, final Map<String, EnterpriseBeanInfo> infos) throws OpenEJBException { for (final EjbRelation ejbRelation : jar.getEjbJar().getRelationships().getEjbRelation()) { final Iterator<EjbRelationshipRole> iterator = ejbRelation.getEjbRelationshipRole().iterator(); final EjbRelationshipRole left = iterator.next(); final EjbRelationshipRole right = iterator.next(); // left role info final CmrFieldInfo leftCmrFieldInfo = initRelationshipRole(left, right, infos); final CmrFieldInfo rightCmrFieldInfo = initRelationshipRole(right, left, infos); leftCmrFieldInfo.mappedBy = rightCmrFieldInfo; rightCmrFieldInfo.mappedBy = leftCmrFieldInfo; } } private CmrFieldInfo initRelationshipRole( final EjbRelationshipRole role, final EjbRelationshipRole relatedRole, final Map<String, EnterpriseBeanInfo> infos) throws OpenEJBException { final CmrFieldInfo cmrFieldInfo = new CmrFieldInfo(); // find the entityBeanInfo info for this role final String ejbName = role.getRelationshipRoleSource().getEjbName(); final EnterpriseBeanInfo enterpriseBeanInfo = infos.get(ejbName); if (enterpriseBeanInfo == null) { throw new OpenEJBException("Relation role source ejb not found " + ejbName); } if (!(enterpriseBeanInfo instanceof EntityBeanInfo)) { throw new OpenEJBException("Relation role source ejb is not an entity bean " + ejbName); } final EntityBeanInfo entityBeanInfo = (EntityBeanInfo) enterpriseBeanInfo; cmrFieldInfo.roleSource = entityBeanInfo; // RoleName: this may be null cmrFieldInfo.roleName = role.getEjbRelationshipRoleName(); cmrFieldInfo.synthetic = role.getCmrField() == null; // CmrFieldName: is null for uni-directional relationships if (role.getCmrField() != null) { cmrFieldInfo.fieldName = role.getCmrField().getCmrFieldName(); // CollectionType: java.util.Collection or java.util.Set if (role.getCmrField().getCmrFieldType() != null) { cmrFieldInfo.fieldType = role.getCmrField().getCmrFieldType().toString(); } if (cmrFieldInfo.fieldType == null && relatedRole.getMultiplicity() == Multiplicity.MANY) { cmrFieldInfo.fieldType = Collection.class.getName(); } } else { final String relatedEjbName = relatedRole.getRelationshipRoleSource().getEjbName(); final EnterpriseBeanInfo relatedEjb = infos.get(relatedEjbName); if (relatedEjb == null) { throw new OpenEJBException("Relation role source ejb not found " + relatedEjbName); } if (!(relatedEjb instanceof EntityBeanInfo)) { throw new OpenEJBException( "Relation role source ejb is not an entity bean " + relatedEjbName); } final EntityBeanInfo relatedEntity = (EntityBeanInfo) relatedEjb; relatedRole.getRelationshipRoleSource(); cmrFieldInfo.fieldName = relatedEntity.abstractSchemaName + "_" + relatedRole.getCmrField().getCmrFieldName(); if (relatedRole.getMultiplicity() == Multiplicity.MANY) { cmrFieldInfo.fieldType = Collection.class.getName(); } } // CascadeDelete cmrFieldInfo.cascadeDelete = role.getCascadeDelete(); // Multiplicity: one or many cmrFieldInfo.many = role.getMultiplicity() == Multiplicity.MANY; // add the field to the entityBean entityBeanInfo.cmrFields.add(cmrFieldInfo); return cmrFieldInfo; } private void initInterceptors(final EjbModule jar, final EjbJarInfo ejbJar) throws OpenEJBException { if (jar.getEjbJar().getInterceptors().length == 0) { return; } if (jar.getEjbJar().getAssemblyDescriptor() == null) { return; } if (jar.getEjbJar().getAssemblyDescriptor().getInterceptorBinding() == null) { return; } for (final Interceptor s : jar.getEjbJar().getInterceptors()) { final InterceptorInfo info = new InterceptorInfo(); info.clazz = s.getInterceptorClass(); copyCallbacks(s.getAroundInvoke(), info.aroundInvoke); copyCallbacks(s.getPostConstruct(), info.postConstruct); copyCallbacks(s.getPreDestroy(), info.preDestroy); copyCallbacks(s.getPostActivate(), info.postActivate); copyCallbacks(s.getPrePassivate(), info.prePassivate); copyCallbacks(s.getAfterBegin(), info.afterBegin); copyCallbacks(s.getBeforeCompletion(), info.beforeCompletion); copyCallbacks(s.getAfterCompletion(), info.afterCompletion); copyCallbacks(s.getAroundTimeout(), info.aroundTimeout); ejbJar.interceptors.add(info); } for (final InterceptorBinding binding : jar.getEjbJar().getAssemblyDescriptor().getInterceptorBinding()) { final InterceptorBindingInfo info = new InterceptorBindingInfo(); info.ejbName = binding.getEjbName(); info.excludeClassInterceptors = binding.getExcludeClassInterceptors(); info.excludeDefaultInterceptors = binding.getExcludeDefaultInterceptors(); info.interceptors.addAll(binding.getInterceptorClass()); if (binding.getInterceptorOrder() != null) { info.interceptorOrder.addAll(binding.getInterceptorOrder().getInterceptorClass()); } info.method = toInfo(binding.getMethod()); info.className = binding.getClassName(); ejbJar.interceptorBindings.add(info); } } private void initMethodTransactions( final EjbModule jar, final Map ejbds, final EjbJarInfo ejbJarInfo) { final List<ContainerTransaction> containerTransactions = jar.getEjbJar().getAssemblyDescriptor().getContainerTransaction(); for (final ContainerTransaction cTx : containerTransactions) { final MethodTransactionInfo info = new MethodTransactionInfo(); info.description = cTx.getDescription(); info.transAttribute = cTx.getTransAttribute().toString(); info.methods.addAll(getMethodInfos(cTx.getMethod(), ejbds)); ejbJarInfo.methodTransactions.add(info); } } private void initMethodConcurrency( final EjbModule jar, final Map ejbds, final EjbJarInfo ejbJarInfo) { final List<ContainerConcurrency> containerConcurrency = jar.getEjbJar().getAssemblyDescriptor().getContainerConcurrency(); for (final ContainerConcurrency att : containerConcurrency) { final MethodConcurrencyInfo info = new MethodConcurrencyInfo(); info.description = att.getDescription(); if (att.getLock() != null) { info.concurrencyAttribute = att.getLock().toString(); } info.accessTimeout = toInfo(att.getAccessTimeout()); info.methods.addAll(getMethodInfos(att.getMethod(), ejbds)); ejbJarInfo.methodConcurrency.add(info); } } private void copyConcurrentMethods( final SessionBean bean, final EjbJarInfo ejbJarInfo, final Map ejbds) { for (final ConcurrentMethod method : bean.getConcurrentMethod()) { final MethodConcurrencyInfo info = new MethodConcurrencyInfo(); if (method.getLock() != null) { info.concurrencyAttribute = method.getLock().toString(); } info.accessTimeout = toInfo(method.getAccessTimeout()); final Method m = new Method(bean.getEjbName(), null, method.getMethod().getMethodName()); m.setMethodParams(method.getMethod().getMethodParams()); info.methods.add(getMethodInfo(m, ejbds)); ejbJarInfo.methodConcurrency.add(info); } } private void copySchedules( final List<Timer> timers, final List<MethodScheduleInfo> scheduleInfos) { final Map<NamedMethod, MethodScheduleInfo> methodScheduleInfoMap = new HashMap<NamedMethod, MethodScheduleInfo>(); for (final Timer timer : timers) { final NamedMethod timeoutMethod = timer.getTimeoutMethod(); MethodScheduleInfo methodScheduleInfo = methodScheduleInfoMap.get(timer.getTimeoutMethod()); if (methodScheduleInfo == null) { methodScheduleInfo = new MethodScheduleInfo(); methodScheduleInfoMap.put(timeoutMethod, methodScheduleInfo); methodScheduleInfo.method = toInfo(timeoutMethod); } final ScheduleInfo scheduleInfo = new ScheduleInfo(); // Copy TimerSchedule final TimerSchedule timerSchedule = timer.getSchedule(); if (timerSchedule != null) { scheduleInfo.second = timerSchedule.getSecond(); scheduleInfo.minute = timerSchedule.getMinute(); scheduleInfo.hour = timerSchedule.getHour(); scheduleInfo.dayOfWeek = timerSchedule.getDayOfWeek(); scheduleInfo.dayOfMonth = timerSchedule.getDayOfMonth(); scheduleInfo.month = timerSchedule.getMonth(); scheduleInfo.year = timerSchedule.getYear(); } // Copy other attributes scheduleInfo.timezone = timer.getTimezone(); if (timer.getStart() != null) { scheduleInfo.start = timer.getStart().toGregorianCalendar().getTime(); } if (timer.getEnd() != null) { scheduleInfo.end = timer.getEnd().toGregorianCalendar().getTime(); } scheduleInfo.info = timer.getInfo(); if (timer.getPersistent() != null) { scheduleInfo.persistent = timer.getPersistent(); } methodScheduleInfo.schedules.add(scheduleInfo); } scheduleInfos.addAll(methodScheduleInfoMap.values()); } private void initApplicationExceptions(final EjbModule jar, final EjbJarInfo ejbJarInfo) { for (final ApplicationException applicationException : jar.getEjbJar().getAssemblyDescriptor().getApplicationException()) { final ApplicationExceptionInfo info = new ApplicationExceptionInfo(); info.exceptionClass = applicationException.getExceptionClass(); info.rollback = applicationException.isRollback(); info.inherited = applicationException.isInherited(); ejbJarInfo.applicationException.add(info); } } private void initSecurityRoles(final EjbModule jar, final EjbJarInfo ejbJarInfo) { final List<SecurityRole> roles = jar.getEjbJar().getAssemblyDescriptor().getSecurityRole(); for (final SecurityRole sr : roles) { final SecurityRoleInfo info = new SecurityRoleInfo(); info.description = sr.getDescription(); info.roleName = sr.getRoleName(); if (securityRoles.contains(sr.getRoleName())) { ConfigUtils.logger.warning("conf.0102", jar.getJarLocation(), sr.getRoleName()); } else { securityRoles.add(sr.getRoleName()); } ejbJarInfo.securityRoles.add(info); } } private void initMethodPermissions( final EjbModule jar, final Map ejbds, final EjbJarInfo ejbJarInfo) { final List<MethodPermission> methodPermissions = jar.getEjbJar().getAssemblyDescriptor().getMethodPermission(); for (final MethodPermission mp : methodPermissions) { final MethodPermissionInfo info = new MethodPermissionInfo(); info.description = mp.getDescription(); info.roleNames.addAll(mp.getRoleName()); info.methods.addAll(getMethodInfos(mp.getMethod(), ejbds)); info.unchecked = mp.getUnchecked(); ejbJarInfo.methodPermissions.add(info); } } private void initExcludesList(final EjbModule jar, final Map ejbds, final EjbJarInfo ejbJarInfo) { final ExcludeList methodPermissions = jar.getEjbJar().getAssemblyDescriptor().getExcludeList(); for (final Method excludedMethod : methodPermissions.getMethod()) { ejbJarInfo.excludeList.add(getMethodInfo(excludedMethod, ejbds)); } } private void resolveRoleLinks(final EnterpriseBeanInfo bean, final JndiConsumer item) { if (!(item instanceof RemoteBean)) { return; } final RemoteBean rb = (RemoteBean) item; final List<SecurityRoleRef> refs = rb.getSecurityRoleRef(); for (final SecurityRoleRef ref : refs) { final SecurityRoleReferenceInfo info = new SecurityRoleReferenceInfo(); info.description = ref.getDescription(); info.roleLink = ref.getRoleLink(); info.roleName = ref.getRoleName(); if (info.roleLink == null) { info.roleLink = info.roleName; } bean.securityRoleReferences.add(info); } } private List<MethodInfo> getMethodInfos(final List<Method> ms, final Map ejbds) { if (ms == null) { return Collections.emptyList(); } final List<MethodInfo> mi = new ArrayList<MethodInfo>(ms.size()); for (final Method method : ms) { final MethodInfo methodInfo = getMethodInfo(method, ejbds); mi.add(methodInfo); } return mi; } private MethodInfo getMethodInfo(final Method method, final Map ejbds) { final MethodInfo methodInfo = new MethodInfo(); final EjbDeployment d = (EjbDeployment) ejbds.get(method.getEjbName()); methodInfo.description = method.getDescription(); methodInfo.ejbDeploymentId = d == null ? null : d.getDeploymentId(); methodInfo.ejbName = method.getEjbName(); methodInfo.methodIntf = method.getMethodIntf() == null ? null : method.getMethodIntf().toString(); methodInfo.methodName = method.getMethodName(); if (methodInfo.methodName == null || methodInfo.methodName.equals("")) { methodInfo.methodName = "*"; } methodInfo.className = method.getClassName(); if (methodInfo.className == null || methodInfo.className.equals("")) { methodInfo.className = "*"; } final MethodParams mp = method.getMethodParams(); if (mp != null) { methodInfo.methodParams = mp.getMethodParam(); } return methodInfo; } private EnterpriseBeanInfo initSessionBean( final SessionBean s, final EjbJarInfo ejbJar, final Map m) throws OpenEJBException { EnterpriseBeanInfo bean = null; if (s.getSessionType() == SessionType.STATEFUL) { bean = new StatefulBeanInfo(); bean.passivable = s.getPassivationCapable(); final StatefulBeanInfo stateful = (StatefulBeanInfo) bean; copyCallbacks(s.getPostActivate(), stateful.postActivate); copyCallbacks(s.getPrePassivate(), stateful.prePassivate); copyCallbacks(s.getAfterBegin(), stateful.afterBegin); copyCallbacks(s.getBeforeCompletion(), stateful.beforeCompletion); copyCallbacks(s.getAfterCompletion(), stateful.afterCompletion); for (final InitMethod initMethod : s.getInitMethod()) { final InitMethodInfo init = new InitMethodInfo(); init.beanMethod = toInfo(initMethod.getBeanMethod()); init.createMethod = toInfo(initMethod.getCreateMethod()); stateful.initMethods.add(init); } for (final RemoveMethod removeMethod : s.getRemoveMethod()) { final RemoveMethodInfo remove = new RemoveMethodInfo(); remove.beanMethod = toInfo(removeMethod.getBeanMethod()); remove.retainIfException = removeMethod.getRetainIfException(); stateful.removeMethods.add(remove); } copyConcurrentMethods(s, ejbJar, m); } else if (s.getSessionType() == SessionType.MANAGED) { bean = new ManagedBeanInfo(); final ManagedBeanInfo managed = (ManagedBeanInfo) bean; if (s instanceof ManagedBean) { // this way we support managed beans in ejb-jar.xml (not in the spec but // can be useful) managed.hidden = ((ManagedBean) s).isHidden(); } else { managed.hidden = true; } copyCallbacks(s.getPostActivate(), managed.postActivate); copyCallbacks(s.getPrePassivate(), managed.prePassivate); for (final RemoveMethod removeMethod : s.getRemoveMethod()) { final RemoveMethodInfo remove = new RemoveMethodInfo(); remove.beanMethod = toInfo(removeMethod.getBeanMethod()); remove.retainIfException = removeMethod.getRetainIfException(); managed.removeMethods.add(remove); } } else if (s.getSessionType() == SessionType.SINGLETON) { bean = new SingletonBeanInfo(); final ConcurrencyManagementType type = s.getConcurrencyManagementType(); bean.concurrencyType = type != null ? type.toString() : ConcurrencyManagementType.CONTAINER.toString(); bean.loadOnStartup = s.getInitOnStartup(); copyCallbacks(s.getAroundTimeout(), bean.aroundTimeout); copySchedules(s.getTimer(), bean.methodScheduleInfos); // See JndiEncInfoBuilder.buildDependsOnRefs for processing of DependsOn // bean.dependsOn.addAll(s.getDependsOn()); copyConcurrentMethods(s, ejbJar, m); } else { bean = new StatelessBeanInfo(); copySchedules(s.getTimer(), bean.methodScheduleInfos); } if (s.getSessionType() != SessionType.STATEFUL) { copyCallbacks(s.getAroundTimeout(), bean.aroundTimeout); } bean.localbean = s.getLocalBean() != null; bean.timeoutMethod = toInfo(s.getTimeoutMethod()); copyCallbacks(s.getAroundInvoke(), bean.aroundInvoke); copyCallbacks(s.getPostConstruct(), bean.postConstruct); copyCallbacks(s.getPreDestroy(), bean.preDestroy); copyAsynchronous(s.getAsyncMethod(), bean.asynchronous); bean.asynchronousClasses.addAll(s.getAsynchronousClasses()); final EjbDeployment d = (EjbDeployment) m.get(s.getEjbName()); if (d == null) { throw new OpenEJBException( "No deployment information in openejb-jar.xml for bean " + s.getEjbName() + ". Please redeploy the jar"); } bean.ejbDeploymentId = d.getDeploymentId(); bean.containerId = d.getContainerId(); final Icon icon = s.getIcon(); bean.largeIcon = icon == null ? null : icon.getLargeIcon(); bean.smallIcon = icon == null ? null : icon.getSmallIcon(); bean.description = s.getDescription(); bean.displayName = s.getDisplayName(); bean.ejbClass = s.getEjbClass(); bean.ejbName = s.getEjbName(); bean.home = s.getHome(); bean.remote = s.getRemote(); bean.localHome = s.getLocalHome(); bean.local = s.getLocal(); bean.proxy = s.getProxy(); bean.parents.addAll(s.getParents()); bean.businessLocal.addAll(s.getBusinessLocal()); bean.businessRemote.addAll(s.getBusinessRemote()); final TransactionType txType = s.getTransactionType(); bean.transactionType = txType != null ? txType.toString() : TransactionType.CONTAINER.toString(); bean.serviceEndpoint = s.getServiceEndpoint(); bean.properties.putAll(d.getProperties()); bean.statefulTimeout = toInfo(s.getStatefulTimeout()); bean.restService = s.isRestService() && !(s instanceof StatefulBean); return bean; } private void copyAsynchronous( final List<AsyncMethod> methods, final List<NamedMethodInfo> methodInfos) { for (final AsyncMethod asyncMethod : methods) { final NamedMethodInfo info = new NamedMethodInfo(); info.methodName = asyncMethod.getMethodName(); if (asyncMethod.getMethodParams() != null) { info.methodParams = asyncMethod.getMethodParams().getMethodParam(); } methodInfos.add(info); } } private TimeoutInfo toInfo(final Timeout timeout) { if (timeout == null) { return null; } final TimeoutInfo accessTimeout = new TimeoutInfo(); accessTimeout.time = timeout.getTimeout(); accessTimeout.unit = timeout.getUnit().toString(); return accessTimeout; } private EnterpriseBeanInfo initMessageBean(final MessageDrivenBean mdb, final Map m) throws OpenEJBException { final MessageDrivenBeanInfo bean = new MessageDrivenBeanInfo(); bean.timeoutMethod = toInfo(mdb.getTimeoutMethod()); copyCallbacks(mdb.getAroundTimeout(), bean.aroundTimeout); copyCallbacks(mdb.getAroundInvoke(), bean.aroundInvoke); copyCallbacks(mdb.getPostConstruct(), bean.postConstruct); copyCallbacks(mdb.getPreDestroy(), bean.preDestroy); copySchedules(mdb.getTimer(), bean.methodScheduleInfos); final EjbDeployment d = (EjbDeployment) m.get(mdb.getEjbName()); if (d == null) { throw new OpenEJBException( "No deployment information in openejb-jar.xml for bean " + mdb.getEjbName() + ". Please redeploy the jar"); } bean.ejbDeploymentId = d.getDeploymentId(); bean.containerId = d.getContainerId(); final Icon icon = mdb.getIcon(); bean.largeIcon = icon == null ? null : icon.getLargeIcon(); bean.smallIcon = icon == null ? null : icon.getSmallIcon(); bean.description = mdb.getDescription(); bean.displayName = mdb.getDisplayName(); bean.ejbClass = mdb.getEjbClass(); bean.ejbName = mdb.getEjbName(); final TransactionType txType = mdb.getTransactionType(); bean.transactionType = txType != null ? txType.toString() : TransactionType.CONTAINER.toString(); bean.properties.putAll(d.getProperties()); if (mdb.getMessagingType() != null) { bean.mdbInterface = mdb.getMessagingType(); } else { bean.mdbInterface = "javax.jms.MessageListener"; } final ResourceLink resourceLink = d.getResourceLink("openejb/destination"); if (resourceLink != null) { bean.destinationId = resourceLink.getResId(); } if (mdb.getMessageDestinationType() != null) { bean.activationProperties.put("destinationType", mdb.getMessageDestinationType()); } final ActivationConfig activationConfig = mdb.getActivationConfig(); if (activationConfig != null) { for (final ActivationConfigProperty property : activationConfig.getActivationConfigProperty()) { final String name = property.getActivationConfigPropertyName(); final String value = property.getActivationConfigPropertyValue(); bean.activationProperties.put(name, value); } } return bean; } private NamedMethodInfo toInfo(final NamedMethod method) { if (method == null) { return null; } final NamedMethodInfo info = new NamedMethodInfo(); info.methodName = method.getMethodName(); if (method.getMethodParams() != null) { info.methodParams = method.getMethodParams().getMethodParam(); } return info; } private void copyCallbacks( final List<? extends CallbackMethod> from, final List<CallbackInfo> to) { for (final CallbackMethod callback : from) { final CallbackInfo info = new CallbackInfo(); info.className = callback.getClassName(); info.method = callback.getMethodName(); to.add(info); } } private EnterpriseBeanInfo initEntityBean(final EntityBean e, final Map m) throws OpenEJBException { final EntityBeanInfo bean = new EntityBeanInfo(); final EjbDeployment d = (EjbDeployment) m.get(e.getEjbName()); if (d == null) { throw new OpenEJBException( "No deployment information in openejb-jar.xml for bean " + e.getEjbName() + ". Please redeploy the jar"); } bean.ejbDeploymentId = d.getDeploymentId(); bean.containerId = d.getContainerId(); final Icon icon = e.getIcon(); bean.largeIcon = icon == null ? null : icon.getLargeIcon(); bean.smallIcon = icon == null ? null : icon.getSmallIcon(); bean.description = e.getDescription(); bean.displayName = e.getDisplayName(); bean.ejbClass = e.getEjbClass(); bean.abstractSchemaName = e.getAbstractSchemaName(); bean.ejbName = e.getEjbName(); bean.home = e.getHome(); bean.remote = e.getRemote(); bean.localHome = e.getLocalHome(); bean.local = e.getLocal(); bean.transactionType = "Container"; bean.primKeyClass = e.getPrimKeyClass(); bean.primKeyField = e.getPrimkeyField(); bean.persistenceType = e.getPersistenceType().toString(); bean.reentrant = String.valueOf(e.getReentrant()); bean.properties.putAll(d.getProperties()); final CmpVersion cmpVersion = e.getCmpVersion(); if (e.getPersistenceType() == PersistenceType.CONTAINER) { if (cmpVersion != null && cmpVersion == CmpVersion.CMP1) { bean.cmpVersion = 1; } else { bean.cmpVersion = 2; } } final List<CmpField> cmpFields = e.getCmpField(); for (final CmpField cmpField : cmpFields) { bean.cmpFieldNames.add(cmpField.getFieldName()); } if (bean.persistenceType.equalsIgnoreCase("Container")) { for (final Query q : e.getQuery()) { final QueryInfo query = new QueryInfo(); query.queryStatement = q.getEjbQl().trim(); final MethodInfo method = new MethodInfo(); method.ejbName = bean.ejbName; method.className = "*"; final QueryMethod qm = q.getQueryMethod(); method.methodName = qm.getMethodName(); if (qm.getMethodParams() != null) { method.methodParams = qm.getMethodParams().getMethodParam(); } query.method = method; final ResultTypeMapping resultType = q.getResultTypeMapping(); if (ResultTypeMapping.REMOTE.equals(resultType)) { query.remoteResultType = true; } bean.queries.add(query); } for (final org.apache.openejb.jee.oejb3.Query q : d.getQuery()) { final QueryInfo query = new QueryInfo(); query.description = q.getDescription(); query.queryStatement = q.getObjectQl().trim(); final MethodInfo method = new MethodInfo(); method.ejbName = bean.ejbName; method.className = "*"; final org.apache.openejb.jee.oejb3.QueryMethod qm = q.getQueryMethod(); method.methodName = qm.getMethodName(); if (qm.getMethodParams() != null) { method.methodParams = qm.getMethodParams().getMethodParam(); } query.method = method; bean.queries.add(query); } } return bean; } }
/** @version $Rev:$ $Date:$ */ public class OpenEJBLifecycle implements ContainerLifecycle { public static final ThreadLocal<AppInfo> CURRENT_APP_INFO = new ThreadLocal<AppInfo>(); // Logger instance private static final Logger logger = Logger.getInstance(LogCategory.OPENEJB_CDI, OpenEJBLifecycle.class); /** Discover bean classes */ protected ScannerService scannerService; protected final ContextsService contextsService; /** Deploy discovered beans */ private final BeansDeployer deployer; /** Using for lookup operations */ private final JNDIService jndiService; /** Root container. */ private final BeanManagerImpl beanManager; private final WebBeansContext webBeansContext; /** Manages unused conversations */ public OpenEJBLifecycle(final WebBeansContext webBeansContext) { this.webBeansContext = webBeansContext; this.beanManager = webBeansContext.getBeanManagerImpl(); this.deployer = new BeansDeployer(webBeansContext); this.jndiService = webBeansContext.getService(JNDIService.class); this.scannerService = webBeansContext.getScannerService(); this.contextsService = webBeansContext.getContextsService(); } @Override public BeanManager getBeanManager() { return this.beanManager; } @Override public void startApplication(final Object startupObject) { if (ServletContextEvent.class.isInstance(startupObject)) { startServletContext( ServletContext.class.cast( getServletContext(startupObject))); // TODO: check it is relevant return; } else if (!StartupObject.class.isInstance(startupObject)) { logger.debug("startupObject is not of StartupObject type; ignored"); return; } final StartupObject stuff = (StartupObject) startupObject; final ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); // Initalize Application Context logger.info("OpenWebBeans Container is starting..."); final long begin = System.currentTimeMillis(); try { Thread.currentThread().setContextClassLoader(stuff.getClassLoader()); final AppContext appContext = stuff.getAppContext(); if (stuff.getWebContext() == null) { // do it before any other things to keep our singleton finder working appContext.setWebBeansContext(webBeansContext); } // Load all plugins webBeansContext.getPluginLoader().startUp(); // Get Plugin final CdiPlugin cdiPlugin = (CdiPlugin) webBeansContext.getPluginLoader().getEjbPlugin(); cdiPlugin.setClassLoader(stuff.getClassLoader()); cdiPlugin.setWebBeansContext(webBeansContext); // Configure EJB Deployments cdiPlugin.configureDeployments(stuff.getBeanContexts()); // Resournce Injection Service final CdiResourceInjectionService injectionService = (CdiResourceInjectionService) webBeansContext.getService(ResourceInjectionService.class); // todo use startupObject allDeployments to find Comp in priority (otherwise we can keep N // times comps and loose time at injection time injectionService.setAppContext( stuff.getAppContext(), stuff.getBeanContexts() != null ? stuff.getBeanContexts() : Collections.<BeanContext>emptyList()); // Deploy the beans CdiScanner cdiScanner = null; try { // Scanning process logger.debug("Scanning classpaths for beans artifacts."); if (CdiScanner.class.isInstance(scannerService)) { cdiScanner = CdiScanner.class.cast(scannerService); cdiScanner.setContext(webBeansContext); cdiScanner.init(startupObject); } else { cdiScanner = new CdiScanner(); cdiScanner.setContext(webBeansContext); cdiScanner.init(startupObject); } // Scan this.scannerService.scan(); // just to let us write custom CDI Extension using our internals easily CURRENT_APP_INFO.set(stuff.getAppInfo()); addInternalBeans(); // before next event which can register custom beans (JAX-RS) SystemInstance.get().fireEvent(new WebBeansContextBeforeDeploy(webBeansContext)); // Deploy bean from XML. Also configures deployments, interceptors, decorators. deployer.deploy(scannerService); contextsService.init( startupObject); // fire app event and also starts SingletonContext and // ApplicationContext } catch (final Exception e1) { SystemInstance.get() .getComponent(Assembler.class) .logger .error("CDI Beans module deployment failed", e1); throw new OpenEJBRuntimeException(e1); } finally { CURRENT_APP_INFO.remove(); } final Collection<Class<?>> ejbs = new ArrayList<>(stuff.getBeanContexts().size()); for (final BeanContext bc : stuff.getBeanContexts()) { final CdiEjbBean cdiEjbBean = bc.get(CdiEjbBean.class); if (cdiEjbBean == null) { continue; } ejbs.add(bc.getManagedClass()); if (AbstractProducer.class.isInstance(cdiEjbBean)) { AbstractProducer.class .cast(cdiEjbBean) .defineInterceptorStack( cdiEjbBean, cdiEjbBean.getAnnotatedType(), cdiEjbBean.getWebBeansContext()); } bc.mergeOWBAndOpenEJBInfo(); bc.set( InterceptorResolutionService.BeanInterceptorInfo.class, InjectionTargetImpl.class.cast(cdiEjbBean.getInjectionTarget()).getInterceptorInfo()); cdiEjbBean.initInternals(); } // Start actual starting on sub-classes if (beanManager instanceof WebappBeanManager) { ((WebappBeanManager) beanManager).afterStart(); } for (final Class<?> clazz : cdiScanner.getStartupClasses()) { if (ejbs.contains(clazz)) { continue; } starts(beanManager, clazz); } } finally { Thread.currentThread().setContextClassLoader(oldCl); // cleanup threadlocal used to enrich cdi context manually OptimizedLoaderService.ADDITIONAL_EXTENSIONS.remove(); } logger.info( "OpenWebBeans Container has started, it took {0} ms.", Long.toString(System.currentTimeMillis() - begin)); } private void addInternalBeans() { beanManager.getInjectionResolver().clearCaches(); if (!hasBean(beanManager, HttpServletRequest.class)) { beanManager.addInternalBean(new HttpServletRequestBean(webBeansContext)); } if (!hasBean(beanManager, HttpSession.class)) { beanManager.addInternalBean( new InternalBean<>(webBeansContext, HttpSession.class, HttpSession.class)); } if (!hasBean(beanManager, ServletContext.class)) { beanManager.addInternalBean( new InternalBean<>(webBeansContext, ServletContext.class, ServletContext.class)); } beanManager .getInjectionResolver() .clearCaches(); // hasBean() usage can have cached several things } private static boolean hasBean(final BeanManagerImpl beanManagerImpl, final Class<?> type) { return !beanManagerImpl.getInjectionResolver().implResolveByType(false, type).isEmpty(); } private void starts(final BeanManager beanManager, final Class<?> clazz) { final Bean<?> bean = beanManager.resolve(beanManager.getBeans(clazz)); if (!beanManager.isNormalScope(bean.getScope())) { throw new IllegalStateException( "Only normal scoped beans can use @Startup - likely @ApplicationScoped"); } final CreationalContext<Object> creationalContext = beanManager.createCreationalContext(null); beanManager.getReference(bean, clazz, creationalContext).toString(); // don't release now, will be done by the context - why we restrict it to normal scoped beans } @Override public void stopApplication(final Object endObject) { logger.debug("OpenWebBeans Container is stopping."); try { // Fire shut down if (WebappBeanManager.class.isInstance(beanManager)) { WebappBeanManager.class.cast(beanManager).beforeStop(); } webBeansContext.getContextsService().endContext(RequestScoped.class, endObject); webBeansContext.getContextsService().endContext(ConversationScoped.class, endObject); webBeansContext.getContextsService().endContext(SessionScoped.class, endObject); webBeansContext.getContextsService().endContext(ApplicationScoped.class, endObject); webBeansContext.getContextsService().endContext(Singleton.class, endObject); // clean up the EL caches after each request ELContextStore elStore = ELContextStore.getInstance(false); if (elStore != null) { elStore.destroyELContextStore(); } this.beanManager.fireEvent(new BeforeShutdownImpl(), true); // this will now even destroy the ExtensionBeans and other internal stuff this.contextsService.destroy(endObject); // Unbind BeanManager if (jndiService != null) { jndiService.unbind(WebBeansConstants.WEB_BEANS_MANAGER_JNDI_NAME); } // Free all plugin resources ((CdiPlugin) webBeansContext.getPluginLoader().getEjbPlugin()).clearProxies(); webBeansContext.getPluginLoader().shutDown(); // Clear extensions webBeansContext.getExtensionLoader().clear(); // Delete Resolutions Cache beanManager.getInjectionResolver().clearCaches(); // Delete AnnotateTypeCache webBeansContext.getAnnotatedElementFactory().clear(); // After Stop // Clear the resource injection service final ResourceInjectionService injectionServices = webBeansContext.getService(ResourceInjectionService.class); if (injectionServices != null) { injectionServices.clear(); } // Comment out for commit OWB-502 // ContextFactory.cleanUpContextFactory(); CdiAppContextsService.class.cast(contextsService).removeThreadLocals(); WebBeansFinder.clearInstances(WebBeansUtil.getCurrentClassLoader()); // Clear BeanManager this.beanManager.clear(); // Clear singleton list WebBeansFinder.clearInstances(WebBeansUtil.getCurrentClassLoader()); } catch (final Exception e) { logger.error("An error occured while stopping the container.", e); } } /** @return the scannerService */ protected ScannerService getScannerService() { return scannerService; } /** @return the contextsService */ public ContextsService getContextService() { return contextsService; } /** @return the jndiService */ protected JNDIService getJndiService() { return jndiService; } @Override public void initApplication(final Properties properties) { // no-op } public void startServletContext(final ServletContext servletContext) { initializeServletContext(servletContext, webBeansContext); } public static void initializeServletContext( final ServletContext servletContext, final WebBeansContext context) { if (context == null || !context.getBeanManagerImpl().isInUse()) { return; } final ELAdaptor elAdaptor = context.getService(ELAdaptor.class); final ELResolver resolver = elAdaptor.getOwbELResolver(); // Application is configured as JSP if (context.getOpenWebBeansConfiguration().isJspApplication()) { logger.debug("Application is configured as JSP. Adding EL Resolver."); setJspELFactory(servletContext, resolver); } // Add BeanManager to the 'javax.enterprise.inject.spi.BeanManager' servlet context attribute servletContext.setAttribute(BeanManager.class.getName(), context.getBeanManagerImpl()); } /** On Tomcat we need to sometimes force a class load to get our hands on the JspFactory */ private static void setJspELFactory(ServletContext startupObject, ELResolver resolver) { JspFactory factory = JspFactory.getDefaultFactory(); if (factory == null) { try { try { Class.forName("org.apache.jasper.servlet.JasperInitializer"); } catch (final Throwable th) { Class.forName("org.apache.jasper.compiler.JspRuntimeContext"); } factory = JspFactory.getDefaultFactory(); } catch (Exception e) { // ignore } } if (factory != null) { JspApplicationContext applicationCtx = factory.getJspApplicationContext(startupObject); applicationCtx.addELResolver(resolver); } else { logger.debug("Default JSPFactroy instance has not found. Skipping OWB JSP handling"); } } /** * Returns servlet context otherwise throws exception. * * @param object object * @return servlet context */ private Object getServletContext(Object object) { if (ServletContextEvent.class.isInstance(object)) { object = ServletContextEvent.class.cast(object).getServletContext(); return object; } return object; } public static class InternalBean<T> extends BuiltInOwbBean<T> { private final String id; protected InternalBean( final WebBeansContext webBeansContext, final Class<T> api, final Class<?> type) { super( webBeansContext, WebBeansType.MANAGED, api, new SimpleProducerFactory<T>( new ProviderBasedProducer<>( webBeansContext, type, new OpenEJBComponentProvider(webBeansContext, type), false))); this.id = "openejb#container#" + api.getName(); } @Override public boolean isPassivationCapable() { return true; } @Override protected String providedId() { return id; } @Override public Class<?> proxyableType() { return null; } } public static class HttpServletRequestBean extends InternalBean<HttpServletRequest> { private final Set<Type> types; protected HttpServletRequestBean(final WebBeansContext webBeansContext) { super(webBeansContext, HttpServletRequest.class, HttpServletRequest.class); this.types = new HashSet<>(); // here we need 2 types (+Object) otherwise decoratione etc fails this.types.add(HttpServletRequest.class); this.types.add(ServletRequest.class); this.types.add(Object.class); } @Override public Set<Type> getTypes() { return types; } } private static class OpenEJBComponentProvider<T> implements Provider<T>, Serializable { private Class<?> type; private transient WebBeansContext webBeansContext; public OpenEJBComponentProvider(final WebBeansContext webBeansContext, final Class<?> type) { this.webBeansContext = webBeansContext; this.type = type; } @Override public T get() { if (webBeansContext == null) { webBeansContext = WebBeansContext.currentInstance(); } return (T) SystemInstance.get().getComponent(type); } Object readResolve() throws ObjectStreamException { return get(); } } }
@SuppressWarnings({"UnusedDeclaration"}) public class OpenEJBNamingContextListener implements LifecycleListener, PropertyChangeListener { private static final Logger logger = Logger.getInstance( LogCategory.OPENEJB.createChild("tomcat"), "org.apache.openejb.util.resources"); /** Associated standardServer. */ private final StandardServer standardServer; /** Has the listener been started? */ private boolean running = false; /** Associated naming resources. */ private final NamingResources namingResources; public OpenEJBNamingContextListener(StandardServer standardServer) { this.standardServer = standardServer; namingResources = standardServer.getGlobalNamingResources(); } public void lifecycleEvent(LifecycleEvent event) { if (event.getLifecycle() != standardServer) { return; } if (Lifecycle.START_EVENT.equals(event.getType())) { start(); } else if (Lifecycle.STOP_EVENT.equals(event.getType())) { stop(); } } public boolean isRunning() { return running; } public void start() { if (running) return; namingResources.addPropertyChangeListener(this); processInitialNamingResources(); running = true; } public void stop() { if (!running) return; namingResources.removePropertyChangeListener(this); running = false; } public void propertyChange(PropertyChangeEvent event) { if (!running) return; Object source = event.getSource(); if (source == namingResources) { processGlobalResourcesChange( event.getPropertyName(), event.getOldValue(), event.getNewValue()); } } /** * Process a property change on the global naming resources, by making the corresponding addition * or removal to OpenEJB. * * @param name Property name of the change to be processed * @param oldValue The old value (or <code>null</code> if adding) * @param newValue The new value (or <code>null</code> if removing) */ private void processGlobalResourcesChange(String name, Object oldValue, Object newValue) { // NOTE - It seems that the Context for global JNDI resources // is left in read-write mode, so we do not have to change it here if (name.equals("ejb")) { if (oldValue != null) { ContextEjb ejb = (ContextEjb) oldValue; if (ejb.getName() != null) { removeEjb(ejb.getName()); } } if (newValue != null) { ContextEjb ejb = (ContextEjb) newValue; if (ejb.getName() != null) { addEjb(ejb); } } } else if (name.equals("environment")) { if (oldValue != null) { ContextEnvironment env = (ContextEnvironment) oldValue; if (env.getName() != null) { removeEnvironment(env.getName()); } } if (newValue != null) { ContextEnvironment env = (ContextEnvironment) newValue; if (env.getName() != null) { addEnvironment(env); } } } else if (name.equals("localEjb")) { if (oldValue != null) { ContextLocalEjb ejb = (ContextLocalEjb) oldValue; if (ejb.getName() != null) { removeLocalEjb(ejb.getName()); } } if (newValue != null) { ContextLocalEjb ejb = (ContextLocalEjb) newValue; if (ejb.getName() != null) { addLocalEjb(ejb); } } } else if (name.equals("resource")) { if (oldValue != null) { ContextResource resource = (ContextResource) oldValue; if (resource.getName() != null) { removeResource(resource.getName()); } } if (newValue != null) { ContextResource resource = (ContextResource) newValue; if (resource.getName() != null) { addResource(resource); } } } else if (name.equals("resourceEnvRef")) { if (oldValue != null) { ContextResourceEnvRef resourceEnvRef = (ContextResourceEnvRef) oldValue; if (resourceEnvRef.getName() != null) { removeResourceEnvRef(resourceEnvRef.getName()); } } if (newValue != null) { ContextResourceEnvRef resourceEnvRef = (ContextResourceEnvRef) newValue; if (resourceEnvRef.getName() != null) { addResourceEnvRef(resourceEnvRef); } } } else if (name.equals("resourceLink")) { if (oldValue != null) { ContextResourceLink rl = (ContextResourceLink) oldValue; if (rl.getName() != null) { removeResourceLink(rl.getName()); } } if (newValue != null) { ContextResourceLink rl = (ContextResourceLink) newValue; if (rl.getName() != null) { addResourceLink(rl); } } } } private void processInitialNamingResources() { // Resource links ContextResourceLink[] resourceLinks = namingResources.findResourceLinks(); for (ContextResourceLink resourceLink : resourceLinks) { addResourceLink(resourceLink); } // Resources ContextResource[] resources = namingResources.findResources(); for (ContextResource resource : resources) { addResource(resource); } // Resources Env ContextResourceEnvRef[] resourceEnvRefs = namingResources.findResourceEnvRefs(); for (ContextResourceEnvRef resourceEnvRef : resourceEnvRefs) { addResourceEnvRef(resourceEnvRef); } // Environment entries ContextEnvironment[] contextEnvironments = namingResources.findEnvironments(); for (ContextEnvironment contextEnvironment : contextEnvironments) { addEnvironment(contextEnvironment); } // EJB references ContextEjb[] ejbs = namingResources.findEjbs(); for (ContextEjb ejb : ejbs) { addEjb(ejb); } } public void addEjb(ContextEjb ejb) {} public void addEnvironment(ContextEnvironment env) { bindResource(env); } public void addLocalEjb(ContextLocalEjb localEjb) {} public void addResource(ContextResource resource) { bindResource(resource); } public void addResourceEnvRef(ContextResourceEnvRef resourceEnvRef) { bindResource(resourceEnvRef); } private void bindResource(ResourceBase res) { try { Context globalNamingContext = standardServer.getGlobalNamingContext(); Object value = globalNamingContext.lookup(res.getName()); String type = res.getType(); bindResource(res.getName(), value, type); } catch (NamingException e) { logger.error("Unable to lookup Global Tomcat resource " + res.getName(), e); } } private void bindResource(final String name, final Object value, final String type) { Assembler assembler = (Assembler) SystemInstance.get().getComponent(org.apache.openejb.spi.Assembler.class); try { assembler .getContainerSystem() .getJNDIContext() .lookup(Assembler.OPENEJB_RESOURCE_JNDI_PREFIX + name); return; } catch (NamingException ne) { // no-op: OK } final ResourceInfo resourceInfo = new ResourceInfo(); resourceInfo.id = name; resourceInfo.service = "Resource"; resourceInfo.types.add(type); PassthroughFactory.add(resourceInfo, value); logger.info( "Importing a Tomcat Resource with id '" + resourceInfo.id + "' of type '" + type + "'."); try { assembler.createResource(resourceInfo); } catch (OpenEJBException e) { logger.error("Unable to bind Global Tomcat resource " + name + " into OpenEJB", e); } } public void addResourceLink(ContextResourceLink resourceLink) {} public void removeEjb(String name) {} public void removeEnvironment(String name) {} public void removeLocalEjb(String name) {} public void removeResource(String name) { // there isn't any way to remove a resource yet } public void removeResourceEnvRef(String name) { // there isn't any way to remove a resource yet } public void removeResourceLink(String name) {} }
/** @version $Rev$ $Date$ */ public class BeginWebBeansListener implements ServletContextListener, ServletRequestListener, HttpSessionListener, HttpSessionActivationListener { private final String contextKey; /** Logger instance */ private static final Logger logger = Logger.getInstance(LogCategory.OPENEJB_CDI, BeginWebBeansListener.class); protected FailOverService failoverService; /** Manages the container lifecycle */ protected WebBeansContext webBeansContext; /** * Default constructor * * @param webBeansContext the OWB context */ public BeginWebBeansListener(WebBeansContext webBeansContext) { this.webBeansContext = webBeansContext; this.failoverService = this.webBeansContext.getService(FailOverService.class); this.contextKey = "org.apache.tomee.catalina.WebBeansListener@" + webBeansContext.hashCode(); } /** {@inheritDoc} */ @Override public void requestDestroyed(ServletRequestEvent event) { // no-op } /** {@inheritDoc} */ @Override public void requestInitialized(final ServletRequestEvent event) { final Object oldContext = ThreadSingletonServiceImpl.enter(this.webBeansContext); if (event != null) { event.getServletRequest().setAttribute(contextKey, oldContext); } try { if (logger.isDebugEnabled()) { logger.debug( "Starting a new request : [{0}]", event == null ? "null" : event.getServletRequest().getRemoteAddr()); } if (webBeansContext instanceof WebappWebBeansContext) { // start before child ((WebappWebBeansContext) webBeansContext) .getParent() .getContextsService() .startContext(RequestScoped.class, event); } this.webBeansContext.getContextsService().startContext(RequestScoped.class, event); // we don't initialise the Session here but do it lazily if it gets requested // the first time. See OWB-457 } catch (final Exception e) { logger.error(OWBLogConst.ERROR_0019, event == null ? "null" : event.getServletRequest()); WebBeansUtil.throwRuntimeExceptions(e); } } /** {@inheritDoc} */ @Override public void sessionCreated(final HttpSessionEvent event) { try { if (logger.isDebugEnabled()) { logger.debug("Starting a session with session id : [{0}]", event.getSession().getId()); } if (webBeansContext instanceof WebappWebBeansContext) { // start before child ((WebappWebBeansContext) webBeansContext) .getParent() .getContextsService() .startContext(SessionScoped.class, event.getSession()); } this.webBeansContext .getContextsService() .startContext(SessionScoped.class, event.getSession()); } catch (final Exception e) { logger.error(OWBLogConst.ERROR_0020, event.getSession()); WebBeansUtil.throwRuntimeExceptions(e); } } /** {@inheritDoc} */ @Override public void sessionDestroyed(HttpSessionEvent event) { ensureRequestScope(); } private void ensureRequestScope() { final Context reqCtx = webBeansContext.getContextsService().getCurrentContext(RequestScoped.class); if (reqCtx == null || !webBeansContext .getContextsService() .getCurrentContext(RequestScoped.class) .isActive()) { requestInitialized(null); EndWebBeansListener.FAKE_REQUEST.set(true); } } @Override public void sessionWillPassivate(HttpSessionEvent event) { ensureRequestScope(); } @Override public void sessionDidActivate(HttpSessionEvent event) { if (failoverService.isSupportFailOver() || failoverService.isSupportPassivation()) { failoverService.sessionDidActivate(event.getSession()); } } @Override public void contextInitialized(ServletContextEvent servletContextEvent) { try { OpenEJBLifecycle.initializeServletContext( servletContextEvent.getServletContext(), webBeansContext); } catch (final Exception e) { logger.warning(e.getMessage(), e); } ensureRequestScope(); } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { ensureRequestScope(); } }
/** @version $Rev$ $Date$ */ public class OptimizedLoaderService implements LoaderService { private static final Logger log = Logger.getInstance(LogCategory.OPENEJB.createChild("cdi"), OptimizedLoaderService.class); public static final ThreadLocal<Collection<String>> ADDITIONAL_EXTENSIONS = new ThreadLocal<Collection<String>>(); private final LoaderService loaderService; public OptimizedLoaderService() { this(new DefaultLoaderService()); } public OptimizedLoaderService(final LoaderService loaderService) { this.loaderService = loaderService; } @Override public <T> List<T> load(final Class<T> serviceType) { return load(serviceType, Thread.currentThread().getContextClassLoader()); } @Override public <T> List<T> load(final Class<T> serviceType, final ClassLoader classLoader) { // ServiceLoader is expensive (can take up to a half second). This is an optimization if (OpenWebBeansPlugin.class.equals(serviceType)) { return (List<T>) loadWebBeansPlugins(classLoader); } // As far as we know, this only is reached for CDI Extension discovery if (Extension.class.equals(serviceType)) { return (List<T>) loadExtensions(classLoader); } return loaderService.load(serviceType, classLoader); } protected List<? extends Extension> loadExtensions(final ClassLoader classLoader) { final List<Extension> list = loaderService.load(Extension.class, classLoader); final Collection<String> additional = ADDITIONAL_EXTENSIONS.get(); if (additional != null) { for (final String name : additional) { try { list.add(Extension.class.cast(classLoader.loadClass(name).newInstance())); } catch (final Exception ignored) { // no-op } } } final Collection<Extension> extensionCopy = new ArrayList<>(list); final Iterator<Extension> it = list.iterator(); while (it.hasNext()) { if (it.hasNext()) { if (isFiltered(extensionCopy, it.next())) { it.remove(); } } } return list; } // mainly intended to avoid conflicts between internal and overrided spec extensions private boolean isFiltered(final Collection<Extension> extensions, final Extension next) { final ClassLoader containerLoader = ParentClassLoaderFinder.Helper.get(); final Class<? extends Extension> extClass = next.getClass(); if (extClass.getClassLoader() != containerLoader) { return false; } final String name = extClass.getName(); switch (name) { case "org.apache.bval.cdi.BValExtension": for (final Extension e : extensions) { final String en = e.getClass().getName(); // org.hibernate.validator.internal.cdi.ValidationExtension but allowing few evolutions of // packages if (en.startsWith("org.hibernate.validator.") && en.endsWith("ValidationExtension")) { log.info("Skipping BVal CDI integration cause hibernate was found in the application"); return true; } } break; case "org.apache.batchee.container.cdi.BatchCDIInjectionExtension": // see // org.apache.openejb.batchee.BatchEEServiceManager return "true" .equals(SystemInstance.get().getProperty("tomee.batchee.cdi.use-extension", "false")); case "org.apache.commons.jcs.jcache.cdi.MakeJCacheCDIInterceptorFriendly": final String spi = "META-INF/services/javax.cache.spi.CachingProvider"; try { final Enumeration<URL> appResources = Thread.currentThread().getContextClassLoader().getResources(spi); if (appResources != null && appResources.hasMoreElements()) { final Collection<URL> containerResources = Collections.list(containerLoader.getResources(spi)); do { if (!containerResources.contains(appResources.nextElement())) { log.info( "Skipping JCS CDI integration cause another provide was found in the application"); return true; } } while (appResources.hasMoreElements()); } } catch (final Exception e) { // no-op } break; default: } return false; } private List<? extends OpenWebBeansPlugin> loadWebBeansPlugins(final ClassLoader loader) { final List<OpenWebBeansPlugin> list = new ArrayList<>(2); list.add(new CdiPlugin()); { final Class<?> clazz; try { clazz = loader.loadClass("org.apache.geronimo.openejb.cdi.GeronimoWebBeansPlugin"); try { list.add(OpenWebBeansPlugin.class.cast(clazz.newInstance())); } catch (final Exception e) { log.error("Unable to load OpenWebBeansPlugin: GeronimoWebBeansPlugin"); } } catch (final ClassNotFoundException e) { // ignore } } { final Class<?> clazz; try { clazz = loader.loadClass("org.apache.webbeans.jsf.plugin.OpenWebBeansJsfPlugin"); try { list.add( OpenWebBeansPlugin.class.cast( Proxy.newProxyInstance( loader, new Class<?>[] {OpenWebBeansPlugin.class}, new ClassLoaderAwareHandler( clazz.getSimpleName(), clazz.newInstance(), loader)))); } catch (final Exception e) { log.error("Unable to load OpenWebBeansPlugin: OpenWebBeansJsfPlugin"); } } catch (final ClassNotFoundException e) { // ignore } } return list; } }
// TODO: rework it // constraint: be able to use EM in web components (contextDestroyed() listener for instance) and // opposite (link TWAB/Assembler) // issue: StandardRoot is not lazy stopped // proposals: // - change the Assembler TWAB.undeployWebapps call to be correct. // - lazy stop StandardRoot // - integrate more finely with StandardContext to be able to ensure we are called when expected public class TomEEWebappClassLoader extends ParallelWebappClassLoader { private static final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB, TomEEWebappClassLoader.class.getName()); private static final ThreadLocal<ClassLoaderConfigurer> INIT_CONFIGURER = new ThreadLocal<>(); private static final ThreadLocal<Context> CONTEXT = new ThreadLocal<>(); public static final String TOMEE_WEBAPP_FIRST = "tomee.webapp-first"; public static final String TOMEE_EAR_DEFAULT = "tomee.ear.webapp-first"; static { boolean result = ClassLoader.registerAsParallelCapable(); if (!result) { LOGGER.warning("Can't register // tomee webapp classloader"); } } public static final String CLASS_EXTENSION = ".class"; private boolean restarting; private boolean forceStopPhase = Boolean.parseBoolean( SystemInstance.get().getProperty("tomee.webappclassloader.force-stop-phase", "false")); private ClassLoaderConfigurer configurer; private final boolean isEar; private final ClassLoader containerClassLoader; private volatile boolean originalDelegate; private final int hashCode; private Collection<File> additionalRepos; private volatile boolean stopped = false; private final Map<String, Boolean> filterTempCache = new HashMap<>(); // used only in sync block + isEar private volatile LazyStopStandardRoot webResourceRoot; public TomEEWebappClassLoader() { hashCode = construct(); setJavaseClassLoader(getSystemClassLoader()); containerClassLoader = ParentClassLoaderFinder.Helper.get(); isEar = getParent() != null && !getParent().equals(containerClassLoader) && defaultEarBehavior(); originalDelegate = getDelegate(); } public TomEEWebappClassLoader(final ClassLoader parent) { super(parent); hashCode = construct(); setJavaseClassLoader(getSystemClassLoader()); containerClassLoader = ParentClassLoaderFinder.Helper.get(); isEar = getParent() != null && !getParent().equals(containerClassLoader) && defaultEarBehavior(); originalDelegate = getDelegate(); } private int construct() { setDelegate(isDelegate()); configurer = INIT_CONFIGURER.get(); return super.hashCode(); } @Override public void setDelegate(final boolean delegate) { this.delegate = delegate; this.originalDelegate = delegate; } @Override public void stop() throws LifecycleException { // in our destroyapplication method we need a valid classloader to // TomcatWebAppBuilder.afterStop() if (forceStopPhase || restarting) { internalStop(); } } public Collection<File> getAdditionalRepos() { initAdditionalRepos(); return additionalRepos; } @Override public Class<?> loadClass(final String name, final boolean resolve) throws ClassNotFoundException { if ("org.apache.openejb.hibernate.OpenEJBJtaPlatform".equals(name) || "org.apache.openejb.jpa.integration.hibernate.PrefixNamingStrategy".equals(name) || "org.apache.openejb.jpa.integration.eclipselink.PrefixSessionCustomizer".equals(name) || "org.apache.openejb.jpa.integration.eclipselink.OpenEJBServerPlatform".equals(name) || "org.apache.openejb.jpa.integration.eclipselink.OpenEJBServerPlatform$OpenEJBJTATransactionController" .equals(name) || "org.apache.openejb.eclipselink.JTATransactionController".equals(name) || "org.apache.tomee.mojarra.TomEEInjectionProvider".equals(name)) { // don't load them from system classloader (breaks all in embedded mode and no sense in other // cases) synchronized (this) { final ClassLoader old = getJavaseClassLoader(); setJavaseClassLoader(NoClassClassLoader.INSTANCE); delegate = false; try { return super.loadClass(name, resolve); } finally { setJavaseClassLoader(old); setDelegate(originalDelegate); } } } // avoid to redefine classes from server in this classloader is it not already loaded if (URLClassLoaderFirst.shouldDelegateToTheContainer( this, name)) { // dynamic validation handling overriding try { return OpenEJB.class .getClassLoader() .loadClass( name); // we could use containerClassLoader but this is server loader so cut it even // more } catch (final ClassNotFoundException e) { synchronized (this) { return super.loadClass(name, resolve); } } catch (final NoClassDefFoundError ncdfe) { synchronized (this) { return super.loadClass(name, resolve); } } } else if (name.startsWith("javax.faces.") || name.startsWith("org.apache.webbeans.jsf")) { synchronized (this) { delegate = false; try { return super.loadClass(name, resolve); } finally { setDelegate(originalDelegate); } } } synchronized ( this) { // TODO: rework it to avoid it and get aligned on Java 7 classloaders (but not a big // issue) if (isEar) { final boolean filter = filter(name, true); filterTempCache.put(name, filter); // will be called again by super.loadClass() so cache it if (!filter) { if (URLClassLoaderFirst.class.isInstance(getParent())) { // true final URLClassLoaderFirst urlClassLoaderFirst = URLClassLoaderFirst.class.cast(getParent()); Class<?> c = urlClassLoaderFirst.findAlreadyLoadedClass(name); if (c != null) { return c; } c = urlClassLoaderFirst.loadInternal(name, resolve); if (c != null) { return c; } } return loadWithDelegate( getResource(name.replace('.', '/') + CLASS_EXTENSION) == null, resolve, name); } } return super.loadClass(name, resolve); } } private Class<?> loadWithDelegate( final boolean delegate, final boolean resolve, final String name) throws ClassNotFoundException { setDelegate(delegate); try { return super.loadClass(name, resolve); } finally { filterTempCache.remove(name); // no more needed since class is loaded, avoid to waste mem setDelegate(originalDelegate); } } @Override public void setResources(final WebResourceRoot resources) { this.resources = resources; if (StandardRoot.class.isInstance(resources)) { final List<WebResourceSet> jars = (List<WebResourceSet>) Reflections.get(resources, "jarResources"); if (jars != null && !jars.isEmpty()) { final Iterator<WebResourceSet> jarIt = jars.iterator(); while (jarIt.hasNext()) { final WebResourceSet set = jarIt.next(); if (set.getBaseUrl() == null) { continue; } final File file = URLs.toFile(set.getBaseUrl()); try { if (file.exists() && (!TomEEClassLoaderEnricher.validateJarFile(file) || !jarIsAccepted(file))) { // need to remove this resource LOGGER.warning("Removing " + file.getAbsolutePath() + " since it is offending"); jarIt.remove(); } } catch (final IOException e) { // ignore } } } } } @Override protected boolean filter(final String inName, final boolean isClassName) { final String name = inName == null || isClassName ? inName : inName.replace('/', '.').replace(".class", ""); if ("org.apache.tomee.mojarra.TomEEInjectionProvider".equals(name)) { return false; } if (isEar) { // check we are called from super and we already cached the result in loadClass synchronized (this) { final Boolean cache = filterTempCache.get(name); if (cache != null) { return cache; } } } return URLClassLoaderFirst.shouldSkip(name); } public void internalDestroy() { try { if (!stopped) { try { internalStop(); } catch (final LifecycleException e) { // no-op } } super.destroy(); } finally { cleanUpClassLoader(); } } public void internalStop() throws LifecycleException { if (stopped) { return; } // reset classloader because of tomcat classloaderlogmanager // to be sure we reset the right loggers final Thread thread = Thread.currentThread(); final ClassLoader loader = thread.getContextClassLoader(); thread.setContextClassLoader(this); try { super.stop(); // super.destroy(); if (webResourceRoot != null) { webResourceRoot.internalStop(); webResourceRoot = null; } stopped = true; } finally { thread.setContextClassLoader(loader); if (!forceStopPhase) { cleanUpClassLoader(); } } } public void restarting() { restarting = true; } public void restarted() { restarting = false; } public boolean isRestarting() { return restarting; } public boolean isForceStopPhase() { return forceStopPhase; } public boolean isStopped() { return stopped; } public synchronized void initAdditionalRepos() { if (additionalRepos != null) { return; } if (CONTEXT.get() != null) { additionalRepos = new LinkedList<>(); final String contextPath = CONTEXT.get().getServletContext().getContextPath(); final String name = contextPath.isEmpty() ? "ROOT" : contextPath.substring(1); final String externalRepositories = SystemInstance.get().getProperty("tomee." + name + ".externalRepositories"); if (externalRepositories != null) { for (final String additional : externalRepositories.split(",")) { final String trim = additional.trim(); if (!trim.isEmpty()) { final File file = new File(trim); additionalRepos.add(file); } } } } } // embeddeding implementation of sthg (JPA, JSF) can lead to classloading issues if we don't // enrich the webapp // with our integration jars // typically the class will try to be loaded by the common classloader // but the interface implemented or the parent class // will be in the webapp @Override public void start() throws LifecycleException { super.start(); // do it first otherwise we can't use this as classloader // mainly for tomee-maven-plugin initAdditionalRepos(); if (additionalRepos != null && !additionalRepos.isEmpty()) { for (final File f : additionalRepos) { final DirResourceSet webResourceSet = new PremptiveDirResourceSet(resources, "/", f.getAbsolutePath(), "/"); resources.addPreResources(webResourceSet); } resources.setCachingAllowed(false); } // add configurer enrichments if (configurer != null) { // add now we removed all we wanted final URL[] enrichment = configurer.additionalURLs(); for (final URL url : enrichment) { super.addURL(url); } } // add internal enrichments for (final URL url : SystemInstance.get().getComponent(WebAppEnricher.class).enrichment(this)) { super.addURL(url); } // WEB-INF/jars.xml final File war = Contexts.warPath(CONTEXT.get()); final File jarsXml = new File(war, "WEB-INF/" + QuickJarsTxtParser.FILE_NAME); final ClassLoaderConfigurer configurerTxt = QuickJarsTxtParser.parse(jarsXml); if (configurerTxt != null) { configurer = new CompositeClassLoaderConfigurer(configurer, configurerTxt); } stopped = false; } public void addURL(final URL url) { if (configurer == null || configurer.accept(url)) { super.addURL(url); } } private boolean jarIsAccepted(final File file) { if (configurer == null) { return true; } try { if (!configurer.accept(file.toURI().toURL())) { LOGGER.warning( "jar '" + file.getAbsolutePath() + "' is excluded: " + file.getName() + ". It will be ignored."); return false; } } catch (final MalformedURLException e) { // no-op } return true; } protected boolean defaultEarBehavior() { return !SystemInstance.get().getOptions().get(TOMEE_EAR_DEFAULT, false /*bck compat*/); } private static boolean isDelegate() { return !SystemInstance.get().getOptions().get(TOMEE_WEBAPP_FIRST, true); } @Override public InputStream getResourceAsStream(final String name) { if (!getState().isAvailable()) { return null; } try { return super.getResourceAsStream(name); } catch (final NullPointerException npe) { // workaround cause of a bug in tomcat 8.5.0, keeping it even if we upgraded until we don't // support 8.5.0 anymore final URL url = super.getResource(name); if (url != null) { try { return url.openStream(); } catch (final IOException e) { // no-op } } return null; } } @Override public Enumeration<URL> getResources(final String name) throws IOException { if (!getState().isAvailable()) { return null; } if ("META-INF/services/javax.servlet.ServletContainerInitializer".equals(name)) { final Collection<URL> list = new ArrayList<>(Collections.list(super.getResources(name))); final Iterator<URL> it = list.iterator(); while (it.hasNext()) { final URL next = it.next(); final File file = Files.toFile(next); if (!file.isFile() && NewLoaderLogic.skip(next)) { it.remove(); } } return Collections.enumeration(list); } if ("META-INF/services/javax.websocket.ContainerProvider".equals(name)) { final Collection<URL> list = new ArrayList<>(Collections.list(super.getResources(name))); final Iterator<URL> it = list.iterator(); while (it.hasNext()) { final URL next = it.next(); final File file = Files.toFile(next); if (!file.isFile() && NewLoaderLogic.skip(next)) { it.remove(); } } return Collections.enumeration(list); } if ("META-INF/faces-config.xml".equals(name)) { // mojarra workaround try { if (WebBeansContext.currentInstance() == null && Boolean.parseBoolean( SystemInstance.get().getProperty("tomee.jsf.ignore-owb", "true"))) { final Collection<URL> list = new HashSet<>(Collections.list(super.getResources(name))); final Iterator<URL> it = list.iterator(); while (it.hasNext()) { final String fileName = Files.toFile(it.next()).getName(); if (fileName.startsWith("openwebbeans-" /*jsf|el22*/) && fileName.endsWith(".jar")) { it.remove(); } } return Collections.enumeration(list); } } catch (final Throwable th) { // no-op } } return URLClassLoaderFirst.filterResources(name, super.getResources(name)); } @Override public boolean equals(final Object other) { return other != null && ClassLoader.class.isInstance(other) && hashCode() == other.hashCode(); } @Override public int hashCode() { return hashCode; } @Override public TomEEWebappClassLoader copyWithoutTransformers() { final TomEEWebappClassLoader result = new TomEEWebappClassLoader(getParent()); result.additionalRepos = additionalRepos; result.configurer = configurer; super.copyStateWithoutTransformers(result); try { result.start(); } catch (LifecycleException e) { throw new IllegalStateException(e); } return result; } @Override public void destroy() { if (forceStopPhase) { internalDestroy(); } } private void cleanUpClassLoader() { final LogManager lm = LogManager.getLogManager(); if (ClassLoaderLogManager.class.isInstance( lm)) { // weak ref but ensure it is really removed otherwise in some cases we leak Map.class.cast(Reflections.get(lm, "classLoaderLoggers")).remove(this); } } public static void initContext(final ClassLoaderConfigurer configurer) { INIT_CONFIGURER.set(configurer); } public static void initContext(final Context ctx) { CONTEXT.set(ctx); } public static void cleanContext() { INIT_CONFIGURER.remove(); CONTEXT.remove(); } public void setWebResourceRoot(LazyStopStandardRoot webResourceRoot) { this.webResourceRoot = webResourceRoot; } private static class NoClassClassLoader extends ClassLoader { private static final NoClassClassLoader INSTANCE = new NoClassClassLoader(); @Override public Class<?> loadClass(final String name) throws ClassNotFoundException { throw new ClassNotFoundException(); } } private static final class PremptiveDirResourceSet extends DirResourceSet { private static final String WEB_INF_CLASSES = "/WEB-INF/classes"; public PremptiveDirResourceSet( final WebResourceRoot resources, final String s, final String absolutePath, final String s1) { super(resources, s, absolutePath, s1); } @Override public WebResource getResource(final String path) { return super.getResource(computePath(path)); } @Override public String[] list(final String path) { return super.list(computePath(path)); } private static String computePath(final String path) { if (WEB_INF_CLASSES.equals(path)) { return "/"; } return path.startsWith(WEB_INF_CLASSES) ? path.substring(WEB_INF_CLASSES.length()) : path; } } }
public class SingletonInstanceManager { private static final Logger logger = Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources"); private SecurityService securityService; private final SingletonContext sessionContext; private final WebServiceContext webServiceContext; public SingletonInstanceManager(SecurityService securityService) { this.securityService = securityService; sessionContext = new SingletonContext(this.securityService); webServiceContext = new EjbWsContext(sessionContext); } protected void start(BeanContext beanContext) throws OpenEJBException { if (beanContext.isLoadOnStartup()) { initialize(beanContext); } } private void initialize(BeanContext beanContext) throws OpenEJBException { try { ThreadContext callContext = new ThreadContext(beanContext, null); ThreadContext old = ThreadContext.enter(callContext); try { getInstance(callContext); } finally { ThreadContext.exit(old); } } catch (OpenEJBException e) { throw new OpenEJBException("Singleton startup failed: " + beanContext.getDeploymentID(), e); } } public Instance getInstance(final ThreadContext callContext) throws OpenEJBException { final BeanContext beanContext = callContext.getBeanContext(); Data data = (Data) beanContext.getContainerData(); AtomicReference<Future<Instance>> singleton = data.singleton; try { // Has the singleton been created yet? // If there is a Future object in the AtomicReference, then // it's either been created or is being created now. Future<Instance> singletonFuture = singleton.get(); if (singletonFuture != null) return singletonFuture.get(); // The singleton has not been created nor is being created // We will construct this FutureTask and compete with the // other threads for the right to create the singleton FutureTask<Instance> task = new FutureTask<Instance>( new Callable<Instance>() { public Instance call() throws Exception { return createInstance(callContext, beanContext); } }); do { // If our FutureTask was the one to win the slot // than we are the ones responsible for creating // the singleton while the others wait. if (singleton.compareAndSet(null, task)) { task.run(); } // If we didn't win the slot and no other FutureTask // has been set by a different thread, than we need // to try again. } while ((singletonFuture = singleton.get()) == null); // At this point we can safely return the singleton return singletonFuture.get(); } catch (InterruptedException e) { Thread.interrupted(); throw new ApplicationException( new NoSuchEJBException("Singleton initialization interrupted").initCause(e)); } catch (ExecutionException e) { Throwable throwable = e.getCause(); if (throwable instanceof ApplicationException) { throw (ApplicationException) throwable; } throw new ApplicationException( new NoSuchEJBException("Singleton initialization failed").initCause(e.getCause())); } } private void initializeDependencies(BeanContext beanContext) throws OpenEJBException { SystemInstance systemInstance = SystemInstance.get(); ContainerSystem containerSystem = systemInstance.getComponent(ContainerSystem.class); for (String dependencyId : beanContext.getDependsOn()) { BeanContext dependencyContext = containerSystem.getBeanContext(dependencyId); if (dependencyContext == null) { throw new OpenEJBException( "Deployment does not exist. Deployment(id='" + dependencyContext + "')"); } final Object containerData = dependencyContext.getContainerData(); // Bean may not be a singleton or may be a singleton // managed by a different container implementation if (containerData instanceof Data) { Data data = (Data) containerData; data.initialize(); } } } private Instance createInstance(ThreadContext callContext, BeanContext beanContext) throws ApplicationException { try { initializeDependencies(beanContext); final InstanceContext context = beanContext.newInstance(); if (context.getBean() instanceof SessionBean) { final Operation originalOperation = callContext.getCurrentOperation(); try { callContext.setCurrentOperation(Operation.CREATE); final Method create = beanContext.getCreateMethod(); final InterceptorStack ejbCreate = new InterceptorStack( context.getBean(), create, Operation.CREATE, new ArrayList<InterceptorData>(), new HashMap()); ejbCreate.invoke(); } finally { callContext.setCurrentOperation(originalOperation); } } ReadWriteLock lock; if (beanContext.isBeanManagedConcurrency()) { // Bean-Managed Concurrency lock = new BeanManagedLock(); } else { // Container-Managed Concurrency lock = new ReentrantReadWriteLock(); } return new Instance( context.getBean(), context.getInterceptors(), context.getCreationalContext(), lock); } catch (Throwable e) { if (e instanceof java.lang.reflect.InvocationTargetException) { e = ((java.lang.reflect.InvocationTargetException) e).getTargetException(); } String t = "The bean instance " + beanContext.getDeploymentID() + " threw a system exception:" + e; logger.error(t, e); throw new ApplicationException( new NoSuchEJBException("Singleton failed to initialize").initCause(e)); } } public void freeInstance(ThreadContext callContext) { BeanContext beanContext = callContext.getBeanContext(); Data data = (Data) beanContext.getContainerData(); Future<Instance> instanceFuture = data.singleton.get(); // Possible the instance was never created if (instanceFuture == null) return; Instance instance; try { instance = instanceFuture.get(); } catch (InterruptedException e) { Thread.interrupted(); logger.error( "Singleton shutdown failed because the thread was interrupted: " + beanContext.getDeploymentID(), e); return; } catch (ExecutionException e) { // Instance was never initialized return; } try { callContext.setCurrentOperation(Operation.PRE_DESTROY); callContext.setCurrentAllowedStates(null); Method remove = instance.bean instanceof SessionBean ? beanContext.getCreateMethod() : null; List<InterceptorData> callbackInterceptors = beanContext.getCallbackInterceptors(); InterceptorStack interceptorStack = new InterceptorStack( instance.bean, remove, Operation.PRE_DESTROY, callbackInterceptors, instance.interceptors); // Transaction Demarcation for Singleton PostConstruct method TransactionType transactionType; if (beanContext.getComponentType() == BeanType.SINGLETON) { Set<Method> callbacks = callbackInterceptors.get(callbackInterceptors.size() - 1).getPreDestroy(); if (callbacks.isEmpty()) { transactionType = TransactionType.RequiresNew; } else { transactionType = beanContext.getTransactionType(callbacks.iterator().next()); if (transactionType == TransactionType.Required) { transactionType = TransactionType.RequiresNew; } } } else { transactionType = beanContext.isBeanManagedTransaction() ? TransactionType.BeanManaged : TransactionType.NotSupported; } TransactionPolicy transactionPolicy = EjbTransactionUtil.createTransactionPolicy(transactionType, callContext); try { // Call the chain interceptorStack.invoke(); if (instance.creationalContext != null) { instance.creationalContext.release(); } } catch (Throwable e) { // RollBack Transaction EjbTransactionUtil.handleSystemException(transactionPolicy, e, callContext); } finally { EjbTransactionUtil.afterInvoke(transactionPolicy, callContext); } } catch (Throwable re) { logger.error("Singleton shutdown failed: " + beanContext.getDeploymentID(), re); } } /** * This method has no work to do as all instances are removed from the pool on getInstance(...) * and not returned via poolInstance(...) if they threw a system exception. * * @param callContext * @param bean */ public void discardInstance(ThreadContext callContext, Object bean) {} public void deploy(BeanContext beanContext) throws OpenEJBException { Data data = new Data(beanContext); beanContext.setContainerData(data); beanContext.set(EJBContext.class, this.sessionContext); // Create stats interceptor StatsInterceptor stats = new StatsInterceptor(beanContext.getBeanClass()); beanContext.addSystemInterceptor(stats); MBeanServer server = LocalMBeanServer.get(); ObjectNameBuilder jmxName = new ObjectNameBuilder("openejb.management"); jmxName.set("J2EEServer", "openejb"); jmxName.set("J2EEApplication", null); jmxName.set("EJBModule", beanContext.getModuleID()); jmxName.set("SingletonSessionBean", beanContext.getEjbName()); jmxName.set("j2eeType", ""); jmxName.set("name", beanContext.getEjbName()); // register the invocation stats interceptor try { ObjectName objectName = jmxName.set("j2eeType", "Invocations").build(); server.registerMBean(new ManagedMBean(stats), objectName); data.add(objectName); } catch (Exception e) { logger.error("Unable to register MBean ", e); } try { final Context context = beanContext.getJndiEnc(); context.bind("comp/EJBContext", sessionContext); context.bind("comp/WebServiceContext", webServiceContext); context.bind("comp/TimerService", new TimerServiceWrapper()); } catch (NamingException e) { throw new OpenEJBException("Failed to bind EJBContext/WebServiceContext/TimerService", e); } } public void undeploy(BeanContext beanContext) { Data data = (Data) beanContext.getContainerData(); if (data == null) return; MBeanServer server = LocalMBeanServer.get(); for (ObjectName objectName : data.jmxNames) { try { server.unregisterMBean(objectName); } catch (Exception e) { logger.error("Unable to unregister MBean " + objectName); } } beanContext.setContainerData(null); } private final class Data { private final AtomicReference<Future<Instance>> singleton = new AtomicReference<Future<Instance>>(); private final List<ObjectName> jmxNames = new ArrayList<ObjectName>(); private final BeanContext info; public Data(BeanContext info) { this.info = info; } public ObjectName add(ObjectName name) { jmxNames.add(name); return name; } public void initialize() throws OpenEJBException { SingletonInstanceManager.this.initialize(info); } } private static class BeanManagedLock implements ReadWriteLock { private final Lock lock = new Lock() { public void lock() {} public void lockInterruptibly() {} public Condition newCondition() { throw new java.lang.UnsupportedOperationException("newCondition()"); } public boolean tryLock() { return true; } public boolean tryLock(long time, TimeUnit unit) { return true; } public void unlock() {} }; public Lock readLock() { return lock; } public Lock writeLock() { return lock; } } }