/* * 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.managers; import org.rioproject.impl.servicebean.ServiceElementUtil; import org.rioproject.monitor.*; import org.rioproject.monitor.service.InstantiatorResource; import org.rioproject.monitor.service.ProvisionException; import org.rioproject.monitor.service.ProvisionRequest; import org.rioproject.monitor.service.ServiceProvisionContext; import org.rioproject.monitor.service.tasks.ProvisionFailureEventTask; import org.rioproject.monitor.service.tasks.ProvisionTask; import org.rioproject.monitor.service.util.LoggingUtil; import org.rioproject.impl.service.ServiceResource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; /** * Manages services of type fixed. */ public class FixedServiceManager extends PendingServiceElementManager { private final List<ServiceResource> inProcessResource = Collections.synchronizedList(new ArrayList<ServiceResource>()); private final ServiceProvisionContext context; private final Logger logger = LoggerFactory.getLogger(FixedServiceManager.class); /** * Create a FixedServiceManager * * @param context The ServiceProvisionContext */ public FixedServiceManager(final ServiceProvisionContext context) { super("Fixed-Service TestManager"); this.context = context; } /** * Process the entire Fixed collection over all known ServiceResource * instances */ @Override public void process() { ServiceResource[] resources = context.getSelector().getServiceResources(); logger.debug("{} processing {} resources", getType(), resources.length); for (ServiceResource resource : resources) { process(resource); } } /** * Used to deploy a specific ProvisionRequest to all ServiceResource * instances that support the requirements of the ServiceElement * * @param request The ProvisionRequest to deploy */ public void deploy(final ProvisionRequest request) { deploy(request, null); } /** * Used to deploy a specific ProvisionRequest to a specific ServiceResource * instance. * * @param request The ProvisionRequest to deploy */ public void deploy(final ProvisionRequest request, String hostAddress) { try { logger.debug("Deploy [{}]", LoggingUtil.getLoggingName(request) ); ServiceResource[] resources; boolean changeInstanceId; if(hostAddress==null) { resources = context.getSelector().getServiceResources(request); changeInstanceId = true; } else { resources = context.getSelector().getServiceResources(hostAddress, true); changeInstanceId = false; } logger.debug("{} processing {} resources", getType(), resources.length); /* Filter out isolated associations and max per machine levels * set at the physical level */ resources = context.getSelector().filterMachineBoundaries(request, resources); if (resources.length > 0) resources = context.getSelector().filterIsolated(request, resources); if (resources.length > 0) { for (ServiceResource resource : resources) { try { inProcessResource.add(resource); doDeploy(resource, request, changeInstanceId); } finally { inProcessResource.remove(resource); } } } } catch (Throwable t) { logger.warn("FixedServiceManager deployNew", t); } } /* * Process the fixed services collection with an input ServiceResource */ public void process(final ServiceResource resource) { if (resource == null) throw new IllegalArgumentException("ServiceResource is null"); if (inProcessResource.contains(resource)) return; inProcessResource.add(resource); InstantiatorResource ir = (InstantiatorResource) resource.getResource(); logger.trace("{} processing {}", getType(), ir.getName()); try { if(getSize() == 0) return; if(logger.isTraceEnabled()) { dumpCollection(); } /* Now traverse the collection for everything else, skipping * the service elements that have been processed */ synchronized (collection) { Set<Key> requests = collection.keySet(); int numDeployed = 0; for (Key requestKey : requests) { ProvisionRequest request = collection.get(requestKey); try { if (clearedMaxPerMachineAndIsolated(request, ir.getHostAddress()) && ir.canProvision(request)) { numDeployed = doDeploy(resource, request); } } catch (ProvisionException e) { request.setType(ProvisionRequest.Type.UNINSTANTIABLE); logger.warn("Service [{}] is un-instantiable, do not resubmit", LoggingUtil.getLoggingName(request)); processProvisionFailure(request, e); } } } } catch (Throwable t) { logger.warn("Processing FixedService Collection", t); } finally { inProcessResource.remove(resource); ir.setDynamicEnabledOn(); } } /* * Helper method to dispatch a ProvisionFailureEventTask and send a ProvisionFailureEvent */ void processProvisionFailure(ProvisionRequest request, Exception e) { ProvisionFailureEvent event = new ProvisionFailureEvent(context.getEventSource(), request.getServiceElement(), request.getFailureReasons(), e); context.getProvisionFailurePool().execute(new ProvisionFailureEventTask(event, context.getFailureHandler())); } /** * Do the deployment for a fixed service * * @param resource The ServiceResource * @param request The ProvisionRequest * @return The number deployed * @throws Exception If there are errors */ private int doDeploy(final ServiceResource resource, final ProvisionRequest request) throws Exception { return (doDeploy(resource, request, true)); } /** * Do the deployment for a fixed service * * @param resource The ServiceResource * @param req The ProvisionRequest * @param changeInstanceID If true, increment the instanceID * @return The number deployed * @throws Exception If there are errors */ private int doDeploy(final ServiceResource resource, final ProvisionRequest req, final boolean changeInstanceID) throws Exception { int numAllowed = getNumAllowed(resource, req); if (numAllowed > 0) { long currentID = req.getServiceElement().getServiceBeanConfig().getInstanceID(); StringBuilder b = new StringBuilder(); b.append("doDeploy ").append(numAllowed).append(" ["); b.append(LoggingUtil.getLoggingName(req)).append("] instances"); for (int i = 0; i < numAllowed; i++) { ProvisionRequest request = ProvisionRequest.copy(req); ServiceProvisionContext spc = getServiceProvisionContext(); long nextID = (changeInstanceID ? request.getInstanceIDMgr().getNextInstanceID() : currentID); if(changeInstanceID) logger.warn("[{}] Changing instanceID", LoggingUtil.getLoggingName(request)); request.setServiceElement(ServiceElementUtil.prepareInstanceID(request.getServiceElement(), true, nextID)); logger.trace("[{}] instanceID : {}", LoggingUtil.getLoggingName(request), request.getServiceElement().getServiceBeanConfig().getInstanceID()); spc.getInProcess().add(request.getServiceElement()); spc.setProvisionRequest(request); spc.setServiceResource(resource); spc.getProvisioningPool().execute(new ProvisionTask(spc, null)); } logger.debug(b.toString()); } return (numAllowed); } /* * Determine how many services can be allocated based on how many * are already on the resource minus the number planned */ private int getNumAllowed(final ServiceResource resource, final ProvisionRequest request) { /* Filter out isolated associations and max per machine levels set * at the physical level */ InstantiatorResource ir = (InstantiatorResource) resource.getResource(); if (!clearedMaxPerMachineAndIsolated(request, ir.getHostAddress())) return 0; int planned = request.getServiceElement().getPlanned(); int actual = ir.getServiceElementCount(request.getServiceElement()); int numAllowed = planned - actual; if (request.getServiceElement().getMaxPerMachine() != -1 && request.getServiceElement().getMaxPerMachine() < numAllowed) numAllowed = request.getServiceElement().getMaxPerMachine(); logger.trace("Cybernode {} has {}, can accommodate {} of {}", ir.getName(), actual, numAllowed, LoggingUtil.getLoggingName(request)); return (numAllowed); } /* * Filter out isolated associations and max per machine levels set * at the physical level */ private boolean clearedMaxPerMachineAndIsolated(final ProvisionRequest request, final String hostAddress) { /* Filter out isolated associations and max per machine levels set * at the physical level */ ServiceResource[] sr = context.getSelector().filterMachineBoundaries(request, context.getSelector().getServiceResources(hostAddress, true)); if (sr.length == 0) return false; sr = context.getSelector().filterIsolated(request, sr); return sr.length != 0; } public ServiceProvisionContext getServiceProvisionContext() { return new ServiceProvisionContext(context.getSelector(), context.getProvisioningPool(), context.getInProcess(), context.getEventSource(), context.getWatch(), context.getDispatcher(), context.getProvisionFailurePool(), context.getFailureHandler(), context.getServiceProvisionEventSequenceNumber()); } }