/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.mx.persistence;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Vector;
import javax.management.Descriptor;
import javax.management.InstanceNotFoundException;
import javax.management.IntrospectionException;
import javax.management.JMException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.modelmbean.InvalidTargetObjectTypeException;
import javax.management.modelmbean.ModelMBean;
import javax.management.modelmbean.ModelMBeanInfo;
import javax.management.modelmbean.RequiredModelMBean;
import org.apache.log4j.Logger;
import org.jboss.mx.modelmbean.ModelMBeanConstants;
import org.jboss.mx.modelmbean.ModelMBeanInvoker;
import org.jboss.mx.server.registry.BasicMBeanRegistry;
import org.jboss.mx.server.registry.MBeanEntry;
import org.jboss.mx.server.registry.MbeanInfoDb;
/**
* Class responsible for storing and loading the MBean info database.
* @author Matt Munz
*/
public class MbeanInfoDbPm
extends MBeanInfoOdb
implements PersistenceManager
{
protected boolean fLoadedFromFs;
protected Vector fNamesToRestore;
protected Vector fInfosToRestore;
protected MBeanServer fMbeanServer;
protected MbeanInfoDb fMbeanInfoDb;
protected File fMbiDbRoot;
public MbeanInfoDbPm()
{
super();
}
/**
* @todo finish implementing
*/
public void load(ModelMBeanInvoker mbean, MBeanInfo info)
throws MBeanException
{
logger().debug("Loading the MBI DB");
setMbeanInfoDb((MbeanInfoDb) mbean.getResource());
if(!loadedFromFs())
{
// get mbi db root from descriptor
Descriptor d = ((ModelMBeanInfo) info).getMBeanDescriptor();
String dir = (String) d.getFieldValue(
ModelMBeanConstants.PERSIST_LOCATION);
if((dir != null) && (!dir.equals("")))
{
setMbiDbRoot(new File(dir));
}
String message = "Loading the MBI DB from the filesystem. location: ";
message += mbiDbRoot();
logger().debug(message);
File[] mbiFiles = mbiDbRoot().listFiles();
if(mbiFiles == null)
{
return;
}
// loop over each item in the mbeaninfo store
for(int index = 0; index < mbiFiles.length; index++)
{
/// for each, load, make a new mbean, and register that mbean
File curFile = mbiFiles[index];
ObjectName nameToRestore = null;
try
{
nameToRestore = objectName(curFile);
}
catch(MalformedObjectNameException cause)
{
throw new MBeanException(cause,
"Object Name was stored incorrectly.");
}
MBeanInfo infoToRestore = null;
try
{
infoToRestore = load(curFile);
}
catch(IOException cause)
{
throw new MBeanException(cause,
"Couldn't read the MBeanInfo file.");
}
catch(ClassNotFoundException cause2)
{
String message2 = "Couldn't find the Class specified in the object file.";
throw new MBeanException(cause2, message2);
}
if(infoToRestore == null)
{
throw new MBeanException(new Exception(
"Null loaded MBean info. Error on load."),
"Could not load");
}
namesToRestore().add(nameToRestore);
infosToRestore().add(infoToRestore);
}
setLoadedFromFs(true);
}
try
{
register();
}
catch(Exception cause)
{
throw new MBeanException(cause,
"Error trying to register loaded MBeans");
}
}
public void store(MBeanInfo info) throws MBeanException
{
logger().debug("storing MBI DB State");
Enumeration queue = mbeanInfoDb().mbiPersistenceQueue();
for(; queue.hasMoreElements();)
{
ObjectName curName = (ObjectName) queue.nextElement();
logger().debug("queue elem: " + curName);
MBeanInfo curInfo = null;
try
{
curInfo = getMBeanServer().getMBeanInfo(curName);
}
catch(InstanceNotFoundException cause)
{
throw new MBeanException(cause);
}
catch(JMException cause3)
{
throw new MBeanException(cause3);
}
if(curInfo == null)
{
throw new MBeanException(
new Exception("Current MBean Info object is null."),
"Could not store null object.");
}
try
{
store(curName, curInfo);
}
catch(IOException cause2)
{
throw new MBeanException(cause2);
}
mbeanInfoDb().removeFromMbiQueue(curName);
logger().info("Successfully stored mbi for " + curName);
}
}
protected void store(ObjectName name, MBeanInfo info)
throws IOException
{
File location = new File(mbiDbRoot(), fileName(name));
logger().debug("Storing mbi at: " + location);
mbiDbRoot().mkdirs();
store(info, location);
}
/**
* Iterates over the loaded MBean infos and ObjectNames, creates an MBean for each, and
* registers it with the server. This includes creating the resource object as well.
*/
protected void register() throws JMException,
InvalidTargetObjectTypeException
{
// iterate over all loaded infos and register them.
logger().debug("registering...");
Enumeration names = namesToRestore().elements();
Enumeration infos = infosToRestore().elements();
try
{
while(names.hasMoreElements() && infos.hasMoreElements())
{
ObjectName curName = (ObjectName) names.nextElement();
logger().debug("curName: " + curName);
ModelMBeanInfo curInfo = (ModelMBeanInfo) infos.nextElement();
Descriptor mbeanDescriptor = curInfo.getMBeanDescriptor();
String fieldName = ModelMBeanConstants.RESOURCE_CLASS;
String className = (String) mbeanDescriptor.getFieldValue(fieldName);
logger().debug("className: " + className);
Object resource = getMBeanServer().instantiate(className);
ModelMBean modelmbean = new RequiredModelMBean();
modelmbean.setModelMBeanInfo(curInfo);
modelmbean.setManagedResource(resource, "ObjectReference");
getMBeanServer().registerMBean(modelmbean, curName);
}
}
finally
{
namesToRestore().removeAllElements();
infosToRestore().removeAllElements();
}
}
protected MBeanServer getMBeanServer() throws JMException
{
if(fMbeanServer == null)
{
Collection col = MBeanServerFactory.findMBeanServer(null);
if(col.isEmpty())
{
throw new JMException("No MBeanServer found");
}
fMbeanServer = (MBeanServer) col.iterator().next();
}
return fMbeanServer;
}
/**
* JDK 1.3.1 substitute for jdk 1.4.1 String.replaceAll()
* Does not accept regular expressions...
* returns the object string where all instances of target are replaced with replacement
* @todo replace with a more appropriate string util if available
*/
protected String replaceAll(String object, String target, String replacement)
{
String result = new String(object);
return replaceAll(object, target, replacement, 0);
}
/**
* Iterative
*/
protected String replaceAll(String object, String target, String replacement, int curIndex)
{
int indexOfMatch = object.indexOf(target, curIndex);
if(indexOfMatch < curIndex)
{
return object;
}
String prefix = "";
if(indexOfMatch > 0)
{
prefix = object.substring(0, indexOfMatch);
}
String tail = object.substring(indexOfMatch + target.length());
String newObject = prefix + replacement + tail;
return replaceAll(newObject, target, replacement, indexOfMatch + replacement.length());
}
protected String objNameSeparator()
{
return ":";
}
protected String objNameSepRep()
{
return "___";
}
protected String fileName(ObjectName name)
{
String fileName = name.getCanonicalName();
fileName = replaceAll(fileName, objNameSeparator(), objNameSepRep());
return fileName;
}
protected ObjectName objectName(File fileName)
throws MalformedObjectNameException
{
String objectName = fileName.getName();
objectName = replaceAll(objectName, objNameSepRep(), objNameSeparator());
return new ObjectName(objectName);
}
protected boolean loadedFromFs()
{
return fLoadedFromFs;
}
protected void setLoadedFromFs(boolean newLoadedFromFs)
{
fLoadedFromFs = newLoadedFromFs;
}
protected Vector namesToRestore()
{
if(fNamesToRestore == null)
{
fNamesToRestore = new Vector(10);
}
return fNamesToRestore;
}
protected Vector infosToRestore()
{
if(fInfosToRestore == null)
{
fInfosToRestore = new Vector(10);
}
return fInfosToRestore;
}
protected File mbiDbRoot()
{
if(fMbiDbRoot == null)
{
fMbiDbRoot = new File("../conf/mbean-info-db/");
}
return fMbiDbRoot;
}
protected void setMbiDbRoot(File newMbiDbRoot)
{
fMbiDbRoot = newMbiDbRoot;
}
protected MbeanInfoDb mbeanInfoDb()
{
return fMbeanInfoDb;
}
protected void setMbeanInfoDb(MbeanInfoDb newMbeanInfoDb)
{
fMbeanInfoDb = newMbeanInfoDb;
}
}