/* * 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.impl.servicebean; import com.sun.jini.lookup.entry.LookupAttributes; import net.jini.config.Configuration; import net.jini.config.ConfigurationException; import net.jini.config.ConfigurationProvider; import net.jini.core.discovery.LookupLocator; import net.jini.core.entry.Entry; import net.jini.discovery.DiscoveryGroupManagement; import org.rioproject.associations.AssociationDescriptor; import org.rioproject.associations.AssociationType; import org.rioproject.servicebean.ServiceBeanContext; import org.rioproject.deploy.SystemComponent; import org.rioproject.log.LoggerConfig; import org.rioproject.opstring.ClassBundle; import org.rioproject.opstring.ServiceBeanConfig; import org.rioproject.opstring.ServiceElement; import org.rioproject.resolver.RemoteRepository; import org.rioproject.sla.SLA; import org.rioproject.impl.sla.SLAPolicyHandler; import org.rioproject.sla.ServiceLevelAgreements; import org.rioproject.system.capability.PlatformCapability; import org.rioproject.impl.watch.ThreadDeadlockMonitor; import org.rioproject.watch.WatchDescriptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.management.MBeanServerConnection; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; /** * The ServiceElementUtil class provides static methods to assist in working * with a {@link org.rioproject.opstring.ServiceElement} * * @author Dennis Reedy */ public final class ServiceElementUtil { private static Logger logger = LoggerFactory.getLogger("org.rioproject.impl.servicebean.ServiceElementUtil"); private ServiceElementUtil() {} public static String getLoggingName(ServiceBeanContext context) { if(context==null) return "<unknown>"; return getLoggingName(context.getServiceElement()); } public static String getLoggingName(ServiceElement element) { StringBuilder sb = new StringBuilder(); sb.append(element.getOperationalStringName()).append("/").append(element.getName()); Long id = element.getServiceBeanConfig().getInstanceID(); if(id!=null) { sb.append(":").append(id.toString()); } return sb.toString(); } /** * Check to see if the ThreadDeadlockMonitor has been declared as an SLA. * If not, add the default setup for the ThreadDeadlockMonitor * * @param sElem The ServiceElement to use * @param mbsc An optional MBeanServerConnection to set to the * ThreadDeadlockDetector * * @throws IllegalArgumentException if the ServiceElement parameter is null */ public static void setThreadDeadlockDetector(ServiceElement sElem, MBeanServerConnection mbsc) { WatchDescriptor threadDeadlockDesc = getWatchDescriptor(sElem, ThreadDeadlockMonitor.ID); if(threadDeadlockDesc == null) { SLA sla = new SLA(ThreadDeadlockMonitor.ID, 0, 1); sla.setSlaPolicyHandler(SLAPolicyHandler.class.getName()); threadDeadlockDesc = ThreadDeadlockMonitor.getWatchDescriptor(); threadDeadlockDesc.setMBeanServerConnection(mbsc); sla.setWatchDescriptors(threadDeadlockDesc); sElem.getServiceLevelAgreements().addServiceSLA(sla); } else { threadDeadlockDesc.setMBeanServerConnection(mbsc); } } /** * Get the WatchDescriptor from an SLA for the given ID * * @param sElem The ServiceElement to use * @param name The WatchDescriptor name * * @return The matching WatchDescriptor or null if not found * * @throws IllegalArgumentException if either of the parameters are null */ public static WatchDescriptor getWatchDescriptor(ServiceElement sElem, String name) { if(sElem == null) throw new IllegalArgumentException("ServiceElement cannot be null"); if(name == null) throw new IllegalArgumentException("name cannot be null"); WatchDescriptor wDesc = null; ServiceLevelAgreements slas = sElem.getServiceLevelAgreements(); for(SLA sla : slas.getServiceSLAs()) { WatchDescriptor[] wDescs = sla.getWatchDescriptors(); for(WatchDescriptor wd : wDescs) { if(wd.getName().equals(name)) { wDesc = wd; break; } } } return wDesc; } /** * Determine if the LoggerConfig attributes are different between * the two ServiceElement instances * * @param sElem1 ServiceElement to compare * @param sElem2 ServiceElement to compare * * @return True if there is a difference between the LoggerConfig attributes, * false otherwise */ public static boolean hasDifferentLoggerConfig(ServiceElement sElem1, ServiceElement sElem2) { if(sElem1==null || sElem2==null) throw new IllegalArgumentException("parameters cannot be null"); boolean different = false; LoggerConfig[] loggerConfigs2 = sElem2.getServiceBeanConfig().getLoggerConfigs(); LoggerConfig[] loggerConfigs1 = sElem1.getServiceBeanConfig().getLoggerConfigs(); if(loggerConfigs1!=null && loggerConfigs2!=null) { for (LoggerConfig aLoggerConfigs2 : loggerConfigs2) { if (LoggerConfig.isNewLogger(aLoggerConfigs2, loggerConfigs1)) { different = true; break; } else if (LoggerConfig.levelChanged(aLoggerConfigs2, loggerConfigs1)) { different = true; break; } } } return(different); } /** * Determine if there are different ServiceUI declarations in the * ServiceElement instance * * @param serviceUIs Array of attributes * @param sElem2 ServiceElement to compare * @param codebase The codebase to use * * @return True if there are differences. false if the same */ public static boolean hasDifferentServiceUIs(Entry[] serviceUIs, ServiceElement sElem2, String codebase) { if(serviceUIs==null || sElem2==null || codebase==null) { StringBuilder sb = new StringBuilder(); if(serviceUIs==null) sb.append("serviceUIs"); if(sElem2==null) { if(sb.length()>0) sb.append(", "); sb.append("sElem2"); } if(codebase==null) { if(sb.length()>0) sb.append(", "); sb.append("codebase"); } throw new IllegalArgumentException("The provided parameters " + "("+sb.toString()+") were passed " + "in with null values, they cannot be " + "null"); } try { Configuration config2 = ConfigurationProvider.getInstance(sElem2.getServiceBeanConfig().getConfigArgs()); String className = sElem2.getComponentBundle().getClassName(); String serviceBeanComponent = className.substring(0, className.lastIndexOf(".")); /* Get any configured ServiceUIs */ Entry[] serviceUIs1 = (Entry[])config2.getEntry(serviceBeanComponent, "serviceUIs", Entry[].class, new Entry[0], codebase); return(!LookupAttributes.equal(serviceUIs, serviceUIs1)); } catch (ConfigurationException e) { if(logger.isTraceEnabled()) logger.trace("Getting ServiceUIs from ServiceElement", e); } return(false); } /** * Determine if the Discovery groups are different between * the two ServiceElement instances * * @param sElem1 ServiceElement to compare * @param sElem2 ServiceElement to compare * * @return True if there is a difference between the Discovery groups, * false otherwise */ public static boolean hasDifferentGroups(ServiceElement sElem1, ServiceElement sElem2) { if(sElem1==null || sElem2==null) throw new IllegalArgumentException("parameters cannot be null"); boolean different = false; String[] groups1 = sElem1.getServiceBeanConfig().getGroups(); String[] groups2 = sElem2.getServiceBeanConfig().getGroups(); if (groups1 == DiscoveryGroupManagement.ALL_GROUPS && groups2 == DiscoveryGroupManagement.ALL_GROUPS) return false; else if (groups1 == null && groups2 == null) return false; else if (groups1 == null || groups2 == null) return true; else if (groups1.length != groups2.length) { different = true; } else { for (String aGroups1 : groups1) { boolean matched = false; for (String aGroups2 : groups2) { if (aGroups1.equals(aGroups2)) { matched = true; break; } } if (logger.isTraceEnabled()) { StringBuilder builder = new StringBuilder(); builder.append("["); builder.append(sElem1.getName()).append(":").append(sElem1.getServiceBeanConfig().getInstanceID()); builder.append("] groups [").append(aGroups1).append("] matched in groups2 ?").append(matched); logger.trace(builder.toString()); } if (!matched) { different = true; break; } } } return(different); } /** * Determine if the LookupLocators are different between * the two ServiceElement instances * * @param sElem1 ServiceElement to compare * @param sElem2 ServiceElement to compare * * @return True if there is a difference between the LookupLocators, * false otherwise */ public static boolean hasDifferentLocators(ServiceElement sElem1, ServiceElement sElem2) { if(sElem1==null || sElem2==null) throw new IllegalArgumentException("parameters cannot be null"); boolean different = false; LookupLocator[] locs1 = sElem1.getServiceBeanConfig().getLocators(); LookupLocator[] locs2 = sElem2.getServiceBeanConfig().getLocators(); if(locs1 == null && locs2 == null) return(false); if(locs1 == null || locs2 == null) return (true); if(locs1.length != locs2.length) { different = true; } else { for (LookupLocator aLocs1 : locs1) { boolean matched = false; for (LookupLocator aLocs2 : locs2) { if (aLocs1.equals(aLocs2)) { matched = true; break; } } if (!matched) { different = true; break; } } } return(different); } /** * Set the instanceID, optionally making a copy of the ServiceElement * * @param sElem The ServiceElement to use * @param copy If true, make a copy of the ServiceElement before assigning * the instanceID * @param id The instanceID to assign * * @return A ServiceElement with it's instanceID set to the value provided */ public static ServiceElement prepareInstanceID(ServiceElement sElem, boolean copy, long id) { ServiceElement elem = sElem; if(copy) elem = copyServiceElement(sElem); /* set the instance id */ Map<String, Object> parms = elem.getServiceBeanConfig().getConfigurationParameters(); parms.put(ServiceBeanConfig.INSTANCE_ID, id); ServiceBeanConfig sbConfig = new ServiceBeanConfig(parms, elem.getServiceBeanConfig().getConfigArgs()); /* Get the initialization parameters and add them */ Map<String, Object> initParms = elem.getServiceBeanConfig().getInitParameters(); for (Map.Entry<String, Object> e : initParms.entrySet()) { sbConfig.addInitParameter(e.getKey(), e.getValue()); } if(!elem.getServiceBeanConfig().getAdditionalEntries().isEmpty()) { List<Entry> entries = elem.getServiceBeanConfig().getAdditionalEntries(); sbConfig.addAdditionalEntries(entries.toArray(new Entry[entries.size()])); } elem.setServiceBeanConfig(sbConfig); return(elem); } /** * Make a copy of the ServiceElement and set the instance ID * * @param sElem ServiceElement to use * @param id the id to set * * @return A new ServiceElement */ public static ServiceElement prepareInstanceID(ServiceElement sElem, long id) { return(prepareInstanceID(sElem, true, id)); } /** * Get the next instance ID * * @param lArray An array of ids * * @return The next instanceID */ public static synchronized long getNextID(long[] lArray) { long nextID = 1; if(lArray.length>0) { Arrays.sort(lArray); for(int i=0,x=1; i<lArray.length; i++,x++) { if(lArray[i]!=x) { nextID = x; break; } else { nextID=x+1; } } } return(nextID); } /** * Make a copy of the ServiceElement * * @param sElem The ServiceElement to copy * * @return A new ServiceElement */ public static ServiceElement copyServiceElement(ServiceElement sElem) { ServiceBeanConfig oldSBC = sElem.getServiceBeanConfig(); ServiceBeanConfig sbc = new ServiceBeanConfig(oldSBC.getConfigurationParameters(), oldSBC.getConfigArgs()); for(Map.Entry<String, Object> entry : oldSBC.getInitParameters().entrySet()) { sbc.addInitParameter(entry.getKey(), entry.getValue()); } sbc.addLoggerConfig(oldSBC.getLoggerConfigs()); if(!oldSBC.getAdditionalEntries().isEmpty()) { List<Entry> entries = oldSBC.getAdditionalEntries(); sbc.addAdditionalEntries(entries.toArray(new Entry[entries.size()])); } ServiceElement elem = new ServiceElement(sElem.getProvisionType(), sbc, sElem.getServiceLevelAgreements(), sElem.getExportBundles(), sElem.getFaultDetectionHandlerBundle(), sElem.getComponentBundle()); elem.setPlanned(sElem.getPlanned()); elem.setCluster(sElem.getCluster()); elem.setMaxPerMachine(sElem.getMaxPerMachine()); elem.setMatchOnName(sElem.getMatchOnName()); elem.setMachineBoundary(sElem.getMachineBoundary()); elem.setAutoAdvertise(sElem.getAutoAdvertise()); elem.setDiscoveryManagementPooling(sElem.getDiscoveryManagementPooling()); elem.setAssociationDescriptors(sElem.getAssociationDescriptors()); elem.setExecDescriptor(sElem.getExecDescriptor()); elem.setStagedData(sElem.getStagedData()); elem.setFork(sElem.forkService()); List<RemoteRepository> rr = new ArrayList<RemoteRepository>(); rr.addAll(Arrays.asList(sElem.getRemoteRepositories())); elem.setRemoteRepositories(rr); elem.setRuleMaps(sElem.getRuleMaps()); return(elem); } /** * Add a name,value pair to the ServiceBeanConfig * * @param sbc The current ServiceBeanConfig to set * @param key The key to set * @param value The value for the key * * @return A ServiceBeanConfig with the added properties */ public static ServiceBeanConfig addConfigParameter(final ServiceBeanConfig sbc, final String key, final Integer value) { if(sbc == null || key == null || value == null) throw new IllegalArgumentException("parameters cannot be null"); Map<String, Object> configParms = sbc.getConfigurationParameters(); configParms.put(key, value); ServiceBeanConfig newConfig = new ServiceBeanConfig(configParms, sbc.getConfigArgs()); Map<String, Object> initParms = sbc.getInitParameters(); for (Map.Entry<String, Object> e : initParms.entrySet()) { newConfig.addInitParameter(e.getKey(), e.getValue()); } if(!sbc.getAdditionalEntries().isEmpty()) { List<Entry> entries = sbc.getAdditionalEntries(); newConfig.addAdditionalEntries(entries.toArray(new Entry[entries.size()])); } return (newConfig); } /** * Determines if the name, interfaces and opStringName equate to * attributes found in the provided ServiceElement * * @param sElem The ServiceElement to test, must not be null * @param name The name to check, may be null * @param interfaces The ames of the interfaces the service advertises, * must not be null * @param opStringName The name of the operationalString, may be null * @return If the attributes can be found in the ServiceElement, return * true */ public static boolean matchesServiceElement(ServiceElement sElem, String name, String[] interfaces, String opStringName) { if(sElem==null) throw new IllegalArgumentException("sElem is null"); if(interfaces == null) throw new IllegalArgumentException("interfaces is null"); 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) { boolean attrsMatch = true; if(opStringName!=null) { if(!sElem.getOperationalStringName().equals(opStringName)) { attrsMatch = false; } } if(attrsMatch) { if(name!=null) { if(!name.equals(sElem.getName())) attrsMatch = false; } } return(attrsMatch); } return(false); } /** * Get the PlatformCapability instances that match declared operational * requirements * * @param sElem The ServiceElement to use * @param pCaps Array of PlatformCapability objects * objects * @return Array of matching * {@link org.rioproject.system.capability.PlatformCapability} objects. If there * are no matching PlatformCapability instances, a zero-length array is * returned. A new array is allocated each time. * */ public static PlatformCapability[] getMatchedPlatformCapabilities(ServiceElement sElem, PlatformCapability[] pCaps) { ServiceLevelAgreements slas = sElem.getServiceLevelAgreements(); SystemComponent[] requirements = slas.getSystemRequirements().getSystemComponents(); List<PlatformCapability> list = new ArrayList<PlatformCapability>(); if(requirements.length >= 0) { /* * Iterate through all resource PlatformCapability objects to * determine which ones support our declared requirements */ for (SystemComponent requirement : requirements) { for (PlatformCapability pCap : pCaps) { if (pCap.supports(requirement)) { list.add(pCap); } } } } return (list.toArray(new PlatformCapability[list.size()])); } /** * Get the AssociationDescriptors from the ServiceElement that match the * {@link org.rioproject.associations.AssociationType} type * * @param elem The ServiceElement * @param type The AssociationType type * @return An array of AssociationDescriptor instances that match the * AssociationType type. If there are no matching AssociationDescriptors, * return an empty array. A new array is allocated each time */ public static AssociationDescriptor[] getAssociationDescriptors(ServiceElement elem, AssociationType type) { AssociationDescriptor[] aDescs = elem.getAssociationDescriptors(); List<AssociationDescriptor> list = new ArrayList<AssociationDescriptor>(); for (AssociationDescriptor aDesc : aDescs) { if (aDesc.getAssociationType() == type) { list.add(aDesc); } } return(list.toArray(new AssociationDescriptor[list.size()])); } /** * Format discovery settings * * @param sbConfig The ServiceElement to use * * @return a String with discovery settings formatted */ public static String formatDiscoverySettings(ServiceBeanConfig sbConfig) { if(sbConfig==null) return ""; Map<String, Object> conf = sbConfig.getConfigurationParameters(); StringBuilder buff = new StringBuilder(); String[] groups = (String[])conf.get(ServiceBeanConfig.GROUPS); buff.append("Groups: "); if(groups == null || groups.length == 0) buff.append("<none>"); if(groups != null && groups.length > 0) { if(groups.length == 1 && groups[0].equals("all")) { buff.append("all"); } else { for(int i = 0; i < groups.length; i++) { if(i>0) buff.append(", "); buff.append(groups[i]); } } } buff.append("\n"); buff.append("Locators: "); LookupLocator[] locs = (LookupLocator[])conf.get(ServiceBeanConfig.LOCATORS); if(locs == null || locs.length == 0) buff.append("<none>"); if(locs != null && locs.length > 0) { for(int i=0; i<locs.length; i++) { if(i>0) buff.append(", "); buff.append("jini://").append(locs[i].getHost()).append(":").append(locs[i].getPort()); } } return buff.toString(); } }