/** * */ package com.cosylab.acs.maci.manager.app; import java.lang.reflect.Constructor; import java.util.concurrent.ThreadFactory; import java.util.logging.Level; import java.util.logging.Logger; import org.omg.CORBA.NO_IMPLEMENT; import org.omg.CORBA.ORB; import org.omg.CORBA.Policy; import org.omg.CosNaming.NamingContext; import org.omg.CosNaming.NamingContextHelper; import org.omg.PortableServer.IdAssignmentPolicyValue; import org.omg.PortableServer.LifespanPolicyValue; import org.omg.PortableServer.POA; import org.omg.PortableServer.RequestProcessingPolicyValue; import org.omg.PortableServer.Servant; import org.omg.PortableServer.ServantRetentionPolicyValue; import org.omg.PortableServer.POAPackage.AdapterAlreadyExists; import org.omg.PortableServer.POAPackage.AdapterNonExistent; import org.omg.PortableServer.POAPackage.InvalidPolicy; import com.cosylab.CDB.DAL; import si.ijs.maci.AdministratorOperations; import alma.ACS.OffShoot; import alma.ACS.OffShootHelper; import alma.ACS.OffShootOperations; import alma.ACSErrTypeCommon.wrappers.AcsJBadParameterEx; import alma.ACSErrTypeCommon.wrappers.AcsJNotImplementedEx; import alma.ACSErrTypeCommon.wrappers.AcsJUnexpectedExceptionEx; import alma.JavaContainerError.wrappers.AcsJContainerEx; import alma.JavaContainerError.wrappers.AcsJContainerServicesEx; import alma.acs.concurrent.DaemonThreadFactory; import alma.acs.container.AdvancedContainerServices; import alma.acs.container.ContainerServicesBase; import alma.acs.logging.AcsLogLevel; import alma.acs.logging.AcsLogger; import alma.acs.logging.ClientLogManager; import alma.acs.nc.AcsEventPublisher; import alma.acs.nc.AcsEventSubscriber; /** * @TODO: Share some code with jcont and laser alarms who also implement ContainerServicesBase, * e.g. through a new ContainerServicesBaseImpl class in module acsContainerServices. * * @author msekoranja */ public class ManagerContainerServices implements ContainerServicesBase, AdvancedContainerServices { private final ORB orb; private final DAL dal; private final Logger logger; private AcsLogger componentLogger; private final POA clientPOA; private POA offshootPoa; private Policy[] offshootPolicies; /** * NCPublisher can be instantiated only using reflection, because modules jcontnc comes after jmanager */ private final String CLASSNAME_NC_PUBLISHER = "alma.acs.nc.NCPublisher"; private final ThreadFactory threadFactory; /** * @param orb * @param dal * @param logger */ public ManagerContainerServices(ORB orb, POA clientPOA, DAL dal, Logger logger) { this.orb = orb; this.clientPOA = clientPOA; this.offshootPoa = null; // on demand this.dal = dal; this.logger = logger; this.threadFactory = new DaemonThreadFactory(ManagerContainerServices.class.getSimpleName()); } /** * @see alma.acs.container.ContainerServices#activateOffShoot(org.omg.PortableServer.Servant) */ public <T extends Servant & OffShootOperations > OffShoot activateOffShoot(T servant) throws AcsJContainerServicesEx { checkOffShootServant(servant); OffShoot shoot = null; try { checkOffShootPOA(); org.omg.CORBA.Object actObj = null; offshootPoa.activate_object(servant); actObj = offshootPoa.servant_to_reference(servant); actObj._hash(Integer.MAX_VALUE); // just to provoke an exc. if something is wrong with our new object logger.finer("offshoot of type '" + servant.getClass().getName() + "' activated as a CORBA object."); shoot = OffShootHelper.narrow(actObj); } catch (Throwable thr) { String msg = "failed to activate offshoot object of type '" + servant.getClass().getName() + "' for client '" + getName() + "'. "; // flatten the exception chain by one level if possible if (thr instanceof AcsJContainerServicesEx && thr.getCause() != null) { msg += "(" + thr.getMessage() + ")"; thr = thr.getCause(); } logger.log(Level.FINE, msg, thr); AcsJContainerServicesEx ex = new AcsJContainerServicesEx(thr); throw ex; } return shoot; } public void deactivateOffShoot(Object offshootImpl) throws AcsJContainerServicesEx { if( offshootImpl instanceof Servant ) { Servant servant = (Servant)offshootImpl; checkOffShootServant(servant); byte[] id = null; try { id = offshootPoa.servant_to_id(servant); offshootPoa.deactivate_object(id); } catch (Throwable thr) { String msg = "failed to deactivate offshoot of type '" + servant.getClass().getName() + "' (ID=" + String.valueOf(id) + ")"; logger.log(Level.WARNING, msg, thr); AcsJContainerServicesEx ex = new AcsJContainerServicesEx(thr); ex.setContextInfo(msg); throw ex; } } else { AcsJContainerServicesEx ex = new AcsJContainerServicesEx(); ex.setContextInfo("Not yet implemented"); throw ex; } } /** * Creates the shared offshoot poa on demand */ public void checkOffShootPOA() throws AcsJContainerEx, AcsJUnexpectedExceptionEx { final String offshootPoaName = "offshootPoa"; synchronized (clientPOA) { try { // can we reuse it? offshootPoa = clientPOA.find_POA(offshootPoaName, false); } catch (AdapterNonExistent e) { logger.finest("will have to create offshoot POA"); if (offshootPolicies == null) { offshootPolicies = new Policy[4]; offshootPolicies[0] = clientPOA.create_id_assignment_policy(IdAssignmentPolicyValue.SYSTEM_ID); offshootPolicies[1] = clientPOA.create_lifespan_policy(LifespanPolicyValue.TRANSIENT); offshootPolicies[2] = clientPOA .create_request_processing_policy(RequestProcessingPolicyValue.USE_ACTIVE_OBJECT_MAP_ONLY); offshootPolicies[3] = clientPOA .create_servant_retention_policy(ServantRetentionPolicyValue.RETAIN); } try { offshootPoa = clientPOA.create_POA(offshootPoaName, clientPOA.the_POAManager(), offshootPolicies); logger.finest("successfully created offshoot POA"); } catch (InvalidPolicy ex) { AcsJContainerEx ex2 = new AcsJContainerEx(ex); ex2.setContextInfo("Attempted to create offshoot POA with invalid policies."); throw ex2; } catch (AdapterAlreadyExists ex) { // we sync on componentPOA, so this should never happen throw new AcsJUnexpectedExceptionEx(ex); } } } } /** * @param cbServant * @throws ContainerException */ private void checkOffShootServant(Servant servant) throws AcsJContainerServicesEx { if (servant == null) { AcsJBadParameterEx cause = new AcsJBadParameterEx(); cause.setParameter("servant"); cause.setParameterValue("null"); throw new AcsJContainerServicesEx(cause); } if (!(servant instanceof OffShootOperations)) { String msg = "invalid offshoot servant provided. Must implement " + OffShootOperations.class.getName(); logger.fine(msg); AcsJContainerServicesEx ex = new AcsJContainerServicesEx(); ex.setContextInfo(msg); throw ex; } } public AdvancedContainerServices getAdvancedContainerServices() { return this; } public DAL getCDB() { return dal; } public synchronized AcsLogger getLogger() { if (componentLogger == null) { componentLogger = ClientLogManager.getAcsLogManager().getLoggerForComponent(getName()); } return componentLogger; } public String getName() { return "ManagerContainerServices"; } public ThreadFactory getThreadFactory() { return threadFactory; } public String corbaObjectToString(org.omg.CORBA.Object objRef) { String str = orb.object_to_string(objRef); logger.finer("converted corba object reference of type " + objRef.getClass().getName() + " to the string " + str); return str; } public org.omg.CORBA.Object corbaObjectFromString(String strObjRef) { org.omg.CORBA.Object objRef = orb.string_to_object(strObjRef); logger.finer("converted corba object reference string " + strObjRef + " back to a corba object reference."); return objRef; } /** * Returns a reference to a new CORBA Any. In Java the only way to do * this is through the ORB itself (i.e., the create_any method). * @return org.omg.CORBA.Any * @throws NullPointerException if the Any object could not be created. */ public org.omg.CORBA.Any getAny() { org.omg.CORBA.Any any = orb.create_any(); if (any == null) { // should never happen, but we check just in case, // since there is a difficult to verify NPE when Any is created by MC for sending alarms. String msg = "Failed to create org.omg.CORBA.Any"; logger.warning(msg); throw new NullPointerException(msg); } return any; } public ORB getORB() { return orb; } public void connectManagerAdmin(AdministratorOperations adminOp, boolean retryConnectOnFailure) throws AcsJContainerEx { throw new NO_IMPLEMENT(); } public void disconnectManagerAdmin(AdministratorOperations adminOp) { throw new NO_IMPLEMENT(); } @Override public <T> AcsEventPublisher<T> createNotificationChannelPublisher(String channelName, Class<T> eventType) throws AcsJContainerServicesEx { return createNotificationChannelPublisher(channelName, null, eventType); } @Override public <T> AcsEventPublisher<T> createNotificationChannelPublisher( String channelName, String channelNotifyServiceDomainName, Class<T> eventType) throws AcsJContainerServicesEx { AcsEventPublisher<T> publisher = null; try { // TODO: Matej please help, is there a more elegant way to get the naming service ref? org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService"); NamingContext ncRef = NamingContextHelper.narrow(objRef); Object[] args = new Object[]{ channelName, channelNotifyServiceDomainName, this, ncRef }; // // TODO: Can we do this without the direct cast? The usual "asSubclass" is not enough // because we don't create a subclass of Class<T> but rather of Class<U<T>>. // Also the getGenericInterfaces / ParameterizedType trick does not work because because we don't have a // concrete parameterized type. Class<AcsEventPublisher<T>> clazz = (Class<AcsEventPublisher<T>>) Class.forName(CLASSNAME_NC_PUBLISHER); Constructor<? extends AcsEventPublisher<T>> constructor = clazz.getConstructor(String.class, String.class, ContainerServicesBase.class, NamingContext.class); publisher = constructor.newInstance(args); } catch(ClassNotFoundException e) { // TODO: maybe we could prevent future NCPublisher creation tries, since the class isn't and will not be loaded // The same applies for the next "catch" block logger.log(AcsLogLevel.ERROR, "Cannot create NC publisher because the 'NCPublisher' class is not present in the classpath", e); AcsJContainerServicesEx ex = new AcsJContainerServicesEx(e); ex.setContextInfo("'" + CLASSNAME_NC_PUBLISHER + "' class not present in the classpath"); throw ex; } catch(ClassCastException e) { logger.log(AcsLogLevel.ERROR, "Cannot create NC publisher because loaded class '" + CLASSNAME_NC_PUBLISHER + "' is not of type 'AcsEventPublisher", e); AcsJContainerServicesEx ex = new AcsJContainerServicesEx(e); ex.setContextInfo("'" + CLASSNAME_NC_PUBLISHER + "' class does not extend 'AcsEventPublisher'"); throw ex; } catch(Throwable e) { logger.log(AcsLogLevel.ERROR, "Unexpected error while creating new AcsEventPublisher object", e); AcsJContainerServicesEx ex = new AcsJContainerServicesEx(e); throw ex; } // m_publishers.put( (channelNotifyServiceDomainName == null ? "" : channelNotifyServiceDomainName) + "/" + channelName, publisher); return publisher; } @Override public <T> AcsEventSubscriber<T> createNotificationChannelSubscriber(String channelName, Class<T> eventType) throws AcsJContainerServicesEx { throw new AcsJContainerServicesEx(new AcsJNotImplementedEx("createNotificationChannelSubscriber not yet implemented in this special alarm service CS class.")); } @Override public <T> AcsEventSubscriber<T> createNotificationChannelSubscriber(String channelName, String channelNotifyServiceDomainName, Class<T> eventType) throws AcsJContainerServicesEx { throw new AcsJContainerServicesEx(new AcsJNotImplementedEx("createNotificationChannelSubscriber not yet implemented in this special alarm service CS class.")); } }