/*
* Copyright to the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.rioproject.impl.servicebean;
import net.jini.admin.Administrable;
import net.jini.id.Uuid;
import net.jini.io.MarshalledInstance;
import org.rioproject.admin.ServiceBeanControl;
import org.rioproject.impl.container.DiscardManager;
import org.rioproject.servicebean.ServiceBeanManager;
import org.rioproject.servicebean.ServiceBeanManagerException;
import org.rioproject.servicebean.ServiceElementChangeListener;
import org.rioproject.deploy.ServiceBeanInstance;
import org.rioproject.deploy.ServiceProvisionListener;
import org.rioproject.opstring.OperationalStringException;
import org.rioproject.opstring.OperationalStringManager;
import org.rioproject.opstring.ServiceBeanConfig;
import org.rioproject.opstring.ServiceElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.management.NotificationBroadcasterSupport;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
/**
* Implement ServiceBeanManager support
*
* @see org.rioproject.servicebean.ServiceBeanManager
*
* @author Dennis Reedy
*/
@SuppressWarnings("PMD.AvoidThrowingRawExceptionTypes")
public class DefaultServiceBeanManager implements ServiceBeanManager {
private static final String COMPONENT="org.rioproject.impl.servicebean";
private static Logger logger = LoggerFactory.getLogger(COMPONENT);
private DiscardManager discardManager;
private OperationalStringManager opStringManager;
private ServiceElement sElem;
/** ServiceID */
private Uuid serviceID;
/** Cybernode Uuid */
private Uuid cybernodeUuid;
/** The marshalledInstance */
private MarshalledInstance marshalledInstance;
/** The host name the service bean was instantiated on */
private String hostName;
/** The host address the service bean was instantiated on */
private String hostAddress;
/** List of listeners */
private final List<ServiceElementChangeListener> listenerList = new ArrayList<ServiceElementChangeListener>();
/** Flag to indicate we are in the process of updating the
* ServiceElement. This will avoid unnecessary ServiceBeanConfig updates
* if DiscoveryManagement attributes have changed */
boolean updating = false;
private final NotificationBroadcasterSupport notificationBroadcasterSupport = new NotificationBroadcasterSupport();
/**
* Create a DefaultServiceBeanManager
*
* @param sElem The ServiceElement
* @param hostName The host name the service bean was instantiated on
* @param hostAddress The host address the service bean was instantiated on
* @param cybernodeUuid The Uuuid of the Cybernode
*
* @throws IllegalArgumentException if the sElem hostName, or hostAddress parameters are null
*/
public DefaultServiceBeanManager(final ServiceElement sElem, final String hostName, final String hostAddress, final Uuid cybernodeUuid) {
this(sElem, null, hostName, hostAddress, cybernodeUuid);
}
/**
* Create a DefaultServiceBeanManager
*
* @param sElem The ServiceElement
* @param opStringManager The OperationalStringManager
* @param hostName The host name the service bean was instantiated on
* @param hostAddress The host address the service bean was instantiated on
* @param cybernodeUuid The Uuid of the Cybernode
*
* @throws IllegalArgumentException if the sElem hostName, or hostAddress parameters are null
*/
public DefaultServiceBeanManager(final ServiceElement sElem,
final OperationalStringManager opStringManager,
final String hostName,
final String hostAddress,
final Uuid cybernodeUuid) {
super();
if(sElem==null)
throw new IllegalArgumentException("sElem is null");
if(hostName==null)
throw new IllegalArgumentException("hostName is null");
if(hostAddress==null)
throw new IllegalArgumentException("hostAddress is null");
if(cybernodeUuid==null)
throw new IllegalArgumentException("cybernodeUuid is null");
this.sElem = sElem;
this.opStringManager = opStringManager;
this.hostName = hostName;
this.hostAddress = hostAddress;
this.cybernodeUuid = cybernodeUuid;
}
/**
* Set the ServiceElement for the ServiceBean
*
* @param newElem The ServiceElement for the ServiceBean
*/
public void setServiceElement(final ServiceElement newElem) {
if(newElem==null)
throw new IllegalArgumentException("sElem is null");
ServiceElement preElem = sElem;
this.sElem = newElem;
try {
updating = true;
stateChange(preElem, sElem);
} finally {
updating = false;
}
}
/**
* Set the ServiceID for the ServiceBean
*
* @param serviceID The Service Identifier for the ServiceBean
*/
public void setServiceID(final Uuid serviceID) {
if(serviceID==null)
throw new IllegalArgumentException("serviceID is null");
this.serviceID = serviceID;
}
/**
* @see org.rioproject.servicebean.ServiceBeanManager#getServiceID
*/
public Uuid getServiceID() {
return(serviceID);
}
/**
* Set the Object that can be used to communicate to the ServiceBean
*
* @param mi The MarshalledInstance containing the proxy that can be used
* to communicate to the ServiceBean
*/
public void setMarshalledInstance(final MarshalledInstance mi) {
this.marshalledInstance = mi;
}
/**
* Set the DiscardManager for the ServiceBean
*
* @param discardManager The DiscardManager for the ServiceBean
*/
public void setDiscardManager(final DiscardManager discardManager) {
this.discardManager = discardManager;
}
/**
* @see org.rioproject.servicebean.ServiceBeanManager#getDiscardManager
*/
public DiscardManager getDiscardManager() {
return(discardManager);
}
/**
* Set the OperationalStringManager
*
* @param opStringManager The OperationalStringManager
*/
public void setOperationalStringManager(final OperationalStringManager opStringManager) {
this.opStringManager = opStringManager;
}
/**
* @see org.rioproject.servicebean.ServiceBeanManager#getOperationalStringManager
*/
public OperationalStringManager getOperationalStringManager() {
return(opStringManager);
}
/**
* @see org.rioproject.servicebean.ServiceBeanManager#update
*/
public void update(final ServiceBeanConfig sbConfig) throws ServiceBeanManagerException {
if(sbConfig==null)
throw new IllegalArgumentException("ServiceBeanConfig is null");
if(sElem==null) {
logger.warn("No ServiceElement to update ServiceBeanConfig");
return;
}
if(updating) {
if(logger.isTraceEnabled())
logger.trace("Updating ServiceElement, ServiceBeanConfig update ignored");
return;
}
ServiceElement preElem = ServiceElementUtil.copyServiceElement(sElem);
Long instanceID = sElem.getServiceBeanConfig().getInstanceID();
sElem.setServiceBeanConfig(sbConfig);
if(instanceID!=null)
sElem = ServiceElementUtil.prepareInstanceID(sElem, false, instanceID);
else
logger.warn("No instanceID for [{}] to update", sElem.getName());
if(opStringManager==null) {
logger.warn("No OperationalStringManager to update ServiceBeanConfig");
return;
}
try {
opStringManager.update(getServiceBeanInstance());
} catch (OperationalStringException e) {
throw new ServiceBeanManagerException("Unable to update ServiceBeanConfig", e);
} catch (RemoteException e) {
throw new ServiceBeanManagerException("Problem communicating to OperationalStringManager, " +
"unable to update ServiceBeanConfig", e);
}
stateChange(preElem, sElem);
}
/**
* @see org.rioproject.servicebean.ServiceBeanManager#increment
*
* @throws ServiceBeanManagerException if the increment fails for any reason
*/
public void increment() throws ServiceBeanManagerException {
increment(null);
}
/**
* @see org.rioproject.servicebean.ServiceBeanManager#increment
*/
public void increment(final ServiceProvisionListener listener) throws ServiceBeanManagerException {
if(opStringManager==null) {
throw new ServiceBeanManagerException("No OperationalStringManager to increment service");
}
try {
opStringManager.increment(sElem, false, listener);
} catch (OperationalStringException e) {
throw new ServiceBeanManagerException("Unable to increment", e);
} catch (RemoteException e) {
throw new ServiceBeanManagerException("Problem communicating to OperationalStringManager, unable to increment", e);
}
}
/**
* @see org.rioproject.servicebean.ServiceBeanManager#decrement
*/
public void decrement(final boolean destroy) throws ServiceBeanManagerException {
if(opStringManager==null) {
throw new ServiceBeanManagerException("No OperationalStringManager to decrement service");
}
try {
opStringManager.decrement(getServiceBeanInstance(), false, destroy);
} catch (OperationalStringException e) {
e.printStackTrace();
} catch (RemoteException e) {
throw new ServiceBeanManagerException("Problem communicating to OperationalStringManager, unable to decrement", e);
}
}
/**
* @see org.rioproject.servicebean.ServiceBeanManager#relocate
*/
public void relocate(final ServiceProvisionListener listener, final Uuid uuid) throws ServiceBeanManagerException {
if(opStringManager==null) {
throw new ServiceBeanManagerException("No OperationalStringManager to relocate service");
}
if(sElem.getProvisionType()!= ServiceElement.ProvisionType.DYNAMIC)
throw new ServiceBeanManagerException("Relocation only available for DYNAMIC services");
try {
opStringManager.relocate(getServiceBeanInstance(), listener, uuid);
} catch (OperationalStringException e) {
throw new ServiceBeanManagerException("Unable to relocate ServiceBeanConfig", e);
} catch (RemoteException e) {
throw new ServiceBeanManagerException("Problem communicating to OperationalStringManager, unable to relocate", e);
}
}
/**
* @see org.rioproject.servicebean.ServiceBeanManager#getServiceBeanInstance
*/
public ServiceBeanInstance getServiceBeanInstance() {
return(new ServiceBeanInstance(serviceID,
marshalledInstance,
sElem.getServiceBeanConfig(),
hostName,
hostAddress,
cybernodeUuid));
}
/**
* @see org.rioproject.servicebean.ServiceBeanManager#getServiceBeanControl()
*/
public ServiceBeanControl getServiceBeanControl() throws ServiceBeanManagerException {
if(marshalledInstance==null)
throw new ServiceBeanManagerException("Unable to obtain ServiceBeanControl, there is no marshalled proxy instance");
ServiceBeanControl serviceBeanControl;
try {
Object proxy = marshalledInstance.get(false);
if(proxy instanceof Administrable) {
Object adminObject = ((Administrable)proxy).getAdmin();
if(adminObject instanceof ServiceBeanControl) {
serviceBeanControl = (ServiceBeanControl)proxy;
} else {
throw new ServiceBeanManagerException(String.format("Service is not an instanceof %s",
ServiceBeanControl.class.getName()));
}
} else {
throw new ServiceBeanManagerException(String.format("%s is derivable from %s, however, the service proxy does not implement %s",
ServiceBeanControl.class.getName(),
Administrable.class.getName(),
Administrable.class.getName()));
}
} catch (Exception e) {
throw new ServiceBeanManagerException("Unable to obtain ServiceBeanControl", e);
}
return serviceBeanControl;
}
/**
* Notify all registered ServiceElementChangeListener instances.
*
* @param preElem The old ServiceElement
* @param postElem An updated ServiceElement
*/
void stateChange(final ServiceElement preElem, final ServiceElement postElem) {
notifyListeners(preElem, postElem);
}
/**
* @see org.rioproject.servicebean.ServiceBeanManager#addListener
*/
public void addListener(final ServiceElementChangeListener l) {
if(l == null) {
throw new IllegalArgumentException("can't add null listener");
}
synchronized(listenerList) {
listenerList.add(l);
}
}
/**
* @see org.rioproject.servicebean.ServiceBeanManager#removeListener
*/
public void removeListener(ServiceElementChangeListener l) {
if(l==null)
return;
synchronized(listenerList) {
if(listenerList.contains(l))
listenerList.remove(l);
}
}
/**
* @see org.rioproject.servicebean.ServiceBeanManager#getNotificationBroadcasterSupport()
*/
public NotificationBroadcasterSupport getNotificationBroadcasterSupport() {
return notificationBroadcasterSupport;
}
/*
* Notify all registered listeners of the ServiceElement change
*/
private synchronized void notifyListeners(final ServiceElement preElem, final ServiceElement postElem) {
ServiceElementChangeListener[] listeners;
synchronized(listenerList) {
listeners = listenerList.toArray(new ServiceElementChangeListener[listenerList.size()]);
}
for (ServiceElementChangeListener listener : listeners)
listener.changed(preElem, postElem);
}
}