/* * 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.monitor.service; import com.sun.jini.proxy.BasicProxyTrustVerifier; import net.jini.config.Configuration; import net.jini.config.ConfigurationException; import net.jini.config.EmptyConfiguration; import net.jini.export.Exporter; import net.jini.id.Uuid; import net.jini.security.BasicProxyPreparer; import net.jini.security.ProxyPreparer; import net.jini.security.TrustVerifier; import net.jini.security.proxytrust.ServerProxyTrust; import org.rioproject.deploy.*; import org.rioproject.impl.config.ExporterConfig; import org.rioproject.impl.opstring.OAR; import org.rioproject.impl.opstring.OpString; import org.rioproject.impl.service.ServiceResource; import org.rioproject.monitor.ProvisionMonitor; import org.rioproject.monitor.ProvisionMonitorEvent; import org.rioproject.monitor.service.channel.ServiceChannel; import org.rioproject.monitor.service.channel.ServiceChannelEvent; import org.rioproject.monitor.service.channel.ServiceChannelListener; import org.rioproject.monitor.service.persistence.StateManager; import org.rioproject.monitor.service.tasks.RedeploymentTask; import org.rioproject.monitor.service.tasks.TaskTimer; import org.rioproject.opstring.*; import org.rioproject.resolver.RemoteRepository; import org.rioproject.resolver.ResolverHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.rmi.RemoteException; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; /** * The DefaultOpStringManager provides the management for an OperationalString that * has been deployed to the ProvisionMonitor */ @SuppressWarnings("PMD.ConstructorCallsOverridableMethod") public class DefaultOpStringManager implements OperationalStringManager, OpStringManager, ServerProxyTrust { /** Component name we use to find items in the configuration */ static final String CONFIG_COMPONENT = "org.rioproject.monitor"; /** ProvisionMonitor logger. */ static Logger logger = LoggerFactory.getLogger(DefaultOpStringManager.class); private OperationalString opString; /** * Collection of ServiceElementManager instances */ private final List<ServiceElementManager> svcElemMgrs = new ArrayList<ServiceElementManager>(); /** * Collection of nested DefaultOpStringManager instances */ private final List<OpStringManager> nestedManagers = new ArrayList<OpStringManager>(); /** * The DefaultOpStringManager parents for this DefaultOpStringManager */ private final List<OpStringManager> parents = new ArrayList<OpStringManager>(); /** * Property that indicates the mode of the DefaultOpStringManager. If active is * true, the DefaultOpStringManager will inform it's ServiceElementmanager * instances to actively provision services. If active is false, the * DefaultOpStringManager will inform its ServiceElementManager instances to * keep track of the service described by it's ServiceElement object but * not issue provision requests */ private final AtomicBoolean active = new AtomicBoolean(true); /** * The Exporter for the OperationalStringManager */ private Exporter exporter; /** * Object supporting remote semantics required for an * OperationalStringManager */ private OperationalStringManager proxy; /** * A List of scheduled TimerTasks */ private final List<TimerTask> scheduledTaskList = Collections.synchronizedList(new ArrayList<TimerTask>()); /** * A list a deployed Dates */ private final List<Date> deployDateList = Collections.synchronizedList(new ArrayList<Date>()); /** * Local copy of the deployment status of the OperationalString */ private int deployStatus; /** * ProxyPreparer for ServiceProvisionListener proxies */ private ProxyPreparer serviceProvisionListenerPreparer; /** The associated OperationalString archive (if any) */ private OAR oar; /** The service proxy for the ProvisionMonitor */ private ProvisionMonitor serviceProxy; private final Configuration config; private ProvisionMonitorEventProcessor eventProcessor; private final OpStringManagerController opStringMangerController; private StateManager stateManager; private ServiceProvisioner provisioner; private Uuid uuid; private boolean standAlone; private final OpStringManager parent; /** * Create an DefaultOpStringManager, making it available to receive incoming * calls supporting the OperationalStringManager interface * * @param opString The OperationalString to manage * @param parent The DefaultOpStringManager parent. May be null * @param config Configuration object * @param opStringMangerController The managing entity for OpStringManagers */ public DefaultOpStringManager(final OperationalString opString, final OpStringManager parent, final Configuration config, final OpStringManagerController opStringMangerController) { this.opString = opString; this.parent = parent; this.config = config; this.opStringMangerController = opStringMangerController; } public void initialize(final boolean mode) throws IOException { try { exporter = ExporterConfig.getExporter(config, CONFIG_COMPONENT, "opStringManagerExporter"); if (logger.isDebugEnabled()) logger.debug("Deployment [{}] using exporter {}", opString.getName(), exporter); /* Get the ProxyPreparer for ServiceProvisionListener instances */ Configuration myConfig = (config == null ? EmptyConfiguration.INSTANCE : config); serviceProvisionListenerPreparer = (ProxyPreparer) myConfig.getEntry(CONFIG_COMPONENT, "serviceProvisionListenerPreparer", ProxyPreparer.class, new BasicProxyPreparer()); } catch (ConfigurationException e) { logger.warn("Getting opStringManager Exporter", e); } proxy = (OperationalStringManager) exporter.export(this); this.active.set(mode); if (parent != null) { addParent(parent); parent.addNested(this); standAlone = false; } else { standAlone = opString.getNestedOperationalStrings().length==0; } if(logger.isDebugEnabled()) logger.debug("Manager for {} standAlone: {}", opString.getName(), standAlone); if (opString.loadedFrom() != null && opString.loadedFrom().toExternalForm().startsWith("file") && opString.loadedFrom().toExternalForm().endsWith(".oar")) { File f = new File(opString.loadedFrom().getFile()); try { oar = new OAR(f); oar.setDeployDir(f.getParent()); } catch (Exception e) { logger.warn("Could no create OAR", e); } } } public OperationalStringManager getOperationalStringManager() { return proxy; } public OAR getOAR() { return oar; } void setServiceProxy(final ProvisionMonitor serviceProxy) { this.serviceProxy = serviceProxy; } void setEventProcessor(final ProvisionMonitorEventProcessor eventProcessor) { this.eventProcessor = eventProcessor; } void setStateManager(final StateManager stateManager) { this.stateManager = stateManager; } /** * @see OpStringManager#getProxy() */ public OperationalStringManager getProxy() { return (proxy); } /** * Set the active mode. If the new mode is not equal to the old mode, * iterate through the Collection of ServiceElementManager instances and * set their mode to be equal to the DefaultOpStringManager mode * * @param newActive the new mode */ public synchronized void setActive(final boolean newActive) { synchronized (this) { if (active.get() != newActive) { active.set(newActive); List<ServiceElement> list = new ArrayList<ServiceElement>(); ServiceElementManager[] mgrs = getServiceElementManagers(); for (ServiceElementManager mgr : mgrs) { mgr.setActive(active.get()); list.add(mgr.getServiceElement()); } if (logger.isDebugEnabled()) logger.debug("OperationalStringManager for [{}] set active [{}] for OperationalString [{}]", getProxy().toString(), active, getName()); if (active.get()) { ServiceElement[] sElems = list.toArray(new ServiceElement[list.size()]); updateServiceElements(sElems); } /* Trickle down effect : update all nested managers of the * new active state */ OpStringManager[] nestedMgrs = nestedManagers.toArray(new OpStringManager[nestedManagers.size()]); for (OpStringManager nestedMgr : nestedMgrs) { nestedMgr.setActive(newActive); } } else { if (logger.isTraceEnabled()) logger.trace("OperationalStringManager for [{}] already has active state of [{}]", opString.getName(), active); } } } /** * Get the active property * * @return The active property */ public boolean isActive() { return active.get(); } /** * @see org.rioproject.opstring.OperationalStringManager#setManaging(boolean) */ public void setManaging(final boolean newActive) { setActive(newActive); } /** * @see org.rioproject.opstring.OperationalStringManager#isManaging */ public boolean isManaging() { return isActive(); } /** * @see org.rioproject.opstring.OperationalStringManager#getDeploymentDates */ public Date[] getDeploymentDates() { return deployDateList.toArray(new Date[deployDateList.size()]); } /** * @see OpStringManager#setDeploymentStatus(int) */ public void setDeploymentStatus(final int status) { opString.setDeployed(status); deployStatus = status; if (deployStatus == OperationalString.UNDEPLOYED) { if (!nestedManagers.isEmpty()) { OpStringManager[] nestedMgrs = nestedManagers.toArray(new OpStringManager[nestedManagers.size()]); for (OpStringManager nestedMgr : nestedMgrs) { if (nestedMgr.getParentCount() == 1 && !nestedMgr.isStandAlone()) nestedMgr.setDeploymentStatus(OperationalString.UNDEPLOYED); } } } } /** * @see OpStringManager#addDeploymentDate(java.util.Date) */ public void addDeploymentDate(final Date date) { if (date != null) deployDateList.add(date); } /** * Create all ServiceElementManager instances * * @param provisioner The ServiceProvisioner * @param uuid The Uuid of the ProvisionMonitorImpl. If the uuid of a * discovered service matches our uuid, don't spend the overhead of creating * a FaultDetectionHandler * @param listener A ServiceProvisionListener that will be notified * of services are they are provisioned. This notification approach is * only valid at DefaultOpStringManager creation (deployment), when services are * provisioned at OperationalString deployment time * @return A map of reasons and corresponding exceptions from creating * service element manager instances. If the map has no entries there * are no errors */ Map<String, Throwable> createServiceElementManagers(final ServiceProvisioner provisioner, final Uuid uuid, final ServiceProvisionListener listener) { this.provisioner = provisioner; this.uuid = uuid; Map<String, Throwable> map = new HashMap<String, Throwable>(); ServiceElement[] sElems = opString.getServices(); for (ServiceElement sElem : sElems) { try { if (sElem.getExportBundles().length > 0) { createServiceElementManager(sElem, false, listener); } else { String message = String.format("Service [%s] has no declared interfaces, cannot deploy", sElem.getName()); logger.warn(message); map.put(sElem.getName(), new Exception(message)); } } catch (Exception e) { Throwable cause = e.getCause(); if (cause == null) cause = e; logger.warn("Creating ServiceElementManager for [{}],deployment [{}]", sElem.getName(), sElem.getOperationalStringName(), e); map.put(sElem.getName(), cause); } } return (map); } /** * Start all ServiceElementManager instances * * @param listener A ServiceProvisionListener that will be notified * of services are they are provisioned. This notification approach is * only valid at DefaultOpStringManager creation (deployment), when services are * provisioned at OperationalString deployment time * * @throws java.rmi.RemoteException If the DeployAdmin cannot be obtained */ void startManager(final ServiceProvisionListener listener) throws RemoteException { startManager(listener, new HashMap()); } /** * Start all ServiceElementManager instances * * @param listener A ServiceProvisionListener that will be notified * of services are they are provisioned. This notification approach is * only valid at DefaultOpStringManager creation (deployment), when services are * provisioned at OperationalString deployment time * @param knownInstanceMap Known ServiceBeanInstance objects. * * @throws java.rmi.RemoteException If the DeployAdmin cannot be obtained */ void startManager(final ServiceProvisionListener listener, final Map knownInstanceMap) throws RemoteException { addDeploymentDate(new Date(System.currentTimeMillis())); setDeploymentStatus(OperationalString.DEPLOYED); ServiceElementManager[] mgrs = getServiceElementManagers(); IdleServiceListener idleServiceListener = null; UndeployOption undeployOption = opString.getUndeployOption(); if(undeployOption!=null && undeployOption.getType().equals(UndeployOption.Type.WHEN_IDLE)) { idleServiceListener = new IdleServiceListener(this); } for (ServiceElementManager mgr : mgrs) { ServiceElement elem = mgr.getServiceElement(); ServiceBeanInstance[] instances = (ServiceBeanInstance[]) knownInstanceMap.get(elem); try { int alreadyRunning = mgr.startManager(listener, instances); if(logger.isTraceEnabled()) { logger.trace("{} ServiceElementManager has {} instances already running {}", opString.getName(), elem.getName(), alreadyRunning); } if (alreadyRunning > 0) { updateServiceElements(new ServiceElement[]{mgr.getServiceElement()}); } if(idleServiceListener !=null) { logger.info("Deployment {} has an IDLE undeploy option; when: {}, timeUnit: {}", opString.getName(), undeployOption.getWhen(), undeployOption.getTimeUnit()); mgr.setIdleTime(undeployOption.getTimeUnit().toMillis(undeployOption.getWhen())); ServiceChannel.getInstance().subscribe(idleServiceListener, elem, ServiceChannelEvent.Type.IDLE); } } catch (Exception e) { logger.warn("Starting ServiceElementManager", e); } } if(logger.isTraceEnabled()) { logger.info("Started managers for {}", opString.getName()); } } class IdleServiceListener implements ServiceChannelListener { final OpStringManager manager; final Map<ServiceElement, Boolean> tracking = new HashMap<ServiceElement, Boolean>(); IdleServiceListener(OpStringManager manager) { this.manager = manager; } public void notify(ServiceChannelEvent event) { boolean undeploy = true; tracking.put(event.getServiceElement(), true); for(ServiceElementManager manager : getServiceElementManagers()) { if(manager.isTrackingIdleBehavior() && !tracking.containsKey(event.getServiceElement())) { undeploy = false; break; } } if(undeploy) { logger.info("Terminating [{}] due to idle services", getName()); opStringMangerController.undeploy(manager, true); } } } /** * Create a specific ServiceElementManager, add it to the Collection of * ServiceElementManager instances, and start the manager * * @param sElem The ServiceElement the ServiceElementManager will * manage * @param start Whether to start the ServiceElementManager at creation * discovered service matches our uuid, don't spend the overhead of creating * a FaultDetectionHandler * @param listener A ServiceProvisionListener that will be notified * of services are they are provisioned. This notification approach is * only valid when the ServiceElementManager is created, and services are * provisioned at OperationalString deployment time * @throws Exception if the ServiceElementManager cannot be created */ void createServiceElementManager(final ServiceElement sElem, final boolean start, final ServiceProvisionListener listener) throws Exception { ServiceElementManager svcElemMgr = new ServiceElementManager(sElem, proxy, provisioner, uuid, isActive(), config); /* Set event attributes */ svcElemMgr.setEventProcessor(eventProcessor); svcElemMgr.setEventSource(serviceProxy); svcElemMgrs.add(svcElemMgr); if (start) { int alreadyRunning = svcElemMgr.startManager(listener); if (alreadyRunning > 0) { updateServiceElements(new ServiceElement[]{sElem}); } } } /** * @see org.rioproject.opstring.OperationalStringManager#update(OperationalString) */ public Map<String, Throwable> update(final OperationalString newOpString) throws OperationalStringException, RemoteException { if (!isActive()) { OperationalStringManager primary = opStringMangerController.getPrimary(getName()); if (primary == null) { logger.warn("Primary testManager not located, force state to active for [{}]", getName()); setActive(true); } else { logger.info("Forwarding update request to primary testManager for [{}]", getName()); return (primary.update(newOpString)); } } try { opStringMangerController.getDeploymentVerifier().verifyOperationalString(newOpString, getRemoteRepositories()); } catch (Exception e) { throw new OperationalStringException("Verifying deployment for [" + newOpString.getName() + "]", e); } Map<String, Throwable> map = doUpdateOperationalString(newOpString); ProvisionMonitorEvent event = new ProvisionMonitorEvent(serviceProxy, ProvisionMonitorEvent.Action.OPSTRING_UPDATED, doGetOperationalString()); eventProcessor.processEvent(event); return (map); } public RemoteRepository[] getRemoteRepositories() { Collection<RemoteRepository> remoteRepositories = new ArrayList<RemoteRepository>(); if (oar != null) remoteRepositories.addAll(oar.getRepositories()); return remoteRepositories.toArray(new RemoteRepository[remoteRepositories.size()]); } /** * @see OpStringManager#doUpdateOperationalString(org.rioproject.opstring.OperationalString) */ public Map<String, Throwable> doUpdateOperationalString(final OperationalString newOpString) { if (newOpString == null) throw new IllegalArgumentException("OperationalString cannot be null"); if (logger.isInfoEnabled()) { logger.info("Updating {} deployment", newOpString.getName()); } Map<String, Throwable> map = new HashMap<String, Throwable>(); ServiceElement[] sElems = newOpString.getServices(); List<ServiceElementManager> notRefreshed = new ArrayList<ServiceElementManager>(svcElemMgrs); /* Refresh ServiceElementManagers */ for (ServiceElement sElem : sElems) { try { ServiceElementManager svcElemMgr = getServiceElementManager(sElem); if (svcElemMgr == null) { createServiceElementManager(sElem, true, null); } else { svcElemMgr.setServiceElement(sElem); notRefreshed.remove(svcElemMgr); } } catch (Exception e) { map.put(sElem.getName(), e); logger.warn("Refreshing ServiceElementManagers", e); } } /* * Process nested Operational Strings. If a nested * OperationalString does not exist it will be created. * If it does exist check the number of parents, if its only referenced * by this testManager update it */ OperationalString[] nested = newOpString.getNestedOperationalStrings(); for (int i = 0; i < nested.length; i++) { if (!opStringMangerController.opStringExists(nested[i].getName())) { try { opStringMangerController.addOperationalString(nested[i], map, this, null, null); } catch (Exception e) { Throwable cause = e.getCause(); if (cause == null) cause = e; map.put(sElems[i].getName(), cause); logger.warn("Adding nested OperationalString [{}]", nested[i].getName(), e); } } else { OpStringManager nestedMgr = opStringMangerController.getOpStringManager(nested[i].getName()); if (nestedMgr.getParentCount() == 1 && nestedMgr.getParents().contains(this)) { Map<String, Throwable> nestedMap = nestedMgr.doUpdateOperationalString(nested[i]); map.putAll(nestedMap); } } } /* * If there are ServiceElementManagers that are not needed * remove them */ for (ServiceElementManager mgr : notRefreshed) { mgr.stopManager(true); svcElemMgrs.remove(mgr); } opString = newOpString; stateChanged(false); if (isActive()) updateServiceElements(sElems); return (map); } /** * @see OpStringManager#getParents() */ public Collection<OpStringManager> getParents() { Collection<OpStringManager> rents = new ArrayList<OpStringManager>(); rents.addAll(parents); return rents; } private void stateChanged(final boolean remove) { if(stateManager!=null) stateManager.stateChanged(this, remove); } /** * Verify all services are being monitored by iterating through the * Collection of ServiceElementManager instances and invoking each * instance's verify() method * * @param listener A ServiceProvisionListener that will be notified * of services if they are provisioned. */ public void verify(final ServiceProvisionListener listener) { for (ServiceElementManager mgr : svcElemMgrs) { mgr.verify(listener); } for (OpStringManager nestedMgr : nestedManagers) { nestedMgr.verify(listener); } } /** * Update ServiceElement instances to ServiceBeanInstantiators which are * hosting the ServiceElement instance(s). If the OperationalStringManager * is not active. do not perform this task * * @param elements Array of ServiceElement instances to update */ void updateServiceElements(final ServiceElement[] elements) { if (!isActive()) return; ServiceResource[] resources = provisioner.getServiceResourceSelector().getServiceResources(); Map<InstantiatorResource, List<ServiceElement>> map =new HashMap<InstantiatorResource, List<ServiceElement>>(); for (ServiceResource resource : resources) { InstantiatorResource ir = (InstantiatorResource) resource.getResource(); for (ServiceElement element : elements) { int count = ir.getServiceElementCount(element); if (logger.isTraceEnabled()) logger.trace("{} at [{}] has [{}] of [{}]", ir.getName(), ir.getHostAddress(), count, element.getName()); if (count > 0) { List<ServiceElement> list = map.get(ir); if (list == null) list = new ArrayList<ServiceElement>(); list.add(element); map.put(ir, list); } } } for (Map.Entry<InstantiatorResource, List<ServiceElement>> entry : map.entrySet()) { InstantiatorResource ir = entry.getKey(); List<ServiceElement> list = entry.getValue(); ServiceElement[] elems = list.toArray(new ServiceElement[list.size()]); try { ServiceBeanInstantiator sbi = ir.getInstantiator(); if (logger.isTraceEnabled()) logger.trace("Update {} at [{}] with [{}] elements", ir.getName(), ir.getHostAddress(), elems.length); sbi.update(elems, getProxy()); } catch (RemoteException e) { if (logger.isTraceEnabled()) { logger.trace("Updating ServiceElement for {} at [{}]", ir.getName(), ir.getHostAddress(), e); } else { logger.info("{}: {} Updating ServiceElement for {} at [{}]", e.getClass().getName(), e.getMessage(), ir.getName(), ir.getHostAddress()); } } } } /** * @see OpStringManager#terminate(boolean) */ public OperationalString[] terminate(final boolean killServices) { List<OperationalString> terminated = new ArrayList<OperationalString>(); terminated.add(doGetOperationalString()); /* Cancel all scheduled Tasks */ TimerTask[] tasks = getTasks(); for (TimerTask task : tasks) task.cancel(); /* Unexport the testManager */ try { exporter.unexport(true); } catch (IllegalStateException e) { if (logger.isDebugEnabled()) logger.debug("OperationalStringManager not unexported"); } /* Remove ourselves from the collection */ if(opStringMangerController.remove(this)) { if(logger.isDebugEnabled()) logger.debug("Removed [{}]", getName()); } else { logger.warn("Did not remove [{}] when terminating", getName()); } /* Stop all ServiceElementManager instances */ for (ServiceElementManager mgr : svcElemMgrs) { mgr.stopManager(killServices); } /* Adjust parent/nested relationships */ if (!parents.isEmpty()) { for (OpStringManager parent : parents) { parent.removeNested(this); } parents.clear(); } OpStringManager[] nestedMgrs = nestedManagers.toArray(new OpStringManager[nestedManagers.size()]); for (OpStringManager nestedMgr : nestedMgrs) { /* If the nested DefaultOpStringManager has only 1 parent, then * terminate (undeploy) that DefaultOpStringManager as well */ if (nestedMgr.getParentCount() == 1 && !nestedMgr.isStandAlone()) { terminated.add(nestedMgr.doGetOperationalString()); nestedMgr.terminate(killServices); } else { nestedMgr.removeParent(this); } } if (logger.isInfoEnabled()) logger.info("OpStringManager [{}] terminated", getName()); return (terminated.toArray(new OperationalString[terminated.size()])); } /** * Get the name of this Operational String * * @return The name of this Operational String */ public String getName() { return (opString.getName()); } /* * @see org.rioproject.opstring.OperationalStringManager#addServiceElement */ public void addServiceElement(final ServiceElement sElem, final ServiceProvisionListener listener) throws OperationalStringException { if (sElem == null) throw new IllegalArgumentException("ServiceElement is null"); if (sElem.getOperationalStringName() == null) throw new IllegalArgumentException("ServiceElement must have an OperationalString name"); if (!sElem.getOperationalStringName().equals(opString.getName())) throw new IllegalArgumentException("ServiceElement has wrong OperationalString name. " + "Provided " +"[" + sElem.getOperationalStringName() + "], " + "should be [" + opString.getName() + "]"); if (!isActive()) throw new OperationalStringException("not the primary OperationalStringManager"); try { doAddServiceElement(sElem, listener); stateChanged(false); ProvisionMonitorEvent event = new ProvisionMonitorEvent(serviceProxy, ProvisionMonitorEvent.Action.SERVICE_ELEMENT_ADDED, sElem); eventProcessor.processEvent(event); } catch (Throwable t) { throw new OperationalStringException("Adding ServiceElement", t); } if (logger.isDebugEnabled()) logger.debug("Added service [{}/{}]", sElem.getOperationalStringName(), sElem.getName()); } /** * @see OpStringManager#doAddServiceElement(ServiceElement, ServiceProvisionListener) */ public void doAddServiceElement(final ServiceElement sElem, final ServiceProvisionListener listener) throws Exception { if (sElem.getExportBundles().length > 0) { /*File pomFile = null; if(oar!=null) { File dir = new File(oar.getDeployDir()); pomFile = OARUtil.find("pom.xml", dir); }*/ opStringMangerController.getDeploymentVerifier().verifyOperationalStringService(sElem, ResolverHelper.getResolver(), getRemoteRepositories()); createServiceElementManager(sElem, true, listener); opString.addService(sElem); stateChanged(true); } else { throw new OperationalStringException("Interfaces are null"); } } /* * @see org.rioproject.opstring.OperationalStringManager#removeServiceElement */ public void removeServiceElement(final ServiceElement sElem, final boolean destroy) throws OperationalStringException { if (sElem == null) throw new IllegalArgumentException("ServiceElement is null"); if (!isActive()) throw new OperationalStringException("not the primary OperationalStringManager"); try { doRemoveServiceElement(sElem, destroy); ProvisionMonitorEvent event = new ProvisionMonitorEvent(serviceProxy, ProvisionMonitorEvent.Action.SERVICE_ELEMENT_REMOVED, sElem); eventProcessor.processEvent(event); } catch (Throwable t) { if (t instanceof OperationalStringException) throw (OperationalStringException) t; throw new OperationalStringException("Removing ServiceElement", t); } if (logger.isDebugEnabled()) logger.debug("Removed service [{}/{}]", sElem.getOperationalStringName(), sElem.getName()); } /** * @see OpStringManager#doRemoveServiceElement(ServiceElement, boolean) */ public void doRemoveServiceElement(final ServiceElement sElem, final boolean destroy)throws OperationalStringException { ServiceElementManager svcElemMgr = getServiceElementManager(sElem); if (svcElemMgr == null) throw new OperationalStringException("OperationalStringManager for [" + opString.getName() + "], " + "is not managing service " + "[" +sElem.getOperationalStringName() +"/" +sElem.getName() +"]", false); svcElemMgr.stopManager(destroy); if (!svcElemMgrs.remove(svcElemMgr)) logger.warn("UNABLE to remove ServiceElementManager for [{}/{}]", sElem.getOperationalStringName(), sElem.getName()); else { logger.info(String.format("Removed ServiceElementManager for [%s/%s]", sElem.getOperationalStringName(), sElem.getName())); opString.removeService(sElem); stateChanged(true); } } /* * @see org.rioproject.opstring.OperationalStringManager#update */ public void update(final ServiceElement sElem) throws OperationalStringException { if (sElem == null) throw new IllegalArgumentException("ServiceElement is null"); if (!isActive()) throw new OperationalStringException("not the primary OperationalStringManager"); try { doUpdateServiceElement(sElem); ProvisionMonitorEvent.Action action = ProvisionMonitorEvent.Action.SERVICE_ELEMENT_UPDATED; ProvisionMonitorEvent event = new ProvisionMonitorEvent(serviceProxy, action, sElem); eventProcessor.processEvent(event); } catch (Throwable t) { logger.warn("Updating ServiceElement [{}]", sElem.getName(), t); throw new OperationalStringException("Updating ServiceElement [" + sElem.getName() + "]", t); } } /** * @see OpStringManager#doUpdateServiceElement(ServiceElement) */ public void doUpdateServiceElement(final ServiceElement sElem) throws Exception { ServiceElementManager svcElemMgr = getServiceElementManager(sElem); if (svcElemMgr == null) { doAddServiceElement(sElem, null); } else { svcElemMgr.setServiceElement(sElem); svcElemMgr.verify(null); stateChanged(false); updateServiceElements(new ServiceElement[]{sElem}); } } /** * @see org.rioproject.opstring.OperationalStringManager#relocate */ public void relocate(final ServiceBeanInstance instance, final ServiceProvisionListener listener, final Uuid uuid) throws OperationalStringException, RemoteException { if (instance == null) throw new IllegalArgumentException("instance is null"); if (!isActive()) throw new OperationalStringException("not the primary OperationalStringManager"); ServiceProvisionListener preparedListener = null; if (listener != null) preparedListener = (ServiceProvisionListener) serviceProvisionListenerPreparer.prepareProxy(listener); try { ServiceElementManager svcElemMgr = getServiceElementManager(instance); if (svcElemMgr == null) throw new OperationalStringException("Unmanaged ServiceBeanInstance " + "[" + instance.getServiceBeanConfig().getName() + "], " + "[" + instance.toString() + "]", false); if (svcElemMgr.getServiceElement().getProvisionType() != ServiceElement.ProvisionType.DYNAMIC) throw new OperationalStringException("Service must be dynamic to be relocated"); svcElemMgr.relocate(instance, preparedListener, uuid); } catch (Throwable t) { logger.warn("Relocating ServiceBeanInstance {}: {}", t.getClass().getName(), t.getMessage()); if (t instanceof OperationalStringException) throw (OperationalStringException) t; throw new OperationalStringException("Relocating ServiceBeanInstance", t); } } /** * @see org.rioproject.opstring.OperationalStringManager#update */ public void update(final ServiceBeanInstance instance) throws OperationalStringException { if (instance == null) throw new IllegalArgumentException("instance is null"); try { ServiceElement sElem = doUpdateServiceBeanInstance(instance); ProvisionMonitorEvent event = new ProvisionMonitorEvent(serviceProxy, sElem.getOperationalStringName(), instance); eventProcessor.processEvent(event); } catch (Throwable t) { logger.warn("Updating ServiceBeanInstance [{}] {}: {}", instance.getServiceBeanConfig().getName(), t.getClass().getName(), t.getMessage()); throw new OperationalStringException("Updating ServiceBeanInstance", t); } } /** * @see OpStringManager#doUpdateServiceBeanInstance(ServiceBeanInstance) */ public ServiceElement doUpdateServiceBeanInstance(final ServiceBeanInstance instance) throws OperationalStringException { ServiceElementManager svcElemMgr = getServiceElementManager(instance); if (svcElemMgr == null) throw new OperationalStringException("Unmanaged ServiceBeanInstance [" + instance.toString() + "]", false); svcElemMgr.update(instance); return (svcElemMgr.getServiceElement()); } /* * @see org.rioproject.opstring.OperationalStringManager#increment */ public synchronized void increment(final ServiceElement sElem, final boolean permanent, final ServiceProvisionListener listener) throws OperationalStringException, RemoteException { if (sElem == null) throw new IllegalArgumentException("ServiceElement is null"); if (!isActive()) throw new OperationalStringException("not the primary OperationalStringManager"); ServiceProvisionListener preparedListener = null; if (listener != null) preparedListener = (ServiceProvisionListener) serviceProvisionListenerPreparer.prepareProxy(listener); try { ServiceElementManager svcElemMgr = getServiceElementManager(sElem); if (svcElemMgr == null) throw new OperationalStringException("Unmanaged ServiceElement [" + sElem.getName() + "]", false); ServiceElement changed = svcElemMgr.increment(permanent, preparedListener); if (changed == null) return; stateChanged(false); updateServiceElements(new ServiceElement[]{changed}); ProvisionMonitorEvent event = new ProvisionMonitorEvent(serviceProxy, ProvisionMonitorEvent.Action.SERVICE_BEAN_INCREMENTED, changed); eventProcessor.processEvent(event); } catch (Throwable t) { String message = String.format("Incrementing ServiceElement [%s] %s: %s" , sElem.getName(), t.getClass().getName(), t.getMessage()); logger.warn(message); throw new OperationalStringException(message, t); } } /* * @see org.rioproject.opstring.OperationalStringManager#getPendingCount */ public int getPendingCount(final ServiceElement sElem) { if (sElem == null) throw new IllegalArgumentException("ServiceElement is null"); int numPending = -1; ServiceElementManager svcElemMgr = getServiceElementManager(sElem); if (svcElemMgr != null) numPending = svcElemMgr.getPendingCount(); return (numPending); } /* * @see org.rioproject.opstring.OperationalStringManager#trim */ public int trim(final ServiceElement sElem, final int trimUp) throws OperationalStringException { if (sElem == null) throw new IllegalArgumentException("ServiceElement is null"); if (!isActive()) throw new OperationalStringException("not the primary OperationalStringManager"); if (sElem.getProvisionType() != ServiceElement.ProvisionType.DYNAMIC) return (-1); int numTrimmed; try { ServiceElementManager svcElemMgr = getServiceElementManager(sElem); if (svcElemMgr == null) throw new OperationalStringException("Unmanaged ServiceElement [" + sElem.getName() + "]", false); numTrimmed = svcElemMgr.trim(trimUp); if (numTrimmed > 0) { stateChanged(false); ServiceElement updatedElement = svcElemMgr.getServiceElement(); updateServiceElements(new ServiceElement[]{updatedElement}); ProvisionMonitorEvent event = new ProvisionMonitorEvent(serviceProxy, ProvisionMonitorEvent.Action.SERVICE_BEAN_DECREMENTED, updatedElement); eventProcessor.processEvent(event); } return (numTrimmed); } catch (Throwable t) { logger.warn("Trimming ServiceElement [{}] {}: {}",sElem.getName(), t.getClass().getName(), t.getMessage()); throw new OperationalStringException("Trimming ServiceElement ["+sElem.getName()+"]", t); } } /* * @see org.rioproject.opstring.OperationalStringManager#decrement */ public void decrement(final ServiceBeanInstance instance, final boolean recommended, final boolean destroy) throws OperationalStringException { if (instance == null) throw new IllegalArgumentException("instance is null"); if (!isActive()) throw new OperationalStringException("not the primary OperationalStringManager"); ServiceElementManager svcElemMgr = getServiceElementManager(instance); if (svcElemMgr == null) throw new OperationalStringException("Unmanaged ServiceBeanInstance [" + instance.toString() + "]", false); ServiceElement sElem = svcElemMgr.decrement(instance, recommended, destroy); if(sElem==null) return; stateChanged(false); updateServiceElements(new ServiceElement[]{sElem}); ProvisionMonitorEvent event = new ProvisionMonitorEvent(serviceProxy, ProvisionMonitorEvent.Action.SERVICE_BEAN_DECREMENTED, sElem.getOperationalStringName(), sElem, instance); eventProcessor.processEvent(event); } /** * Determine of this DefaultOpStringManager has any parents * * @return If true, this DefaultOpStringManager is top-level (has no * parents) */ public boolean isTopLevel() { return parents.isEmpty(); } /* * @see org.rioproject.opstring.OperationalStringManager#getOperationalString */ public OperationalString getOperationalString() { return (doGetOperationalString()); } /* * @see org.rioproject.opstring.OperationalStringManager#getServiceElement */ public ServiceElement getServiceElement(final Object proxy) { if (proxy == null) throw new IllegalArgumentException("proxy is null"); ServiceElementManager mgr = null; try { mgr = getServiceElementManager(proxy); } catch (IOException e) { if (logger.isTraceEnabled()) logger.trace("Getting ServiceElementManager for proxy", e); } if (mgr == null) logger.warn("No ServiceElementManager found for proxy {}", proxy); ServiceElement element = null; if (mgr != null) { element = mgr.getServiceElement(); } return (element); } /* * @see org.rioproject.opstring.OperationalStringManager#getServiceBeanInstances */ public ServiceBeanInstance[] getServiceBeanInstances(final ServiceElement sElem) throws OperationalStringException { if (sElem == null) throw new IllegalArgumentException("ServiceElement is null"); try { ServiceElementManager mgr = getServiceElementManager(sElem); if (mgr == null) throw new OperationalStringException("Unmanaged ServiceElement [" + sElem.getName() + "]", false); return (mgr.getServiceBeanInstances()); } catch (Exception e) { if (e instanceof OperationalStringException) { throw (OperationalStringException) e; } else { logger.warn("Getting ServiceBeanInstances for ServiceElement [{}]", sElem.getName(), e); throw new OperationalStringException("Getting ServiceBeanInstances for ServiceElement " + "["+sElem.getName() + "]", e); } } } /* * @see org.rioproject.opstring.OperationalStringManager#getServiceElement */ public ServiceElement getServiceElement(final String[] interfaces, final String name) { if (interfaces == null) throw new IllegalArgumentException("interfaces cannot be null"); for (ServiceElementManager mgr : svcElemMgrs) { ServiceElement sElem = mgr.getServiceElement(); boolean found = false; ClassBundle[] exports = sElem.getExportBundles(); for (ClassBundle export : exports) { boolean matched = false; for (String anInterface : interfaces) { if (export.getClassName().equals(anInterface)) matched = true; } if (matched) { found = true; break; } } if (found) { if (name == null) return (sElem); if (name.equals(sElem.getName())) return (sElem); } } return (null); } /** * Get the OperationalString the DefaultOpStringManager is managing * * @return The OperationalString the DefaultOpStringManager is managing */ public OperationalString doGetOperationalString() { OpString opstr = new OpString(opString.getName(), opString.loadedFrom()); opstr.setDeployed(deployStatus); for (ServiceElementManager mgr : svcElemMgrs) { opstr.addService(mgr.getServiceElement()); } for (OpStringManager nestedMgr : nestedManagers) { opstr.addOperationalString(nestedMgr.doGetOperationalString()); } opString = opstr; return (opString); } /** * @see org.rioproject.opstring.OperationalStringManager#redeploy(ServiceElement, * ServiceBeanInstance, boolean, boolean, long, ServiceProvisionListener) */ public void redeploy(final ServiceElement sElem, final ServiceBeanInstance instance, final boolean clean, final long delay, final ServiceProvisionListener listener) throws OperationalStringException { redeploy(sElem, instance, clean, true, delay, listener); } /** * @see org.rioproject.opstring.OperationalStringManager#redeploy(ServiceElement, * ServiceBeanInstance, boolean, long, ServiceProvisionListener) */ public void redeploy(final ServiceElement sElem, final ServiceBeanInstance instance, final boolean clean, final boolean sticky, final long delay, final ServiceProvisionListener listener) throws OperationalStringException { if (!isActive()) throw new OperationalStringException("not the primary OperationalStringManager"); ServiceProvisionListener preparedListener = null; if (listener != null) { try { preparedListener = (ServiceProvisionListener) serviceProvisionListenerPreparer.prepareProxy(listener); } catch (RemoteException e) { logger.trace("Notifying ServiceProvisionListener of redeployment, continue with redeployment.", e); } } if (delay > 0) { doScheduleRedeploymentTask(delay, sElem, instance, clean, sticky, preparedListener); } else { if (sElem == null && instance == null) doRedeploy(clean, sticky, preparedListener); else doRedeploy(sElem, instance, clean, sticky, preparedListener); } } /** * @see org.rioproject.opstring.OperationalStringManager#getServiceStatements */ public ServiceStatement[] getServiceStatements() { List<ServiceStatement> statements = new ArrayList<ServiceStatement>(); for (ServiceElementManager mgr : getServiceElementManagers()) { statements.add(mgr.getServiceStatement()); } return statements.toArray(new ServiceStatement[statements.size()]); } /** * @see org.rioproject.opstring.OperationalStringManager#getDeploymentMap */ public DeploymentMap getDeploymentMap() { Map<ServiceElement, List<DeployedService>> map = new HashMap<ServiceElement, List<DeployedService>>(); for (ServiceElementManager mgr : getServiceElementManagers()) { map.put(mgr.getServiceElement(), mgr.getServiceDeploymentList()); } return new DeploymentMap(map); } /* * Redeploy the OperationalString */ public void doRedeploy(final boolean clean, final boolean sticky, final ServiceProvisionListener listener) throws OperationalStringException { if (!isActive()) throw new OperationalStringException("not the primary OperationalStringManager"); for (ServiceElementManager mgr : svcElemMgrs.toArray(new ServiceElementManager[svcElemMgrs.size()])) doRedeploy(mgr.getServiceElement(), null, clean, sticky, listener); } /* * Redeploy a ServiceElement or a ServiceBeanInstance */ public void doRedeploy(final ServiceElement sElem, final ServiceBeanInstance instance, final boolean clean, final boolean sticky, final ServiceProvisionListener listener) throws OperationalStringException { if (!isActive()) throw new OperationalStringException("not the primary OperationalStringManager"); ServiceElementManager svcElemMgr = null; RedeploymentTask scheduledTask = null; if (sElem != null) { svcElemMgr = getServiceElementManager(sElem); scheduledTask = getScheduledRedeploymentTask(sElem, null); } else if (instance != null) { svcElemMgr = getServiceElementManager(instance); scheduledTask = getScheduledRedeploymentTask(null, instance); } if (svcElemMgr == null) { String message = sElem==null? "Unmanaged ServiceElement" :"Unmanaged ServiceElement [" + sElem.getName() + "]"; throw new OperationalStringException(message); } if (scheduledTask != null) { long exec = (scheduledTask.scheduledExecutionTime() - System.currentTimeMillis()) / 1000; if (exec > 0) { String item = (sElem == null ? "ServiceBeanInstance" : "ServiceElement"); throw new OperationalStringException(item+" already scheduled for redeployment in "+exec+" seconds"); } } /* Redeployment is for a ServiceElement */ if (sElem != null) { ServiceBeanInstance[] instances = svcElemMgr.getServiceBeanInstances(); if (instances.length > 0) { for (ServiceBeanInstance inst : instances) svcElemMgr.redeploy(inst, clean, sticky, listener); } else { svcElemMgr.redeploy(listener); } /* Redeployment is for a ServiceBeanInstance */ } else { svcElemMgr.redeploy(instance, clean, sticky, listener); } } /** * @see OpStringManager#doScheduleRedeploymentTask(long, ServiceElement, ServiceBeanInstance, boolean, boolean, ServiceProvisionListener) */ public void doScheduleRedeploymentTask(final long delay, final ServiceElement sElem, final ServiceBeanInstance instance, final boolean clean, final boolean sticky, final ServiceProvisionListener listener) throws OperationalStringException { RedeploymentTask scheduledTask = getScheduledRedeploymentTask(sElem, instance); if (scheduledTask != null) { long exec = (scheduledTask.scheduledExecutionTime() - System.currentTimeMillis()) / 1000; throw new OperationalStringException("Already " + "scheduled " + "for redeployment " + "in " + exec + " seconds"); } RedeploymentTask task = new RedeploymentTask(this, sElem, instance, clean, sticky, listener); addTask(task); TaskTimer.getInstance().schedule(task, delay); Date redeployDate = new Date(System.currentTimeMillis() + delay); Object[] parms = new Object[]{redeployDate, clean, sticky, listener}; ProvisionMonitorEvent event = new ProvisionMonitorEvent(serviceProxy, opString.getName(), sElem, instance, parms); eventProcessor.processEvent(event); if (logger.isTraceEnabled()) { String name = (instance == null ? sElem.getName() : instance.getServiceBeanConfig().getName()); String item = (instance == null ? "ServiceElement" : "ServiceBeanInstance"); logger.trace("Schedule [{}] {} redeploy in [{}] millis", name, item, delay); } } /** * Check for a scheduled RedeploymentTask for either the ServiceElement or * theServiceBeanInstance. * * @param sElem the ServiceElement to check * @param instance The corresponding ServiceBeanInstance * @return The scheduled RedeploymentTask, or null if not found */ RedeploymentTask getScheduledRedeploymentTask(final ServiceElement sElem, final ServiceBeanInstance instance) { TimerTask[] tasks = getTasks(); RedeploymentTask scheduledTask = null; for (TimerTask task : tasks) { if (task instanceof RedeploymentTask) { RedeploymentTask rTask = (RedeploymentTask) task; if (sElem != null && rTask.getServiceElement() != null) { if (rTask.getServiceElement().equals(sElem)) { scheduledTask = rTask; break; } if (instance != null && rTask.getInstance() != null) { if (rTask.getInstance().equals(instance)) { scheduledTask = rTask; break; } } } } } return (scheduledTask); } /** * Get all ServiceElementManager instances * * @return All ServiceElementManager instances as an array */ public ServiceElementManager[] getServiceElementManagers() { return (svcElemMgrs.toArray(new ServiceElementManager[svcElemMgrs.size()])); } /** * @see OpStringManager#getServiceElementManager(ServiceElement) */ public ServiceElementManager getServiceElementManager(final ServiceElement sElem) { for (ServiceElementManager mgr : svcElemMgrs) { ServiceElement sElem1 = mgr.getServiceElement(); if (sElem.equals(sElem1)) { return (mgr); } } return (null); } /** * Get the ServiceElementManager for a ServiceBeanInstance instance * * @param instance The ServiceBeanInstance instance * @return The ServiceElementManager that is * managing the ServiceElement. If no ServiceElementManager is found, * null is returned */ ServiceElementManager getServiceElementManager(final ServiceBeanInstance instance) { for (ServiceElementManager mgr : svcElemMgrs) { if (mgr.hasServiceBeanInstance(instance)) return (mgr); } return (null); } /** * Get the ServiceElementManager from a service proxy * * @param proxy The service proxy * @return The ServiceElementManager that is * managing the ServiceElement. If no ServiceElementManager is found, * null is returned * @throws IOException If the service proxy from a ServiceBeanInstance * returned from a ServiceElementManager cannot be unmarshalled */ ServiceElementManager getServiceElementManager(final Object proxy) throws IOException { for (ServiceElementManager mgr : svcElemMgrs) { ServiceBeanInstance[] instances = mgr.getServiceBeanInstances(); for (ServiceBeanInstance instance : instances) { try { if (instance.getService().equals(proxy)) return (mgr); } catch (ClassNotFoundException e) { logger.warn("Unable to obtain proxy", e); } } } return (null); } /** * @see OpStringManager#addNested(OpStringManager) */ public void addNested(final OpStringManager nestedMgr) { nestedManagers.add(nestedMgr); nestedMgr.addParent(this); } /** * Remove a nested OpStringManager * * @param nestedMgr The nested OpStringManager to remove */ public void removeNested(final OpStringManager nestedMgr) { nestedManagers.remove(nestedMgr); } /** * Add a parent for this OpStringManager. This OpStringManager will * now be a nested OpStringManager * * @param parent The parent for this OpStringManager. */ public void addParent(final OpStringManager parent) { if (parents.contains(parent)) return; parents.add(parent); } /** * Remove a parent from this OpStringManager. * * @param parent The parent to remove */ public void removeParent(final OpStringManager parent) { parents.remove(parent); } /** * Get the number of parents the OpStringManager has * * @return The number of parents the OpStringManager has */ public int getParentCount() { return (parents.size()); } public boolean isStandAlone() { return standAlone; } /** * Returns a <code>TrustVerifier</code> which can be used to verify that a * given proxy to this policy handler can be trusted */ public TrustVerifier getProxyVerifier() { return (new BasicProxyTrustVerifier(proxy)); } /** * Get all in process TimerTask instances * * @return Array of in process TimerTask instances. If there are no * TimerTask instances return a zero-length array */ TimerTask[] getTasks() { return (scheduledTaskList.toArray(new TimerTask[scheduledTaskList.size()])); } /** * Add a TimerTask to the Collection of TimerTasks * * @param task The TimerTask to add */ public void addTask(final TimerTask task) { if (task != null) scheduledTaskList.add(task); } /** * Remove a TimerTask from Collection of scheduled TimerTask * instances * * @param task The TimerTask to remove */ public void removeTask(final TimerTask task) { if (task != null) scheduledTaskList.remove(task); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; DefaultOpStringManager manager = (DefaultOpStringManager) o; return opString.getName().equals(manager.opString.getName()); } @Override public int hashCode() { return opString.getName().hashCode(); } }