/* * ALMA - Atacama Large Millimiter Array * (c) European Southern Observatory, 2002 * Copyright by ESO (in the framework of the ALMA collaboration), * All rights reserved * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ package alma.acs.container; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; import org.omg.PortableServer.Servant; import si.ijs.maci.ComponentSpec; import alma.ACS.OffShoot; import alma.ACS.OffShootOperations; import alma.JavaContainerError.wrappers.AcsJContainerServicesEx; import alma.acs.alarmsystem.source.AlarmSource; import alma.acs.component.ComponentDescriptor; import alma.acs.component.ComponentQueryDescriptor; import alma.acs.component.ComponentStateManager; import alma.entities.commonentity.EntityT; import alma.maciErrType.wrappers.AcsJComponentDeactivationFailedEx; import alma.maciErrType.wrappers.AcsJComponentDeactivationUncleanEx; /** * Through this interface, the container offers services to its hosted components. * The component must call these methods explicitly; in this respect, * ContainerServices is different from the other services that the container * provides without the component implementation knowing about it. * It can be thought of as a callback handle or a library. *

* Currently, methods are added to this interface as the functionality becomes available. * At some point we will have to declutter the interface by introducing 2nd-level interfaces * that harbor cohesive functionality. For example, instead of calling * myContainerServices.getComponent(...), the new call will then be something like * myContainerServices.communication().getComponent(...). *

* created on Oct 24, 2002 12:56:36 PM * @author hsommer */ public interface ContainerServices extends ContainerServicesBase { ///////////////////////////////////////////////////////////// // basic needs (the rest comes from the base class) ///////////////////////////////////////////////////////////// /** * Delivers the ComponentStateManager object * through which the component and the container administrate the * state of the component. *

* The component needs to access the ComponentStateManager * if it wishes to change its state. * If it doesn't, only the container will change the state based on * the information it has available. * * @return the state manager * @see alma.ACS.ComponentStates */ public ComponentStateManager getComponentStateManager(); ///////////////////////////////////////////////////////////// // access to other components ///////////////////////////////////////////////////////////// /** * Gets a component specified by its instance name. * Delegates to {@link si.ijs.maci.ManagerOperations#get_component(int, java.lang.String, boolean, org.omg.CORBA.IntHolder) get_component}. *

* * @param componentUrl the ACS CURL of the deployed component instance. * @return the CORBA proxy for the component. * @throws AcsJContainerServicesEx if something goes wrong. */ public org.omg.CORBA.Object getComponent(String componentUrl) throws AcsJContainerServicesEx; /** * Gets a non-sticky reference to a component. * This is typically used by "weak clients" such as graphical user interfaces that only want to observe the running system * without interfering with its functioning. *

* A non-sticky reference does not bind the Manager to keep alive the Component, and the Client requesting a non-sticky reference * is not considered when checking for reference counts. * The non-sticky reference should not be released, as that call will fail. * The Manager can deactivate Components independently of any non-sticky reference. * Since a non-sticky reference is not considered in reference counting, it will also not activate the component if it is * not already active. As a consequence, asking for a non-sticky reference to a not-active Component throws an exception. * The client represented by id (the handle) must have adequate access rights to access the component. * @param curl the component URL (component instance name) * @return the CORBA proxy for the component. * @throws AcsJContainerServicesEx if something goes wrong * @since ACS 6.0 */ public org.omg.CORBA.Object getComponentNonSticky(String curl) throws AcsJContainerServicesEx; /** * Gets the default component specified by the component type. * The type is the IDL type, such as IDL:alma/PS/PowerSupply:1.0. *

* A default instance for the given type must have been declared beforehand * (either statically in the CDB config files, or dynamically), * otherwise an exception is thrown. *

* To get more information on the returned component, call * {@link #getComponentDescriptor} with the instance name that * you can get from the component using {@link alma.ACS.ACSComponentOperations#name}. *

* Delegates to {@link si.ijs.maci.ManagerOperations#get_default_component}. * @param componentIDLType * @return * @throws AcsJContainerServicesEx */ public org.omg.CORBA.Object getDefaultComponent(String componentIDLType) throws AcsJContainerServicesEx; /** * Gets a component that will run collocated with a given component. * @param compUrl the component's name (URL) * @param targetCompUrl the name (URL) of the target component, in whose container we also want compUrl to run. * @return the component reference, which should be cast using the appropriate CORBA narrow operation. Never null. * @throws AcsJContainerServicesEx If the call failed and no component reference could be obtained. * @since ACS 5.0.3 */ public org.omg.CORBA.Object getCollocatedComponent(String compUrl, String targetCompUrl) throws AcsJContainerServicesEx; /** * Dynamic version of {@link #getCollocatedComponent(String, String)}. * @param compSpec the description of the component to be created * @param markAsDefaul if true, the new component will become the default component for its IDL type. * @param targetCompUrl targetCompUrl the name (URL) of the target component, in whose container we also want compUrl to run. * @return * @throws AcsJContainerServicesEx If the call failed and no component reference could be obtained. * @since ACS 6.0.4 */ public org.omg.CORBA.Object getCollocatedComponent(ComponentQueryDescriptor compSpec, boolean markAsDefaul, String targetCompUrl) throws AcsJContainerServicesEx; /** * Gets a component whose instance is not registered in the CDB * at deployment time. *

* The fields of compSpec can be filled in at various levels of detail, * allowing the manager to blend in missing data from static deployment information. * For a detailed description of the various options, * please refer to the ACS documentation. *

* To get more information on the returned component, call * {@link #getComponentDescriptor} with the instance name that * you've specified or that you can get from the component in case it was * assigned (see {@link alma.ACS.ACSComponentOperations#name()}). *

* Delegates to {@link si.ijs.maci.ManagerOperations#get_dynamic_component}. * * @param compSpec the description of the component to be created * @param markAsDefault if true, the new component will become the default component for its IDL type. */ public org.omg.CORBA.Object getDynamicComponent(ComponentQueryDescriptor compSpec, boolean markAsDefault) throws AcsJContainerServicesEx; /** * More powerful and thus more dangerous version of {@link #getDynamicComponent(ComponentQueryDescriptor, boolean)} * which exposes a CORBA struct directly. * * @param compSpec the description of the component to be created * @param markAsDefault if true, the new component will become the default component for its IDL type. * @deprecated use {@link #getDynamicComponent(ComponentQueryDescriptor, boolean)} instead. * if you need to set not only the standard fields component_name or component_type, * but also the more advanced values component_code or container_name, * please send a request to ACS so that access to these fields be included in the * ComponentQueryDescriptor given to the recommended version of this method. */ public org.omg.CORBA.Object getDynamicComponent(ComponentSpec compSpec, boolean markAsDefault) throws AcsJContainerServicesEx; /** * Finds components by their instance name (curl) and/or by their type. * Wildcards can be used for the curl and type. * This method returns a possibly empty array of component curls; * for each curl, you may then call {@link #getComponent(String) getComponent} * to obtain the reference. * * @param curlWildcard (null is understood as "*") * @param typeWildcard (null is understood as "*") * @return the curls of the component(s) that match the search. * @see si.ijs.maci.ManagerOperations#get_component_info(int, int[], java.lang.String, java.lang.String, boolean) */ public String[] findComponents(String curlWildcard, String typeWildcard) throws AcsJContainerServicesEx; /** * Gets the component descriptor which contains meta data for the component. * (Not to be confused with a component descriptor in the EJB sense.) *

* To be used primarily after retrieval of a component with * {@link #getDefaultComponent(String) getDefaultComponent} * or {@link #getDynamicComponent(ComponentQueryDescriptor, boolean) getDynamicComponent}, * when some data like the instance name is not known. * The idea behind having this method separately is that in many cases, * components are not interested in this information, and are happier to * get back from these methods directly the remote reference to another component, * instead of always dealing with a ComponentDescriptor. * * @param componentUrl the unique name of a component * @return the descriptor from which the various data items can be obtained. * @throws ContainerException if componentUrl is unknown * or anything else goes wrong * @see si.ijs.maci.ComponentInfo */ public ComponentDescriptor getComponentDescriptor(String componentUrl) throws AcsJContainerServicesEx; /** * Releases the specified component. This involves notification of the manager, * as well as calling _release() on the CORBA stub for that component. * If the curl is not known to the container, the request will be ignored. *

* This method will return only when the component has actually been released, * which may take some time in case there are still active requests being processed. *

* This method is kept for convenience, providing a specific subset of the functionality that * the more flexible {@link #releaseComponent(String, ComponentReleaseCallback)} offers. * It blocks the client until the component is released or a timeout of 60 seconds has * occurred, and logs all errors of component release at level DEBUG. * * @param componentUrl the name/curl of the component instance as used by the manager */ public void releaseComponent(String componentUrl); /** * Callback that can be optionally given to * {@link ContainerServices#releaseComponent(String, ComponentReleaseCallback)}. * Users may override the methods they need in their subclasses of ComponentReleaseCallback. *

* Note that {@link #awaitComponentRelease(long, TimeUnit)} is not a callback method * but should make it easier to synchronize user code execution with component release. *

* An instance of ComponentReleaseCallback can be used for only one component release call. */ public static class ComponentReleaseCallback { private CountDownLatch sync = new CountDownLatch(1); /** * Called by ACS to release the thread (if any) that blocks on {@link #awaitComponentRelease(long, TimeUnit)}. */ final void callOver() { sync.countDown(); } /** * Called when a CORBA or other communication error occurred. */ public void errorCommunicationFailure(Throwable thr) {} /** * Called when the client cannot legally release the component, e.g. because it no longer holds a reference to it. */ public void errorNoPermission(String reason) {} /** * Called when the component reference has been successfully released. * @param deactivationUncleanEx If the component was deactivated with problems, this exception will be forwarded; otherwise null for clean deactivation. */ public void componentReleased(AcsJComponentDeactivationUncleanEx deactivationUncleanEx) {} /** * Called when the target component deactivation failed. * @param deactivationFailureEx to provide details about the failure. */ public void errorComponentReleaseFailed(AcsJComponentDeactivationFailedEx deactivationFailureEx) {} /** * This is not a callback method but a convenience method to "park" the calling thread * until *

* A client that only wants to wait for component release without caring about the details * does not have to subclass ComponentReleaseCallback, * but can simply call awaitComponentRelease. * The client may in addition override the callback methods though. * * @param timeout The maximum time to wait for the component release to succeed. * @param unit The unit of timeout. * @return true if the component was released properly, false if the call returns because of a timeout. * See {@link CountDownLatch#await(long, TimeUnit)}. * @throws InterruptedException */ public final boolean awaitComponentRelease(long timeout, TimeUnit unit) throws InterruptedException { return sync.await(timeout, unit); } } /** * Variant of {@link ComponentReleaseCallback} which logs all errors. */ public static class ComponentReleaseCallbackWithLogging extends ComponentReleaseCallback { private final Logger logger; private Level level; public ComponentReleaseCallbackWithLogging(Logger logger, Level level) { this.logger = logger; this.level = level; } public void errorCommunicationFailure(Throwable thr) { logger.log(level, "errorCommunicationFailure: ", thr); } public void errorNoPermission(String reason) { logger.log(level, "errorNoPermission: " + reason); } public void componentReleased(AcsJComponentDeactivationUncleanEx deactivationUncleanEx) { logger.log(level, "componentReleased: ", deactivationUncleanEx); } public void errorComponentReleaseFailed(AcsJComponentDeactivationFailedEx deactivationFailureEx) { logger.log(level, "errorComponentReleaseFailed: ", deactivationFailureEx); } } /** * Releases the reference to the specified component. * Releasing a component reference may result in the deactivation of that component, * if no other clients hold (sticky) references. *

* This call will return as soon as the release request has been delivered to the ACS manager, * which means that the reference count evaluation and possible component deactivation will happen * only after returning from this call. *

* If your code must synchronize with the reference evaluation and possible component deactivation in the target container, * or if you are interested in exceptions that may occur during component deactivation, * then you should supply the optional ComponentRequestCallback object and block execution of your * calling thread until you receive the callback. *

* If an exception (such as no-permission) is thrown during the synchronous first part * of the underlying call to the manager, then this exception will not be thrown upward by this method * but will instead be reported to the optional callback object, just like any * exception that happens later during the asynchronous part of the component release. * The idea here is to have either "interested" clients that want to get all exceptions, * or "easy" clients that do not care about any exceptions, thus do not provide a callback object, * and also do not want to bother about a try/catch block. * * @param componentUrl the name/curl of the component instance as used by the manager * @param callback may be null if you do not need to wait for component deactivation or to see the results. * An new instance of ComponentReleaseCallback is required for every call. * @since ACS 9.1 */ public void releaseComponent(String componentUrl, ComponentReleaseCallback callback); public static interface ComponentListener { /** * Called to find out whether a filter should be applied * such that only notifications arrive for components to which the caller holds a reference. */ boolean includeForeignComponents(); /** * Called when components become available */ void componentsAvailable(List comps); /** * Called when components become unavailable */ void componentsUnavailable(List compNames); } /** * Allows a client to register a callback object that gets notified when some * component(s) in use by the client (= components the client requested previously) * dies or comes back to life (with ComponentListener#includeForeignComponents()==false). *

* If the client wants to get notified even for components that it does not hold a reference to, * then ComponentListener#includeForeignComponents() should return true; * notification about components that this client does not use may be limited though, e.g. * to components collocated in the same container. * * @param listener * @see si.ijs.maci.ClientOperations#components_available(si.ijs.maci.ComponentInfo[]) * @since ACS 6.0 */ public void registerComponentListener(ComponentListener listener); /** * Wraps a component reference (or offshoot reference etc) such that the given timeout is applied on * the client side of calls to this (possibly remote) object. * If the total call, including de-/serialization and network travel, takes longer than the given timeout, * an org.omg.CORBA.TIMEOUT exception will be thrown. *

* This allows us to override the general timeout given at the system level (e.g. orb.properties file in case of jacorb) * and the container-level timeout given in the CDB container configuration. * It is possible to set the timeout to values that are shorter or longer than the default timeout. * You should chose a timeout value that matches the expected response time, with a large safety margin of * *

* Note that calls to which the specified timeout should apply must be made on the object reference returned from this method, * and not on the original object that gets passed to this method! * Some corba implementations may apply the timeout to both objects though, or return the original object. *

* * @param corbaRef Reference to a component or an offshoot as obtained from some of the other container services methods. * @param timeoutSeconds the custom client side timeout in seconds, to be used for all calls to the given object reference. * @return A new object reference which should be used to make calls with the specified timeout applied. */ public org.omg.CORBA.Object getReferenceWithCustomClientSideTimeout(org.omg.CORBA.Object originalCorbaRef, double timeoutSeconds) throws AcsJContainerServicesEx; ///////////////////////////////////////////////////////////// // support for XML entities and binding classes ///////////////////////////////////////////////////////////// /** * Creates a unique id and sets it on the given (binding class) entity object. * The id will be redundantly stored in an encrypted format so that later it can be verified that * the id is indeed the one originally assigned. * * @param entity must be freshly created and */ public void assignUniqueEntityId(EntityT entity) throws AcsJContainerServicesEx; /** * Converts a "flat-XML" remote object (RO) interface * (as obtained from the various getComponent methods, in the * case of components, or by retrieving offshoots from components, * in the case of offshoots) to a "transparent-XML" RO interface. * This is only applicable to ROs that contain XML entities * in their IDL interface methods, and for which the build process * has been set up to generate XML binding classes and the "transparent-XML" * interface in addition to the standard Java-IDL compiler output. *

* In the case that the remote object is a component, the container can * fulfill this request in two different ways: *

    *
  1. Remote component: * if the specified component runs in a different container, * a dynamic wrapper object will be created around the provided CORBA stub. * The wrapper object will translate between entity object parameters * in the form of serialized XML (as found in flatXmlIF) * and the corresponding Java binding classes (in transparentXmlIF). *
  2. Collocated component: * if the specified component runs in the same container, the container * may choose to shortcut the (de-) serialization of XML binding classes. * In this case, Java binding classes are transported in memory, * and all communication with the other component is done without CORBA. *
* In either case, the returned Object implements the * transparentXmlIF interface. * The client component that calls this method should only cast to that interface, * and does not need to know which of the two transport mechanisms are being used. * * @param transparentXmlIF remote object interface with XML binding classes. * @param objectReference reference to the remote object to be wrapped, which * implements flatXmlIF. * Currently supported remote objects are ACS Components and OffShoots. * @param flatXmlIF remote object interface ("xxxOperations") where entity objects are represented as * serialized XML inside a CORBA struct. * @return the object that implements transparentXmlIF. */ public T getTransparentXmlWrapper( Class transparentXmlIF, F objectReference, Class flatXmlIF) throws AcsJContainerServicesEx; /** * Activates an Object as an OffShoot. *

* In contrast to the old {@link #activateOffShoot(Servant)} method, which always expects a * Servant (either subclass of xyzPOA skeleton or a xyzPOATie instance), this method is more flexible and * receives two arguments: *

    *
  • The object implementing {@link alma.ACS.OffShootOperations}, but without * restricting it to be a Servant, and
  • *
  • The operations interface that this object directly implements.
  • *
* This way, we support *
    *
  • Activation of "normal" OffShoots:
    * offshootImpl should be a corba Servant, either a subclass of the * XyzPOA skeleton, or a XyzPOATie instance (delegation model).
    * idlOpInterface should be XyzOperations.class. *
  • *
  • OffShoots featuring automatic XML (de-)serialization, similar to what has always been offered for ACS Components.
    * offshootImpl should be an object that implements the generated XyzJ interface * (which uses XML binding classes and extends OffShootOperations). * This object is not expected to be a Corba Servant.
    * idlOpInterface should be XyzJ.class. *
* Since ACS 9.0, when giving an OffShoot with XML entities (de-)serialization, automatic * interception code is created to wrap the given object, and a XyzPOATie instance is * created automatically and used as the servant. * * Since ACS 4.1.2, a tie servant is detected, and interception code gets inserted between the * POATie skeleton and the offshoot implementation class. This way, the container * can intercept (and log) calls to offshoots in the same way as it does for calls to components. * It is therefore recommended to use the tie approach for all offshoot servants, * unless there is a reason to avoid container interception. *

* @param The type of offshootImpl, one of the xyzJ or * xyzOperations interfaces * @param offshootImpl the object that implements the OffShoot logic * @param idlOpInterface the IDL operations interface implemented by offshootImpl; * currently, must be one of xyzOperations or xyzJ * @return The Corba-activated offshoot object. Needs a narrow-cast to the subtype, like * CBdouble myCBdouble = alma.ACS.CBdoubleHelper.narrow(...). * @throws AcsJContainerServicesEx if anything goes wrong, * especially if offshootImpl is does not implement {@link alma.ACS.OffShootOperations}. * @since ACS 9.0 */ OffShoot activateOffShoot(T offshootImpl, Class idlOpInterface) throws AcsJContainerServicesEx; ///////////////////////////////////////////////////////////// // Alarm Service API ///////////////////////////////////////////////////////////// /** * Returns the {@link AlarmSource} owned by this object. The {@link AlarmSource} object * allows to raise and clear alarms, among other advanced operations *

* @TODO: We could remove the AcsJContainerServicesEx declaration, it is currently not needed. * * @return The {@link AlarmSource} owned by this object */ public AlarmSource getAlarmSource(); ///////////////////////////////////////////////////////////// // other ///////////////////////////////////////////////////////////// }