/*
* 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 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.DiscoveryManagement;
import org.rioproject.associations.AssociationManagement;
import org.rioproject.config.Constants;
import org.rioproject.event.EventDescriptor;
import org.rioproject.event.EventHandler;
import org.rioproject.impl.associations.DefaultAssociationManagement;
import org.rioproject.impl.client.DiscoveryManagementPool;
import org.rioproject.impl.client.JiniClient;
import org.rioproject.impl.config.AggregateConfig;
import org.rioproject.impl.config.ConfigHelper;
import org.rioproject.impl.system.ComputeResource;
import org.rioproject.impl.system.measurable.MeasurableCapability;
import org.rioproject.impl.watch.WatchDataSourceRegistry;
import org.rioproject.impl.watch.WatchRegistry;
import org.rioproject.loader.CommonClassLoader;
import org.rioproject.loader.ServiceClassLoader;
import org.rioproject.opstring.ServiceBeanConfig;
import org.rioproject.opstring.ServiceElement;
import org.rioproject.servicebean.ComputeResourceManager;
import org.rioproject.servicebean.ServiceBeanContext;
import org.rioproject.servicebean.ServiceBeanManager;
import org.rioproject.sla.SLA;
import org.rioproject.system.capability.PlatformCapability;
import org.rioproject.system.capability.software.SoftwareSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.security.auth.Subject;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.*;
/**
* DefaultServiceBeanContext implements the ServiceBeanContext interface
*
* @author Dennis Reedy
*/
public class DefaultServiceBeanContext implements ServiceBeanContext, ComputeResourceManager {
/** The ServiceElement */
private ServiceElement sElem;
/**
* The ServiceBeanManager, providing a mechanism for the ServiceBean to
* obtain a DiscardManager, and request it's ServiceElement be updated to
* known OperationalStringManager instance(s)
*/
private ServiceBeanManager serviceBeanManager;
/** Get the ServiceBean's join specifics */
private DiscoveryManagement serviceDiscoMgmt;
/** The ComputeResource this ServiceBean has been instantiated on */
private ComputeResource computeResource;
/**
* The exportCodebase attribute identifies the codebase used to export
* ServiceBean JARs
*/
private String exportCodebase;
/** List of PlatformCapability instances that were created */
private final List<PlatformCapability> platformList = new ArrayList<PlatformCapability>();
/** DefaultAssociationManagement for the ServiceBean */
private AssociationManagement associationManagement;
/** Shared Configuration for the ServiceBean to use*/
private final Configuration sharedConfig;
/** WatchRegistry for storing watches and corresponding WatchDataSources */
private final WatchRegistry watchRegistry;
/**
* The eventTable associates an EventHandler to an EventDescriptor for the
* ServiceProvider. Event registration requests for events this
* ServiceProvider has advertised will consult the eventTable to determine
* the correct EventHandler to use in order to return an event registration
*/
private final Map<Long, EventHandler> eventTable = new HashMap<Long, EventHandler>();
/** Collection of attributes */
private final List<Entry> attrs = new ArrayList<Entry>();
/** The service's configuration, created lazily */
private Configuration serviceBeanConfig;
/** Optional configuration files */
private String[] configurationFiles;
/* The Subject used to authenticate the service */
private Subject subject;
/** A Logger instance for this component */
private static Logger logger = LoggerFactory.getLogger(DefaultServiceBeanContext.class.getName());
/**
* Create a DefaultServiceBeanContext
*
* @param sElem The ServiceElement
* @param serviceBeanManager The ServiceBeanManager
* @param computeResource The ComputeResource object representing
* capabilities of the compute resource the service has been instantiated on
* @param sharedConfig Configuration from the "platform" which will be used
* as the shared configuration with an AggregateConfig
*/
public DefaultServiceBeanContext(final ServiceElement sElem,
final ServiceBeanManager serviceBeanManager,
final ComputeResource computeResource,
/* Optional */
final Configuration sharedConfig) {
if(sElem == null)
throw new IllegalArgumentException("sElem is null");
if(serviceBeanManager == null)
throw new IllegalArgumentException("serviceBeanManager is null");
if(computeResource == null)
throw new IllegalArgumentException("computeResource is null");
this.sElem = sElem;
this.serviceBeanManager = serviceBeanManager;
this.computeResource = computeResource;
this.sharedConfig = sharedConfig;
watchRegistry = new WatchDataSourceRegistry();
watchRegistry.setServiceBeanContext(this);
ClassLoader cCL = Thread.currentThread().getContextClassLoader();
if(cCL instanceof ServiceClassLoader) {
ServiceClassLoader scl = (ServiceClassLoader)cCL;
URL urls[] = scl.getURLs();
if(urls!=null && urls.length>0) {
if(urls[0].getProtocol().equals("artifact"))
exportCodebase = urls[0].toExternalForm();
else
exportCodebase = urls[0].getProtocol()+"://"+urls[0].getHost()+":"+urls[0].getPort()+"/";
}
}
}
/**
* Set the Subject used to authenticate the service
*
* @param subject The Subject
*/
public void setSubject(final Subject subject) {
this.subject = subject;
}
/**
* Get the Subject used to authenticate the service
*
* @return The Subject
*/
public Subject getSubject() {
return(subject);
}
/**
* Set the ServiceElement for the ServiceBean
*
* @param newElem The ServiceElement
*/
public void setServiceElement(final ServiceElement newElem) {
if(newElem == null)
throw new IllegalArgumentException("sElem is null");
boolean update = (sElem != null);
sElem = newElem;
if(serviceBeanManager instanceof DefaultServiceBeanManager)
((DefaultServiceBeanManager)serviceBeanManager).setServiceElement(sElem);
if(update && associationManagement!=null) {
if(associationManagement instanceof DefaultAssociationManagement) {
((DefaultAssociationManagement)associationManagement).setServiceBeanContext(this);
}
}
}
/**
* @see org.rioproject.servicebean.ServiceBeanContext#getExportCodebase
*/
public String getExportCodebase() {
return (exportCodebase);
}
/**
* @see org.rioproject.servicebean.ServiceBeanContext#getConfiguration
*/
public Configuration getConfiguration() throws ConfigurationException {
if(serviceBeanConfig==null) {
logger.debug("Getting configuration for {}/{}", sElem.getOperationalStringName(), sElem.getName());
ClassLoader cCL = Thread.currentThread().getContextClassLoader();
String[] args;
try {
args = ConfigHelper.getConfigArgs(sElem, cCL);
} catch (IllegalArgumentException e) {
throw new ConfigurationException("Could not create configuration, bad arguments " +
"["+Arrays.toString(sElem.getServiceBeanConfig().getConfigArgs())+"]",
e);
} catch (IOException e) {
throw new ConfigurationException("Could not create configuration", e);
}
if(logger.isDebugEnabled()) {
StringBuilder sb = new StringBuilder();
for(String s : args) {
if(sb.length()>0)
sb.append("\n");
sb.append("\t").append(s);
}
logger.debug("{}/{} CONFIG ARGS: \n{}", sElem.getOperationalStringName(), sElem.getName(), sb);
}
if(sharedConfig!=null) {
serviceBeanConfig = new AggregateConfig(sharedConfig, args, cCL);
} else {
serviceBeanConfig = ConfigurationProvider.getInstance(args, cCL);
}
/* If a temporary file was created remove it */
try {
if(args.length==1 &&
(args[0].endsWith(".config") || args[0].endsWith(".groovy"))) {
File file = new File(args[0]);
File parent = file.getParentFile().getCanonicalFile();
File tmpDir = new File(System.getProperty("java.io.tmpdir")).getCanonicalFile();
if(parent.equals(tmpDir) &&
file.getName().startsWith("tmp")) {
if(file.delete() && logger.isTraceEnabled())
logger.trace("Deleted temporary configuration file {}", file.getName());
}
}
logger.debug("Configuration for {}/{} created", sElem.getOperationalStringName(), sElem.getName());
} catch(IOException e) {
logger.warn("Unable to get canonical file for the tmp directory, cannot remove generated config file(s)",
e);
}
}
return(serviceBeanConfig);
}
public void setConfiguration(final Configuration serviceBeanConfig) {
this.serviceBeanConfig = serviceBeanConfig;
}
void setConfigurationFiles(final String... configFiles) {
configurationFiles = new String[configFiles.length];
System.arraycopy(configFiles, 0, configurationFiles, 0, configFiles.length);
}
@SuppressWarnings("unused")
public String[] getConfigurationFiles() {
return configurationFiles;
}
/**
* @see org.rioproject.servicebean.ServiceBeanContext#getServiceBeanConfig
*/
public ServiceBeanConfig getServiceBeanConfig() {
return (sElem.getServiceBeanConfig());
}
/**
* @see org.rioproject.servicebean.ServiceBeanContext#getServiceElement
*/
public ServiceElement getServiceElement() {
return (sElem);
}
/**
* Set the ServiceBeanManager for the ServiceBean
*
* @param serviceBeanManager The ServiceBeanManager
*/
public void setServiceBeanManager(final ServiceBeanManager serviceBeanManager) {
if(serviceBeanManager==null)
throw new IllegalArgumentException("serviceBeanManager us null");
this.serviceBeanManager = serviceBeanManager;
}
/**
* @see org.rioproject.servicebean.ServiceBeanContext#getServiceBeanManager
*/
public ServiceBeanManager getServiceBeanManager() {
return (serviceBeanManager);
}
/**
* @see org.rioproject.servicebean.ServiceBeanContext#getComputeResourceManager
*/
public ComputeResourceManager getComputeResourceManager() {
return this;
}
/**
* @see org.rioproject.servicebean.ServiceBeanContext#getInitParameter
*/
public Object getInitParameter(final String name) {
if(name==null)
throw new IllegalArgumentException("name is null");
return(sElem.getServiceBeanConfig().getInitParameters().get(name));
}
/**
* @see org.rioproject.servicebean.ServiceBeanContext#getInitParameterNames
*/
public Iterable<String> getInitParameterNames() {
return (sElem.getServiceBeanConfig().getInitParameters().keySet());
}
/**
* Get the name of the OperationalString
*
* @return The name of the OperationalString
*/
public String getOperationalStringName() {
return (sElem.getOperationalStringName());
}
/**
* @see org.rioproject.servicebean.ServiceBeanContext#getDiscoveryManagement()
*/
public DiscoveryManagement getDiscoveryManagement() throws IOException {
if(serviceDiscoMgmt == null) {
logger.trace("Create DiscoveryManagement for {}/{}", sElem.getOperationalStringName(), sElem.getName());
DiscoveryManagementPool discoPool = DiscoveryManagementPool.getInstance();
String locatorString = System.getProperty(Constants.LOCATOR_PROPERTY_NAME);
List<LookupLocator> locators = new ArrayList<LookupLocator>();
if(sElem.getServiceBeanConfig().getLocators()!=null)
locators.addAll(
Arrays.asList(sElem.getServiceBeanConfig().getLocators()));
if(locatorString!=null) {
LookupLocator[] systemLocators = JiniClient.parseLocators(locatorString);
if(locators.isEmpty()) {
locators.addAll(Arrays.asList(systemLocators));
} else {
List<LookupLocator> toAdd = new ArrayList<LookupLocator>();
for(LookupLocator lookLoc : systemLocators) {
boolean add = true;
for(LookupLocator ll : locators) {
if(ll.equals(lookLoc)) {
add = false;
break;
}
}
if(add)
toAdd.add(lookLoc);
}
for(LookupLocator ll : toAdd)
locators.add(ll);
}
}
LookupLocator[] locatorsToUse = locators.isEmpty()?null:
locators.toArray(new LookupLocator[locators.size()]);
if(sElem.getDiscoveryManagementPooling()) {
serviceDiscoMgmt = discoPool.getDiscoveryManager(getOperationalStringName(),
sElem.getServiceBeanConfig().getGroups(),
locatorsToUse);
} else {
Configuration discoConfig = null;
try {
discoConfig = getConfiguration();
} catch(ConfigurationException e) {
logger.trace("Getting Configuration while creating DiscoveryManagement", e);
}
serviceDiscoMgmt = discoPool.getDiscoveryManager(serviceBeanManager.getServiceID().toString(),
sElem.getServiceBeanConfig().getGroups(),
locatorsToUse,
null,
discoConfig);
}
logger.trace("Created DiscoveryManagement for {}/{}", sElem.getOperationalStringName(), sElem.getName());
}
return (serviceDiscoMgmt);
}
/**
* @see org.rioproject.servicebean.ServiceBeanContext#getAssociationManagement
*/
public org.rioproject.associations.AssociationManagement getAssociationManagement() {
if(associationManagement==null) {
this.associationManagement = new DefaultAssociationManagement();
}
return (associationManagement);
}
/**
* @see org.rioproject.servicebean.ServiceBeanContext#getWatchRegistry
*/
public WatchRegistry getWatchRegistry() {
return watchRegistry;
}
/**
* The eventTable associates an EventHandler to an EventDescriptor for the
* ServiceBean. Event registration requests for events this
* ServiceBean has advertised will consult the eventTable to determine
* the correct EventHandler to use in order to return an event registration
*
* @return The Map of event IDs to EventHandler instances
*/
public Map<Long, EventHandler> getEventTable() {
return(eventTable);
}
/**
* @see org.rioproject.servicebean.ServiceBeanContext#registerEventHandler
*/
public void registerEventHandler(final EventDescriptor descriptor, final EventHandler handler) {
eventTable.put(descriptor.eventID, handler);
addAttribute(descriptor);
}
/**
* @see org.rioproject.servicebean.ServiceBeanContext#addAttribute
*/
public void addAttribute(final Entry attribute) {
if(attribute!=null)
attrs.add(attribute);
}
/**
* Get the attribute list
*
* @return The attribute list
*/
public Collection<Entry> getAttributes() {
return attrs;
}
/**
* @see org.rioproject.servicebean.ComputeResourceManager#getComputeResource
*/
public ComputeResource getComputeResource() {
return (computeResource);
}
/**
* @see org.rioproject.servicebean.ComputeResourceManager#getPlatformCapability
*/
public PlatformCapability getPlatformCapability(final String name) {
if(name == null)
throw new IllegalArgumentException("name is null");
PlatformCapability pCap = computeResource.getPlatformCapability(name);
return (pCap);
}
/**
* @see org.rioproject.servicebean.ComputeResourceManager#getMatchedPlatformCapabilities
*/
public PlatformCapability[] getMatchedPlatformCapabilities() {
PlatformCapability[] pCaps = computeResource.getPlatformCapabilities();
return(ServiceElementUtil.getMatchedPlatformCapabilities(sElem, pCaps));
}
/**
* Create a PlatformCapability
*
* @param className The fully qualified classname to instantiate, must not be null
* @param mapping If not null, the attributes will be set to the instantiated
* PlatformCapability
*
* @return A PlatformCapability object with attributes applied
*
* @throws ClassNotFoundException If the platform capability class cannot
* be found
* @throws IllegalAccessException If there is a security exception
* @throws InstantiationException If the class cannot be created
*/
public static PlatformCapability createPlatformCapability(final String className, final Map<String, Object> mapping)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
if(className == null)
throw new IllegalArgumentException("className is null");
PlatformCapability pCap;
if(className.equals(SoftwareSupport.class.getSimpleName())) {
pCap = new SoftwareSupport();
} else if(className.equals(SoftwareSupport.class.getName())) {
pCap = new SoftwareSupport();
} else {
CommonClassLoader cl = CommonClassLoader.getInstance();
Class clazz = cl.loadClass(className);
pCap = (PlatformCapability)clazz.newInstance();
}
if(mapping!=null)
pCap.defineAll(mapping);
return (pCap);
}
/**
* Remove all PlatformCapability instances the ServiceBean added
*/
public void removePlatformCapabilities() {
for (PlatformCapability pCap : platformList) {
computeResource.removePlatformCapability(pCap, true);
}
platformList.clear();
}
/**
* @see org.rioproject.servicebean.ComputeResourceManager#getMatchedMeasurableCapabilities
*/
public MeasurableCapability[] getMatchedMeasurableCapabilities() {
List<MeasurableCapability> list = new ArrayList<MeasurableCapability>();
SLA[] slas = sElem.getServiceLevelAgreements().getServiceSLAs();
MeasurableCapability[] mCaps = computeResource.getMeasurableCapabilities();
/*
* Check each of the MeasuredCapability objects for a match
*/
for (SLA sla : slas) {
for (MeasurableCapability mCap : mCaps) {
if (mCap.getId().equals(sla.getIdentifier())) {
list.add(mCap);
}
}
}
return (list.toArray(new MeasurableCapability[list.size()]));
}
}