/* * 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.deploy.ServiceProvisionListener; import org.rioproject.impl.servicebean.ServiceElementUtil; import org.rioproject.monitor.service.ProvisionRequest; import org.rioproject.monitor.service.util.LoggingUtil; import org.rioproject.opstring.ServiceElement; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; /** * Abstract class which will manage ProvisionRequest instances that are waiting * to be provisioned. There are two types of ServiceElements which require * management: * <ol> * <li>ServiceElement objects which could not be provisioned and need to be put * on a pending list. These elements have the provision type of DYNAMIC, and * will be provisioned when instantiation resources become available that meet * their operational requirements * <li>ServiceElement objects that will be provisioned to all instantiation * resources that match their operational requirements. These elements have the * provision type of FIXED * </ol> * * @author Dennis Reedy */ public abstract class PendingServiceElementManager { /** Sorted collection of pending provision requests */ protected final TreeMap<Key, ProvisionRequest> collection; /** Index into the collection to insert elements */ private long collectionIndex = 1; /** A descriptive String type */ private final String type; /** A Logger */ private final Logger logger = LoggerFactory.getLogger(PendingServiceElementManager.class.getName()); /** * A key for the sortable set */ static class Key implements Comparable { int priority; ServiceElement sElem; long index; long timestamp; Key(ServiceElement sElem, long index, long timestamp) { this.sElem = sElem; this.index = index; this.timestamp = timestamp; } /* * @see java.lang.Comparable#compareTo(java.lang.Object) */ public int compareTo(Object o) { if(!(o instanceof Key)) throw new ClassCastException(); if(this==o) return(0); Key that = (Key)o; int comparison; long now = System.currentTimeMillis(); /* The priority is the high order bit, if not set then check if * the ServiceElement objects are equal, if they are, make sure * instanceIDs are sorted. If the ServiceElement instances dont match, * compare on the timestamp, then the index */ if(this.priority==0 && that.priority==0) { if(this.sElem.equals(that.sElem)) { Long thisInstanceID = this.sElem.getServiceBeanConfig().getInstanceID(); Long thatInstanceID = that.sElem.getServiceBeanConfig().getInstanceID(); comparison = thisInstanceID.compareTo(thatInstanceID); } else { /* Dont have different timestamps, use index */ if(this.timestamp == that.timestamp) { comparison = (this.index>that.index ? 1 : -1); } else { /* age before beauty :) */ comparison = (( (now-this.timestamp) > (now-that.timestamp)) ?-1 : 1); } } } else { /* Priority based comparison, a higher the priority comes before * a lower one */ comparison = (this.priority>that.priority ? -1 : 1); } return(comparison); } } /** * Create a PendingServiceElementManager * * @param type A descriptive name for the Manager */ PendingServiceElementManager(String type) { collection = new TreeMap<Key, ProvisionRequest>(new Comparator<Key>() { public int compare(Key key1, Key key2) { return (key1).compareTo(key2); } }); this.type = type; } /** * @return The descriptive type of this Manager */ public String getType() { return (type); } /** * Add an element to the pending collection with an index * * @param request The ProvisionRequest * @param index The index of the ServiceElement * @return The index that was used to insert the ProvisionRequest into the * collection */ public long addProvisionRequest(ProvisionRequest request, long index) { long ndx; synchronized(collection) { Long keyIndex = (index == 0 ? collectionIndex++ : index); Key key = new Key(request.getServiceElement(), keyIndex, request.getTimestamp()); collection.put(key, request); ndx = keyIndex; } return (ndx); } /** * Get the size of the collection * * @return The size of the collection */ int getSize() { int size; synchronized(collection) { size = collection.size(); } return (size); } /** * Get the number of ServiceElement instances in the collection that match * provided ServiceElement * * @param sElem The ServiceElement to match * * @return The number of ServiceElement matches */ int getCount(ServiceElement sElem) { int count = 0; synchronized(collection) { Collection<ProvisionRequest> provisionRequests = collection.values(); for (ProvisionRequest pr : provisionRequests) { if (pr.getServiceElement().equals(sElem)) { count++; } } } return (count); } /** * Remove all ServiceElement instances from the collection * * @param sElem The ServiceElement * @param numToRemove The number to remove * * @return An array of ProvisionRequest instances that have been removed. If * there are no instances that have been removed, return an empty array */ public ProvisionRequest[] removeServiceElement(ServiceElement sElem, int numToRemove) { List<Key> removals = new ArrayList<Key>(); List<ProvisionRequest> removed = new ArrayList<ProvisionRequest>(); synchronized(collection) { Set<Key> keys = collection.keySet(); for (Key key : keys) { ProvisionRequest pr = collection.get(key); if (pr != null && sElem.equals(pr.getServiceElement())) removals.add(key); } } if(!removals.isEmpty()) { if(removals.size()>numToRemove) { removals = removals.subList((removals.size()-numToRemove), removals.size()); } logger.info("{}: removing [{}] [{}] instances", type, removals.size(), LoggingUtil.getLoggingName(sElem)); synchronized(collection) { for (Key removal : removals) { ProvisionRequest pr = collection.remove(removal); removed.add(pr); } } } return (removed.toArray(new ProvisionRequest[removed.size()])); } /** * Remove all ServiceElement instances from the collection * * @param sElem The ServiceElement * * @return An array of ProvisionRequest instances that have been removed. If * there are no instances that have been removed, return an empty array */ public ProvisionRequest[] removeServiceElement(ServiceElement sElem) { List<Key> removals = new ArrayList<Key>(); List<ProvisionRequest> removed = new ArrayList<ProvisionRequest>(); synchronized(collection) { Set<Key> keys = collection.keySet(); for (Key key : keys) { ProvisionRequest pr = collection.get(key); if (pr != null && sElem.equals(pr.getServiceElement())) removals.add(key); } } if(!removals.isEmpty()) { logger.debug("{}: removing [{}] [{}] instances", type, removals.size(), LoggingUtil.getLoggingName(sElem)); synchronized(collection) { for (Key removal : removals) { ProvisionRequest pr = collection.remove(removal); removed.add(pr); } } } else { logger.debug("{}: There are no pending instances of [{}] to remove ", type, LoggingUtil.getLoggingName(sElem)); } return (removed.toArray(new ProvisionRequest[removed.size()])); } /** * Determine if the ServiceElement is in the collection * * @param sElem The ServiceElement * * @return If found return true */ public boolean hasServiceElement(ServiceElement sElem) { boolean contains = false; synchronized(collection) { Set<Key> keys = collection.keySet(); for (Key key : keys) { ProvisionRequest pr = collection.get(key); if (sElem.equals(pr.getServiceElement())) { contains = true; break; } } } return (contains); } /** * For each ProvisionRequest in the Collection of ProvisionRequest instances, * which contain the ServiceElement, update the ProvisionRequest with the * provided ServiceElement * * @param sElem The ServiceElement * @param listener A ServiceProvisionListener to be notified */ public void updateProvisionRequests(ServiceElement sElem, ServiceProvisionListener listener) { synchronized(collection) { Set<Key> keys = collection.keySet(); for (Key key : keys) { ProvisionRequest pr = collection.get(key); if (sElem.equals(pr.getServiceElement())) { /* Preserve instance IDs */ Long id = pr.getServiceElement().getServiceBeanConfig().getInstanceID(); ServiceElement newElem = sElem; if (id != null) newElem = ServiceElementUtil.prepareInstanceID(sElem, id.intValue()); pr.setServiceElement(newElem); if(listener!=null) { pr.setServiceProvisionListener(listener); } } } } } /** * A concrete implementation on how to process the collection is required as * follows: The collection will be processed, attempting to have each * ServiceElement provisioned to available ServiceInstantiation resources. * Each element will be processed with it's ordinal index ensuring that if * there are no available resources it will be put back into the collection * in order */ public abstract void process(); /** * Get all ProvisionRequest instances * * @param sElem The ServiceElement to use * * @return An array of ProvisionRequest instances */ ProvisionRequest[] getProvisionRequests(ServiceElement sElem) { ProvisionRequest[] prs; synchronized(collection) { /* Get all ProvisionRequest instances */ if(sElem==null) { Collection<ProvisionRequest> c = collection.values(); prs = c.toArray(new ProvisionRequest[c.size()]); } else { /* Get the ProvisionRequest instances for a ServiceElement */ ArrayList<ProvisionRequest> items = new ArrayList<ProvisionRequest>(); Set<Key> keys = collection.keySet(); for (Key key : keys) { ProvisionRequest pr = collection.get(key); if (sElem.equals(pr.getServiceElement())) { items.add(pr); } } prs = items.toArray(new ProvisionRequest[items.size()]); } } return(prs); } /** * Dumps the contents of the collection */ public void dumpCollection() { if(logger.isTraceEnabled()) { ProvisionRequest[] elements = getProvisionRequests(null); StringBuilder buffer = new StringBuilder(); int x=1; buffer.append("\n"); buffer.append(type); buffer.append(" collection size : "); buffer.append(elements.length).append("\n"); buffer.append("--\n"); for (ProvisionRequest element : elements) { ServiceElement sElem = element.getServiceElement(); Long id = sElem.getServiceBeanConfig().getInstanceID(); buffer.append(x++); buffer.append(" "); buffer.append(sElem.getOperationalStringName()); buffer.append("/"); buffer.append(sElem.getName()); if(!type.startsWith("Fixed")) { buffer.append(" instanceID="); buffer.append(id); } buffer.append("\n"); } buffer.append("--"); logger.trace(buffer.toString()); } } }