/*******************************************************************************
* ALMA - Atacama Large Millimiter Array
* (c) European Southern Observatory, 2002
* Copyright by ESO (in the framework of the ALMA collaboration)
* and Cosylab 2002, 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.impl;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import org.omg.CORBA.Any;
import org.omg.CORBA.NO_RESOURCES;
import org.omg.CosPropertyService.PropertySet;
import org.omg.PortableServer.Servant;
import com.cosylab.CDB.DAL;
import alma.ACS.CharacteristicComponentDesc;
import alma.ACS.CharacteristicComponentOperations;
import alma.ACS.NoSuchCharacteristic;
import alma.ACS.OffShootOperations;
import alma.ACS.Property;
import alma.ACS.PropertyDesc;
import alma.ACS.PropertyHelper;
import alma.ACS.PropertyOperations;
import alma.ACS.jbaci.PrioritizedExecutor;
import alma.ACS.jbaci.PrioritizedRunnable;
import alma.ACS.jbaci.PrioritizedRunnableComparator;
import alma.JavaContainerError.wrappers.AcsJContainerServicesEx;
import alma.acs.component.ComponentImplBase;
import alma.acs.component.ComponentLifecycleException;
import alma.acs.container.ContainerServices;
import alma.acs.logging.AcsLogLevel;
import alma.maciErrType.wrappers.AcsJComponentCleanUpEx;
/**
* Implementation of <code>alma.ACS.CharacteristicComponentImpl</code>.
* @author <a href="mailto:matej.sekoranjaATcosylab.com">Matej Sekoranja</a>
* @author <a href="mailto:cmenayATcsrg.inf.utfsm.cl">Camilo Menay</a>
* @author <a href="mailto:cmaureirATinf.utfsm.cl">Cristian Maureira</a>
* @version $id$
*/
public class CharacteristicComponentImpl extends ComponentImplBase
implements CharacteristicComponentOperations, PrioritizedExecutor {
/**
* CharacteristicModel implementation (delegate).
*/
protected CharacteristicModelImpl characteristicModelImpl;
/**
* CharacteristicComponent descriptor (lazy initialization).
*/
private CharacteristicComponentDesc characteristicComponentDesc;
/**
* List of all component properties (needed on component destruction).
*/
protected Map<PropertyOperations, Servant> properties;
/**
* Component thread pool.
*/
private ThreadPoolExecutor threadPool;
/**
* Number of requests in thread pool (guarantees order of execution).
*/
private static final int MAX_REQUESTS = 100;
/**
* Number of threads in thread pool.
*/
private static final int MAX_POOL_THREADS = 10;
/**
* @see alma.acs.component.ComponentLifecycle#initialize(alma.acs.container.ContainerServices)
*/
public void initialize(ContainerServices containerServices)
throws ComponentLifecycleException {
super.initialize(containerServices);
try
{
DAL dal = m_containerServices.getCDB();
// create characteristic model
// TODO think of error handling; why creating model per instance...
characteristicModelImpl = new CharacteristicModelImpl("alma/" + m_instanceName, dal);
} catch (AcsJContainerServicesEx ce)
{
throw new ComponentLifecycleException("Failed to create characteristic model.", ce);
}
// create properties list
properties = new HashMap<PropertyOperations, Servant>();
}
/**
* @see alma.acs.component.ComponentLifecycle#cleanUp()
*/
public void cleanUp() throws AcsJComponentCleanUpEx {
// shutdown thread-pool
if (threadPool != null)
{
// initiate shutdown
threadPool.shutdown();
boolean nicePoolShutdown = false;
// first be kind and wait up to 3 seconds to terminate
try {
nicePoolShutdown = threadPool.awaitTermination(3, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// noop
}
boolean cleanPoolShutdown = nicePoolShutdown;
if (!nicePoolShutdown) {
// no more "mister-nice-guy", terminate all
threadPool.shutdownNow();
try {
cleanPoolShutdown = threadPool.awaitTermination(1, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// noop
}
}
String msg = "jbaci thread pool shutdown ";
if (!cleanPoolShutdown) {
msg += "failed.";
}
else if (!nicePoolShutdown) {
msg += "succeeded, but had to terminate running threads.";
}
else {
msg += "succeeded.";
}
m_logger.log(AcsLogLevel.DELOUSE, msg);
}
// destroy all properties
if (properties.size() != 0)
{
Destroyable[] propertyArray = null;
synchronized (properties)
{
propertyArray = new Destroyable[properties.size()];
properties.keySet().toArray(propertyArray);
}
for (int i = 0; i < propertyArray.length; i++)
{
try
{
propertyArray[i].destroy();
}
catch (Throwable th)
{
// TODO or even log here
m_logger.log(Level.WARNING, "jBaci::CharacteristicComponentImpl::cleanUp - Error while destroying the properties.");
th.printStackTrace();
}
}
}
super.cleanUp();
}
/**
* Get component container services.
* @return component container services.
*/
public ContainerServices getComponentContainerServices()
{
return m_containerServices;
}
/**
* Execute action.
* If the maximum pool size or queue size is bounded,
* then it is possible for incoming execute requests to block.
* <code>BACIExecutor</code> uses default 'Run' blocking policy:
* The thread making the execute request runs the task itself. This policy helps guard against lockup.
* @param action action to execute.
* @return <code>true</code> on success.
*/
public boolean execute(PrioritizedRunnable action)
{
try
{
if (threadPool == null)
{
// TODO make PriorityBlockingQueue bounded!!! (to MAX_REQUESTS)
// TODO should I use PooledExecutorWithWaitInNewThreadWhenBlocked...?
threadPool = new ThreadPoolExecutor(MAX_POOL_THREADS, MAX_POOL_THREADS, 1, TimeUnit.MINUTES,
new PriorityBlockingQueue<Runnable>(MAX_REQUESTS, new PrioritizedRunnableComparator<Runnable>()),
m_containerServices.getThreadFactory());
threadPool.allowCoreThreadTimeOut(true);
}
threadPool.execute(action);
return true;
}
catch (Throwable th)
{
return false;
}
}
/**
* Register property on this component (and optionally CORBA activate).
* Registration is needed for property destruction on component destruction.
* @param propertyImpl property implementation.
* @param propertyServant property CORBA servant (e.g. Rx<type>POATie class). If <code>null</code> property will
* be treated as non-CORBA property and no CORBA activation will be done.
* @return CORBA activated property reference, <code>null</code> if <code>propertyServant == null</code>.
*/
public <T extends Servant & OffShootOperations> Property registerProperty(PropertyOperations propertyImpl, T propertyServant) {
// allow activation if already in property list...
Property property = null;
if (propertyServant != null)
{
try
{
// TODO pesistent, user ID activation
property = PropertyHelper.narrow(
getComponentContainerServices().activateOffShoot(propertyServant)
);
// set reference to itself
if (propertyImpl instanceof PropertyReferenceHolder)
((PropertyReferenceHolder)propertyImpl).setPropertyRef(property);
}
catch (Throwable th)
{
// TODO log
m_logger.log(Level.WARNING, "jBaci::CharacteristicComponentImpl::registerProperty - No resources to register the new property.");
throw new NO_RESOURCES(th.getMessage());
}
}
// add to list
synchronized (properties)
{
if (!properties.containsKey(propertyImpl))
properties.put(propertyImpl, propertyServant);
}
return property;
}
/**
* Unregister property on this component (and optionally CORBA deactivate).
* Should be called by <code>PropertyImpl.destroy()</code> method.
* @param propertyImpl property implementation.
*/
public void unregisterProperty(PropertyOperations propertyImpl) {
Servant propertyServant = null;
// remove from list
synchronized (properties)
{
propertyServant = properties.remove(propertyImpl);
}
// deativate CORBA monitor servant
if (propertyServant != null)
{
try
{
getComponentContainerServices().deactivateOffShoot(propertyServant);
}
catch (Throwable th)
{
m_logger.log(Level.WARNING, "jBaci::CharacteristicComponentImpl::unregisterProperty - Error when trying to deactivate a property.");
th.printStackTrace();
}
}
}
/*********************** [ CharacteristicComponent ] ***********************/
/**
* NOTE: <code>characteristic_component_ref</code> member of <code>CharacteristicComponentDesc</code> is always set to <code>null</code>.
* @see alma.ACS.CharacteristicComponentOperations#descriptor()
*/
public CharacteristicComponentDesc descriptor() {
if (characteristicComponentDesc == null)
{
PropertyDesc[] propertyDescriptors = null;
synchronized (properties)
{
int i = 0;
propertyDescriptors = new PropertyDesc[properties.size()];
Iterator<PropertyOperations> iter = properties.keySet().iterator();
while (iter.hasNext())
propertyDescriptors[i++] = ((PropertyImpl)iter.next()).getPropertyDescriptor();
}
// TODO CORBA reference to this component to be set
characteristicComponentDesc = new CharacteristicComponentDesc(null,
m_instanceName,
propertyDescriptors,
get_all_characteristics());
}
return characteristicComponentDesc;
}
/*********************** [ CharacteristicModel ] ***********************/
/**
* @see alma.ACS.CharacteristicModelOperations#get_characteristic_by_name(java.lang.String)
*/
public Any get_characteristic_by_name(String name)
throws NoSuchCharacteristic {
//for create the Any
characteristicModelImpl.lendContainerServices(m_containerServices);
Any ret = characteristicModelImpl.get_characteristic_by_name(name);
if(ret!=null)
return characteristicModelImpl.get_characteristic_by_name(name);
else
throw new NoSuchCharacteristic();
}
/**
* @see alma.ACS.CharacteristicModelOperations#find_characteristic(java.lang.String)
*/
public String[] find_characteristic(String wildcard) {
return characteristicModelImpl.find_characteristic(wildcard);
}
/**
* @see alma.ACS.CharacteristicModelOperations#get_all_characteristics()
*/
public PropertySet get_all_characteristics() {
characteristicModelImpl.lendContainerServices(m_containerServices);
return characteristicModelImpl.get_all_characteristics();
}
}