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.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.jacorb.config.*; import org.slf4j.Logger; import org.jacorb.notification.FilterManager; import org.jacorb.notification.IContainer; import org.jacorb.notification.OfferManager; import org.jacorb.notification.SubscriptionManager; import org.jacorb.notification.conf.Attributes; import org.jacorb.notification.conf.Default; import org.jacorb.notification.engine.TaskProcessor; import org.jacorb.notification.interfaces.Disposable; import org.jacorb.notification.interfaces.FilterStage; import org.jacorb.notification.interfaces.JMXManageable; 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.NO_IMPLEMENT; import org.omg.CORBA.OBJECT_NOT_EXIST; import org.omg.CORBA.ORB; import org.omg.CosEventChannelAdmin.AlreadyConnected; import org.omg.CosEventComm.Disconnected; import org.omg.CosNotification.NamedPropertyRangeSeqHolder; import org.omg.CosNotification.Property; import org.omg.CosNotification.QoSAdminOperations; import org.omg.CosNotification.UnsupportedQoS; import org.omg.CosNotifyChannelAdmin.ConnectionAlreadyActive; import org.omg.CosNotifyChannelAdmin.ConnectionAlreadyInactive; import org.omg.CosNotifyChannelAdmin.NotConnected; import org.omg.CosNotifyChannelAdmin.ProxyType; import org.omg.CosNotifyFilter.Filter; import org.omg.CosNotifyFilter.FilterAdminOperations; import org.omg.CosNotifyFilter.FilterNotFound; import org.omg.CosNotifyFilter.MappingFilter; import org.omg.CosNotifyFilter.MappingFilterHelper; import org.omg.PortableServer.POA; import org.picocontainer.PicoContainer; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** * @jmx.mbean * @jboss.xmbean * * @author Alphonse Bendt */ public abstract class AbstractProxy implements FilterAdminOperations, QoSAdminOperations, FilterStage, IServantLifecyle, Configurable, JMXManageable, AbstractProxyMBean { private final MappingFilter nullMappingFilterRef_; private final boolean isIDPublic_; protected final Logger logger_; private final AtomicBoolean connected_ = new AtomicBoolean(false); protected final QoSPropertySet qosSettings_; private final Integer id_; protected final OfferManager offerManager_; protected final SubscriptionManager subscriptionManager_; private MappingFilter lifetimeFilter_; private MappingFilter priorityFilter_; /** * delegate for FilterAdminOperations */ private final FilterManager filterManager_; private final AtomicBoolean destroyed_ = new AtomicBoolean(false); private final AtomicBoolean disposeInProgress_ = new AtomicBoolean(false); private final AtomicInteger errorCounter_ = new AtomicInteger(0); private final POA poa_; private final ORB orb_; private final TaskProcessor taskProcessor_; private boolean isInterFilterGroupOperatorOR_; private final boolean disposedProxyDisconnectsClient_; private final AtomicBoolean active_ = new AtomicBoolean(true); private final DisposableManager disposables_ = new DisposableManager(); private final PicoContainer container_; private org.omg.CORBA.Object client_; private final String parentMBean_; protected final Set eventTypes_ = new HashSet(); private JMXManageable.JMXCallback jmxCallback_; protected Configuration config_; private final ServantLifecyleControl servantLifecycle_; // ////////////////////////////////////// protected AbstractProxy(IAdmin admin, ORB orb, POA poa, Configuration conf, TaskProcessor taskProcessor, OfferManager offerManager, SubscriptionManager subscriptionManager) { parentMBean_ = admin.getAdminMBean(); id_ = new Integer(admin.getProxyID()); isIDPublic_ = admin.isIDPublic(); container_ = admin.getContainer(); orb_ = orb; poa_ = poa; taskProcessor_ = taskProcessor; offerManager_ = offerManager; subscriptionManager_ = subscriptionManager; filterManager_ = new FilterManager(); nullMappingFilterRef_ = MappingFilterHelper.narrow(orb.string_to_object(orb.object_to_string(null))); logger_ = ((org.jacorb.config.Configuration) conf).getLogger(getClass().getName()); disposedProxyDisconnectsClient_ = conf.getAttribute( Attributes.DISPOSE_PROXY_CALLS_DISCONNECT, Default.DEFAULT_DISPOSE_PROXY_CALLS_DISCONNECT).equals("on"); qosSettings_ = new QoSPropertySet(conf, QoSPropertySet.PROXY_QOS); servantLifecycle_ = new ServantLifecyleControl(this, conf); configure(conf); } public void configure(Configuration conf) { config_ = conf; } // ////////////////////////////////////// public void registerDisposable(Disposable d) { disposables_.addDisposable(d); } public boolean isIDPublic() { return isIDPublic_; } public final POA getPOA() { return poa_; } protected ORB getORB() { return orb_; } public final org.omg.CORBA.Object activate() { return servantLifecycle_.activate(); } protected TaskProcessor getTaskProcessor() { return taskProcessor_; } // //////////////////////////////////////////////////// // delegate FilterAdmin Operations to FilterManager // // //////////////////////////////////////////////////// public final int add_filter(Filter filter) { return filterManager_.add_filter(filter); } public final void remove_filter(int n) throws FilterNotFound { filterManager_.remove_filter(n); } public final Filter get_filter(int n) throws FilterNotFound { return filterManager_.get_filter(n); } public final int[] get_all_filters() { return filterManager_.get_all_filters(); } public final void remove_all_filters() { filterManager_.remove_all_filters(); } // ////////////////////////////////////// // TODO implement public void validate_event_qos(Property[] qosProps, NamedPropertyRangeSeqHolder propSeqHolder) { throw new NO_IMPLEMENT(); } public final void validate_qos(Property[] props, NamedPropertyRangeSeqHolder propertyRange) throws UnsupportedQoS { qosSettings_.validate_qos(props, propertyRange); } public final void set_qos(Property[] qosProps) throws UnsupportedQoS { qosSettings_.set_qos(qosProps); } public final Property[] get_qos() { return qosSettings_.get_qos(); } public final void priority_filter(MappingFilter filter) { priorityFilter_ = filter; } public final MappingFilter priority_filter() { if (priorityFilter_ == null) { return nullMappingFilterRef_; } return priorityFilter_; } public final MappingFilter lifetime_filter() { if (lifetimeFilter_ == null) { return nullMappingFilterRef_; } return lifetimeFilter_; } public final void lifetime_filter(MappingFilter filter) { lifetimeFilter_ = filter; } public final Integer getID() { return id_; } public final List getFilters() { return filterManager_.getFilters(); } public final void deactivate() { servantLifecycle_.deactivate(); } private void tryDisconnectClient() { try { if (disposedProxyDisconnectsClient_ && connected_.get()) { logger_.info("disconnect_client"); disconnectClient(); client_._release(); } } catch (Exception e) { logger_.info("disconnect_client raised an unexpected error: will be ignored", e); } finally { connected_.set(false); client_ = null; } } public final boolean isDestroyed() { return destroyed_.get(); } protected void checkDestroyStatus() throws OBJECT_NOT_EXIST { if (!destroyed_.compareAndSet(false, true)) { logger_.error("Already destroyed"); throw new OBJECT_NOT_EXIST(); } } /** * @jmx.managed-operation description = "Destroy this Proxy" impact = "ACTION" */ public final void destroy() { checkDestroyStatus(); container_.dispose(); final List list = container_.getComponentInstancesOfType(IContainer.class); for (Iterator i = list.iterator(); i.hasNext();) { IContainer element = (IContainer) i.next(); element.destroy(); } } public void dispose() { logger_.info("Destroy Proxy " + id_); disposeInProgress_.set(true); // //////////////////////////// tryDisconnectClient(); clientDisconnected(); // //////////////////////////// removeListener(); // //////////////////////////// remove_all_filters(); // //////////////////////////// disposables_.dispose(); deactivate(); } protected abstract void clientDisconnected(); public abstract ProxyType MyType(); void setInterFilterGroupOperatorOR(boolean b) { isInterFilterGroupOperatorOR_ = b; } public final boolean hasInterFilterGroupOperatorOR() { return isInterFilterGroupOperatorOR_; } /** * @jmx.managed-attribute description = "Connection Status." * access = "read-only" */ public final boolean getConnected() { return !disposeInProgress_.get() && connected_.get(); } public final boolean hasLifetimeFilter() { return lifetimeFilter_ != null; } public final boolean hasPriorityFilter() { return priorityFilter_ != null; } public final MappingFilter getLifetimeFilter() { return lifetimeFilter_; } public final MappingFilter getPriorityFilter() { return priorityFilter_; } /** * @jmx.managed-operation impact = "ACTION" * description = "reset the error counter to its initial value" */ public void resetErrorCounter() { errorCounter_.set(0); } /** * @jmx.managed-attribute description = "error counter" * access = "read-only" */ public final int getErrorCounter() { return errorCounter_.get(); } public final int incErrorCounter() { return errorCounter_.getAndIncrement(); } public boolean isSuspended() { return !active_.get(); } public final void suspend_connection() throws NotConnected, ConnectionAlreadyInactive { checkIsConnected(); if (!active_.compareAndSet(true, false)) { throw new ConnectionAlreadyInactive(); } connectionSuspended(); } /** * this is an extension point. */ protected void connectionSuspended() { // No Op } public final void resume_connection() throws NotConnected, ConnectionAlreadyActive { checkIsConnected(); if (!active_.compareAndSet(false, true)) { throw new ConnectionAlreadyActive(); } connectionResumed(); } /** * this is an extension point. invoked when resume_connection was called successfully. */ protected void connectionResumed() { // NO OP } protected void checkIsConnected() throws NotConnected { if (!connected_.get()) { throw new NotConnected(); } } protected void checkIsNotConnected() throws AlreadyConnected { if (connected_.get()) { throw new AlreadyConnected(); } } protected void checkStillConnected() throws Disconnected { if (!connected_.get()) { logger_.error("access on a not connected proxy"); destroy(); throw new Disconnected(); } } protected void connectClient(org.omg.CORBA.Object client) { connected_.set(true); client_ = client; } /** * invoke the proxy specific disconnect method. */ protected abstract void disconnectClient(); protected void handleDisconnected(Disconnected e) { logger_.error("Illegal state: Client think it's disconnected. " + "Proxy thinks Client is still connected. The Proxy will be destroyed.", e); destroy(); } protected abstract void removeListener(); public final String getJMXObjectName() { return parentMBean_ + ", proxy=" + getMBeanName(); } public final String getMBeanName() { return getMBeanType() + "-" + getID(); } protected String getMBeanType() { String clazzName = getClass().getName(); String rawClazz = clazzName.substring(clazzName.lastIndexOf('.') + 1); return rawClazz.substring(0, rawClazz.length() - "Impl".length()); } public String[] getJMXNotificationTypes() { return (String[]) eventTypes_.toArray(new String[eventTypes_.size()]); } public void setJMXCallback(JMXManageable.JMXCallback callback) { jmxCallback_ = callback; } protected void sendNotification(String type, String message) { if (jmxCallback_ != null) { jmxCallback_.sendJMXNotification(type, message); } } protected void sendNotification(String type, String message, Object payload) { if (jmxCallback_ != null) { jmxCallback_.sendJMXNotification(type, message, payload); } } /** * @jmx.managed-attribute description = "current Status for this Proxy (NOT CONNECTED|ACTIVE|SUSPENDED|DESTROYED)" * access = "read-only" */ public String getStatus() { final String _status; if (destroyed_.get()) { _status = "DESTROYED"; } else if (!connected_.get()) { _status = "NOT CONNECTED"; } else { _status = active_.get() ? "ACTIVE" : "SUSPENDED"; } return _status; } /** * @jmx.managed-attribute description = "IOR of the connected client" * access = "read-only" */ public String getClientIOR() { return (client_ != null) ? orb_.object_to_string(client_) : ""; } /** * @jmx.managed-attribute description = "InterFilterGroupOperator used for this proxy" * access = "read-only" * currencyTimeLimit = "2147483647" */ public String getInterFilterGroupOperator() { return isInterFilterGroupOperatorOR_ ? "OR_OP" : "AND_OP"; } }