package org.mobicents.slee.runtime.eventrouter.routingtask; import java.lang.reflect.Method; import java.util.Collection; import javax.slee.Address; import javax.slee.SLEEException; import javax.slee.profile.ProfileID; import javax.slee.profile.ProfileSpecificationID; import org.apache.log4j.Logger; import org.mobicents.slee.container.SleeContainer; import org.mobicents.slee.container.component.ProfileSpecificationComponent; import org.mobicents.slee.container.component.SbbComponent; import org.mobicents.slee.container.component.ServiceComponent; import org.mobicents.slee.container.component.deployment.jaxb.descriptors.sbb.MEventEntry; import org.mobicents.slee.container.profile.ProfileTableImpl; import org.mobicents.slee.container.service.Service; import org.mobicents.slee.container.service.ServiceFactory; import org.mobicents.slee.runtime.activity.ActivityContext; import org.mobicents.slee.runtime.eventrouter.DeferredEvent; import org.mobicents.slee.runtime.sbb.SbbConcrete; import org.mobicents.slee.runtime.sbb.SbbObject; import org.mobicents.slee.runtime.sbb.SbbObjectPool; import org.mobicents.slee.runtime.sbbentity.SbbEntity; import org.mobicents.slee.runtime.sbbentity.SbbEntityFactory; import org.mobicents.slee.runtime.transaction.SleeTransactionManager; public class InitialEventProcessor { private static final Logger logger = Logger.getLogger(InitialEventProcessor.class); private final SleeContainer sleeContainer; private static final String NULL_STRING = "null"; /** * @param sleeContainer */ public InitialEventProcessor(SleeContainer sleeContainer) { this.sleeContainer = sleeContainer; } /** * Compute a convergence name for the Sbb for the given Slee event. * Convergence names are used to instantiate the Sbb. I really ought to move * this to SleeContainer.java * * @param sleeEvent - * slee event for the convergence name computation * @return the convergence name or null if this is not an initial event for * this service */ private String computeConvergenceName(DeferredEvent sleeEvent, ServiceComponent serviceComponent) throws Exception { final SbbComponent sbbComponent = serviceComponent.getRootSbbComponent(); MEventEntry mEventEntry = sbbComponent.getDescriptor().getEventEntries().get(sleeEvent.getEventTypeId()); InitialEventSelectorImpl selector = new InitialEventSelectorImpl( sleeEvent.getEventTypeId(), sleeEvent.getEvent(), sleeEvent.getActivityContextHandle(), mEventEntry.getInitialEventSelects(), mEventEntry.getInitialEventSelectorMethod(), sleeEvent .getAddress()); /* * An initial-event-selector-method-name element. This element is * optional and is meaningful only if initial-event is true. It * identifies an in itial event selector method. The SLEE invokes this * optional method to d etermine if an event of the specified event type * is an initial event if the SBB is a root SBB of a Service (see * Section 8.5.4). Note that this method is not static. You can either * used a pooled instance of the object or create a new instance of the * object to run the specified method. */ if (selector.isSelectMethod()) { // According to Section 8.5.4, page 115, some fields should be set // before calling the selector method // selector.setEvent(sleeEvent.getEventObject()); // selector.setEventName(); //TODO: not sure what value to put here // selector.setActivity(sleeEvent.getActivityContext().getActivity());//TODO: // see how to get the activity now selector.setAddress(sleeEvent.getAddress()); selector.setCustomName(null); selector.setInitialEvent(true); SbbObjectPool pool = sleeContainer.getSbbPoolManagement().getObjectPool(serviceComponent.getServiceID(), sbbComponent.getSbbID()); SbbObject sbbObject = (SbbObject) pool.borrowObject(); SbbConcrete concreteSbb = (SbbConcrete) sbbObject.getSbbConcrete(); Object[] args = new Object[] { selector }; ClassLoader oldCl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader( sbbComponent.getClassLoader()); final Method m = sbbComponent.getInitialEventSelectorMethods().get(selector.getSelectMethodName()); selector = (InitialEventSelectorImpl) m.invoke(concreteSbb, args); if (selector == null) { return null; } if (!selector.isInitialEvent()) { return null; } } finally { Thread.currentThread().setContextClassLoader(oldCl); pool.returnObject(sbbObject); } } StringBuilder buff = new StringBuilder(); if (selector.isActivityContextSelected()) { buff.append(sleeEvent.getActivityContextHandle()); } else buff.append(NULL_STRING); // TODO the ProfileTle select varile for now is null buff.append(NULL_STRING); if (selector.isAddressSelected()) { Address address = selector.getAddress(); if (address == null) buff.append(NULL_STRING); else buff.append(address.toString()); } else buff.append(NULL_STRING); // If event type is selected append it to te convergence name. if (selector.isEventTypeSelected()) { buff.append(selector.getEventTypeID()); } else buff.append(NULL_STRING); /* * Event. The value of this variable (if selected) is unique for each * event fired, e.g. each invocation of an SBB fire event method or each * firing of an event by a resource adaptor (using SLEE vendor specific * fire event methods). It is unique regardless of whether the same pair * of event object and Activity Context object (in the case of SBB fired * event, or Activity object in case of resource adaptor fired event) * are passed to the fire event method. There are two unique events * fired in the following scenarios: * * o An SBB invoking the same fire event method twice. From the SLEEs * perspective, the two fire method invocations fire two unique events * even if the Activity Context object and event object passed to the * fire event method are the same. * * o An SBB firing an event in its event handler method. The event fired * through the fire event method is a different event even if the same * Activity Context object and event object passed to the event handler * method is passed to the fire event method. * * o A resource adaptor entity invoking one or more SLEE provided * methods for firing events multiple times. From the SLEE???s * perspective, these invocations fire multiple unique events even if * the Activity object and event object passed are the same. */ if (selector.isEventSelected()) { buff.append(sleeEvent.hashCode()); // TODO: use a more unique value // than the hash code } else buff.append(NULL_STRING); /* * The address attribute of the InitialEventSelector object provides the * default address. The value of this attribute may be null if there is * no default address. The value of this attribute determines the value * of the address variable in the convergence name if the address * variable is selected and is also used to look up Address Profiles in * the Address Profile Table of the Service if the Address Profile * variable is selected. * * o If the address attribute is null when the initial event selector * method returns, then the address convergence name variable is not * selected, i.e. same as setting AddressSelected attribute to false. * * o If the AddressProfile variable is set to true and the address is * not null but does not locate any Address Profile in the Address * Profile Table of the Service, then no convergence name is created, * i.e. same as setting PossibleInitialEvent to false. */ if (selector.isAddressProfileSelected()) { if (selector.getAddress() == null) { buff.append(NULL_STRING); } else { ProfileSpecificationID addressProfileId = sbbComponent.getDescriptor().getAddressProfileSpecRef(); ProfileSpecificationComponent profileSpecificationComponent = sleeContainer.getComponentRepositoryImpl().getComponentByID(addressProfileId); String addressProfileTable = serviceComponent.getDescriptor().getMService().getAddressProfileTable(); // Cannot find an address profile table spec. if (addressProfileTable == null) { throw new SLEEException("null address profile table in service !"); } ProfileTableImpl profileTable = sleeContainer.getSleeProfileTableManager().getProfileTable(addressProfileTable); Collection<ProfileID> profileIDs = profileTable.getProfilesByAttribute(profileSpecificationComponent.isSlee11() ? "address" : "addresses", selector.getAddress(), profileSpecificationComponent.isSlee11()); if (profileIDs.isEmpty()) // no profiles located return null; else { buff.append(profileIDs.iterator().next()); } } } else buff.append(NULL_STRING); String customName = selector.getCustomName(); buff.append(customName); return buff.toString(); } public SbbEntity processInitialEvent(ServiceComponent serviceComponent, DeferredEvent deferredEvent, SleeTransactionManager txMgr, ActivityContext ac) { SbbEntity sbbEntity = null; if (logger.isDebugEnabled()) { logger.debug("Initial event processing for " + serviceComponent+" and "+deferredEvent); } /* * Start of SLEE originated invocation sequence * ============================================ We run a SLEE * originated invocation sequence here for every service that * this might be an intial event for */ /* * Use the initial event select to compute the convergence names * for the service. This is a method that is provided by the * service deployment. The names set is composed by only one * convergence name the error is due an error in the pseudocode */ final Service service = ServiceFactory.getService(serviceComponent); if (service.getState().isActive()) { String name = null; try { name = computeConvergenceName(deferredEvent,serviceComponent); } catch (Exception e) { logger.error("Failed to compute convergance name: "+e.getMessage(),e); } if (name != null) { if (!service.containsConvergenceName(name)) { if (logger.isDebugEnabled()) { logger.debug("Computed convergence name for "+serviceComponent+" and "+deferredEvent+" is " + name + ", creating sbb entity and attaching to activity context."); } // Create a new root sbb entity sbbEntity = service.addChild(name); // attach sbb entity on AC if (ac.attachSbbEntity(sbbEntity.getSbbEntityId())) { // do the reverse on the sbb entity sbbEntity.afterACAttach(deferredEvent.getActivityContextHandle()); } } else { if (logger.isDebugEnabled()) { logger.debug("Computed convergence name for "+service+" and "+deferredEvent+" is " + name + ", sbb entity already exists, attaching to activity context (if not attached yet)"); } // get sbb entity id for this convergence name sbbEntity = SbbEntityFactory.getSbbEntity(service.getRootSbbEntityId(name)); // attach sbb entity on AC if (ac.attachSbbEntity(sbbEntity.getSbbEntityId())) { // do the reverse on the sbb entity sbbEntity.afterACAttach(deferredEvent.getActivityContextHandle()); } } } else { if (logger.isDebugEnabled()) { logger.debug("Computed convergence name for "+service+" and "+deferredEvent+" is null, either the root sbb is not interested in the event or an error occurred."); } } } return sbbEntity; } }