/*
* 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.system;
import net.jini.config.Configuration;
import net.jini.config.ConfigurationException;
import org.rioproject.config.PlatformCapabilityConfig;
import org.rioproject.config.PlatformLoader;
import org.rioproject.costmodel.ResourceCostModel;
import org.rioproject.system.SystemWatchID;
import org.rioproject.impl.util.FileUtils;
import org.rioproject.system.capability.PlatformCapability;
import org.rioproject.impl.system.capability.PlatformCapabilityLoader;
import org.rioproject.system.capability.connectivity.TCPConnectivity;
import org.rioproject.system.capability.platform.OperatingSystem;
import org.rioproject.system.capability.platform.ProcessorArchitecture;
import org.rioproject.system.capability.platform.StorageCapability;
import org.rioproject.system.capability.software.J2SESupport;
import org.rioproject.system.capability.software.NativeLibrarySupport;
import org.rioproject.system.capability.software.RioSupport;
import org.rioproject.impl.system.measurable.MeasurableCapability;
import org.rioproject.impl.system.measurable.SigarHelper;
import org.rioproject.impl.system.measurable.cpu.CPU;
import org.rioproject.impl.system.measurable.disk.DiskSpace;
import org.rioproject.impl.system.measurable.memory.Memory;
import org.rioproject.impl.system.measurable.memory.SystemMemory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.*;
/**
* The SystemCapabilities represents the capabilities of the ComputeResource
* determined from a capabilities configuration file and default qualitative
* and quantitative mechanisms.
*
* @author Dennis Reedy
*/
public class SystemCapabilities implements SystemCapabilitiesLoader {
public static final String COMPONENT = "org.rioproject.system";
public static final String CAPABILITY = COMPONENT+".capability";
public static final String NATIVE_LIBS = COMPONENT+".native";
public static final String PROCESSOR = ProcessorArchitecture.class.getName();
public static final String OPSYS = OperatingSystem.class.getName();
public static final String TCPIP = TCPConnectivity.class.getName();
public static final String J2SE = J2SESupport.class.getName();
public static final String MEMORY = org.rioproject.system.capability.platform.Memory.class.getName();
public static final String SYSTEM_MEMORY = org.rioproject.system.capability.platform.SystemMemory.class.getName();
public static final String STORAGE = StorageCapability.class.getName();
public static final String NATIVE_LIB_CLASS = NativeLibrarySupport.class.getName();
public static final String RIO = RioSupport.class.getName();
static Logger logger = LoggerFactory.getLogger(COMPONENT);
private String platformConfigDir;
/**
* Get the MeasurableCapability objects based on a passed in Configuration
*
* @param config A Configuration to use to assist in creating
* MeasurableCapability objects
*
* @return Return an array of <code>MeasurableCapability</code> objects. This
* method will create a new array of <code>MeasurableCapability</code> objects
* each time it is invoked. At a minimum the following MeasurableCapability
* objects will be returned:
*
* <ul>
* <li>org.rioproject.system.measurable.cpu.CPU
* <li>org.rioproject.system.measurable.memory.Memory
* </ul>
*
* If the operating system is not a member of the "Windows" family of
* operating systems, an additional <code>MeasurableCapability</code> is
* returned :
*
* <ul>
* <li>org.rioproject.system.measurable.disk.DiskSpace
* </ul>
*/
public MeasurableCapability[] getMeasurableCapabilities(Configuration config) {
if(config==null)
throw new IllegalArgumentException("config is null");
List<MeasurableCapability> measurables = new ArrayList<MeasurableCapability>();
/* Create the Memory MeasurableCapability. This will measure memory
* for the JVM */
MeasurableCapability memory = new Memory(config);
if(memory.isEnabled())
measurables.add(memory);
/* If SIGAR is available, create a Memory MeasurableCapability for the
* physical machine as well */
boolean haveSigar = SigarHelper.sigarAvailable();
if(haveSigar) {
MeasurableCapability systemMemory = new SystemMemory(config);
if(systemMemory.isEnabled())
measurables.add(systemMemory);
}
/* Load memory pool management */
try {
MeasurableCapability[] pools =
(MeasurableCapability[])config.getEntry(COMPONENT+".memory.pool",
"memoryPools",
MeasurableCapability[].class,
null,
config);
if(pools!=null)
measurables.addAll(Arrays.asList(pools));
} catch(ConfigurationException e) {
logger.warn("Loading CPU MeasurableCapability", e);
}
/* Create the CPU MeasurableCapability */
MeasurableCapability cpu = new CPU(config);
if(cpu.isEnabled())
measurables.add(cpu);
MeasurableCapability jvmCpu = new CPU(config, SystemWatchID.PROC_CPU, true);
if(jvmCpu.isEnabled())
measurables.add(jvmCpu);
/*
* Load the DiskSpace capability only if we have SIGAR or if SIGAR is
* not available and not running on Windows
*/
MeasurableCapability diskSpace = null;
if(haveSigar) {
diskSpace = getDiskSpace(config);
} else if(!OperatingSystemType.isWindows()) {
diskSpace = getDiskSpace(config);
}
if(diskSpace!=null && diskSpace.isEnabled())
measurables.add(diskSpace);
/*
* Load any additional MeasurableCapability instances that have been
* configured
*/
try {
MeasurableCapability[] mCaps =
(MeasurableCapability[])config.getEntry(COMPONENT,
"measurableCapabilities",
MeasurableCapability[].class,
null);
if(mCaps!=null) {
measurables.addAll(Arrays.asList(mCaps));
}
} catch (ConfigurationException e) {
logger.warn("Loading MeasurableCapability array", e);
}
return(measurables.toArray(new MeasurableCapability[measurables.size()]));
}
/**
* Get the PlatformCapability objects
*
* @return An array of <code>PlatformCapability</code> objects. This
* method will create a new array of <code>PlatformCapability</code> objects
* each time it is invoked. If there are no <code>PlatformCapability</code>
* objects contained within the <code>platforms</code> Collection, a
* zero-length array will be returned.
*/
public PlatformCapability[] getPlatformCapabilities(Configuration config) {
List<PlatformCapability> platforms = new ArrayList<PlatformCapability>();
try {
/*
* Load default platform (qualitative) capabilities
*/
ProcessorArchitecture processor = new ProcessorArchitecture();
platforms.add(processor);
PlatformCapability operatingSystem = new OperatingSystem();
platforms.add(operatingSystem);
PlatformCapability tcpIP = new TCPConnectivity();
platforms.add(tcpIP);
PlatformCapability j2se = new J2SESupport();
platforms.add(j2se);
List<PlatformCapability> platformCapabilityList = new ArrayList<PlatformCapability>();
PlatformCapability[] pCaps = (PlatformCapability[])config.getEntry(COMPONENT,
"platformCapabilities",
PlatformCapability[].class,
new PlatformCapability[0]);
platformCapabilityList.addAll(Arrays.asList(pCaps));
PlatformCapability[] addCaps = (PlatformCapability[])config.getEntry(COMPONENT,
"addPlatformCapabilities",
PlatformCapability[].class,
new PlatformCapability[0]);
platformCapabilityList.addAll(Arrays.asList(addCaps));
/*
* Load the default capabilities
*/
PlatformLoader loader = new PlatformLoader();
pCaps = createPlatformCapabilities(loader.getDefaultPlatform(getRioHome()));
platformCapabilityList.addAll(Arrays.asList(pCaps));
/*
* Get additional platform configurations
*/
String platformDir = getPlatformConfigurationDirectory(config);
if(platformDir!=null) {
PlatformCapability[] caps = parsePlatformConfig(loader, platformDir);
platformCapabilityList.addAll(Arrays.asList(caps));
} else {
logger.warn("Unable to establish the platform configuration directory, most likely RIO_HOME is not set.");
}
/*
* Get the final array of PlatformCapability instances
*/
pCaps = platformCapabilityList.toArray(new PlatformCapability[platformCapabilityList.size()]);
for (PlatformCapability pCap : pCaps) {
if (pCap.getClass().getName().equals(RIO)) {
if (getRioHome() != null) {
pCap.setPath(getRioHome());
}
}
platforms.add(pCap);
}
/* Find out if we have loaded a StorageCapability class */
PlatformCapability storage = findCapability(platforms, STORAGE);
if(storage==null) {
storage = getPlatformCapability(STORAGE);
platforms.add(storage);
}
/* Find out if we have loaded a Memory class */
PlatformCapability memory = findCapability(platforms, MEMORY);
if(memory == null) {
memory = getPlatformCapability(MEMORY);
platforms.add(memory);
}
/* Find out if we have loaded a SystemMemory class */
PlatformCapability systemMemory = findCapability(platforms, SYSTEM_MEMORY);
if(systemMemory == null) {
systemMemory = getPlatformCapability(SYSTEM_MEMORY);
platforms.add(systemMemory);
}
/* Create NativeLibrarySupport objects */
String nativeLibDirs = System.getProperty(NATIVE_LIBS);
List<File> dirList = new ArrayList<File>();
if(nativeLibDirs!=null && nativeLibDirs.length()>0) {
StringTokenizer st = new StringTokenizer(nativeLibDirs, File.pathSeparator+" ");
while(st.hasMoreTokens()) {
String dirName = st.nextToken();
File dir = new File(dirName);
if(dir.isDirectory() && dir.canRead()) {
dirList.add(dir);
if(logger.isDebugEnabled())
logger.debug("Adding directory [{}] to check for native libraries", dirName);
} else {
logger.warn("Invalid directory name or access permissions to check for native libraries [{}]. Continuing ...",
dirName);
}
}
final String[] libExtensions = getLibExtensions();
File[] dirs = dirList.toArray(new File[dirList.size()]);
for (File dir : dirs) {
File[] files = dir.listFiles(new FileFilter() {
public boolean accept(File pathName) {
try {
if(FileUtils.isSymbolicLink(pathName)) {
return false;
}
} catch (IOException e) {
logger.warn( "Trying to determine whether the file is a symbolic link", e);
}
boolean matches = false;
for(String libExtension : libExtensions) {
if(pathName.getName().endsWith(libExtension)) {
matches = true;
break;
}
}
return matches;
}
});
for (File file : files) {
String fileName = file.getName();
int index = fileName.lastIndexOf(".");
if (index != -1) {
if (logger.isDebugEnabled())
logger.debug("Create NativeLibrarySupport object for [{}]", fileName);
PlatformCapability nLib = getPlatformCapability(NATIVE_LIB_CLASS);
String name;
/*if (!OperatingSystemType.isWindows()) {
name = fileName.substring(3, index);
} else {*/
name = fileName.substring(0, index);
//}
nLib.define(NativeLibrarySupport.NAME, name);
nLib.define(NativeLibrarySupport.FILENAME, fileName);
nLib.setPath(dir.getCanonicalPath());
platforms.add(nLib);
} else {
logger.warn("Illegal Shared Library name="+fileName);
}
}
}
} /* End creating NativeLibrarySupport objects */
} catch(Throwable t) {
logger.error("Getting PlatformCapability objects", t);
}
return(platforms.toArray(new PlatformCapability[platforms.size()]));
}
/**
* Get the PlatformCapability name table
*
* @return A Map of PlatformCapability names to PlatformCapability classnames
*/
public Map<String, String> getPlatformCapabilityNameTable() {
Map<String, String> nameTable = new HashMap<String, String>();
nameTable.put("ConnectivityCapability", CAPABILITY+".connectivity.ConnectivityCapability");
nameTable.put("TCPConnectivity", TCPIP);
nameTable.put("J2SESupport", J2SE);
nameTable.put("NativeLibrarySupport", NATIVE_LIB_CLASS);
nameTable.put("RioSupport", RIO);
nameTable.put("SoftwareSupport", CAPABILITY+".software.SoftwareSupport");
nameTable.put("ByteOrientedDevice", CAPABILITY+".system.ByteOrientedDevice");
nameTable.put("Memory", MEMORY);
nameTable.put("OperatingSystem", OPSYS);
nameTable.put("ProcessorArchitecture", PROCESSOR);
nameTable.put("StorageCapability", STORAGE);
return nameTable;
}
public String getPlatformConfigurationDirectory(Configuration config) {
if(platformConfigDir==null) {
String rioHome = getRioHome();
if(rioHome==null) {
return null;
}
String defaultDir = rioHome+File.separator+"config"+File.separator+"platform";
if(config!=null) {
try {
platformConfigDir = (String)config.getEntry(COMPONENT,
"platformDirs",
String.class,
defaultDir);
} catch (ConfigurationException e) {
logger.warn("An exception occurred tying to read the "+
"{}.platformDirs property, continue on " +
"and use default value of {}",
COMPONENT, defaultDir,
e);
platformConfigDir = defaultDir;
}
} else {
platformConfigDir = defaultDir;
}
}
return platformConfigDir;
}
protected PlatformCapability getPlatformCapability(String className) throws Exception {
Class pCapClass = Class.forName(className);
return((PlatformCapability)pCapClass.newInstance());
}
/*
* Load the DiskSpace measurable capability
*/
private MeasurableCapability getDiskSpace(Configuration config) {
MeasurableCapability diskSpace = null;
try {
diskSpace = (MeasurableCapability)config.getEntry(COMPONENT,
"disk",
MeasurableCapability.class,
new DiskSpace(config),
config);
} catch(ConfigurationException e) {
logger.warn("Loading DiskSpace MeasurableCapability", e);
}
return diskSpace;
}
/*
* Determine if a class has been loaded
*/
private PlatformCapability findCapability(List<PlatformCapability> pCaps, String name) {
PlatformCapability o = null;
for(PlatformCapability pCap : pCaps) {
if(pCap.getClass().getName().equals(name)) {
o = pCap;
break;
}
}
return(o);
}
/*
* Get the library extension to search for. Determined by the operating
* system name
*/
private String[] getLibExtensions() {
String opSys = System.getProperty("os.name");
if(opSys.startsWith("Windows"))
return(new String[]{"dll"});
if(opSys.startsWith("Mac"))
return(new String[]{"jnilib", "dylib"});
return(new String[]{"so"});
}
/*
* Load the platform configuration file
*/
private PlatformCapability[] parsePlatformConfig(PlatformLoader loader, String configDir) throws Exception {
return(createPlatformCapabilities(loader.parsePlatform(configDir)));
}
/*
* Create an array of PlatformCapability classes from parsed
* PlatformLoader.PlatformCapabilityConfig classes
*/
private PlatformCapability[] createPlatformCapabilities(PlatformCapabilityConfig[] caps) throws Exception {
PlatformCapability[] pCaps = new PlatformCapability[caps.length];
for(int i=0; i<caps.length; i++) {
Map<String, Object> attrs = new HashMap<String, Object>();
attrs.put(PlatformCapability.NAME, caps[i].getName());
if(caps[i].getDescription()!=null)
attrs.put(PlatformCapability.DESCRIPTION, caps[i].getDescription());
if(caps[i].getManufacturer()!=null)
attrs.put(PlatformCapability.MANUFACTURER, caps[i].getManufacturer());
if(caps[i].getVersion()!=null)
attrs.put(PlatformCapability.VERSION, caps[i].getVersion());
PlatformCapability pCap = (PlatformCapability)Class.forName(caps[i].getPlatformClass()).newInstance();
pCap.defineAll(attrs);
if(caps[i].getClasspath()!=null)
pCap.setClassPath(caps[i].getClasspath());
if(caps[i].getPath()!=null)
pCap.setPath(caps[i].getPath());
if(caps[i].geCostModelClass()!=null) {
ResourceCostModel costModel = (ResourceCostModel)Class.forName(caps[i].geCostModelClass()).newInstance();
pCap.setResourceCostModel(costModel);
}
PlatformCapabilityLoader.getLoadableClassPath(pCap);
pCaps[i] = pCap;
}
return(pCaps);
}
private String getRioHome() {
String rioHome = System.getProperty("rio.home");
if(rioHome==null) {
rioHome = System.getenv("RIO_HOME");
if(rioHome!=null) {
System.setProperty("rio.home", rioHome);
logger.info("Set rio.home to "+System.getProperty("rio.home"));
}
}
return rioHome;
}
}