Storing webservice properties using dynamic MBeans.
Recently I needed to store some settings in a JSR-181 webservice. Since I did not have a user interface and I don’t want to use property files I thought to try and store them in a MBean using JMX.
This gives the administrator the change to alter the properties through the Oracle Enterprise Manager instead of digging for property files on the server. It actually is pretty straightforward to implement a MBean. However to implement it dynamic is a bit harder so here how I did it:
First create a class which name ends with: MBean and implements the DynamicMBean interface.
Here’s my class:
public class SettingsMBean implements DynamicMBean {
private Properties properties = null;
private MBeanInfo info = null;
private MBeanConstructorInfo[] conInfo = null;
private MBeanOperationInfo[] operInfo = null;
private MBeanAttributeInfo[] attrInfo = null;
private MBeanNotificationInfo[] notifInfo = null;
public static final String LOADPROPERTIES = "loadProperties";
public static final String SAVEPROPERTIES = "saveProperties";
public SettingsMBean() {
}
public Object getAttribute(String attribute) {
return properties.getProperty(attribute);
}
public void setAttribute(Attribute attribute) {
if (properties.getProperty(attribute.getName()) != null) {
properties.setProperty(attribute.getName(),(String)attribute.getValue());
}
}
public AttributeList getAttributes(String[] attributes) {
AttributeList list = new AttributeList();
list.add(new Attribute("properties", properties));
for (String name: attributes) {
String value = properties.getProperty(name);
if (value != null) {
list.add(new Attribute(name, value));
}
}
return list;
}
public AttributeList setAttributes(AttributeList attributes) {
Attribute[] attrs = (Attribute[])attributes.toArray(new Attribute[0]);
AttributeList retlist = new AttributeList();
for (Attribute attr: attrs) {
String name = attr.getName();
Object value = attr.getValue();
if ((properties.getProperty(name) != null) && value instanceof String) {
properties.setProperty(name, (String)value);
retlist.add(new Attribute(name, value));
}
}
try {
saveProperties();
} catch (Exception e) {
e.printStackTrace();
return new AttributeList();
}
return retlist;
}
public Object invoke(String actionName, Object[] params, String[] signature) {
if (actionName.compareToIgnoreCase("loadProperties")==0) {
if (loadProperties()) {
this.constructInfo();
}
}
}
public MBeanInfo getMBeanInfo() {
if (this.info == null) {
constructInfo();
}
return info;
}
private Boolean saveProperties() {
//TODO: inplement save method...
}
public Boolean loadProperties() {
//TODO: implement load method...
}
private void constructInfo() {
this.constructConstructorInfo();
this.constructOperationInfo();
this.constructAttributeInfo();
String className = "SettingsMBean";
String description = "Webservice settings MBean";
this.info = new MBeanInfo(className, description, attrInfo, conInfo, operInfo, notifInfo);
}
private void constructConstructorInfo() {
String name = "Default";
String description = "Default no-args constructor";
MBeanParameterInfo[] signature = null; //no params since it's a no-args constructor...
this.conInfo = new MBeanConstructorInfo[1];
this.conInfo[0] = new MBeanConstructorInfo(name, description, signature);
}
private void constructOperationInfo() {
String type = Boolean.TYPE.getName();
int impact = MBeanOperationInfo.ACTION;
this.operInfo = new MBeanOperationInfo[2];
this.operInfo[0] = new MBeanOperationInfo(LOADPROPERTIES, "Loads all properties", null, type, impact);
this.operInfo[1] = new MBeanOperationInfo(SAVEPROPERTIES, "Save all properties", null, type, impact);
}
private void constructAttributeInfo() {
SortedSet names = new TreeSet();
for (Object name : properties.keySet()) {
names.add((String) name);
}
String nameProps = "All properties";
String description = "Webservice properties";
this.attrInfo = new MBeanAttributeInfo[names.size() + 1];
this.attrInfo[0] = new MBeanAttributeInfo(nameProps, "java.util.Properties", description, true, false, false);
Iterator it = names.iterator();
for (int i = 1; i < attrInfo.length; i++) {
String name = it.next();
attrInfo[i] = new MBeanAttributeInfo(name, "java.lang.String","Property " + name, true, true, false);
}
}
}
Second you need to deploy the MBean.
I created a separate .jar file for the bean using ant. I deployed this in my .ear file and created an orion-application.xml in which you can declare the mbean:
<orion-application>
<jmx-mbean objectname=":type=Application,name=SettingsMBean"
class="nl.iteye.beans:SettingsMBean">
<description>Settings MBean</description>
</jmx-mbean>
</orion-application>
After deploying you can use the Enterprise Manager to view/update your properties on the fly. I left out some of the details of filling the properties.
I created this with help from Pat Lee.

November 16th, 2007 at 20:52:31
I’ve taken a similar approach to managing our application, but I used the Preferences API instead of Properties. The Preferences API is especially nice for this since you don’t have to worry about path information or any file IO (and associated exceptions).
For projects using Spring there is an even easier approach using the MBeanExporter and the @ManagedResource annotation. This JMX enables any Spring managed bean and (as you mentioned) admin your app through OEM. Since Spring takes care of exporting your beans, you don’t have to worry about the orion-specific config files either. There are a few pitfalls in getting it to work properly in OC4J, but most of that has to do with how you are allowed to name your MBeans.
Its also worth mentioning that this can be used for more than configuration. You can also gather statistics about your running application. For instance, you could add a getInvokeCount() method and increment a counter every time invoke() is called.
November 17th, 2007 at 12:55:55
Hi, We use mbeans for starting and stopping background processes and for status checking. I see you load the mbeans with orion-application but you can load the mbean also with a ServletContextListener
see my blog.
http://biemond.blogspot.com/2007/11/jmx-for-starting-background-processes.html
November 21st, 2007 at 07:38:54
[...] Original post by Albert Sikkema [...]
January 3rd, 2008 at 18:25:13
Hi,
Thanks for the article. I am a newbie to oracle web services (and java in general). I’ve been struggling to find a way to configure my web service(s) via the management interface. Is there any chance I could see a simple example implementation of the loadProperties() and saveProperties() methods?
Thanks
Terry
January 4th, 2008 at 10:11:18
Hi Terry,
I implemented the load and saveproperties methods by just writing our properties to file (using encryption). Here’s an example:
/**
* Loads the properties which are specified by the user.
*/
public Boolean loadProperties() {
FileInputStream fis;
try {
if (properties == null) {
properties = new Properties();
}
synchronized (properties) {
properties.clear();
File f = new File(propertiesfile);
if (f.exists()) {
fis = new FileInputStream(f);
Properties tempProps = new Properties();
tempProps.loadFromXML(fis);
properties = decryptProperties(tempProps);
fis.close();
} else {
loadDefaultProperties();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
/**
* Persist the properties to file.
* @return true if succesfull
*/
public Boolean saveProperties() {
FileOutputStream fos;
try {
File f = new File(propertiesfile);
fos = new FileOutputStream(f);
synchronized (properties) {
String comment = “Written by ” + this.getClass().getName();
encryptProperties(properties).storeToXML(fos, comment, “UTF-8″);
fos.close();
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
You can easily remove the encryption and decryption and use this.
April 15th, 2008 at 21:19:03
Very good article. I have a similar usecase i need to implement. I am newbie to j2ee and jmx, could you help me with the steps for packaging it with ear. How did you package your mbean into ear. Package the mbean as jar, does this also include the jboss-service.xml, where does jboss-service.xml go into ear or jar?? Please give the complete details of packaging the mbean into an existing ear.
I managed to run it by packaging it into .sar and run standalone but i need to pacakge it inot existing .ear now.
Thanks a lot in advance
April 16th, 2008 at 03:05:35
From the above article
“This gives the administrator the change to alter the properties through the Oracle Enterprise Manager instead of digging for property files on the server”
I am trying to do a similar usecase, are these properties inside war,ear or jar or sar? Do you edit them inplace? Could you please let me know how do you do that? If not, if you explode the archive edit and rebundle the archive, how do you manage the production environment, do you assume it is downtime during this update or any other alternative so that the uses has seemless acess to the production applicaiton?
You quick responses would be highly appreciated.
tHanks much