All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.openejb.core.mdb.MdbInstanceFactory Maven / Gradle / Ivy

There is a newer version: 4.7.5
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.openejb.core.mdb;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.ejb.EJBContext;
import javax.ejb.MessageDrivenBean;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.resource.spi.UnavailableException;

import org.apache.openejb.BeanContext;
import org.apache.openejb.OpenEJBException;
import org.apache.openejb.core.BaseContext;
import org.apache.openejb.core.InstanceContext;
import org.apache.openejb.core.Operation;
import org.apache.openejb.core.ThreadContext;
import org.apache.openejb.core.interceptor.InterceptorData;
import org.apache.openejb.core.interceptor.InterceptorStack;
import org.apache.openejb.core.timer.TimerServiceWrapper;
import org.apache.openejb.spi.SecurityService;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;

/**
 * A MdbInstanceFactory creates instances of message driven beans for a single instance. This class differs from other
 * instance managers in OpenEJB as it doesn't do pooling and it creates instances for only a single EJB deployment.
 * 

* The MdbContainer assumes that the resouce adapter is pooling message endpoints so a second level of pooling in the * container would be inefficient. This is true of all known resouce adapters in opensource (ActiveMQ), so if this is * a poor assumption for your resource adapter, contact the OpenEJB developers. *

* This class can optionally limit the number of bean instances and therefore the message endpoints available to the * resource adapter. */ public class MdbInstanceFactory { private static final Logger logger = Logger.getInstance(LogCategory.OPENEJB, "org.apache.openejb.util.resources"); private final BeanContext beanContext; private final SecurityService securityService; private final int instanceLimit; private int instanceCount; private final MdbContext mdbContext; /** * Creates a MdbInstanceFactory for a single specific deployment. * * @param beanContext the deployment for which instances will be created * @param securityService the transaction manager for this container system * @param instanceLimit the maximal number of instances or <= 0 if unlimited */ public MdbInstanceFactory(BeanContext beanContext, SecurityService securityService, int instanceLimit) throws OpenEJBException { this.beanContext = beanContext; this.securityService = securityService; this.instanceLimit = instanceLimit; mdbContext = new MdbContext(securityService); try { final Context context = beanContext.getJndiEnc(); context.bind("comp/EJBContext", mdbContext); context.bind("comp/TimerService", new TimerServiceWrapper()); } catch (NamingException e) { throw new OpenEJBException("Failed to bind EJBContext/TimerService", e); } beanContext.set(EJBContext.class, this.mdbContext); } /** * Gets the maximal number of instances that can exist at any time. * * @return the maximum number of instances or <= 0 if unlimitied */ public int getInstanceLimit() { return instanceLimit; } /** * Gets the current number of created instances. * * @return the current number of instances created */ public synchronized int getInstanceCount() { return instanceCount; } /** * Creates a new mdb instance preforming all necessary lifecycle callbacks * * @param ignoreInstanceCount * @return a new message driven bean instance * @throws UnavailableException if the instance limit has been exceeded or * if an exception occurs while creating the bean instance */ public Object createInstance(boolean ignoreInstanceCount) throws UnavailableException { if (!ignoreInstanceCount) { synchronized (this) { // check the instance limit if (instanceLimit > 0 && instanceCount >= instanceLimit) { throw new UnavailableException("Only " + instanceLimit + " instances can be created"); } // increment the instance count instanceCount++; } } try { Object bean = constructBean(); return bean; } catch (UnavailableException e) { // decrement the instance count if (!ignoreInstanceCount) { synchronized (this) { instanceCount--; } } throw e; } } /** * Frees an instance no longer needed by the resource adapter. This method makes all the necessary lifecycle * callbacks and decrements the instance count. This method should not be used to disposed of beans that have * thrown a system exception. Instead the discardInstance method should be called. * * @param instance the bean instance to free * @param ignoredInstanceCount */ public void freeInstance(Instance instance, boolean ignoredInstanceCount) { if (instance == null) throw new NullPointerException("bean is null"); // decrement the instance count if (!ignoredInstanceCount) { synchronized (this) { instanceCount--; } } ThreadContext callContext = ThreadContext.getThreadContext(); Operation originalOperation = callContext == null ? null : callContext.getCurrentOperation(); BaseContext.State[] originalAllowedStates = callContext == null ? null : callContext.getCurrentAllowedStates(); try { // call post destroy method if (callContext != null) { callContext.setCurrentOperation(Operation.PRE_DESTROY); } Method remove = instance.bean instanceof MessageDrivenBean ? MessageDrivenBean.class.getMethod("ejbRemove") : null; List callbackInterceptors = beanContext.getCallbackInterceptors(); InterceptorStack interceptorStack = new InterceptorStack(instance.bean, remove, Operation.PRE_DESTROY, callbackInterceptors, instance.interceptors); interceptorStack.invoke(); if (instance.creationalContext != null) { instance.creationalContext.release(); } } catch (Throwable re) { MdbInstanceFactory.logger.error("The bean instance " + instance.bean + " threw a system exception:" + re, re); } finally { if (callContext != null) { callContext.setCurrentOperation(originalOperation); callContext.setCurrentAllowedStates(originalAllowedStates); } } } /** * Recreates a bean instance that has thrown a system exception. As required by the EJB specification, lifecycle * callbacks are not invoked. To normally free a bean instance call the freeInstance method. * * @param bean the bean instance to discard * @return the new replacement bean instance */ public Object recreateInstance(Object bean) throws UnavailableException { if (bean == null) throw new NullPointerException("bean is null"); Object newBean = constructBean(); return newBean; } private Object constructBean() throws UnavailableException { BeanContext beanContext = this.beanContext; ThreadContext callContext = new ThreadContext(beanContext, null, Operation.INJECTION); ThreadContext oldContext = ThreadContext.enter(callContext); try { final InstanceContext context = beanContext.newInstance(); if (context.getBean() instanceof MessageDrivenBean) { callContext.setCurrentOperation(Operation.CREATE); Method create = beanContext.getCreateMethod(); final InterceptorStack ejbCreate = new InterceptorStack(context.getBean(), create, Operation.CREATE, new ArrayList(), new HashMap()); ejbCreate.invoke(); } return new Instance(context.getBean(), context.getInterceptors(), context.getCreationalContext()); } catch (Throwable e) { if (e instanceof java.lang.reflect.InvocationTargetException) { e = ((java.lang.reflect.InvocationTargetException) e).getTargetException(); } String message = "The bean instance threw a system exception:" + e; MdbInstanceFactory.logger.error(message, e); throw new UnavailableException(message, e); } finally { ThreadContext.exit(oldContext); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy