package org.openxdm.xcap.server.slee; import java.io.ByteArrayInputStream; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import javax.slee.ActivityContextInterface; import javax.slee.ActivityEndEvent; import javax.slee.ChildRelation; import javax.slee.RolledBackContext; import javax.slee.SbbContext; import javax.slee.serviceactivity.ServiceActivity; import javax.slee.serviceactivity.ServiceActivityFactory; import org.apache.log4j.Logger; import org.mobicents.slee.xdm.server.ServerConfiguration; import org.openxdm.xcap.common.appusage.AppUsage; import org.openxdm.xcap.common.appusage.AppUsageFactory; import org.openxdm.xcap.common.error.InternalServerErrorException; import org.openxdm.xcap.common.uri.ResourceSelector; import org.openxdm.xcap.server.slee.resource.appusagecache.AppUsageCacheResourceAdaptorSbbInterface; import org.openxdm.xcap.server.slee.resource.datasource.DataSourceSbbInterface; public abstract class AbstractAppUsageSbb implements javax.slee.Sbb { private SbbContext sbbContext = null; // This SBB's context private Context myEnv = null; // This SBB's environment private AppUsageCacheResourceAdaptorSbbInterface appUsageCache = null; private Logger logger = getLogger(); protected DataSourceSbbInterface dataSource = null; protected DataSourceSbbInterface getDataSource() { return dataSource; } /** * Called when an sbb object is instantied and enters the pooled state. */ public void setSbbContext(SbbContext context) { this.sbbContext = context; try { myEnv = (Context) new InitialContext().lookup("java:comp/env"); appUsageCache = (AppUsageCacheResourceAdaptorSbbInterface) myEnv .lookup("slee/resources/openxdm/appusagecache/sbbrainterface"); dataSource = (DataSourceSbbInterface) myEnv .lookup("slee/resources/openxdm/datasource/sbbrainterface"); } catch (NamingException e) { logger.error("Can't set sbb context.", e); } } public void unsetSbbContext() { this.sbbContext = null; } public void sbbCreate() throws javax.slee.CreateException { } public void sbbPostCreate() throws javax.slee.CreateException { } public void sbbActivate() { } public void sbbPassivate() { } public void sbbRemove() { } public void sbbLoad() { } public void sbbStore() { } public void sbbExceptionThrown(Exception exception, Object event, ActivityContextInterface activity) { if (logger.isDebugEnabled()) logger.debug("sbbExceptionThrown(exception=" + exception.toString() + ",event=" + event.toString() + ",activity=" + activity.toString() + ")"); } public void sbbRolledBack(RolledBackContext sbbRolledBack) { if (logger.isDebugEnabled()) logger.debug("sbbRolledBack(sbbRolledBack=" + sbbRolledBack.toString() + ")"); } protected SbbContext getSbbContext() { return sbbContext; } // CHILD RELATIONS & RA ABSTRACTIONS // ################################################################ public abstract ChildRelation getRequestProcessorChildRelation(); protected RequestProcessorSbbLocalObject getRequestProcessor() throws InternalServerErrorException { // TODO use CMP to store the child sbb, that will break compatibility with // app usages // get the child relation ChildRelation childRelation = getRequestProcessorChildRelation(); // creates the child sbb if does not exist if (childRelation.isEmpty()) { try { return (RequestProcessorSbbLocalObject) childRelation.create(); } catch (Exception e) { logger.error("unable to create the child sbb.", e); throw new InternalServerErrorException(""); } } else { // return the child sbb return (RequestProcessorSbbLocalObject) childRelation.iterator() .next(); } } private void putAppUsageInCache() { try { appUsageCache.put(getAppUsageFactory()); } catch (InternalServerErrorException e) { logger.error("Unable to put app usage in cache", e); } } private AppUsage borrowAppUsageFromCache(String auid) throws InternalServerErrorException { try { // borrow app usage from cache return appUsageCache.borrow(auid); } catch (Exception e) { logger.error("Unable to borrow app usage instance from cache", e); throw new InternalServerErrorException( "Unable to borrow app usage instance from cache"); } } private void releaseAppUsageToCache(AppUsage appUsage) { appUsageCache.release(appUsage); } private void removeAppUsageFromCache() { appUsageCache.remove(getAUID()); } // ABSTRACT METHODS TO BE IMPLEMENTED // ######################################################### public abstract Logger getLogger(); public abstract String getAUID(); public abstract AppUsageFactory getAppUsageFactory() throws InternalServerErrorException; // XCAP CAPS UPDATE private void updateXCAPCapsGlobalDoc() throws InternalServerErrorException { // we can't use the xcap caps app usage class, may not be loaded final String xcapCapsAUID = "xcap-caps"; final String xcapCapsMimetype = "application/xcap-caps+xml"; if (dataSource.containsAppUsage(xcapCapsAUID)) { // create xcap-caps global/index doc StringBuilder sb1 = new StringBuilder( "<?xml version='1.0' encoding='UTF-8'?><xcap-caps xmlns='urn:ietf:params:xml:ns:xcap-caps'><auids>"); StringBuilder sb2 = new StringBuilder( "</auids><extensions/><namespaces>"); AppUsage xcapCapsAppUsage = null; for (String auid : dataSource.getAppUsages()) { // borrow one app usage object from cache AppUsage appUsage = borrowAppUsageFromCache(auid); // add auid and namespace if (appUsage != null) { sb1.append("<auid>").append(appUsage.getAUID()).append( "</auid>"); sb2.append("<namespace>").append( appUsage.getDefaultDocumentNamespace()).append( "</namespace>"); if (auid.equals(xcapCapsAUID)) { xcapCapsAppUsage = appUsage; } else { // release app usage object releaseAppUsageToCache(appUsage); } } } sb1.append(sb2).append("</namespaces></xcap-caps>"); if (xcapCapsAppUsage != null) { try { getRequestProcessor().put( new ResourceSelector("/" + xcapCapsAUID + "/global/index", null), xcapCapsMimetype, new ByteArrayInputStream(sb1.toString().getBytes( "utf-8")), null, ServerConfiguration.XCAP_ROOT,null); } catch (Exception e) { e.printStackTrace(); throw new InternalServerErrorException( "Failed to put xcap-caps global document. Cause: " + e.getCause() + " Message:" + e.getMessage()); } // release app usage object releaseAppUsageToCache(xcapCapsAppUsage); } } } // EVENT HANDLERS public void onServiceStartedEvent( javax.slee.serviceactivity.ServiceStartedEvent event, ActivityContextInterface aci) { try { // check if it's my service that is starting ServiceActivity sa = ((ServiceActivityFactory) myEnv .lookup("slee/serviceactivity/factory")).getActivity(); if (sa.equals(aci.getActivity())) { if (logger.isInfoEnabled()) { logger.info("Application usage activated"); } // put app usage in cache putAppUsageInCache(); if (logger.isDebugEnabled()) logger.debug("AppUsage cached"); try { dataSource.addAppUsage(getAUID()); } catch (Exception e) { if (logger.isInfoEnabled()) { logger .info("Failed to create the app usage in datasource, it may already exist. Error: " + e.getMessage()); } } // update xcap caps global doc try { updateXCAPCapsGlobalDoc(); } catch (InternalServerErrorException e) { logger.error("failed to update xcap caps global doc", e); } } else { if (logger.isDebugEnabled()) logger.debug("Another service activated..."); // we don't want to receive further events on this activity aci.detach(getSbbContext().getSbbLocalObject()); } } catch (NamingException e) { logger.error("Can't handle service started event.", e); } } public void onActivityEndEvent(ActivityEndEvent event, ActivityContextInterface aci) { if (aci.getActivity() instanceof ServiceActivity) { // service activity ending if (logger.isDebugEnabled()) logger.debug("Service being deactivated...\n"); // remove app usage from cache removeAppUsageFromCache(); if (logger.isDebugEnabled()) logger.debug("AppUsage removed from cache..."); // update xcap caps global doc try { updateXCAPCapsGlobalDoc(); } catch (InternalServerErrorException e) { logger.error("failed to update xcap caps global doc", e); } } } }