/*
* 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 thaowt 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.logging.Level;
import java.util.logging.Logger;
import org.omg.CORBA.IntHolder;
import org.omg.CORBA.ORB;
import org.omg.CORBA.Object;
import si.ijs.maci.Client;
import si.ijs.maci.ClientInfo;
import si.ijs.maci.ComponentInfo;
import si.ijs.maci.ComponentSpec;
import si.ijs.maci.Manager;
import si.ijs.maci.ManagerHelper;
import si.ijs.maci.ManagerOperations;
import alma.ACS.CBDescIn;
import alma.ACS.CBlong;
import alma.ACSErrTypeCommon.wrappers.AcsJUnexpectedExceptionEx;
import alma.JavaContainerError.wrappers.AcsJContainerEx;
import alma.JavaContainerError.wrappers.AcsJContainerServicesEx;
import alma.acs.util.ACSPorts;
import alma.maciErrType.CannotGetComponentEx;
import alma.maciErrType.CannotRegisterComponentEx;
import alma.maciErrType.ComponentConfigurationNotFoundEx;
import alma.maciErrType.ComponentNotAlreadyActivatedEx;
import alma.maciErrType.ComponentSpecIncompatibleWithActiveComponent;
import alma.maciErrType.ComponentSpecIncompatibleWithActiveComponentEx;
import alma.maciErrType.IncompleteComponentSpec;
import alma.maciErrType.IncompleteComponentSpecEx;
import alma.maciErrType.InvalidComponentSpec;
import alma.maciErrType.InvalidComponentSpecEx;
import alma.maciErrType.NoDefaultComponentEx;
import alma.maciErrType.NoPermissionEx;
import alma.maciErrType.wrappers.AcsJCannotGetComponentEx;
import alma.maciErrType.wrappers.AcsJCannotRegisterComponentEx;
import alma.maciErrType.wrappers.AcsJComponentConfigurationNotFoundEx;
import alma.maciErrType.wrappers.AcsJComponentNotAlreadyActivatedEx;
import alma.maciErrType.wrappers.AcsJComponentSpecIncompatibleWithActiveComponentEx;
import alma.maciErrType.wrappers.AcsJIncompleteComponentSpecEx;
import alma.maciErrType.wrappers.AcsJInvalidComponentSpecEx;
import alma.maciErrType.wrappers.AcsJNoDefaultComponentEx;
import alma.maciErrType.wrappers.AcsJNoPermissionEx;
/**
* Proxy class that encapsulates access to the ACS Manager.
* See maci.idl for the various types of client, which include container and admin client.
* <p>
* This class is stateful, so there must be one <code>AcsManagerProxy</code> used per client
* if a process has more than one client to the manager.
* <p>
* Warning: This class is not supposed to be instantiated by components and other non-framework classes.
* Components should only access this class through <code>ContainerServices</code>.
*
* @author hsommer Feb 18, 2003 9:20:14 AM
*/
public class AcsManagerProxy
{
private volatile Manager m_manager;
private final String m_managerLoc;
/**
* Handle representing the container or other client (assigned by Manager at login).
* Note that every component has a separate "component handle".
*/
private volatile int m_mgrHandle = 0;
private final ORB m_orb;
private final Logger m_logger;
private volatile boolean m_shuttingDown;
/** msc(2005-07) client:managerproxy is always 1:1 */
private Client m_managerClient;
/////////////////////////////////////////////////////////////
// creation and connection
/////////////////////////////////////////////////////////////
/**
* Constructor stores parameters, but takes no further action.
*
* @param managerLoc corbaloc string for the Manager
* @param orb active ORB; provided explicitly rather than using {@link alma.acs.container.corba.AcsCorba},
* so we can easily reuse this class for clients outside of the container.
* @param logger
*/
public AcsManagerProxy(String managerLoc, ORB orb, Logger logger)
{
if (managerLoc == null)
{
throw new IllegalArgumentException("argument 'managerLoc' must not be null.");
}
m_managerLoc = managerLoc;
m_orb = orb;
m_logger = logger;
}
/**
* Gets the ACS Manager, either cached or freshly retrieved.
* Note that no login is done here, so call {@link #loginToManager(Client, boolean)} after this.
*
* @return Manager
* @throws AcsJContainerServicesEx
*/
public synchronized Manager getManager() throws AcsJContainerEx
{
if (m_manager == null)
{
if (m_shuttingDown) {
String msg = "call to getManager() fails while shutting down.";
m_logger.fine(msg);
AcsJContainerEx ex = new AcsJContainerEx();
ex.setContextInfo(msg);
throw ex;
}
m_logger.fine("Manager reference not available. Trying to resolve...");
findManager(m_managerLoc, 0);
}
return m_manager;
}
/////////////////////////////////////////////////////////////
// -------- failure detection & automatic reconnect -------//
/////////////////////////////////////////////////////////////
/**
* The lock should only be held for short periods, the threads executing
* our API need to be able to retrieve it quickly.
*
* TODO: replace with lock from concurrent lib
*/
protected final java.lang.Object connectorLock = new java.lang.Object();
/**
* This thread keeps retrying to log in to the manager.
* Before each attempt, it checks whether some outside-world caller
* of loginToManager() has meanwhile accomplished to log in.
*
* notify() on the lock will awake the thread,
* interrupt() will terminate the thread.
*
* msc(2005-07)
*/
protected final Thread connectorThread = new Thread("AcsManagerProxy.ConnectorThread") {
public void run () {
ALIVE: while (true) {
synchronized (connectorLock) {
try {
connectorLock.wait(); // until connectorLock.notify or interrupt
} catch (InterruptedException exc) {
break ALIVE; // quit
}
}
RECONNECT: while (true) {
try {
if (isLoggedIn(false)) {
break RECONNECT; // somebody else succeeded for us
}
m_logger.finer("attempting (re-)login");
loginToManager(1);
break RECONNECT; // managed to reconnect
} catch (AcsJContainerEx e) {
try {
sleep(5000); // sleep, then retry
} catch (InterruptedException exc) {
break ALIVE; // quit
}
}
}
}
}
};
protected void activateReloginToManagerIfDisconnected() {
if (!connectorThread.isAlive()) {
// start check&relogin loop
connectorThread.setDaemon(true);
connectorThread.start();
}
}
/**
* Invoked by the manager methods on failure.
* The "handling" of the exception refers to changing the connection status, logging the exception, etc.
* This method will not throw the given exception, which means that the calling client has to do this herself.
*/
protected void handleRuntimeException (RuntimeException exc) {
if (exc instanceof org.omg.CORBA.NO_PERMISSION // manager changed, or has cut connection
||exc instanceof org.omg.CORBA.OBJECT_NOT_EXIST // manager is down
||exc instanceof org.omg.CORBA.TRANSIENT) // manager is down
{
// store the knowledge that we're unconnected:
// this will make isLoggedIn() return false;
m_mgrHandle = 0;
// wake up connector thread
synchronized (connectorLock) {
connectorLock.notify();
}
}
else if (exc instanceof org.omg.CORBA.TIMEOUT) {
// the timeout usually does not indicate a general problem of the manager, but affects
// only this one invocation. We don't do anything here and let the caller throw the exception.
}
else {
m_logger.log(Level.INFO, "unexpected error occurred: please report this", exc);
return;
}
}
/**
* Finds the Manger using the supplied <code>managerLoc</code>.
*
* If the manager can't be found, this method enters a loop and tries again after every 3 seconds.
* The number of iterations of the loop is bounded by <code>attempts</code>.
*
* @param managerLoc the corbaloc string that uniquely identifies the manager
* as a CORBA service.
* @param attempts The number of attempts to contact the manager (0 means forever).
* If 0, this method will only return when it has successfully contacted the manager service;
* if greater then 0, this method will simply throw a <code>AcsJContainerServicesEx</code>
* if it fails to resolve the manager.
* @throws AcsJContainerEx if anything goes wrong.
*/
private synchronized void findManager(String managerLoc, int attempts)
throws AcsJContainerEx
{
if (attempts<0) {
throw new IllegalArgumentException("Invalid number of attempts to contact the manager: "+attempts);
}
int currentAttempt=attempts;
do
{
if (m_shuttingDown) {
//
AcsJContainerEx ex = new AcsJContainerEx();
ex.setContextInfo("Abandoned because we are shutting down.");
throw ex;
}
try
{
org.omg.CORBA.Object object = m_orb.string_to_object(m_managerLoc);
m_logger.finest("manager corbaloc '" + managerLoc + "' resolved.");
m_manager = ManagerHelper.narrow(object);
if (m_manager == null) {
AcsJContainerEx ex = new AcsJContainerEx();
ex.setContextInfo("received null reference to ACS Manager.");
throw ex;
}
m_logger.finest("manager narrow successful.");
// Set attempts=1 and currentAttempt=0 to exit the loop
attempts=1;
currentAttempt=0;
}
catch (Throwable thr) {
String msg = "Failed to obtain the manager reference from the corbaloc '" + m_managerLoc + "'. ";
if (attempts==0 || currentAttempt>0) {
m_logger.log(Level.INFO, msg + "Will keep trying.");
try {
Thread.sleep(3000);
}
catch (InterruptedException e1) {
// nada
}
}
else {
m_logger.log(Level.WARNING, msg + thr.getMessage());
AcsJContainerEx ex = new AcsJContainerEx(thr);
ex.setContextInfo(msg);
throw ex;
}
}
currentAttempt=(attempts==0)?0:currentAttempt-1;
}
while (attempts==0 || currentAttempt>0);
}
/**
* Logs in to the manager, using the provided manager client CORBA object.
* This method only returns when the login succeeded. Otherwise an exception is thrown.
*
* @param managerClient the IDL-defined client of the manager (see maci.idl),
* of which the container is a subclass.
* @param attempts The number of attempts to find and login (0 means forever)
* If <code>0</code>, a background thread is started to re-login if the connection breaks.
* @throws AcsJContainerServicesEx
*/
public synchronized void loginToManager(Client managerClient, int attempts) throws AcsJContainerEx {
this.m_managerClient = managerClient;
loginToManager(attempts);
// if login has succeeded and keepTrying==true, then also activate the re-login thread
// which sleeps unless handleRuntimeException reports a problem.
if (attempts==0) {
activateReloginToManagerIfDisconnected();
}
}
/**
* Logs in to the Manager.
* Only to be called from within this class (see connectorThread), when the
*
* @param attempts The number of attempts to contact the manager (0 means forever)
* used for the call to {@link #findManager(String, int)}
* @throws AcsJContainerServicesEx
*/
private synchronized void loginToManager(int attempts)
throws AcsJContainerEx
{
if (m_shuttingDown) {
String msg = "call to loginToManager(..) fails while shutting down.";
m_logger.fine(msg);
AcsJContainerEx ex = new AcsJContainerEx();
ex.setContextInfo(msg);
throw ex;
}
if (isLoggedIn(false))
{
m_logger.info("login to Manager requested while being logged in - will first log out...");
logoutFromManager();
}
if (m_manager == null)
{
m_logger.fine("manager reference not yet available in method loginToManager; "
+ "will try to find the manager first...");
findManager(m_managerLoc, attempts);
}
try
{
// login
ClientInfo ci = m_manager.login(m_managerClient);
if (ci == null) {
throw new NullPointerException("received null from manager.login()");
}
if (ci.h <= 0) {
AcsJContainerEx ex = new AcsJContainerEx();
ex.setContextInfo("Got invalid handle from manager login: " + ci.h);
throw ex;
}
m_mgrHandle = ci.h;
}
catch (Throwable thr) {
m_mgrHandle = 0;
String msg = "Failed to login to manager.";
m_logger.log(Level.WARNING, msg);
AcsJContainerEx ex = new AcsJContainerEx(thr);
ex.setContextInfo(msg);
throw ex;
}
m_logger.fine("Manager login done, handle '" + m_mgrHandle + "' obtained.");
}
boolean isLoggedIn(boolean checkPing)
{
boolean loggedIn = ( m_manager != null && m_mgrHandle != 0 );
if (loggedIn && checkPing)
{
loggedIn = pingManager(2000);
}
return loggedIn;
}
/**
* Pings the manager.
* Uses a separate thread so that life can go on if the manager does not respond,
* and the ORB timeout is too long for this purpose.
* <p>
* Currently calls <code>get_client_info</code> to see if the manager responds.
* Todo: should be replaced by a call to Manager.ping when this is available.
*
* @param timeoutMillis timout in milliseconds that can restrict the general ORB timeout.
* @return true if the manager responded within the given time, false otherwise
* @see #isLoggedIn(boolean)
*/
public boolean pingManager(long timeoutMillis)
{
boolean responding = false;
long startTime = System.currentTimeMillis();
PingManagerThread pingThread = new PingManagerThread();
pingThread.start();
do
{
responding = pingThread.isResponding();
try
{
// to save some CPU time
Thread.sleep(5);
}
catch (InterruptedException e)
{//nada
}
}
while (System.currentTimeMillis() - startTime < timeoutMillis);
return responding;
}
private class PingManagerThread extends Thread
{
boolean m_responding = false;
PingManagerThread()
{
super();
setDaemon(true);
}
public void run()
{
try
{
m_manager.ping();
m_responding = true;
}
catch (Throwable thr)
{
// ignore and leave loggedIn false
// todo remove debug message
// System.err.println("isLoggedIn - m_manager.get_client_info problem " + thr);
}
}
boolean isResponding()
{
return m_responding;
}
}
/**
* Logs out from the manager.
* If this fails, a warning is logged, but no exception will be thrown by this method.
*/
public synchronized void logoutFromManager()
{
try
{
if (isLoggedIn(false))
{
m_logger.fine("about to log out from manager...");
m_manager.logout(m_mgrHandle);
m_logger.fine("logged out from manager.");
}
}
catch (Exception ex)
{
m_logger.log(Level.WARNING, "failed to log out gracefully from the manager...", ex);
}
finally
{
m_mgrHandle = 0;
m_manager = null;
}
}
/////////////////////////////////////////////////////////////
// encapsulated methods of the manager
/////////////////////////////////////////////////////////////
/**
* From maci IDL comments:
* <i>
* "Gets all the information that the Manager has about components.
* To invoke this method, the caller must have INTROSPECT_MANAGER access rights,
* or it must have adequate privileges to access the component (the same as with the get_service method).
* Information about all components is returned, unless the active_only parameter is set to True,
* in which case only information about those components that are currently registered with the Manager
* and activated is returned.
* Calling this function does not affect the internal state of the Manager."
* </i>
*
* @param componentHandles Handles of the components whose information is requested.
* If this is an empty sequence, the name_wc and type_wc parameters are used.
* @param name_wc Wildcard that the component's name must match in order for its information to be returned.
* @param type_wc Wildcard that the component's type must match in order for its information to be returned.
* @param active_only
* @return si.ijs.maci.ComponentInfo[] A sequence of ComponentInfo structures containing the entire
* Manager's knowledge about the components. If access is denied to a subset of objects,
* the handles to those objects are set to 0.
*/
public ComponentInfo[] get_component_info(
int[] componentHandles,
String name_wc,
String type_wc,
boolean active_only)
throws AcsJNoPermissionEx
{
if (!isLoggedIn(false)) {
throw new IllegalStateException("Not logged in to the manager.");
}
ComponentInfo[] compInfos = null;
try {
compInfos = m_manager.get_component_info(checkAndGetManagerHandle(), componentHandles, name_wc, type_wc, active_only);
} catch (NoPermissionEx ex) {
throw AcsJNoPermissionEx.fromNoPermissionEx(ex);
} catch (RuntimeException exc) {
handleRuntimeException(exc);
throw exc;
}
// not sure if compInfos == null can ever happen, but we don't want clients to check this case
if (compInfos == null) {
throw new NullPointerException("Manager returned null ComponentInfo[]");
}
return compInfos;
}
/**
* Note that in ACS 10.2 the meaning of the second parameter has slightly changed, but should be transparent.
* Before it was the "activate" option which makes no sense for real services and would typically be "true" when using
* this method for components rather than real services. Now "true" still means that the service should be activated,
* but "false" has the new meaning that we don't use the client handle, but instead use dummy handle '0'.
* This allows the container to get the CDB reference before logging in to the manager.
*
* @return org.omg.CORBA.Object Reference to the service. If the service could not be activated,
* a nil reference is returned, and the status contains an error code detailing the cause of failure
* (one of the component_* constants).
*/
public Object get_service(String service_url, boolean includeComponents)
throws AcsJComponentNotAlreadyActivatedEx, AcsJCannotGetComponentEx, AcsJComponentConfigurationNotFoundEx, AcsJNoPermissionEx
{
int clientId = (includeComponents ? checkAndGetManagerHandle() : 0);
boolean activate = includeComponents;
try {
return m_manager.get_service(clientId, service_url, activate);
} catch (RuntimeException exc) {
handleRuntimeException(exc);
throw exc;
} catch (NoPermissionEx ex) {
throw AcsJNoPermissionEx.fromNoPermissionEx(ex);
} catch (ComponentNotAlreadyActivatedEx ex) {
throw AcsJComponentNotAlreadyActivatedEx.fromComponentNotAlreadyActivatedEx(ex);
} catch (CannotGetComponentEx ex) {
throw AcsJCannotGetComponentEx.fromCannotGetComponentEx(ex);
} catch (ComponentConfigurationNotFoundEx ex) {
throw AcsJComponentConfigurationNotFoundEx.fromComponentConfigurationNotFoundEx(ex);
}
}
/**
* The more restricted version of {@link #get_service(String, boolean, IntHolder) get_service},
* only good for getting components.
*
* @param clientHandle handle of requesting component or other kind of client
* (for non-container clients this will always be the login-handle)
* @param component_url to specify the requested component
* @param activate
* @param status status out-parameter
* @return the component reference (must still be narrowed using the appropriate Corba helper)
* @see ContainerServices#getComponent(String)
*/
public Object get_component(int clientHandle, String component_url, boolean activate)
throws AcsJCannotGetComponentEx, AcsJComponentNotAlreadyActivatedEx, AcsJComponentConfigurationNotFoundEx, AcsJNoPermissionEx
{
if (!isLoggedIn(false)) {
throw new IllegalStateException("Not logged in to the manager.");
}
try {
return m_manager.get_component(clientHandle, component_url, activate);
} catch (RuntimeException exc) {
handleRuntimeException(exc);
throw exc;
} catch (NoPermissionEx ex) {
throw AcsJNoPermissionEx.fromNoPermissionEx(ex);
} catch (ComponentNotAlreadyActivatedEx ex) {
throw AcsJComponentNotAlreadyActivatedEx.fromComponentNotAlreadyActivatedEx(ex);
} catch (CannotGetComponentEx ex) {
throw AcsJCannotGetComponentEx.fromCannotGetComponentEx(ex);
} catch (ComponentConfigurationNotFoundEx ex) {
throw AcsJComponentConfigurationNotFoundEx.fromComponentConfigurationNotFoundEx(ex);
}
}
public Object get_component_non_sticky(int clientHandle, String component_url) throws AcsJCannotGetComponentEx,
AcsJComponentNotAlreadyActivatedEx, AcsJNoPermissionEx {
if (!isLoggedIn(false)) {
throw new IllegalStateException("Not logged in to the manager.");
}
try {
return m_manager.get_component_non_sticky(clientHandle, component_url);
} catch (RuntimeException exc) {
handleRuntimeException(exc);
throw exc;
} catch (NoPermissionEx ex) {
throw AcsJNoPermissionEx.fromNoPermissionEx(ex);
} catch (ComponentNotAlreadyActivatedEx ex) {
throw AcsJComponentNotAlreadyActivatedEx.fromComponentNotAlreadyActivatedEx(ex);
} catch (CannotGetComponentEx ex) {
throw AcsJCannotGetComponentEx.fromCannotGetComponentEx(ex);
}
}
/**
* Gets a component as a "weak client" who does not prevent component unloading in case
* the other real clients release their references.
* Otherwise similar to <code>get_component</code> with <code>activate==false</code>.
*
* @param clientHandle
* @param component_url
* @return the component reference (must still be narrowed using the appropriate Corba helper)
* @throws AcsJComponentNotAlreadyActivatedEx if the requested component has not already been activated by some other client
* @throws AcsJCannotGetComponentEx
* @throws AcsJUnexpectedExceptionEx if the remote call failed with a (CORBA) runtime exception
* @since ACS 6.0
*/
public Object getComponentNonSticky(int clientHandle, String component_url)
throws AcsJComponentNotAlreadyActivatedEx, AcsJCannotGetComponentEx, AcsJNoPermissionEx
{
if (!isLoggedIn(false)) {
throw new IllegalStateException("Not logged in to the manager.");
}
try {
return m_manager.get_component_non_sticky(clientHandle, component_url);
} catch (RuntimeException rtex) {
handleRuntimeException(rtex);
throw rtex;
} catch (ComponentNotAlreadyActivatedEx ex) {
throw AcsJComponentNotAlreadyActivatedEx.fromComponentNotAlreadyActivatedEx(ex);
} catch (CannotGetComponentEx ex) {
throw AcsJCannotGetComponentEx.fromCannotGetComponentEx(ex);
} catch (NoPermissionEx ex) {
throw AcsJNoPermissionEx.fromNoPermissionEx(ex);
}
}
/**
* @param clientHandle handle of requesting component or other kind of client
* (for non-container clients this will always be the login-handle)
* @param componentIDLType the IDL type
* @see ContainerServices#getDefaultComponent(String)
*/
public ComponentInfo get_default_component(int clientHandle, String componentIDLType)
throws AcsJNoDefaultComponentEx, AcsJCannotGetComponentEx, AcsJNoPermissionEx
{
if (!isLoggedIn(false)) {
throw new IllegalStateException("Not logged in to the manager.");
}
try {
return m_manager.get_default_component(clientHandle, componentIDLType);
} catch (RuntimeException exc) {
handleRuntimeException(exc);
throw exc;
} catch (NoPermissionEx ex) {
throw AcsJNoPermissionEx.fromNoPermissionEx(ex);
} catch (NoDefaultComponentEx ex) {
throw AcsJNoDefaultComponentEx.fromNoDefaultComponentEx(ex);
} catch (CannotGetComponentEx ex) {
throw AcsJCannotGetComponentEx.fromCannotGetComponentEx(ex);
}
}
/**
* @param clientHandle handle of requesting component or other kind of client
* (for non-container clients this will always be the login-handle)
* @param c dynamic version of deployment info, may be incomplete, see ACS documentation
* @param mark_as_default if true, make the new component instance the default for its type
* @return a struct which contains the corba reference, as well as name, type, etc.
*
* @throws si.ijs.maci.IncompleteComponentSpec
* @throws si.ijs.maci.InvalidComponentSpec
* Thrown if there is no valid dynamic component found for given resulting structure.
* @throws si.ijs.maci.ComponentSpecIncompatibleWithActiveComponent
* Thrown if the resulting structure is incompatible with a component of the same name
* already active.
*/
public ComponentInfo get_dynamic_component(int clientHandle, ComponentSpec c, boolean mark_as_default)
throws AcsJIncompleteComponentSpecEx, AcsJInvalidComponentSpecEx, AcsJComponentSpecIncompatibleWithActiveComponentEx, AcsJCannotGetComponentEx, AcsJNoPermissionEx
{
if (!isLoggedIn(false)) {
throw new IllegalStateException("Not logged in to the manager.");
}
try {
return m_manager.get_dynamic_component(clientHandle, c, mark_as_default);
} catch (RuntimeException exc) {
handleRuntimeException(exc);
throw exc;
} catch (NoPermissionEx ex) {
throw AcsJNoPermissionEx.fromNoPermissionEx(ex);
} catch (IncompleteComponentSpecEx ex) {
throw AcsJIncompleteComponentSpecEx.fromIncompleteComponentSpecEx(ex);
} catch (InvalidComponentSpecEx ex) {
throw AcsJInvalidComponentSpecEx.fromInvalidComponentSpecEx(ex);
} catch (CannotGetComponentEx ex) {
throw AcsJCannotGetComponentEx.fromCannotGetComponentEx(ex);
} catch (ComponentSpecIncompatibleWithActiveComponentEx ex) {
throw AcsJComponentSpecIncompatibleWithActiveComponentEx.fromComponentSpecIncompatibleWithActiveComponentEx(ex);
}
}
/**
* Encapsulates {@link si.ijs.maci.ManagerOperations#get_collocated_component(int, si.ijs.maci.ComponentSpec, boolean, java.lang.String)}.
*
* @param clientHandle handle of requesting component or other kind of client
* (for non-container clients this will always be the login-handle)
* @param c dynamic version of deployment info, may be incomplete, see ACS documentation
* @param mark_as_default if true, make the new component instance the default for its type
* @param target_component_url
* @return ComponentInfo struct
* @throws IncompleteComponentSpec
* @throws InvalidComponentSpec
* @throws ComponentSpecIncompatibleWithActiveComponent
*/
public ComponentInfo get_collocated_component(int clientHandle, ComponentSpec c, boolean mark_as_default, String target_component_url)
throws AcsJIncompleteComponentSpecEx, AcsJInvalidComponentSpecEx, AcsJComponentSpecIncompatibleWithActiveComponentEx, AcsJCannotGetComponentEx, AcsJNoPermissionEx
{
if (!isLoggedIn(false)) {
throw new IllegalStateException("Not logged in to the manager.");
}
try {
return m_manager.get_collocated_component(clientHandle, c, mark_as_default, target_component_url);
} catch (RuntimeException exc) {
handleRuntimeException(exc);
throw exc;
} catch (NoPermissionEx ex) {
throw AcsJNoPermissionEx.fromNoPermissionEx(ex);
} catch (IncompleteComponentSpecEx ex) {
throw AcsJIncompleteComponentSpecEx.fromIncompleteComponentSpecEx(ex);
} catch (InvalidComponentSpecEx ex) {
throw AcsJInvalidComponentSpecEx.fromInvalidComponentSpecEx(ex);
} catch (CannotGetComponentEx ex) {
throw AcsJCannotGetComponentEx.fromCannotGetComponentEx(ex);
} catch (ComponentSpecIncompatibleWithActiveComponentEx ex) {
throw AcsJComponentSpecIncompatibleWithActiveComponentEx.fromComponentSpecIncompatibleWithActiveComponentEx(ex);
}
}
/**
* From maci IDL comments: <i>"Registers a CORBA object as a component,
* assigning it a CURL and making it accessible through the Manager. The
* component is treated as an immortal component." </i>
*
* @param component_url
* @param type
* @param component
* @return int
*/
public int register_component(String component_url, String type, Object component)
throws AcsJCannotRegisterComponentEx, AcsJNoPermissionEx
{
if (!isLoggedIn(false)) {
throw new IllegalStateException("Not logged in to the manager.");
}
try {
return m_manager.register_component(checkAndGetManagerHandle(), component_url, type, component);
} catch (RuntimeException exc) {
handleRuntimeException(exc);
throw exc;
} catch (NoPermissionEx ex) {
throw AcsJNoPermissionEx.fromNoPermissionEx(ex);
} catch (CannotRegisterComponentEx ex) {
throw AcsJCannotRegisterComponentEx.fromCannotRegisterComponentEx(ex);
}
}
/**
* From maci IDL comments:
* <i>
* "Asynchronously release a component. In order for this operation to be possible,
* the caller represented by the id must have previously successfully requested the
* component via a call to get_component.
* Releasing a component more times than requesting it should be avoided,
* but it produces no errors.
* This method will return before the manager/target container have deactivated the component.
* If the caller wants to synchronize with component deactivation, it must supply
* the optional CBlong callback."
* </i>
*
* @param clientHandle handle of requesting component or other kind of client
* (for non-container clients this will always be the login-handle)
* @param component_url
* @param callback to synch on actual component release, receive possible exceptions,
* and returned number of remaining clients (which could be a useful debugging tool).
* @throws AcsJNoPermissionEx If this client does not hold a valid reference to the target component.
* @throws RuntimeException such as BAD_PARAM, NO_PERMISSION, NO_RESOURCES, OBJECT_NOT_EXIST, TIMEOUT, TRANSIENT UNKNOWN
*/
public void release_component(int clientHandle, String component_url, CBlong callback) throws AcsJNoPermissionEx {
if (!isLoggedIn(false)) {
throw new IllegalStateException("Not logged in to the manager.");
}
try {
// currently we use a dummy CBDescIn. Should take care of the "tag" if we want to reuse the CBlong object.
m_manager.release_component_async(clientHandle, component_url, callback, new CBDescIn());
} catch (RuntimeException exc) {
handleRuntimeException(exc);
throw exc;
} catch (NoPermissionEx ex) {
throw AcsJNoPermissionEx.fromNoPermissionEx(ex);
}
}
/**
* Calls {@link ManagerOperations#force_release_component(int, String)}. This call must not be used by regular
* component code. It is only provided for setting up tests, writing specialized operator tools, and similar purposes.
* @return number of clients of the force-released components.
* @since ACS 5.0.4
*/
public int force_release_component(int clientHandle, String curl) throws AcsJNoPermissionEx
{
if (!isLoggedIn(false)) {
throw new IllegalStateException("Not logged in to the manager.");
}
try {
int clientNumber = m_manager.force_release_component(clientHandle, curl);
return clientNumber;
} catch (RuntimeException exc) {
handleRuntimeException(exc);
throw exc;
} catch (NoPermissionEx ex) {
throw AcsJNoPermissionEx.fromNoPermissionEx(ex);
}
}
/////////////////////////////////////////////////////////////
// other (interaction with container)
/////////////////////////////////////////////////////////////
/**
* Returns the handle that the ACS Manager has assigned to the container/client during login.
* The handle should always be retrieved from here instead of storing its value outside of this class,
* so that a change in handle after a reconnect can be propagated.
*
* @return handle, or 0 if not logged in
*/
public int getManagerHandle()
{
return m_mgrHandle;
}
/**
* Gets the current client handle assigned by the manager, or throws an
* exception if this client is not logged in.
* @throws AcsJNoPermissionEx
* @see {@link #getManagerHandle()}
*/
int checkAndGetManagerHandle() throws AcsJNoPermissionEx {
int managerHandle = m_mgrHandle; // copy to avoid confusion from concurrent change
if (managerHandle <= 0) {
AcsJNoPermissionEx ex = new AcsJNoPermissionEx();
ex.setReason("Currently not logged in with the acs manager.");
ex.setID("client handle: " + managerHandle);
throw ex;
}
return managerHandle;
}
/**
* Notification that the container is in the process of shutting down.
* <p>
* With ACS 7.0.2 this method is no longer synchronized because it deadlocked
* the shutdown hook thread when the manager proxy was in a login loop. See COMP-2602.
*/
public void shutdownNotify()
{
m_shuttingDown = true;
connectorThread.interrupt(); // make thread quit
}
public static String getLocalManagerCorbaloc()
{
// default = localhost
String host = ACSPorts.getIP();
String managerLoc = "corbaloc::" + host + ":" + ACSPorts.getManagerPort() + "/Manager";
return managerLoc;
}
/**
* Creates a new instance, using the same manager, orb and logger.
* The new instance can then be used to log in to the manager (again) independently of this instance.
* <p>
* There is no communication between this instance and the new instance.
* For example, a call to {@link #shutdownNotify()} will not be forwarded.
*/
public AcsManagerProxy createInstance() {
AcsManagerProxy inst = new AcsManagerProxy(m_managerLoc, m_orb, m_logger);
return inst;
}
}