/*
* 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 com.sun.jini.config.Config;
import com.sun.jini.reliableLog.LogHandler;
import com.sun.jini.start.LifeCycle;
import net.jini.config.Configuration;
import net.jini.config.ConfigurationException;
import net.jini.core.entry.Entry;
import net.jini.core.event.UnknownEventException;
import net.jini.core.lookup.ServiceID;
import net.jini.export.Exporter;
import net.jini.id.Uuid;
import net.jini.io.MarshalledInstance;
import net.jini.jeri.BasicILFactory;
import net.jini.jeri.BasicJeriExporter;
import net.jini.lookup.entry.ServiceInfo;
import net.jini.lookup.entry.ServiceType;
import net.jini.lookup.entry.StatusType;
import net.jini.lookup.ui.AdminUI;
import net.jini.security.BasicProxyPreparer;
import net.jini.security.ProxyPreparer;
import net.jini.security.TrustVerifier;
import net.jini.security.proxytrust.ServerProxyTrust;
import org.rioproject.RioVersion;
import org.rioproject.config.Constants;
import org.rioproject.cybernode.Cybernode;
import org.rioproject.cybernode.proxy.CybernodeProxy;
import org.rioproject.deploy.*;
import org.rioproject.entry.BasicStatus;
import org.rioproject.entry.StandardServiceType;
import org.rioproject.entry.UIDescriptorFactory;
import org.rioproject.event.EventDescriptor;
import org.rioproject.impl.client.DiscoveryManagementPool;
import org.rioproject.impl.client.JiniClient;
import org.rioproject.impl.config.ExporterConfig;
import org.rioproject.impl.container.*;
import org.rioproject.impl.jmx.JMXUtil;
import org.rioproject.impl.jmx.MBeanServerFactory;
import org.rioproject.impl.opstring.OpStringLoader;
import org.rioproject.impl.opstring.OpStringManagerProxy;
import org.rioproject.impl.persistence.PersistentStore;
import org.rioproject.impl.persistence.SnapshotHandler;
import org.rioproject.impl.servicebean.DefaultServiceBeanManager;
import org.rioproject.impl.servicebean.ServiceBeanActivation;
import org.rioproject.impl.servicebean.ServiceBeanActivation.LifeCycleManager;
import org.rioproject.impl.servicebean.ServiceBeanAdapter;
import org.rioproject.impl.system.ComputeResource;
import org.rioproject.impl.system.SystemCapabilities;
import org.rioproject.impl.system.measurable.MeasurableCapability;
import org.rioproject.impl.util.BannerProvider;
import org.rioproject.impl.util.BannerProviderImpl;
import org.rioproject.impl.watch.ThreadDeadlockMonitor;
import org.rioproject.impl.watch.ThresholdListener;
import org.rioproject.impl.watch.ThresholdWatch;
import org.rioproject.impl.watch.WatchInjector;
import org.rioproject.net.HostUtil;
import org.rioproject.opstring.OperationalString;
import org.rioproject.opstring.OperationalStringManager;
import org.rioproject.opstring.ServiceElement;
import org.rioproject.servicebean.ServiceBeanContext;
import org.rioproject.servicebean.ServiceBeanManager;
import org.rioproject.serviceui.UIComponentFactory;
import org.rioproject.sla.SLA;
import org.rioproject.sla.SLAThresholdEvent;
import org.rioproject.system.ComputeResourceUtilization;
import org.rioproject.system.capability.PlatformCapability;
import org.rioproject.util.RioManifest;
import org.rioproject.util.TimeUtil;
import org.rioproject.watch.Calculable;
import org.rioproject.watch.ThresholdType;
import org.rioproject.watch.ThresholdValues;
import org.rioproject.watch.WatchDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.management.*;
import java.io.*;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.rmi.AccessException;
import java.rmi.AlreadyBoundException;
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.text.NumberFormat;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Implementation of a Cybernode
*
* @link {org.rioproject.impl.jmx.ThreadDeadlockMonitor#ID}
*
* @author Dennis Reedy
*/
@SuppressWarnings("unused")
public class CybernodeImpl extends ServiceBeanAdapter implements Cybernode,
ServiceBeanContainerListener,
CybernodeImplMBean,
ServerProxyTrust {
/** Component name we use to find items in the Configuration */
private static final String RIO_CONFIG_COMPONENT = "org.rioproject";
/** Component name we use to find items in the Configuration */
private static final String CONFIG_COMPONENT = RIO_CONFIG_COMPONENT+".cybernode";
/** Default Exporter attribute */
private static final String DEFAULT_EXPORTER = "defaultExporter";
/** Logger name */
private static final String LOGGER = CybernodeImpl.class.getName();
/** Cybernode logger. */
private static final Logger logger = LoggerFactory.getLogger(LOGGER);
/** Cybernode logger. */
private static final Logger loaderLogger = LoggerFactory.getLogger(CybernodeImpl.class.getPackage().getName()+".loader");
/**The component name for accessing the service's configuration */
private static String configComponent = CONFIG_COMPONENT;
/** Instance of a ServiceBeanContainer */
private ServiceBeanContainer container;
/** If the Cybernode has been configured an an instantiation resource, and
* the Cybernode removes itself as an asset, this property determines whether
* instantiated services should be terminated upon unregistration */
private boolean serviceTerminationOnUnregister=true;
/** default maximum service limit */
private int serviceLimit=500;
/** Service consumer responsible for Provision Monitor discovery and registration */
private ServiceConsumer svcConsumer=null;
/** Flag indicating the Cybernode is in shutdown sequence */
private final AtomicBoolean shutdownSequence= new AtomicBoolean(false);
/** Collection of services that are in the process of instantiation */
private final List<ServiceProvisionEvent> inProcess = new ArrayList<ServiceProvisionEvent>();
/** Log format version */
private static final int LOG_VERSION = 1;
/** PersistentStore to save state */
//PersistentStore store;
/** ThreadPool for SLAThresholdEvent processing */
private Executor thresholdTaskPool;
private ComputeResourcePolicyHandler computeResourcePolicyHandler;
/** This flag indicates whether the Cybernode has been configured to install
* external software defined by ServiceBean instances */
private boolean provisionEnabled=true;
/** The ServiceStatementManager defines the semantics of reading/writing
* ServiceStatement instances */
private ServiceStatementManager serviceStatementManager;
/** The Timer to use for scheduling a ServiceRecord update task */
private Timer taskTimer;
/** The Configuration for the Service */
private Configuration config;
/** ProxyPreparer for the OperationalStringMonitor */
private ProxyPreparer operationalStringManagerPreparer;
private LifeCycle lifeCycle;
/** Flag to indicate if the Cybernode is enlisted */
private boolean enlisted=false;
private ServiceRecordUpdateTask serviceRecordUpdateTask;
private int registryPort;
private String instantiatorID;
/**
* Create a Cybernode
*/
public CybernodeImpl() {
super();
}
/**
* Create a Cybernode launched from the ServiceStarter framework
*
* @param configArgs Configuration arguments
* @param lifeCycle The LifeCycle object that started the Cybernode
*
* @throws Exception if bootstrapping fails
*/
public CybernodeImpl(String[] configArgs, LifeCycle lifeCycle) throws Exception {
super();
this.lifeCycle = lifeCycle;
bootstrap(configArgs);
}
@Override
public void destroy() {
super.destroy();
}
/**
* Override destroy to ensure that any JSBs are shutdown as well
*/
public void destroy(boolean force) {
if(shutdownSequence.get())
return;
synchronized(CybernodeImpl.class) {
if(serviceRecordUpdateTask!=null)
serviceRecordUpdateTask.cancel();
shutdownSequence.set(true);
if(computeResourcePolicyHandler!=null) {
computeResourcePolicyHandler.terminate();
}
/* Shutdown the ComputeResource */
if(computeResource!=null)
computeResource.shutdown();
/* Stop the consumer */
if(svcConsumer != null)
svcConsumer.destroy();
}
svcConsumer = null;
/* Destroy the container */
if(container != null)
container.terminate();
/* If we have a store, destroy it */
if(snapshotter!=null)
snapshotter.interrupt();
if(store!=null) {
try {
store.destroy();
} catch(Exception e) {
logger.error("While destroying persistent store", e);
}
}
logger.info("{}: destroy() notification", context.getServiceElement().getName());
/* Stop the timer */
if(taskTimer!=null)
taskTimer.cancel();
try {
unadvertise();
} catch (IOException e) {
logger.warn("While unadvertising", e);
}
stop(force);
/* Terminate the ServiceStatementManager */
if(serviceStatementManager!=null)
serviceStatementManager.terminate();
/* Close down all WatchDataSource instances, unexporting them from
* the runtime */
destroyWatches();
/* Unregister all PlatformCapability instances */
if(computeResource!=null) {
PlatformCapability[] pCaps = computeResource.getPlatformCapabilities();
for (PlatformCapability pCap : pCaps) {
try {
ObjectName objectName = getObjectName(pCap);
MBeanServerFactory.getMBeanServer().unregisterMBean(objectName);
} catch (Exception e) {
logger.warn("Unregistering PlatformCapability [{}]", pCap.getName(), e);
}
}
}
/* Terminate the DiscoveryManagementPool */
DiscoveryManagementPool discoPool = DiscoveryManagementPool.getInstance();
if(discoPool!=null)
discoPool.terminate();
/* Tell the utility that started the Cybernode we are going away */
ServiceBeanManager serviceBeanManager = context.getServiceBeanManager();
if(serviceBeanManager!=null) {
DiscardManager discardMgr = serviceBeanManager.getDiscardManager();
if(discardMgr!=null) {
discardMgr.discard();
}
} else {
if(lifeCycle!=null) {
lifeCycle.unregister(this);
}
}
container = null;
}
/**
* Override parent's method to return <code>TrustVerifier</code> which can
* be used to verify that the given proxy to this service can be trusted
*
* @return TrustVerifier The TrustVerifier used to verify the proxy
*
*/
public TrustVerifier getProxyVerifier() {
return (new CybernodeProxy.Verifier(getExportedProxy()));
}
/**
* @see org.rioproject.deploy.ServiceBeanInstantiator#getServiceStatements
*/
public ServiceStatement[] getServiceStatements() {
return(serviceStatementManager.get());
}
/**
* @see org.rioproject.deploy.ServiceBeanInstantiator#getServiceRecords
*/
public ServiceRecord[] getServiceRecords(int filter) {
Set<ServiceRecord> recordSet = new HashSet<ServiceRecord>();
ServiceStatement[] statements = serviceStatementManager.get();
for (ServiceStatement statement : statements) {
ServiceRecord[] records = statement.getServiceRecords(getUuid(), filter);
recordSet.addAll(Arrays.asList(records));
}
if(logger.isTraceEnabled()) {
StringBuilder sb = new StringBuilder();
int i=1;
for(ServiceRecord record : recordSet) {
if(sb.length()>0) {
sb.append("\n");
}
sb.append(String.format("%2d. %-40s instance:%-3d %s",
i++,
ServiceLogUtil.simpleLogName(record.getServiceElement()),
record.getServiceElement().getServiceBeanConfig().getInstanceID(),
record.getServiceID().toString()));
}
String newLine = recordSet.isEmpty()?"":"\n";
String type = filter==ServiceRecord.ACTIVE_SERVICE_RECORD?"ACTIVE_SERVICE_RECORD":"INACTIVE_SERVICE_RECORD";
logger.trace("Returning ({}) {} ServiceRecords{}{}", recordSet.size(), type, newLine, sb.toString());
}
return(recordSet.toArray(new ServiceRecord[recordSet.size()]));
}
/**
* @see org.rioproject.deploy.ServiceBeanInstantiator#getServiceStatement
*/
public ServiceStatement getServiceStatement(ServiceElement elem) {
if(elem==null)
throw new IllegalArgumentException("ServiceElement is null");
return serviceStatementManager.get(elem);
}
/**
* @see org.rioproject.deploy.ServiceBeanInstantiator#getServiceBeanInstances
*/
public ServiceBeanInstance[] getServiceBeanInstances(ServiceElement element) {
ServiceBeanInstance[] sbi = container.getServiceBeanInstances(element);
logger.trace("ServiceBeanInstance count for [{}] = {}", element.getName(), sbi.length);
return (sbi);
}
/**
* @see org.rioproject.deploy.ServiceBeanInstantiator#update
*/
public void update(ServiceElement[] sElements, OperationalStringManager opStringMgr) throws RemoteException {
OperationalStringManager preparedOpStringMgr =
(OperationalStringManager)operationalStringManagerPreparer.prepareProxy(opStringMgr);
logger.trace("Prepared OperationalStringManager proxy: {}", preparedOpStringMgr.toString());
container.update(sElements, preparedOpStringMgr);
}
/**
* @see org.rioproject.deploy.ServiceBeanInstantiator#getName()
*/
public String getName() {
return instantiatorID;
}
/**
* Implemented to support interface contract. The CybernodeProxy returns
* the result of this method without a backend invocation. For completeness
* this method will return the Uuid as well
*
* @see org.rioproject.deploy.ServiceBeanInstantiator#getInstantiatorUuid()
*/
public Uuid getInstantiatorUuid() {
return(getUuid());
}
public InetAddress getInetAddress() {
return getComputeResource().getAddress();
}
/**
* Notification that a ServiceBean has been instantiated
*
* @param serviceRecord The ServiceRecord
*/
public void serviceInstantiated(ServiceRecord serviceRecord) {
ServiceStatement statement = serviceStatementManager.get(serviceRecord.getServiceElement());
if(statement==null) {
/* ServiceStatement not found, create one */
statement = new ServiceStatement(serviceRecord.getServiceElement());
}
statement.putServiceRecord(getUuid(), serviceRecord);
serviceStatementManager.record(statement);
//setChanged(StatusType.NORMAL);
if(loaderLogger.isInfoEnabled()) {
int instantiatedServiceCount = getInstantiatedServiceCount();
ServiceElement service = serviceRecord.getServiceElement();
logger.info("Instantiated {}, {}, total services active: {}",
ServiceLogUtil.logName(service),
ServiceLogUtil.discoveryInfo(service),
instantiatedServiceCount);
}
}
/**
* Notification that a ServiceBean has been discarded
*
* @param serviceRecord The ServiceRecord
*/
public void serviceDiscarded(ServiceRecord serviceRecord) {
if(serviceRecord==null) {
logger.warn("ServiceRecord is null when discarding ServiceBean");
} else {
ServiceStatement statement = serviceStatementManager.get(serviceRecord.getServiceElement());
if(statement!=null) {
if(serviceRecord.getType()!=ServiceRecord.INACTIVE_SERVICE_RECORD) {
serviceRecord.setType(ServiceRecord.INACTIVE_SERVICE_RECORD);
logger.warn("Fixing ServiceRecord for {}, notified as being discarded, but has ServiceRecord.ACTIVE_SERVICE_RECORD",
ServiceLogUtil.logName(serviceRecord.getServiceElement()));
}
statement.putServiceRecord(getUuid(), serviceRecord);
serviceStatementManager.record(statement);
if(loaderLogger.isInfoEnabled()) {
int instantiatedServiceCount = getInstantiatedServiceCount();
loaderLogger.info("Discarded {}, total services active: {}",
ServiceLogUtil.logName(serviceRecord.getServiceElement()), instantiatedServiceCount);
}
} else {
loaderLogger.warn("ServiceStatement is null when discarding ServiceBean {}",
ServiceLogUtil.logName(serviceRecord.getServiceElement()));
}
//setChanged(StatusType.NORMAL);
}
if (svcConsumer != null)
svcConsumer.updateMonitors();
}
private int getInstantiatedServiceCount() {
int instantiatedServiceCount = 0;
ServiceRecord[] records = container.getServiceRecords();
for (ServiceRecord record : records) {
if (record.getType() == ServiceRecord.ACTIVE_SERVICE_RECORD)
instantiatedServiceCount++;
}
return instantiatedServiceCount;
}
/*
* Get the ServiceBeanContext and bootstrap the Cybernode
*/
private void bootstrap(String[] configArgs) throws Exception {
logger.trace("Entering bootstrap");
context = ServiceBeanActivation.getServiceBeanContext(getConfigComponent(),
"Cybernode",
configArgs,
getClass().getClassLoader());
logger.trace("Obtained ServiceBeanContext {}", context);
BannerProvider bannerProvider = (BannerProvider)context.getConfiguration().getEntry(getConfigComponent(),
"bannerProvider",
BannerProvider.class,
new BannerProviderImpl());
logger.info(bannerProvider.getBanner(context.getServiceElement().getName()));
start(context);
LifeCycleManager lMgr = (LifeCycleManager)context. getServiceBeanManager().getDiscardManager();
lMgr.register(getServiceProxy(), context);
}
/**
* Get the component name to use for accessing the services configuration
* properties
*
* @return The component name
*/
public static String getConfigComponent() {
return(configComponent);
}
/**
* Set the component name to use for accessing the services configuration
* properties
*
* @param comp The component name
*/
protected void setConfigComponent(String comp) {
if(comp!=null)
configComponent = comp;
}
/**
* Override ServiceBeanAdapter createProxy to return a Cybernode Proxy
*/
@Override
protected Object createProxy() {
Cybernode cybernode = (Cybernode)getExportedProxy();
if(cybernode==null) {
logger.error("Could not get the exported proxy for the Cybernode, " +
"returning null. The Cybernode will not be able to " +
"accept remote inbound communications");
return null;
}
Object proxy = CybernodeProxy.getInstance(cybernode, getUuid());
logger.trace("Proxy created {}", proxy);
/* Get the registry port */
String sPort = System.getProperty(Constants.REGISTRY_PORT, "0");
registryPort = Integer.parseInt(sPort);
String name = context.getServiceBeanConfig().getName();
if(registryPort!=0) {
try {
String address = HostUtil.getHostAddressFromProperty(Constants.RMI_HOST_ADDRESS);
Registry registry = LocateRegistry.getRegistry(address, registryPort);
try {
registry.bind(name, (Remote)proxy);
logger.debug("Bound to RMI Registry on port={}", registryPort);
} catch(AlreadyBoundException e) {
/*ignore */
}
} catch(AccessException e) {
logger.warn("Binding "+name+" to RMI Registry", e);
} catch(RemoteException e) {
logger.warn("Binding "+name+" to RMI Registry", e);
} catch (java.net.UnknownHostException e) {
logger.warn("Unknown host address locating RMI Registry", e);
}
} else {
logger.debug("RMI Registry property not set, unable to bind {}", name);
}
/*
* Set the MarshalledInstance into the ServiceBeanManager
*/
try {
MarshalledInstance mi = new MarshalledInstance(proxy);
((DefaultServiceBeanManager)context.getServiceBeanManager()).setMarshalledInstance(mi);
} catch (IOException e) {
logger.warn("Unable to create MarshalledInstance for Cybernode proxy, non-fatal error, continuing ...", e);
}
return(proxy);
}
/**
* Override parent's getAdmin to return custom service admin
*
* @return A CybernodeAdminProxy instance
*/
public Object getAdmin() {
Object adminProxy = null;
try {
if(admin == null) {
Exporter adminExporter = getAdminExporter();
if (contextMgr != null)
admin = new CybernodeAdminImpl(this, adminExporter, contextMgr.getContextAttributeLogHandler());
else
admin = new CybernodeAdminImpl(this, adminExporter);
}
admin.setServiceBeanContext(getServiceBeanContext());
((CybernodeAdminImpl)admin).setRegistryPort(registryPort);
adminProxy = admin.getServiceAdmin();
} catch (Throwable t) {
logger.error("Getting CybernodeAdminImpl", t);
}
return (adminProxy);
}
/**
* @see org.rioproject.servicebean.ServiceBean#initialize
*/
public void initialize(ServiceBeanContext context) throws Exception {
/*
* Create the instantiatorID. This will be used as the name set in the proxy, and used to track
* registrations and updates in the ProvisionMonitor
*/
StringBuilder instantiatorIDBuilder = new StringBuilder();
instantiatorIDBuilder.append(context.getServiceElement().getName()).append("-");
String name = ManagementFactory.getRuntimeMXBean().getName();
String pid = name;
int ndx = name.indexOf("@");
if(ndx>=1) {
pid = name.substring(0, ndx);
}
instantiatorIDBuilder.append(pid).append("@");
instantiatorIDBuilder.append(InetAddress.getLocalHost().getHostName());
instantiatorID = instantiatorIDBuilder.toString();
/*
* Determine if a log directory has been provided. If so, create a
* PersistentStore
*/
String logDirName =
(String)context.getConfiguration().getEntry(CONFIG_COMPONENT, "logDirectory", String.class, null);
if(logDirName!=null) {
/* LogHandler required when dealing with the ReliableLog */
CybernodeLogHandler logHandler = new CybernodeLogHandler();
store = new PersistentStore(logDirName, logHandler, logHandler);
logger.debug("Cybernode: using absolute logdir path [{}]", store.getStoreLocation());
store.snapshot();
super.initialize(context, store);
} else {
super.initialize(context);
}
/* Get the Configuration */
config = context.getConfiguration();
try {
Exporter defaultExporter = (Exporter)config.getEntry(RIO_CONFIG_COMPONENT,
DEFAULT_EXPORTER,
Exporter.class,
null);
if(defaultExporter==null)
defaultExporter = new BasicJeriExporter(ExporterConfig.getServerEndpoint(), new BasicILFactory());
logger.trace("{} has been set as the defaultExporter", defaultExporter);
} catch(Exception e) {
logger.error("The {}.{} attribute must be set", RIO_CONFIG_COMPONENT, DEFAULT_EXPORTER);
throw e;
}
/* Set up thread deadlock detection. This seems a little clumsy to use
* the WatchInjector and could probably be improved. This does make the
* most use of the wiring for forked service monitoring. */
long threadDeadlockCheck = (Long)config.getEntry(CONFIG_COMPONENT,
"threadDeadlockCheck",
long.class, (long)5000);
if(threadDeadlockCheck>=1000) {
WatchDescriptor threadDeadlockDescriptor = ThreadDeadlockMonitor.getWatchDescriptor();
threadDeadlockDescriptor.setPeriod(threadDeadlockCheck);
Method getThreadDeadlockCalculable = ThreadDeadlockMonitor.class.getMethod("getThreadDeadlockCalculable");
ThreadDeadlockMonitor threadDeadlockMonitor = new ThreadDeadlockMonitor();
threadDeadlockMonitor.setThreadMXBean(ManagementFactory.getThreadMXBean());
WatchInjector watchInjector = new WatchInjector(this, context);
ThresholdWatch watch = (ThresholdWatch)watchInjector.inject(threadDeadlockDescriptor,
threadDeadlockMonitor,
getThreadDeadlockCalculable);
watch.setThresholdValues(new ThresholdValues(0, 1));
watch.addThresholdListener(new DeadlockedThreadPolicyHandler());
} else {
logger.info("Thread deadlock monitoring has been disabled. The " +
"configured thread deadlock check time was " +
"[{}]. To enable thread deadlock monitoring, the thread deadlock check " +
"time must be >= 1000 milliseconds.", threadDeadlockCheck);
}
try {
serviceLimit = Config.getIntEntry(config, getConfigComponent(), "serviceLimit", 500, 0, Integer.MAX_VALUE);
} catch(Exception e) {
logger.warn("Exception getting serviceLimit, default to 500");
}
/* Get the ProxyPreparer for passed in OperationalStringManager
* instances */
operationalStringManagerPreparer = (ProxyPreparer)config.getEntry(getConfigComponent(),
"operationalStringManagerPreparer",
ProxyPreparer.class,
new BasicProxyPreparer());
/* Check for JMXConnection */
addAttributes(JMXUtil.getJMXConnectionEntries());
/* Add service UIs programmatically */
addAttributes(getServiceUIs());
addAttributes((Entry[]) config.getEntry(getConfigComponent(), "initialLookupAttributes", Entry[].class, new Entry[0]));
/* Get the security policy to apply to loading services */
String serviceSecurityPolicy = (String)config.getEntry(getConfigComponent(),
"serviceSecurityPolicy",
String.class,
null);
if(serviceSecurityPolicy!=null)
System.setProperty("rio.service.security.policy", serviceSecurityPolicy);
/* Establish default operating environment */
Environment.setupDefaultEnvironment();
/* Setup persistent provisioning attributes */
provisionEnabled = (Boolean) config.getEntry(getConfigComponent(), "provisionEnabled", Boolean.class, true);
/*
* The directory to provision external software to. This is the root
* directory where software may be installed by ServiceBean instances which
* require external software to be resident on compute resource the
* Cybernode represents
*/
String provisionRoot = Environment.setupProvisionRoot(provisionEnabled, config);
if(provisionEnabled) {
if(logger.isTraceEnabled())
logger.trace("Software provisioning has been enabled, default provision root location is [{}]",
provisionRoot);
}
computeResource.setPersistentProvisioningRoot(provisionRoot);
/* Setup the native library directory */
String nativeLibDirectories = Environment.setupNativeLibraryDirectories(config);
/* Ensure org.rioproject.system.native property is set. This will be used
* by the org.rioproject.system.SystemCapabilities class */
if(nativeLibDirectories!=null)
System.setProperty(SystemCapabilities.NATIVE_LIBS, nativeLibDirectories);
/* Initialize the ComputeResource */
initializeComputeResource(computeResource);
if(logger.isTraceEnabled()) {
StringBuilder sb = new StringBuilder();
sb.append("Service Limit : ").append(serviceLimit).append("\n");
sb.append("System Capabilities\n");
MeasurableCapability[] mCaps = computeResource.getMeasurableCapabilities();
sb.append("MeasurableCapabilities : (").
append(mCaps.length).
append(")\n");
for (MeasurableCapability mCap : mCaps) {
sb.append("\t").append(mCap.getId()).append("\n");
ThresholdValues tValues = mCap.getThresholdValues();
sb.append("\t\tlow threshold : ").append(tValues.getLowThreshold()).append("\n");
sb.append("\t\thigh threshold : ").append(tValues.getHighThreshold()).append("\n");
sb.append("\t\treport rate : ").append(mCap.getPeriod()).append("\n");
sb.append("\t\tsample size : ");
sb.append(mCap.getSampleSize()).append("\n");
}
PlatformCapability[] pCaps = computeResource.getPlatformCapabilities();
sb.append("PlatformCapabilities : (").append(pCaps.length).append(")\n");
double KB = 1024;
double MB = Math.pow(KB, 2);
double GB = Math.pow(KB, 3);
NumberFormat nf = NumberFormat.getInstance();
nf.setMaximumFractionDigits(2);
for (PlatformCapability pCap : pCaps) {
boolean convert = false;
if(pCap.getClass().getName().contains("StorageCapability") ||
pCap.getClass().getName().contains("Memory")) {
convert = true;
}
sb.append("\t").append(stripPackageName(pCap.getClass().getName())).append("\n");
String[] keys = pCap.getPlatformKeys();
for (String key : keys) {
Object value = pCap.getValue(key);
if(convert && value instanceof Double) {
if(pCap.getClass().getName().contains("StorageCapability")) {
double d = ((Double)value)/GB;
value = nf.format(d)+" GB";
} else {
double d = ((Double)value)/MB;
value = nf.format(d)+" MB";
}
}
sb.append("\t\t").append(key).append(" : ").append(value).append("\n");
}
String path = pCap.getPath();
if (path != null)
sb.append("\t\tPath : ").append(path).append("\n");
}
logger.trace(sb.toString());
}
/* Create the ServiceStatementManager */
serviceStatementManager = Environment.getServiceStatementManager(config);
/* Start the timerTask for updating ServiceRecords */
long serviceRecordUpdateTaskTimer = 60;
try {
serviceRecordUpdateTaskTimer = Config.getLongEntry(config,
getConfigComponent(),
"serviceRecordUpdateTaskTimer",
serviceRecordUpdateTaskTimer,
1,
Long.MAX_VALUE);
} catch(Throwable t) {
logger.warn("Exception getting slaThresholdTaskPoolMinimum", t);
}
taskTimer = new Timer(true);
long period = 1000*serviceRecordUpdateTaskTimer;
long now = System.currentTimeMillis();
serviceRecordUpdateTask = new ServiceRecordUpdateTask();
taskTimer.scheduleAtFixedRate(serviceRecordUpdateTask, new Date(now+period), period);
/*
* Create a thread pool for processing SLAThresholdEvent
*/
thresholdTaskPool = Executors.newCachedThreadPool();
/*
* Create event descriptor for the SLAThresholdEvent and add it as
* an attribute
*/
EventDescriptor thresholdEventDesc = SLAThresholdEvent.getEventDescriptor();
getEventTable().put(thresholdEventDesc.eventID, getSLAEventHandler());
addAttribute(thresholdEventDesc);
addAttribute(new BasicStatus(StatusType.NORMAL));
/* Create the container */
createContainer();
/* Create the consumer which will discover, register and maintain
* connection(s) to ProvisionMonitor instances */
svcConsumer =
new ServiceConsumer(new CybernodeAdapter((ServiceBeanInstantiator)getServiceProxy(),this, computeResource),
serviceLimit,
config);
/* Get the property that determines whether instantiated services
* should be terminated upon unregistration */
serviceTerminationOnUnregister = (Boolean) config.getEntry(getConfigComponent(),
"serviceTerminationOnUnregister",
Boolean.class,
Boolean.TRUE);
logger.debug("serviceTerminationOnUnregister={}", serviceTerminationOnUnregister);
/* Get whether the Cybernode will make itself available as an asset */
boolean doEnlist = (Boolean)config.getEntry(getConfigComponent(), "enlist", Boolean.class, true);
if(doEnlist) {
doEnlist();
} else {
logger.info("Do not enlist with ProvisionManagers as an instantiation resource");
}
/* Create a computeResourcePolicyHandler to watch for thresholds
* being crossed */
computeResourcePolicyHandler = new ComputeResourcePolicyHandler(context.getServiceElement(),
getSLAEventHandler(),
svcConsumer,
makeServiceBeanInstance());
computeResource.addThresholdListener(computeResourcePolicyHandler);
/* Ensure we have a serviceID */
if(serviceID==null) {
serviceID = new ServiceID(getUuid().getMostSignificantBits(), getUuid().getLeastSignificantBits());
logger.debug("Created new ServiceID: {}", serviceID.toString());
}
/* Log discovery setup */
logger.info("Started Cybernode [{}]", JiniClient.getDiscoveryAttributes(context));
loadInitialServices(context.getConfiguration());
/*
* Force a snapshot so the persistent store reflects the current state
* of the Cybernode
*/
if(store!=null)
store.snapshot();
}
/*
* Get the name of the class sans the package name
*/
private String stripPackageName(String className) {
int ndx = className.lastIndexOf(".");
if(ndx==-1)
return className;
return className.substring(ndx+1);
}
/**
* Load any initial services
*
* @param config The Jini configuration to use
*/
protected void loadInitialServices(Configuration config) {
/* Get the timeout value for loading initial services */
long initialServiceLoadDelay = 1000*5;
try {
initialServiceLoadDelay =
Config.getLongEntry(config,
getConfigComponent(),
"initialServiceLoadDelay",
initialServiceLoadDelay,
0,
Long.MAX_VALUE);
} catch(Throwable t) {
logger.warn("Exception getting initialServiceLoadDelay", t);
}
logger.debug("initialServiceLoadDelay={}", initialServiceLoadDelay);
/*
* Schedule the task to Load any configured services
*/
if(initialServiceLoadDelay>0) {
long now = System.currentTimeMillis();
getTaskTimer().schedule(new InitialServicesLoadTask(config), new Date(now+initialServiceLoadDelay));
} else {
InitialServicesLoadTask serviceLoader = new InitialServicesLoadTask(config);
serviceLoader.loadInitialServices();
}
}
/**
* Scheduled Task which will load configured services
*/
class InitialServicesLoadTask extends TimerTask {
Configuration config;
/**
* Create a InitialServicesLoadTask
*
* @param config Configuration, must not be null
*/
InitialServicesLoadTask(Configuration config) {
if(config==null)
throw new IllegalArgumentException("config is null");
this.config = config;
}
/**
* The action to be performed by this timer task.
*/
public void run() {
loadInitialServices();
}
void loadInitialServices() {
/* Load initial services */
String[] initialServices = new String[] {};
try {
initialServices = (String[])config.getEntry(getConfigComponent(),
"initialServices",
String[].class,
initialServices);
} catch(ConfigurationException e) {
logger.warn("Getting initialServices", e);
}
logger.debug("Loading [{}] initialServices", initialServices.length);
for (String initialService : initialServices) {
URL deploymentURL;
try {
if (initialService.startsWith("http:"))
deploymentURL = new URL(initialService);
else
deploymentURL = new File(initialService).toURI().toURL();
load(deploymentURL);
} catch (Throwable t) {
logger.error("Loading initial services : {}", initialService, t);
}
}
}
/*
* Load and activate services
*/
void load(URL deploymentURL) {
if(deploymentURL == null)
throw new IllegalArgumentException("Deployment URL cannot be null");
try {
/* Get the OperationalString loader */
OpStringLoader opStringLoader = new OpStringLoader(this.getClass().getClassLoader());
OperationalString[] opStrings = opStringLoader.parseOperationalString(deploymentURL);
if(opStrings != null) {
for (OperationalString opString : opStrings) {
logger.debug("Activating Deployment [{}]", opString.getName());
ServiceElement[] services = opString.getServices();
for (ServiceElement service : services) {
activate(service);
}
}
}
} catch(Throwable t) {
logger.warn("Activating OperationalString", t);
}
}
}
/*
* Create a ServiceProvisionEvent and instantiate the ServiceElement
*/
private void activate(ServiceElement sElem) {
ServiceProvisionEvent spe = new ServiceProvisionEvent(getServiceProxy(), null, sElem);
try {
instantiate(spe);
} catch (Throwable t) {
logger.warn("Activating service [{}]", sElem.getName(), t);
}
}
/**
* Get the enlisted state
*/
public boolean isEnlisted() {
return(enlisted);
}
/**
* Set the enlisted flag
*
* @param value True if enlisted, false if not
*/
protected void setEnlisted(boolean value) {
enlisted = value;
}
/**
* Have the Cybernode add itself as a resource which can be
* used to instantiate dynamic application services.
*
* If the Cybernode is already enlisted, this method will have
* no effect
*/
protected void doEnlist() {
if(isEnlisted()) {
logger.debug("Already enlisted");
return;
}
logger.info("Enlist with ProvisionManagers as an instantiation resource using: {}", instantiatorID);
try {
svcConsumer.initializeProvisionDiscovery(context.getDiscoveryManagement());
} catch(Exception e) {
logger.warn("Initializing Provision discovery", e);
}
setEnlisted(true);
}
/**
* Get the Timer created for the Cybernode
*
* @return The task Timer used to schedule tasks
*/
protected Timer getTaskTimer() {
return(taskTimer);
}
/**
* Get the {@link net.jini.lookup.entry.ServiceInfo} for the Cybernode
*
* @return The ServiceInfo
*/
@Override
protected ServiceInfo getServiceInfo() {
URL implUrl = getClass().getProtectionDomain().getCodeSource().getLocation();
RioManifest rioManifest;
String build = null;
try {
rioManifest = new RioManifest(implUrl);
build = rioManifest.getRioBuild();
} catch(IOException e) {
logger.warn("Getting Rio Manifest", e);
}
if(build==null)
build="0";
return new ServiceInfo(context.getServiceElement().getName(),
"Asarian Technologies LLC",
"Rio Project",
RioVersion.VERSION,
"Build "+build,
"");
}
@Override
protected ServiceType getServiceType(final String name, final String comment) {
StandardServiceType sType = new StandardServiceType();
sType.name = name;
if(comment!=null)
sType.description = comment;
sType.iconName = "icon/rio-service.jpg";
return sType;
}
private URL[] getUIJars() throws MalformedURLException {
return new URL[]{new URL("artifact:org.rioproject.cybernode:cybernode-ui:"+RioVersion.VERSION),
new URL("artifact:org.rioproject:watch-ui:"+RioVersion.VERSION)};
}
/**
* Override parents getWatchUI, using cybernode-ui.jar as the JAR containing
* org.rioproject.watch.AccumulatorViewer
* @throws MalformedURLException
* @throws IOException
*/
protected Entry getWatchUI() throws IOException {
return(UIDescriptorFactory.getUIDescriptor(
AdminUI.ROLE,
new UIComponentFactory(getUIJars(), "org.rioproject.watch.AccumulatorViewer")));
}
/**
* Get the service UIs to add
*
* @return An array of UIDescriptors used for the service-UIs for the
* Cybernode.
*
* @throws IOException If the UIDescriptors cannot be created
*/
protected Entry[] getServiceUIs() throws IOException {
UIComponentFactory cybernodeUI = new UIComponentFactory(getUIJars(),
"org.rioproject.cybernode.ui.PlatformCapabilityUI");
UIComponentFactory platformCapabilityUI = new UIComponentFactory(getUIJars(),
"org.rioproject.cybernode.ui.CybernodeUI");
Entry[] uis = new Entry[] {UIDescriptorFactory.getUIDescriptor(AdminUI.ROLE, platformCapabilityUI),
UIDescriptorFactory.getUIDescriptor(AdminUI.ROLE, cybernodeUI)};
return(uis);
}
protected ServiceBeanContainer getServiceBeanContainer() {
return container;
}
/**
* @see org.rioproject.deploy.ServiceBeanInstantiator#instantiate
*/
public DeployedService instantiate(ServiceProvisionEvent event)
throws ServiceBeanInstantiationException, UnknownEventException {
DeployedService deployedService;
try {
if(shutdownSequence.get()) {
StringBuilder builder = new StringBuilder();
builder.append(ServiceLogUtil.logName(event)).append(" shutting down, unavailable for service instantiation");
logger.warn(builder.toString());
throw new ServiceBeanInstantiationException(builder.toString());
}
loaderLogger.info("Instantiating {}", ServiceLogUtil.logName(event));
if(event.getID()!=ServiceProvisionEvent.ID) {
logger.warn("Unknown event type [{}], ID={}", event.getClass().getName(), event.getID());
throw new UnknownEventException("Unknown event type ["+event.getID()+"]");
}
/* Verify that the Cybernode does not instantiate a service past
* it's specified max per machine or planned value
*
* This may occur if a provisioner is in the process of deploying
* multiple instances of a service, and service instantiation time takes
* longer then expected, or the off chance that multiple provisioners
* may be managing the same opstring and may not be out of synch with
* each other */
synchronized(inProcess) {
/* Get the number of active instances for the ServiceElement */
int instantiatedServiceCount = 0;
ServiceRecord[] records = container.getServiceRecords();
for (ServiceRecord record : records) {
if (record.getType() == ServiceRecord.ACTIVE_SERVICE_RECORD &&
record.getServiceElement().equals(event.getServiceElement()))
instantiatedServiceCount++;
}
/* Get the number of instances that are in the process of being
* activated for the ServiceElement */
int inProcessServiceCount = 0;
for(ServiceProvisionEvent spe : inProcess) {
if(spe.getServiceElement().equals(event.getServiceElement()))
inProcessServiceCount++;
}
/* Set the temporal service count to be equal to the in process
* count and active instances */
int activeServiceCounter = inProcessServiceCount+instantiatedServiceCount;
if(loaderLogger.isTraceEnabled())
loaderLogger.trace("{} activeServiceCounter=[{}], inProcessServiceCount=[{}], instantiatedServiceCount=[{}]",
ServiceLogUtil.logName(event), activeServiceCounter, inProcessServiceCount, instantiatedServiceCount);
/* First check max per machine */
int maxPerMachine = event.getServiceElement().getMaxPerMachine();
if(maxPerMachine!=-1 && activeServiceCounter >= maxPerMachine) {
if(loaderLogger.isTraceEnabled())
loaderLogger.trace("Abort allocation of {} "+
"activeServiceCounter=[{}] "+
"inProcessServiceCount=[{}] "+
"maxPerMachine=[{}]",
ServiceLogUtil.logName(event), activeServiceCounter, inProcessServiceCount, maxPerMachine);
throw new ServiceBeanInstantiationException("MaxPerMachine "+"["+maxPerMachine+"] has been reached");
}
/* The check planned service count */
int numPlannedServices = event.getServiceElement().getPlanned();
if(activeServiceCounter >= numPlannedServices) {
if(loaderLogger.isTraceEnabled())
loaderLogger.trace("Cancel allocation of {} activeServiceCounter=[{}] numPlannedServices=[{}]",
ServiceLogUtil.logName(event), activeServiceCounter, numPlannedServices+"]");
return(null);
}
inProcess.add(event);
}
int inProcessCount;
synchronized(inProcess) {
inProcessCount = inProcess.size() - container.getActivationInProcessCount();
}
int containerServiceCount = container.getServiceCounter();
if((inProcessCount+containerServiceCount) <= serviceLimit) {
OperationalStringManager opMgr = event.getOperationalStringManager();
if(!event.getServiceElement().forkService()) {
if(loaderLogger.isTraceEnabled())
loaderLogger.trace("Get OpStringManagerProxy for {}", ServiceLogUtil.logName(event));
try {
opMgr = OpStringManagerProxy.getProxy(
event.getServiceElement().getOperationalStringName(),
event.getOperationalStringManager(),
context.getDiscoveryManagement());
if(loaderLogger.isTraceEnabled())
loaderLogger.trace("Got OpStringManagerProxy for {}", ServiceLogUtil.logName(event));
} catch (Exception e) {
loaderLogger.warn("Unable to create proxy for OperationalStringManager, " +
"using provided OperationalStringManager",
e);
if(shutdownSequence.get()) {
throw new ServiceBeanInstantiationException(
String.format("Cancel allocation of %s, Cybernode is shutting down",
ServiceLogUtil.logName(event)));
}
opMgr = event.getOperationalStringManager();
}
}
try {
loaderLogger.trace("Activating {}", ServiceLogUtil.logName(event));
ServiceBeanInstance jsbInstance = container.activate(event.getServiceElement(),
opMgr,
getSLAEventHandler());
loaderLogger.trace("Activated {}", ServiceLogUtil.logName(event));
ServiceBeanDelegate delegate = container.getServiceBeanDelegate(jsbInstance.getServiceBeanID());
ComputeResourceUtilization cru = null;
if(delegate!=null) {
cru = delegate.getComputeResourceUtilization();
}
deployedService = new DeployedService(event.getServiceElement(), jsbInstance, cru);
loaderLogger.trace("Created DeployedService for {}", ServiceLogUtil.logName(event));
} catch(ServiceBeanInstantiationException e) {
if(opMgr instanceof OpStringManagerProxy.OpStringManager) {
try {
((OpStringManagerProxy.OpStringManager)opMgr).terminate();
} catch(IllegalStateException ex) {
logger.warn("Shutting down OpStringManagerProxy more then once for service {}",
ServiceLogUtil.logName(event));
}
}
throw e;
}
return(deployedService);
} else {
throw new ServiceBeanInstantiationException("Service Limit of ["+serviceLimit+"] has been reached");
}
} finally {
synchronized(inProcess) {
inProcess.remove(event);
}
}
}
/**
* Create the container the Cybernode will use
*
* @throws ConfigurationException if the ServiceBeanContainer cannot be
* created using the configuration
*/
void createContainer() throws ConfigurationException {
Configuration config = context.getConfiguration();
ServiceBeanContainer defaultContainer = new ServiceBeanContainerImpl(config);
this.container = (ServiceBeanContainer)config.getEntry(getConfigComponent(),
"serviceBeanContainer",
ServiceBeanContainer.class,
defaultContainer,
config);
this.container.setUuid(getUuid());
this.container.setComputeResource(computeResource);
this.container.addListener(this);
}
/**
* Change the BasicStatus Entry to reflect a change in state
*
* @param statusType The StatusType
*/
void setChanged(StatusType statusType) {
joiner.modifyAttributes(new Entry[]{new BasicStatus()}, new Entry[]{new BasicStatus(statusType)});
}
/**
* Get the ComputeResource associated with this Cybernode
*
* @return The ComputeResource associated with this Cybernode
*/
public ComputeResource getComputeResource() {
return(computeResource);
}
/**
* The initializeComputeResource initializes the instantiated ComputeResource
* object, and adds MeasurableCapability watches to the Watch Registry.
*
* @param computeResource The ComputeResource to initialize
*/
void initializeComputeResource(ComputeResource computeResource) {
/*
* Set whether the Cybernode supports persistent provisioning
*/
computeResource.setPersistentProvisioning(provisionEnabled);
/*
* Have the ComputeResource object start all it's MeasurableCapabilities
*/
computeResource.boot();
/*
* Add MeasurableCapability watches to the Watch Registry
*/
MeasurableCapability[] mCaps = computeResource.getMeasurableCapabilities();
for (MeasurableCapability mCap : mCaps) {
getWatchRegistry().register(mCap);
}
PlatformCapability[] pCaps = computeResource.getPlatformCapabilities();
MBeanServer mbeanServer = MBeanServerFactory.getMBeanServer();
for (PlatformCapability pCap : pCaps) {
try {
ObjectName objectName = getObjectName(pCap);
if (objectName != null)
mbeanServer.registerMBean(pCap, objectName);
} catch (MalformedObjectNameException e) {
logger.warn("PlatformCapability [{}.{}]", pCap.getClass().getName(), pCap.getName(), e);
} catch (NotCompliantMBeanException e) {
logger.warn("PlatformCapability [{}.{}]", pCap.getClass().getName(), pCap.getName(), e);
} catch (MBeanRegistrationException e) {
logger.warn("PlatformCapability [{}.{}]", pCap.getClass().getName(), pCap.getName(), e);
} catch (InstanceAlreadyExistsException e) {
logger.warn("PlatformCapability [{}.{}]", pCap.getClass().getName(), pCap.getName(), e);
}
}
logger.debug("Will update discovered Provision Monitors with resource utilization details at " +
"intervals of {}", TimeUtil.format(computeResource.getReportInterval()));
}
/*
* Get an ObjectName for a PlatformCapability
*/
private ObjectName getObjectName(PlatformCapability pCap)
throws MalformedObjectNameException {
return(JMXUtil.getObjectName(context, "org.rioproject.cybernode", "PlatformCapability", pCap.getName()));
}
/*
* Make a ServiceBeanInstance for the Cybernode
*/
private ServiceBeanInstance makeServiceBeanInstance() throws IOException {
return new ServiceBeanInstance(getUuid(),
new MarshalledInstance(getServiceProxy()),
context.getServiceElement().getServiceBeanConfig(),
computeResource.getHostName(),
computeResource.getAddress().getHostAddress(),
getUuid());
}
/**
* Scheduled Task which will update ServiceStatement instances with the latest and
* greatest ServiceRecords
*/
class ServiceRecordUpdateTask extends TimerTask {
/**
* The action to be performed by this timer task.
*/
public void run() {
ServiceRecord[] records = container.getServiceRecords();
for (ServiceRecord record : records) {
ServiceStatement statement = serviceStatementManager.get(record.getServiceElement());
if (statement != null) {
statement.putServiceRecord(getUuid(), record);
serviceStatementManager.record(statement);
}
}
}
}
/**
* If deadlocked threads are detected fire SLAThresholdEvents
*/
private class DeadlockedThreadPolicyHandler implements ThresholdListener {
public void notify(Calculable calculable, ThresholdValues thresholdValues, ThresholdType type) {
double[] range = new double[]{
thresholdValues.getCurrentLowThreshold(),
thresholdValues.getCurrentHighThreshold()
};
SLA sla = new SLA(calculable.getId(), range);
try {
ServiceBeanInstance instance = makeServiceBeanInstance();
SLAThresholdEvent event = new SLAThresholdEvent(proxy,
context.getServiceElement(),
instance,
calculable,
sla,
"Cybernode Thread Deadlock " +
"Policy Handler",
instance.getHostAddress(),
type);
thresholdTaskPool.execute(new SLAThresholdEventTask(event, getSLAEventHandler()));
} catch(Exception e) {
logger.warn("Could not send a SLA Threshold Notification as a result of compute resource threshold " +
"[{}] being crossed", calculable.getId(), e);
}
}
}
/**
* Class that manages the persistence details for the Cybernode
*/
class CybernodeLogHandler extends LogHandler implements SnapshotHandler {
public void snapshot(OutputStream out) throws IOException {
ObjectOutputStream oostream = new ObjectOutputStream(out);
oostream.writeUTF(CybernodeImpl.class.getName());
oostream.writeInt(LOG_VERSION);
oostream.flush();
}
public void recover(InputStream in) throws Exception {
ObjectInputStream oistream = new ObjectInputStream(in);
if(!CybernodeImpl.class.getName().equals(oistream.readUTF()))
throw new IOException("Log from wrong implementation");
if(oistream.readInt() != LOG_VERSION)
throw new IOException("Wrong log format version");
}
/**
* This method always throws <code>UnsupportedOperationException</code>
* since <code>CybernodeLogHandler</code> should never update a log.
*/
public void applyUpdate(Object update) throws Exception {
throw new UnsupportedOperationException("CybernodeLogHandler : "+
"Recovering log update this "+
"should not happen");
}
public void updatePerformed(int updateCount) {
// empty implementation
}
public void takeSnapshot() throws IOException {
store.snapshot();
}
}
/*---------------------
* Cybernode
* --------------------*/
/*
* @see org.rioproject.cybernode.Cybernode#enlist
*/
public void enlist() {
doEnlist();
}
/*
* @see org.rioproject.cybernode.Cybernode#release(boolean)
*/
public void release(boolean terminateServices) {
doRelease();
setEnlisted(false);
}
private void doRelease() {
logger.debug("Unregister from ProvisionMonitor instances ");
svcConsumer.cancelRegistrations();
if(serviceTerminationOnUnregister)
container.terminateServices();
}
/*---------------------
* CybernodeAdmin
*---------------------*/
/*
* @see org.rioproject.cybernode.CybernodeAdmin#getServiceLimit
*/
public Integer getServiceLimit() {
return(serviceLimit);
}
/*
* @see org.rioproject.cybernode.CybernodeAdmin#setServiceLimit
*/
public void setServiceLimit(Integer limit) {
this.serviceLimit = limit;
svcConsumer.updateMonitors(serviceLimit);
}
/*
* @see org.rioproject.cybernode.CybernodeAdmin#getServiceCount
*/
public Integer getServiceCount() {
return(container.getServiceCounter());
}
/*
* @see org.rioproject.cybernode.CybernodeAdmin#getPersistentProvisioning
*/
public boolean getPersistentProvisioning() {
return(provisionEnabled);
}
/*
* @see org.rioproject.cybernode.CybernodeAdmin#setPersistentProvisioning
*/
public void setPersistentProvisioning(boolean provisionEnabled) throws IOException {
if(this.provisionEnabled==provisionEnabled)
return;
this.provisionEnabled = provisionEnabled;
if(this.provisionEnabled)
Environment.setupProvisionRoot(this.provisionEnabled, config);
computeResource.setPersistentProvisioning(this.provisionEnabled);
}
public double getUtilization() {
return(computeResource.getUtilization());
}
}