/* * Copyright 2008 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 org.rioproject.associations.AssociationDescriptor; import org.rioproject.associations.AssociationType; import org.rioproject.impl.servicebean.ServiceElementUtil; import org.rioproject.opstring.ServiceElement; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Utility to match Associations to ServiceElements. * * @author Dennis Reedy */ public class AssociationMatcher { /** The Logger */ static final Logger logger = LoggerFactory.getLogger(AssociationMatcher.class); private static String errorMessage; /** * This method verifies whether the InstantiatorResource can support any * declared service colocation requirements * * @param sElem The ServiceElement * @param ir The InstantiatorResource * * @return Return true if the provided InstantiatorResource meets service * colocation requirements */ static boolean meetsColocationRequirements(final ServiceElement sElem, final InstantiatorResource ir) { boolean provisionable = true; AssociationDescriptor[] aDescs = sElem.getAssociationDescriptors(); for (AssociationDescriptor aDesc : aDescs) { boolean ok = false; if (aDesc.getAssociationType()==AssociationType.COLOCATED) { if (matches(aDesc, ir.getServiceElements())) { break; } } else { ok = true; } if (!ok) { provisionable = false; break; } } return(provisionable); } /** * This method verifies whether the InstantiatorResource can support any * declared service opposed requirements * * @param sElem The ServiceElement * @param ir The InstantiatorResource * * @return Return true if the provided InstantiatorResource meets service * opposed requirements */ static boolean meetsOpposedRequirements(final ServiceElement sElem, final InstantiatorResource ir) { return(meetsAssociatedRequirements(sElem, AssociationType.OPPOSED, ir, null)); } /** * This method verifies whether the InstantiatorResource can support any * declared service isolation requirements * * @param sElem The ServiceElement * @param ir The InstantiatorResource * @param known An array of InstantiatorResource instances that contain the * ServiceElement, may be null * * @return Return true if the provided InstantiatorResource meets service * isolation requirements */ public static boolean meetsIsolatedRequirements(final ServiceElement sElem, final InstantiatorResource ir, final InstantiatorResource[] known) { return(meetsAssociatedRequirements(sElem, AssociationType.ISOLATED, ir, known)); } /** * This method verifies whether the InstantiatorResource can support any * declared service associated requirements * * @param sElem The ServiceElement * @param type The AssociationType type * @param ir The InstantiatorResource * @param known An array of InstantiatorResource instances that contain the * ServiceElement, may be null * * @return Return true if the provided InstantiatorResource meets service * declared requirements */ private static boolean meetsAssociatedRequirements(final ServiceElement sElem, final AssociationType type, final InstantiatorResource ir, final InstantiatorResource[] known) { boolean provisionable = true; StringBuilder errorLog = new StringBuilder(); AssociationDescriptor[] aDescs = ServiceElementUtil.getAssociationDescriptors(sElem, type); /* Check in process elements, to see if they match any of the service's * opposed requirements */ for (AssociationDescriptor aDesc : aDescs) { if (matches(aDesc, ir.getServiceElementsInprocess(sElem))) { provisionable = false; break; } } /* Check running elements, to see if they match any of the service's * opposed requirements */ if (provisionable) { for (AssociationDescriptor aDesc : aDescs) { if (matches(aDesc, ir.getServiceElements())) { provisionable = false; break; } } } if (!provisionable) { String provType = sElem.getProvisionType().toString(); errorLog.append("Do not allocate ") .append(provType) .append(" service " + "[") .append(sElem.getName()) .append("] to ") .append(ir.getName()) .append(" at [") .append(ir.getHostAddress()) .append("], "); errorLog.append(type.toString()).append( ", services detected: "); for (int i = 0; i < aDescs.length; i++) { if (i > 0) errorLog.append(", "); errorLog.append("[") .append(i + 1) .append("] ") .append(aDescs[i].getName()); } } /* Check if any in process or running elements have an opposed or * isolated requirement to the service that needs to be provisioned */ if (provisionable) { StringBuffer b = new StringBuffer(); int found = getCount(sElem, ir.getServiceElements(), type, b); if(found==0) { found = getCount(sElem, ir.getServiceElementsInprocess(sElem), type, b); } if (found > 0) { String provType = sElem.getProvisionType().toString(); provisionable = false; errorLog.append("Do not allocate ") .append(provType) .append(" service " + "[") .append(sElem.getName()) .append("] to ") .append(ir.getName()) .append(" at [") .append(ir.getHostAddress()) .append("], ") .append("id ") .append("[") .append(ir.getInstantiatorUuid()) .append("], ") .append(found); errorLog.append(" service(s) have ") .append(type.toString()) .append(" associations: "); errorLog.append("{") .append(b.toString()) .append("}"); } } if(provisionable && known!=null && aDescs.length>0) { if(inKnownSet(ir, known)) provisionable = false; } errorMessage = errorLog.toString(); if (!provisionable && logger.isDebugEnabled()) logger.debug(errorLog.toString()); return (provisionable); } static String getLastErrorMessage() { return errorMessage; } /** * Determine if the {@link InstantiatorResource} is in the set of known * InstantiatorResources. Used to check isolated associations. * * @param candidate The InstantiatorResource to check * @param knownOnes Array of known InstantiatorResource instances * @return If the candidate has a host address that is in the known set, * return true, otherwise return false */ static boolean inKnownSet(final InstantiatorResource candidate, final InstantiatorResource[] knownOnes) { boolean inKnownSet = false; if(candidate!=null && knownOnes!=null) { for (InstantiatorResource knownOne : knownOnes) { if (candidate.getHostAddress().equals(knownOne.getHostAddress())) { inKnownSet = true; break; } } } return(inKnownSet); } /** * Determine if the ServiceAssociationMatchFilter matches a * ServiceElement * * @param descriptor The AssociationDescriptor * @param elems Array of ServiceElement instances * @return True if the AssociationFilter matches a ServiceElement */ static boolean matches(final AssociationDescriptor descriptor, final ServiceElement[] elems) { boolean matches = false; ServiceAssociationMatchFilter filter = new ServiceAssociationMatchFilter(); for (ServiceElement elem : elems) { if (filter.check(descriptor, elem)) { matches = true; break; } } return (matches); } /* * Get matching ServiceElement count */ private static int getCount(final ServiceElement sElem, final ServiceElement[] elems, final AssociationType type, final StringBuffer b) { int found = 0; for (ServiceElement elem : elems) { AssociationDescriptor[] ads = ServiceElementUtil.getAssociationDescriptors(elem, type); for (AssociationDescriptor ad : ads) { if (matches(ad, new ServiceElement[]{sElem})) { if (found > 0) b.append(", "); found++; b.append(elem.getName()); } } } return(found); } /** * Service association match filter, used during co-location and opposed matching */ static class ServiceAssociationMatchFilter { public boolean check(final AssociationDescriptor descriptor, final ServiceElement element) { return(ServiceElementUtil.matchesServiceElement(element, descriptor.getName(), descriptor.getInterfaceNames(), descriptor.getOperationalStringName())); } } }