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);
    }
  }
Пример #2
0
  /** {@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;
  }
Пример #4
0
  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;
  }
Пример #5
0
  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;
  }
Пример #6
0
 @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);
   }
 }
Пример #8
0
 @Override
 public void contextInitialized(ServletContextEvent servletContextEvent) {
   try {
     OpenEJBLifecycle.initializeServletContext(
         servletContextEvent.getServletContext(), webBeansContext);
   } catch (final Exception e) {
     logger.warning(e.getMessage(), e);
   }
   ensureRequestScope();
 }
Пример #9
0
 /** {@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);
   }
 }
Пример #10
0
 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));
    }
  }
Пример #13
0
 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;
 }
Пример #14
0
 @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();
 }
Пример #15
0
 @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");
 }
Пример #16
0
  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());
  }
Пример #17
0
  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;
  }
Пример #18
0
 @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);
  }
Пример #20
0
  /** 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;
          }
        });
  }
Пример #23
0
  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);
  }
Пример #24
0
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;
    }
  }
}
Пример #25
0
  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);
    }
  }
Пример #26
0
  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();
  }
Пример #27
0
  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;
  }
Пример #28
0
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;
    }
  }
}
Пример #29
0
  @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;
  }
Пример #30
0
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
      }
    }
  }
}