/*
* 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.cybernode.service;
import net.jini.config.Configuration;
import net.jini.id.Uuid;
import net.jini.id.UuidFactory;
import org.rioproject.impl.container.ServiceBeanContainer;
import org.rioproject.impl.container.ServiceBeanContainerListener;
import org.rioproject.impl.container.ServiceBeanDelegate;
import org.rioproject.impl.container.ServiceLogUtil;
import org.rioproject.deploy.ServiceBeanInstance;
import org.rioproject.deploy.ServiceBeanInstantiationException;
import org.rioproject.deploy.ServiceRecord;
import org.rioproject.event.EventHandler;
import org.rioproject.opstring.OperationalStringManager;
import org.rioproject.opstring.ServiceElement;
import org.rioproject.impl.system.ComputeResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
/**
* The ServiceBeanContainerImpl implements support for a ServiceBeanContainer
*
* @author Dennis Reedy
*/
public class ServiceBeanContainerImpl implements ServiceBeanContainer {
/** identifier token */
private final AtomicInteger token = new AtomicInteger(0);
/** Whether or not we are in a shutdown mode */
private final AtomicBoolean shutdownSequence = new AtomicBoolean(false);
/** The ComputeResource attribute associated to this ServiceBeanContainer */
private ComputeResource computeResource;
/** Collection of ServiceBeanDelegates */
private final Map<Object, ServiceBeanDelegate> controllerMap = new HashMap<Object, ServiceBeanDelegate>();
/**
* Count of activations that have registered with controllerMap but activate
* routine has not finished.
*/
private AtomicInteger activationInProcessCount = new AtomicInteger(0);
/** Uuid for the container */
private Uuid uuid;
/** Collection of ServiceBeanContainerListeners */
private final List<ServiceBeanContainerListener> listeners =
Collections.synchronizedList(new ArrayList<ServiceBeanContainerListener>());
/** Configuration object, which is also used as the shared configuration */
private Configuration config;
/** Logger */
private static final Logger logger = LoggerFactory.getLogger("org.rioproject.cybernode");
/**
* Create a new ServiceBeanContainer
*
* @param config The Configuration to use
*/
public ServiceBeanContainerImpl(Configuration config) {
this.config = config;
}
/**
* @see org.rioproject.impl.container.ServiceBeanContainer#getSharedConfiguration()
*/
public Configuration getSharedConfiguration() {
return (config);
}
/**
* Set the computeResource property.
*
* @param computeResource The ComputeResource to use
*/
public void setComputeResource(ComputeResource computeResource) {
this.computeResource = computeResource;
}
/**
* @see org.rioproject.impl.container.ServiceBeanContainer#getComputeResource()
*/
public ComputeResource getComputeResource() {
return (computeResource);
}
/**
* Terminate the ServiceBeanContainer
*/
public void terminate() {
shutdownSequence.set(true);
terminateServices();
}
/**
* Terminate the ServiceBeanContainer
*/
public void terminateServices() {
ServiceBeanDelegate[] delegates;
synchronized(controllerMap) {
Collection<ServiceBeanDelegate> controllers = controllerMap.values();
delegates = controllers.toArray(new ServiceBeanDelegate[controllers.size()]);
}
for (ServiceBeanDelegate delegate : delegates) {
delegate.terminate();
}
synchronized(controllerMap) {
controllerMap.clear();
}
}
/**
* @see org.rioproject.impl.container.ServiceBeanContainer#getServiceRecords
*/
public ServiceRecord[] getServiceRecords() {
List<ServiceRecord> list = new ArrayList<ServiceRecord>();
ServiceBeanDelegate[] delegates;
synchronized(controllerMap) {
Collection<ServiceBeanDelegate> controllers = controllerMap.values();
delegates = controllers.toArray(new ServiceBeanDelegate[controllers.size()]);
}
for (ServiceBeanDelegate delegate : delegates) {
ServiceRecord record = delegate.getServiceRecord();
if (record != null) {
list.add(record);
}
}
return (list.toArray(new ServiceRecord[list.size()]));
}
/**
* @see org.rioproject.impl.container.ServiceBeanContainer#getServiceCounter()
*/
public synchronized int getServiceCounter() {
int size;
synchronized(controllerMap) {
size = controllerMap.size();
}
return (size);
}
/**
* @see org.rioproject.impl.container.ServiceBeanContainer#getActivationInProcessCount()
*/
public int getActivationInProcessCount() {
return activationInProcessCount.get();
}
/**
* @see org.rioproject.impl.container.ServiceBeanContainer#activate
*/
public ServiceBeanInstance activate(ServiceElement sElem,
OperationalStringManager opStringMgr,
EventHandler slaEventHandler)
throws ServiceBeanInstantiationException {
Uuid serviceID = UuidFactory.generate();
Integer identifier = token.incrementAndGet();
ServiceBeanDelegateImpl delegate = new ServiceBeanDelegateImpl(identifier, serviceID, this);
delegate.setOperationalStringManager(opStringMgr);
delegate.setServiceElement(sElem);
delegate.setEventHandler(slaEventHandler);
synchronized(controllerMap) {
controllerMap.put(identifier, delegate);
activationInProcessCount.incrementAndGet();
}
boolean started = false;
ServiceBeanInstance loadedInstance = null;
try {
loadedInstance = delegate.load();
started = true;
/* notification to shutdown may have come in the middle of
* service creation, if it did, terminate */
if(shutdownSequence.get()) {
delegate.terminate();
throw new ServiceBeanInstantiationException("Resource unavailable, shutting down");
}
if(sElem.getAutoAdvertise()) {
delegate.advertise();
}
} catch(ServiceBeanInstantiationException e) {
if(started) {
discarded(identifier);
delegate.terminate();
}
/* rethrow ServiceBeanInstantiationException */
throw e;
} catch(Throwable t) {
if(started) {
discarded(identifier);
delegate.terminate();
}
logger.error("Could not activate service {}", ServiceLogUtil.logName(sElem), t);
throw new ServiceBeanInstantiationException(String.format("Service %s load failed", ServiceLogUtil.logName(sElem)),
t, true);
} finally {
activationInProcessCount.decrementAndGet();
}
return (loadedInstance);
}
/**
* @see org.rioproject.impl.container.ServiceBeanContainer#update
*/
public void update(ServiceElement[] elements, OperationalStringManager opStringMgr) {
if(elements==null) {
throw new IllegalArgumentException("elements is null");
}
if(opStringMgr==null) {
throw new IllegalArgumentException("opStringMgr is null");
}
for (ServiceElement element : elements) {
ServiceBeanDelegate[] delegates = getDelegates(element);
for (ServiceBeanDelegate delegate : delegates) {
//if(delegate.getServiceRecord().getDiscardedDate()!=null) {
if(delegate.isActive()) {
delegate.update(element, opStringMgr);
} else {
logger.warn(String.format("Service %s has been discarded, do not update",
ServiceLogUtil.logName(element)));
}
}
}
}
/**
* @see org.rioproject.impl.container.ServiceBeanContainer#getServiceBeanInstances
*/
public ServiceBeanInstance[] getServiceBeanInstances(ServiceElement element) {
List<ServiceBeanInstance> list = new ArrayList<ServiceBeanInstance>();
ServiceBeanDelegate[] delegates = getDelegates(element);
for (ServiceBeanDelegate delegate : delegates) {
ServiceBeanInstance instance = delegate.getServiceBeanInstance();
if (instance != null) {
list.add(instance);
}
}
return (list.toArray(new ServiceBeanInstance[list.size()]));
}
public void setUuid(Uuid uuid) {
this.uuid = uuid;
}
public Uuid getUuid() {
return uuid;
}
/*
* Get all ServiceBeanDelegate instances for a ServiceElement
*/
public ServiceBeanDelegate[] getDelegates(ServiceElement element) {
ServiceBeanDelegate[] delegates = getDelegates();
if(element!=null) {
ArrayList<ServiceBeanDelegate> list = new ArrayList<ServiceBeanDelegate>();
for (ServiceBeanDelegate delegate : delegates) {
if (delegate.getServiceElement().equals(element)) {
list.add(delegate);
}
}
delegates = list.toArray(new ServiceBeanDelegate[list.size()]);
}
return(delegates);
}
/**
* @see org.rioproject.impl.container.ServiceBeanContainer#started(Object)
*/
public void started(Object identifier) {
ServiceBeanDelegate delegate;
synchronized(controllerMap) {
delegate = controllerMap.get(identifier);
}
if(delegate == null) {
return;
}
ServiceRecord record = delegate.getServiceRecord();
if(record==null) {
logger.warn("ServiceRecord for [{}] is null, no way to notify container of instantiation",
delegate.getServiceElement().getName());
return;
}
notifyOnInstantiation(delegate.getServiceRecord());
}
/**
* @see org.rioproject.impl.container.ServiceBeanContainer#discarded(Object)
*/
public void discarded(Object identifier) {
ServiceBeanDelegate delegate;
synchronized(controllerMap) {
delegate = controllerMap.get(identifier);
}
if(delegate == null)
return;
notifyOnDiscard(delegate.getServiceRecord());
}
/**
* @see org.rioproject.impl.container.ServiceBeanContainer#remove(Object)
*/
public void remove(Object identifier) {
if(shutdownSequence.get())
return;
synchronized(controllerMap) {
controllerMap.remove(identifier);
}
}
/**
* @see org.rioproject.impl.container.ServiceBeanContainer#addListener
*/
public synchronized void addListener(ServiceBeanContainerListener l) {
if(!listeners.contains(l))
listeners.add(l);
}
/**
* @see org.rioproject.impl.container.ServiceBeanContainer#addListener
*/
public synchronized void removeListener(ServiceBeanContainerListener l) {
listeners.remove(l);
}
public ServiceBeanDelegate getServiceBeanDelegate(Uuid serviceUuid) {
ServiceBeanDelegate delegate = null;
ServiceBeanDelegate[] delegates = getDelegates();
for(ServiceBeanDelegate d : delegates) {
if(d.getServiceBeanInstance()!=null &&
d.getServiceBeanInstance().getServiceBeanID().equals(serviceUuid)) {
delegate = d;
break;
}
}
return delegate;
}
/*
* Notify all <code>ServiceBeanContainerListener</code> objects that a
* ServiceBean has just been instantiated
*/
void notifyOnInstantiation(ServiceRecord serviceRecord) {
ServiceBeanContainerListener[] scl;
synchronized(listeners) {
scl = listeners.toArray(new ServiceBeanContainerListener[listeners.size()]);
}
for(ServiceBeanContainerListener l : scl)
l.serviceInstantiated(serviceRecord);
}
/*
* Notify all <code>ServiceBeanContainerListener</code> objects that a
* ServiceBean has just been discarded
*/
void notifyOnDiscard(ServiceRecord serviceRecord) {
Object[] arrLocal = listeners.toArray();
for(int i = arrLocal.length - 1; i >= 0; i--)
((ServiceBeanContainerListener)arrLocal[i]).serviceDiscarded(serviceRecord);
}
ServiceBeanDelegate[] getDelegates() {
ServiceBeanDelegate[] delegates;
synchronized(controllerMap) {
Collection<ServiceBeanDelegate> controllers = controllerMap.values();
delegates = controllers.toArray(new ServiceBeanDelegate[controllers.size()]);
}
return delegates;
}
}