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); } }
/** {@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); } }
// 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; }
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; }
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; }
@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 } } } } }
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); } }
@Override public void contextInitialized(ServletContextEvent servletContextEvent) { try { OpenEJBLifecycle.initializeServletContext( servletContextEvent.getServletContext(), webBeansContext); } catch (final Exception e) { logger.warning(e.getMessage(), e); } ensureRequestScope(); }
/** {@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); } }
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; }
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 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 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; }
@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 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"); }
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()); }
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; }
@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(); } }
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); }
/** 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"); } }
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 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; } }); }
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); }
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 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); } }
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 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; }
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; } } }
@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; }
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 } } } }