package org.jacorb.notification.servant;
/*
* JacORB - a free Java ORB
*
* Copyright (C) 1999-2014 Gerald Brose / The JacORB Team.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.jacorb.config.*;
import org.slf4j.Logger;
import org.jacorb.notification.FilterManager;
import org.jacorb.notification.IContainer;
import org.jacorb.notification.MessageFactory;
import org.jacorb.notification.OfferManager;
import org.jacorb.notification.SubscriptionManager;
import org.jacorb.notification.container.PicoContainerFactory;
import org.jacorb.notification.interfaces.Disposable;
import org.jacorb.notification.interfaces.FilterStage;
import org.jacorb.notification.interfaces.JMXManageable;
import org.jacorb.notification.interfaces.ProxyEvent;
import org.jacorb.notification.interfaces.ProxyEventListener;
import org.jacorb.notification.lifecycle.IServantLifecyle;
import org.jacorb.notification.lifecycle.ServantLifecyleControl;
import org.jacorb.notification.util.DisposableManager;
import org.jacorb.notification.util.QoSPropertySet;
import org.omg.CORBA.OBJECT_NOT_EXIST;
import org.omg.CORBA.ORB;
import org.omg.CosNotification.NamedPropertyRangeSeqHolder;
import org.omg.CosNotification.Property;
import org.omg.CosNotification.QoSAdminOperations;
import org.omg.CosNotification.UnsupportedQoS;
import org.omg.CosNotifyChannelAdmin.AdminLimitExceeded;
import org.omg.CosNotifyChannelAdmin.EventChannel;
import org.omg.CosNotifyChannelAdmin.InterFilterGroupOperator;
import org.omg.CosNotifyChannelAdmin.ProxyNotFound;
import org.omg.CosNotifyFilter.Filter;
import org.omg.CosNotifyFilter.FilterAdminOperations;
import org.omg.CosNotifyFilter.FilterNotFound;
import org.omg.CosNotifyFilter.MappingFilter;
import org.omg.PortableServer.POA;
import org.picocontainer.MutablePicoContainer;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Abstract Baseclass for Adminobjects.
*
* @jmx.mbean
* @jboss.xmbean
*
* @author Alphonse Bendt
*/
public abstract class AbstractAdmin implements QoSAdminOperations,
FilterAdminOperations, FilterStage, IServantLifecyle, JMXManageable
{
private static final class ITypedAdminImpl implements ITypedAdmin
{
private final IAdmin admin_;
private final MutablePicoContainer container_;
private final String supportedInterface_;
private ITypedAdminImpl(IAdmin admin, MutablePicoContainer container,
String supportedInterface)
{
super();
admin_ = admin;
container_ = container;
supportedInterface_ = supportedInterface;
}
public String getSupportedInterface()
{
return supportedInterface_;
}
public int getProxyID()
{
return admin_.getProxyID();
}
public boolean isIDPublic()
{
return admin_.isIDPublic();
}
public MutablePicoContainer getContainer()
{
return admin_.getContainer();
}
public void destroy()
{
container_.unregisterComponent(ITypedAdmin.class);
admin_.destroy();
}
public String getAdminMBean()
{
return admin_.getAdminMBean();
}
}
/**
* the default InterFilterGroupOperator used.
*/
protected static final InterFilterGroupOperator DEFAULT_FILTER_GROUP_OPERATOR = InterFilterGroupOperator.AND_OP;
////////////////////////////////////////
private final DisposableManager disposables_ = new DisposableManager();
private final Integer id_;
private InterFilterGroupOperator filterGroupOperator_;
protected final MutablePicoContainer container_;
private final FilterManager filterManager_;
private final WeakReference eventChannelReference_;
private final QoSPropertySet qosSettings_;
private final MessageFactory messageFactory_;
protected final OfferManager offerManager_;
protected final SubscriptionManager subscriptionManager_;
protected final Logger logger_;
private final ORB orb_;
private final POA poa_;
protected final Object modifyProxiesLock_ = new Object();
protected final Map pullServants_ = new HashMap();
protected final Map pushServants_ = new HashMap();
private final AtomicInteger proxyIdPool_ = new AtomicInteger(0);
private final AtomicBoolean disposed_ = new AtomicBoolean(false);
private final List proxyEventListener_ = new ArrayList();
private final int channelID_;
private final String parentMBean_;
private JMXManageable.JMXCallback jmxCallback_;
protected final ServantLifecyleControl servantLifecycle_;
////////////////////////////////////////
protected AbstractAdmin(IEventChannel channel, ORB orb, POA poa, Configuration config,
MessageFactory messageFactory, OfferManager offerManager,
SubscriptionManager subscriptionManager)
{
parentMBean_ = channel.getChannelMBean();
container_ = channel.getContainer();
id_ = new Integer(channel.getAdminID());
orb_ = orb;
poa_ = poa;
messageFactory_ = messageFactory;
filterManager_ = new FilterManager();
eventChannelReference_ = new WeakReference(channel.getEventChannel());
channelID_ = channel.getChannelID();
logger_ = ((org.jacorb.config.Configuration) config).getLogger(getClass().getName());
qosSettings_ = new QoSPropertySet(config, QoSPropertySet.ADMIN_QOS);
offerManager_ = offerManager;
subscriptionManager_ = subscriptionManager;
servantLifecycle_ = new ServantLifecyleControl(this, config);
}
public final void registerDisposable(Disposable disposable)
{
disposables_.addDisposable(disposable);
}
public void setInterFilterGroupOperator(InterFilterGroupOperator operator)
{
filterGroupOperator_ = operator;
}
public final POA getPOA()
{
return poa_;
}
protected ORB getORB()
{
return orb_;
}
protected MessageFactory getMessageFactory()
{
return messageFactory_;
}
int getProxyID()
{
return proxyIdPool_.getAndIncrement();
}
public List getFilters()
{
return filterManager_.getFilters();
}
public int add_filter(Filter aFilter)
{
return filterManager_.add_filter(aFilter);
}
public void remove_filter(int aFilterId) throws FilterNotFound
{
filterManager_.remove_filter(aFilterId);
}
public Filter get_filter(int aFilterId) throws FilterNotFound
{
return filterManager_.get_filter(aFilterId);
}
public int[] get_all_filters()
{
return filterManager_.get_all_filters();
}
public void remove_all_filters()
{
filterManager_.remove_all_filters();
}
public final InterFilterGroupOperator MyOperator()
{
return filterGroupOperator_;
}
public final EventChannel MyChannel()
{
return (EventChannel) eventChannelReference_.get();
}
public final int MyID()
{
return getID().intValue();
}
public final int getChannelID()
{
return channelID_;
}
public Property[] get_qos()
{
return qosSettings_.get_qos();
}
public void set_qos(Property[] props) throws UnsupportedQoS
{
if (logger_.isDebugEnabled())
{
logger_.debug("AbstractAdmin.set_qos: " + qosSettings_);
}
qosSettings_.validate_qos(props, new NamedPropertyRangeSeqHolder());
qosSettings_.set_qos(props);
}
public void validate_qos(Property[] props, NamedPropertyRangeSeqHolder propertyRangeSeqHolder)
throws UnsupportedQoS
{
qosSettings_.validate_qos(props, propertyRangeSeqHolder);
}
/**
* @jmx.managed-operation description = "Destroy this Admin" impact = "ACTION"
*/
public final void destroy()
{
checkDestroyStatus();
container_.dispose();
List list = container_.getComponentInstancesOfType(IContainer.class);
for (Iterator i = list.iterator(); i.hasNext();)
{
IContainer element = (IContainer) i.next();
element.destroy();
}
}
private void checkDestroyStatus() throws OBJECT_NOT_EXIST
{
if (!disposed_.compareAndSet(false, true))
{
throw new OBJECT_NOT_EXIST();
}
}
public void dispose()
{
logger_.info("destroy Admin " + MyID());
//////////////////////////////
deactivate();
//////////////////////////////
remove_all_filters();
//////////////////////////////
disposables_.dispose();
proxyEventListener_.clear();
}
public final org.omg.CORBA.Object activate()
{
return servantLifecycle_.activate();
}
public final void deactivate()
{
servantLifecycle_.deactivate();
}
/**
* @jmx.managed-attribute description="TODO"
* access = "read-only"
* currencyTimeLimit = "2147483647"
*/
public Integer getID()
{
return id_;
}
public boolean isDestroyed()
{
return disposed_.get();
}
protected void fireCreateProxyRequestEvent() throws AdminLimitExceeded
{
synchronized (proxyEventListener_)
{
final ProxyEvent _event = new ProxyEvent(this);
final Iterator _i = proxyEventListener_.iterator();
while (_i.hasNext())
{
final ProxyEventListener _listener =
(ProxyEventListener) _i.next();
_listener.actionProxyCreationRequest(_event);
}
}
}
/**
* admin does never have a lifetime filter
*/
public boolean hasLifetimeFilter()
{
return false;
}
/**
* admin does never have a priority filter
*/
public boolean hasPriorityFilter()
{
return false;
}
/**
* admin does not have a lifetime filter
*/
public MappingFilter getLifetimeFilter()
{
throw new UnsupportedOperationException();
}
/**
* admin does not have a priority filter
*/
public MappingFilter getPriorityFilter()
{
throw new UnsupportedOperationException();
}
/**
* @jmx.managed-attribute description="TODO"
* access = "read-only"
* currencyTimeLimit = "2147483647"
*/
public String getInterFilterGroupOperator()
{
return (filterGroupOperator_.value() == InterFilterGroupOperator._AND_OP) ? "AND_OP" : "OR_OP";
}
public boolean hasInterFilterGroupOperatorOR()
{
return (filterGroupOperator_.value() == InterFilterGroupOperator._OR_OP);
}
/**
* fetch the proxy specified by the provided id. this method will not access an event style
* proxy.
*/
protected AbstractProxy getProxy(int id) throws ProxyNotFound
{
final Integer _id = new Integer(id);
AbstractProxy _servant;
synchronized (modifyProxiesLock_)
{
_servant = (AbstractProxy) pullServants_.get(_id);
if (_servant == null)
{
_servant = (AbstractProxy) pushServants_.get(_id);
}
}
if (_servant == null)
{
throw new ProxyNotFound("The proxy with ID=" + id + " does not exist");
}
if (!_servant.isIDPublic())
{
throw new ProxyNotFound("The proxy with ID=" + id
+ " is a EventStyle proxy and therefor not accessible by ID");
}
return _servant;
}
/**
* return the ID's for all NotifyStyle proxies stored in the provided Map.
*/
protected int[] get_all_notify_proxies(Map map, Object lock)
{
final List _allIDsList = new ArrayList();
synchronized (lock)
{
final Iterator _i = map.entrySet().iterator();
while (_i.hasNext())
{
final Map.Entry _entry = (Map.Entry) _i.next();
if (((AbstractProxy) _entry.getValue()).isIDPublic())
{
_allIDsList.add(_entry.getKey());
}
}
}
final int[] _allIDsArray = new int[_allIDsList.size()];
for (int x = 0; x < _allIDsArray.length; ++x)
{
_allIDsArray[x] = ((Integer) _allIDsList.get(x)).intValue();
}
return _allIDsArray;
}
/**
* configure initial QoS Settings for a proxy.
*/
protected void configureQoS(AbstractProxy proxy) throws UnsupportedQoS
{
logger_.debug("configure new AbstractProxy with " + qosSettings_);
proxy.set_qos(qosSettings_.get_qos());
}
/**
* configure the InterFilterGroupOperator a proxy should use.
*/
protected void configureInterFilterGroupOperator(AbstractProxy proxy)
{
if (filterGroupOperator_.value() == InterFilterGroupOperator._OR_OP)
{
proxy.setInterFilterGroupOperatorOR(true);
}
}
public void addProxyEventListener(ProxyEventListener l)
{
synchronized (proxyEventListener_)
{
proxyEventListener_.add(l);
}
}
public void removeProxyEventListener(ProxyEventListener listener)
{
synchronized (proxyEventListener_)
{
proxyEventListener_.remove(listener);
}
}
void fireProxyRemoved(AbstractProxy proxy)
{
synchronized (proxyEventListener_)
{
Iterator i = proxyEventListener_.iterator();
ProxyEvent e = new ProxyEvent(proxy);
while (i.hasNext())
{
((ProxyEventListener) i.next()).actionProxyDisposed(e);
}
}
}
private void fireProxyCreated(AbstractProxy proxy)
{
synchronized (proxyEventListener_)
{
Iterator i = proxyEventListener_.iterator();
ProxyEvent e = new ProxyEvent(proxy);
while (i.hasNext())
{
((ProxyEventListener) i.next()).actionProxyCreated(e);
}
}
}
protected void addProxyToMap(final AbstractProxy proxy, final Map map, final Object lock)
{
synchronized (lock)
{
map.put(proxy.getID(), proxy);
fireProxyCreated(proxy);
}
// it removes proxy from map again.
proxy.registerDisposable(new Disposable()
{
public void dispose()
{
synchronized (lock)
{
map.remove(proxy.getID());
fireProxyRemoved(proxy);
}
}
});
}
protected MutablePicoContainer newContainerForNotifyStyleProxy()
{
return newContainerForProxy(true);
}
protected MutablePicoContainer newContainerForEventStyleProxy()
{
return newContainerForProxy(false);
}
protected MutablePicoContainer newContainerForTypedProxy(final String supportedInterface)
{
final MutablePicoContainer _container = newContainerForNotifyStyleProxy();
final IAdmin _admin = (IAdmin) _container.getComponentInstanceOfType(IAdmin.class);
final ITypedAdmin _typedAdmin = new ITypedAdminImpl(_admin, _container, supportedInterface);
_container.registerComponentInstance(ITypedAdmin.class, _typedAdmin);
return _container;
}
private MutablePicoContainer newContainerForProxy(boolean isIDPublic)
{
final int _proxyID = getProxyID();
return newContainerForProxy(_proxyID, isIDPublic);
}
private MutablePicoContainer newContainerForProxy(final int proxyID, final boolean isIDPublic)
{
final MutablePicoContainer _containerForProxy = PicoContainerFactory
.createChildContainer(container_);
final IAdmin _admin = new IAdmin()
{
public MutablePicoContainer getContainer()
{
return _containerForProxy;
}
public int getProxyID()
{
return proxyID;
}
public boolean isIDPublic()
{
return isIDPublic;
}
public void destroy()
{
container_.removeChildContainer(_containerForProxy);
}
public String getAdminMBean()
{
return getJMXObjectName();
}
};
_containerForProxy.registerComponentInstance(IAdmin.class, _admin);
return _containerForProxy;
}
public final String getJMXObjectName()
{
return parentMBean_ + ", admin=" + getMBeanName();
}
public final String getMBeanName()
{
return getMBeanType() + "-" + getID();
}
abstract protected String getMBeanType();
public String[] getJMXNotificationTypes()
{
return new String[0];
}
public final void setJMXCallback(JMXManageable.JMXCallback callback)
{
jmxCallback_ = callback;
}
protected final void sendNotification(String type, String message)
{
if (jmxCallback_ != null)
{
jmxCallback_.sendJMXNotification(type, message);
}
}
}