package org.mobicents.slee.container.management; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NameAlreadyBoundException; import javax.naming.NamingException; import javax.slee.SLEEException; import javax.slee.management.DeploymentException; import javax.slee.profile.ProfileSpecificationID; import javax.slee.profile.ProfileTableAlreadyExistsException; import javax.slee.profile.UnrecognizedProfileSpecificationException; import javax.slee.profile.UnrecognizedProfileTableNameException; import javax.transaction.SystemException; import org.apache.log4j.Logger; import org.mobicents.slee.container.SleeContainer; import org.mobicents.slee.container.component.ProfileSpecificationComponent; import org.mobicents.slee.container.component.deployment.jaxb.descriptors.common.MEnvEntry; import org.mobicents.slee.container.component.profile.ProfileEntityFramework; import org.mobicents.slee.container.deployment.profile.SleeProfileClassCodeGenerator; import org.mobicents.slee.container.deployment.profile.jpa.JPAProfileEntityFramework; import org.mobicents.slee.container.deployment.profile.jpa.JPAProfileTable; import org.mobicents.slee.container.deployment.profile.jpa.JPAProfileTableFramework; import org.mobicents.slee.container.profile.ProfileTableImpl; import org.mobicents.slee.runtime.facilities.ProfileAlarmFacilityImpl; import org.mobicents.slee.runtime.transaction.TransactionalAction; /** * * Start time:16:56:21 2009-03-13<br> * Project: mobicents-jainslee-server-core<br> * Class that manages ProfileSpecification, profile tables, ProfileObjects. It * is responsible for setting up profile specification env. * * @author <a href="mailto:baranowb@gmail.com"> Bartosz Baranowski </a> * @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a> */ public class SleeProfileTableManager { private static final Logger logger = Logger.getLogger(SleeProfileTableManager.class); private final static SleeProfileClassCodeGenerator sleeProfileClassCodeGenerator = new SleeProfileClassCodeGenerator(); private SleeContainer sleeContainer = null; private JPAProfileTableFramework jpaPTF = null; /** * This map contains mapping - profieltable name ---> profile table concrete * object. see 10.2.4 section of JSLEE 1.1 specs - there can be only single * profile profile table in SLEE container * */ //private ConcurrentHashMap nameToProfileTableMap = new ConcurrentHashMap(); private ConcurrentHashMap<String, ProfileTableImpl> nameToProfileTableMap; public SleeProfileTableManager(SleeContainer sleeContainer) { super(); if (sleeContainer == null) throw new NullPointerException("Parameter must not be null"); this.sleeContainer = sleeContainer; this.nameToProfileTableMap=new ConcurrentHashMap<String, ProfileTableImpl>(); // this.sleeContainer.getCache().getProfileManagementCacheData(); this.jpaPTF = new JPAProfileTableFramework(this); } /** * Installs profile into container, creates default profile and reads * backend storage to search for other profiles - it creates MBeans for all * * @param component * @throws DeploymentException * - this exception is thrown in case of error FIXME: on check * to profile - if we have one profile table active and we * encounter another, what shoudl happen? is there auto init for * all in back end memory? */ public void installProfileSpecification(ProfileSpecificationComponent component) throws DeploymentException { if (logger.isDebugEnabled()) { logger.debug("Installing " + component); } try { this.createJndiSpace(component); // FIXME: we wont use trace and alarm in 1.0 way wont we? ProfileEntityFramework profileEntityFramework = new JPAProfileEntityFramework(component); profileEntityFramework.install(); sleeProfileClassCodeGenerator.process(component); jpaPTF.loadProfileTables(component); } catch (DeploymentException de) { throw de; } catch (Throwable t) { t.printStackTrace(); throw new SLEEException(t.getMessage(),t); } } /** * * @param component * @throws UnrecognizedProfileSpecificationException */ public void uninstallProfileSpecification(ProfileSpecificationComponent component) throws UnrecognizedProfileSpecificationException { Collection<String> profileTableNames = getDeclaredProfileTableNames(component.getProfileSpecificationID()); for(String profileTableName:profileTableNames) { try { this.removeProfileTable(profileTableName); } catch (Throwable e) { throw new SLEEException(e.getMessage(),e); } } component.getProfileEntityFramework().uninstall(); } /** * * @param component * @throws Exception */ private void createJndiSpace(ProfileSpecificationComponent component) throws Exception { Context ctx = (Context) new InitialContext().lookup("java:comp"); if (logger.isDebugEnabled()) { logger.debug("Setting up Profile Spec env. Initial context is " + ctx); } Context envCtx = null; try { envCtx = ctx.createSubcontext("env"); } catch (NameAlreadyBoundException ex) { envCtx = (Context) ctx.lookup("env"); } Context sleeCtx = null; try { sleeCtx = envCtx.createSubcontext("slee"); } catch (NameAlreadyBoundException ex) { sleeCtx = (Context) envCtx.lookup("slee"); } Context facilitiesCtx = null; try { facilitiesCtx = sleeCtx.createSubcontext("facilities"); } catch (NameAlreadyBoundException ex) { facilitiesCtx = (Context) sleeCtx.lookup("facilities"); } ProfileAlarmFacilityImpl alarmFacility = new ProfileAlarmFacilityImpl(this.sleeContainer.getAlarmMBean()); // FIXME: Alexandre: This should be AlarmFacility.JNDI_NAME. Any problem if already bound? try { facilitiesCtx.bind("alarm", alarmFacility); } catch (NamingException e) { // ignore. } for (MEnvEntry mEnvEntry : component.getDescriptor().getEnvEntries()) { Class<?> type = null; if (logger.isDebugEnabled()) { logger.debug("Got an environment entry:" + mEnvEntry); } try { type = Thread.currentThread().getContextClassLoader().loadClass(mEnvEntry.getEnvEntryType()); } catch (Exception e) { throw new DeploymentException(mEnvEntry.getEnvEntryType() + " is not a valid type for an environment entry"); } Object entry = null; String s = mEnvEntry.getEnvEntryValue(); try { if (type == String.class) { entry = new String(s); } else if (type == Character.class) { if (s.length() != 1) { throw new DeploymentException(s + " is not a valid value for an environment entry of type Character"); } entry = new Character(s.charAt(0)); } else if (type == Integer.class) { entry = new Integer(s); } else if (type == Boolean.class) { entry = new Boolean(s); } else if (type == Double.class) { entry = new Double(s); } else if (type == Byte.class) { entry = new Byte(s); } else if (type == Short.class) { entry = new Short(s); } else if (type == Long.class) { entry = new Long(s); } else if (type == Float.class) { entry = new Float(s); } } catch (NumberFormatException e) { throw new DeploymentException("Environment entry value " + s + " is not a valid value for type " + type); } if (logger.isDebugEnabled()) { logger.debug("Binding environment entry with name:" + mEnvEntry.getEnvEntryName() + " type " + entry.getClass() + " with value:" + entry + ". Current classloader = " + Thread.currentThread().getContextClassLoader()); } try { envCtx.bind(mEnvEntry.getEnvEntryName(), entry); } catch (NameAlreadyBoundException ex) { logger.error("Name already bound ! ", ex); } } } /** * * @param profileTableName * @return * @throws NullPointerException * @throws UnrecognizedProfileTableNameException */ public ProfileTableImpl getProfileTable(String profileTableName) throws NullPointerException, UnrecognizedProfileTableNameException { if (profileTableName == null) throw new NullPointerException("profile table name is null"); ProfileTableImpl ptc = (ProfileTableImpl) this.nameToProfileTableMap.get(profileTableName); if (ptc == null) throw new UnrecognizedProfileTableNameException(); else return ptc; } /** * * @return */ public SleeContainer getSleeContainer() { return sleeContainer; } /** * * @param profileSpecificationId * @return */ public ProfileSpecificationComponent getProfileSpecificationComponent(ProfileSpecificationID profileSpecificationId) { // FIXME: we posbily dont need this. return this.sleeContainer.getComponentRepositoryImpl().getComponentByID(profileSpecificationId); } /** * * @return */ public Collection<String> getDeclaredProfileTableNames() { return Collections.unmodifiableSet(new HashSet(this.nameToProfileTableMap.keySet())); } /** * * @param id * @return * @throws UnrecognizedProfileSpecificationException */ public Collection<String> getDeclaredProfileTableNames(ProfileSpecificationID id) throws UnrecognizedProfileSpecificationException { if (this.sleeContainer.getComponentRepositoryImpl().getComponentByID(id) == null) { throw new UnrecognizedProfileSpecificationException("No such profile specification: " + id); } ArrayList<String> names = new ArrayList<String>(); // FIXME: this will fail if done async to change, is this ok ? Iterator<String> it = this.getDeclaredProfileTableNames().iterator(); while (it.hasNext()) { String name = it.next(); if (((ProfileTableImpl) this.nameToProfileTableMap.get(name)).getProfileSpecificationComponent().getProfileSpecificationID().equals(id)) { names.add(name); } } return names; } /** * */ public void startAllProfileTableActivities() { for (Object key : this.getDeclaredProfileTableNames()) { ProfileTableImpl pt = (ProfileTableImpl) this.nameToProfileTableMap.get((String)key); pt.startActivity(); } } /** * * @param profileTableName * @param component * @return * @throws SLEEException */ private ProfileTableImpl createProfileTableInstance(String profileTableName, ProfileSpecificationComponent component) throws SLEEException { ProfileTableImpl profileTable = null; if (component.getProfileTableConcreteClass() == null) { profileTable = new ProfileTableImpl(profileTableName, component, sleeContainer); } else { try { profileTable = (ProfileTableImpl)component.getProfileTableConcreteClass().getConstructor(String.class, ProfileSpecificationComponent.class, SleeContainer.class).newInstance(profileTableName, component, sleeContainer); } catch (Throwable e) { throw new SLEEException(e.getMessage(),e); } } return profileTable; } /** * * @param profileTableName * @param component * @return * @throws ProfileTableAlreadyExistsException * @throws SLEEException */ public ProfileTableImpl addProfileTable(final String profileTableName, ProfileSpecificationComponent component) throws ProfileTableAlreadyExistsException, SLEEException { try { getProfileTable(profileTableName); throw new ProfileTableAlreadyExistsException("there is already a profile table named "+profileTableName); } catch (UnrecognizedProfileTableNameException e) { // expected } // create instance final ProfileTableImpl profileTable = createProfileTableInstance(profileTableName, component); // map it this.nameToProfileTableMap.put(profileTableName, profileTable); TransactionalAction action1 = new TransactionalAction() { public void execute() { nameToProfileTableMap.remove(profileTableName); } }; try { sleeContainer.getTransactionManager().addAfterRollbackAction(action1); } catch (SystemException e) { throw new SLEEException(e.getMessage(),e); } // register usage mbean profileTable.registerUsageMBean(); TransactionalAction action3 = new TransactionalAction() { public void execute() { profileTable.unregisterUsageMBean(); } }; try { sleeContainer.getTransactionManager().addAfterRollbackAction(action3); } catch (SystemException e) { throw new SLEEException(e.getMessage(),e); } // create object pool sleeContainer.getProfileObjectPoolManagement().createObjectPool(profileTable, sleeContainer.getTransactionManager()); // start activity if master of the cluster if(sleeContainer.getCluster().isHeadMember()) { profileTable.startActivity(); } // add default profile try { profileTable.createDefaultProfile(); } catch (Throwable e) { throw new SLEEException(e.getMessage(),e); } jpaPTF.storeProfileTable( new JPAProfileTable(profileTable) ); return profileTable; } /** * * @param profileTableName * @throws NullPointerException * @throws UnrecognizedProfileTableNameException */ public void removeProfileTable(final String profileTableName) throws NullPointerException, UnrecognizedProfileTableNameException { ProfileTableImpl profileTable = getProfileTable(profileTableName); TransactionalAction action = new TransactionalAction() { public void execute() { nameToProfileTableMap.remove(profileTableName); } }; try { sleeContainer.getTransactionManager().addAfterCommitAction(action); } catch (SystemException e) { throw new SLEEException(e.getMessage(),e); } profileTable.remove(); jpaPTF.removeProfileTable(profileTable.getProfileTableName()); } /** * * @param oldProfileTableName * @param newProfileTableName * @throws ProfileTableAlreadyExistsException * @throws NullPointerException * @throws UnrecognizedProfileTableNameException */ public void renameProfileTable(String oldProfileTableName, String newProfileTableName) throws ProfileTableAlreadyExistsException, NullPointerException, UnrecognizedProfileTableNameException { ProfileSpecificationComponent component = getProfileTable(oldProfileTableName).getProfileSpecificationComponent(); removeProfileTable(oldProfileTableName); addProfileTable(newProfileTableName, component); } @Override public String toString() { return "Profile Table Manager: " + "\n+-- Profile Tables: " + getDeclaredProfileTableNames(); } }