1. package org.apache.commons.modeler.modules;
  2. import java.io.FileNotFoundException;
  3. import java.io.FileOutputStream;
  4. import java.io.InputStream;
  5. import java.net.URL;
  6. import java.util.ArrayList;
  7. import java.util.HashMap;
  8. import java.util.List;
  9. import javax.management.Attribute;
  10. import javax.management.MBeanServer;
  11. import javax.management.ObjectName;
  12. import javax.management.loading.MLet;
  13. import javax.xml.transform.TransformerException;
  14. import org.apache.commons.logging.Log;
  15. import org.apache.commons.logging.LogFactory;
  16. import org.apache.commons.modeler.AttributeInfo;
  17. import org.apache.commons.modeler.BaseModelMBean;
  18. import org.apache.commons.modeler.ManagedBean;
  19. import org.apache.commons.modeler.Registry;
  20. import org.apache.commons.modeler.util.DomUtil;
  21. import org.w3c.dom.Document;
  22. import org.w3c.dom.Node;
  23. /** This will create mbeans based on a config file.
  24. * The format is an extended version of MLET.
  25. *
  26. * Classloading. We don't support any explicit classloader tag.
  27. * A ClassLoader is just an mbean ( it can be the standard MLetMBean or
  28. * a custom one ).
  29. *
  30. * XXX add a special attribute to reference the loader mbean,
  31. * XXX figure out how to deal with private loaders
  32. */
  33. public class MbeansSource extends ModelerSource implements MbeansSourceMBean
  34. {
  35. private static Log log = LogFactory.getLog(MbeansSource.class);
  36. Registry registry;
  37. String type;
  38. // true if we are during the original loading
  39. boolean loading=true;
  40. List mbeans=new ArrayList();
  41. static boolean loaderLoaded=false;
  42. private Document document;
  43. private HashMap object2Node = new HashMap();
  44. long lastUpdate;
  45. long updateInterval=10000; // 10s
  46. public void setRegistry(Registry reg) {
  47. this.registry=reg;
  48. }
  49. public void setLocation( String loc ) {
  50. this.location=loc;
  51. }
  52. /** Used if a single component is loaded
  53. *
  54. * @param type
  55. */
  56. public void setType( String type ) {
  57. this.type=type;
  58. }
  59. public void setSource( Object source ) {
  60. this.source=source;
  61. }
  62. public Object getSource() {
  63. return source;
  64. }
  65. public String getLocation() {
  66. return location;
  67. }
  68. /** Return the list of mbeans created by this source.
  69. * It can be used to implement runtime services.
  70. */
  71. public List getMBeans() {
  72. return mbeans;
  73. }
  74. public List loadDescriptors( Registry registry, String location,
  75. String type, Object source)
  76. throws Exception
  77. {
  78. setRegistry(registry);
  79. setLocation(location);
  80. setType(type);
  81. setSource(source);
  82. execute();
  83. return mbeans;
  84. }
  85. public void start() throws Exception {
  86. registry.invoke(mbeans, "start", false);
  87. }
  88. public void stop() throws Exception {
  89. registry.invoke(mbeans, "stop", false);
  90. }
  91. public void init() throws Exception {
  92. if( mbeans==null) execute();
  93. if( registry==null ) registry=Registry.getRegistry();
  94. registry.invoke(mbeans, "init", false);
  95. }
  96. public void destroy() throws Exception {
  97. registry.invoke(mbeans, "destroy", false);
  98. }
  99. public void load() throws Exception {
  100. execute(); // backward compat
  101. }
  102. public void execute() throws Exception {
  103. if( registry==null ) registry=Registry.getRegistry();
  104. try {
  105. InputStream stream=getInputStream();
  106. long t1=System.currentTimeMillis();
  107. document = DomUtil.readXml(stream);
  108. // We don't care what the root node is.
  109. Node descriptorsN=document.getDocumentElement();
  110. if( descriptorsN == null ) {
  111. log.error("No descriptors found");
  112. return;
  113. }
  114. Node firstMbeanN=DomUtil.getChild(descriptorsN, null);
  115. if( firstMbeanN==null ) {
  116. // maybe we have a single mlet
  117. if( log.isDebugEnabled() )
  118. log.debug("No child " + descriptorsN);
  119. firstMbeanN=descriptorsN;
  120. }
  121. MBeanServer server=(MBeanServer)Registry.getServer();
  122. // XXX Not very clean... Just a workaround
  123. if( ! loaderLoaded ) {
  124. // Register a loader that will be find ant classes.
  125. ObjectName defaultLoader= new ObjectName("modeler",
  126. "loader", "modeler");
  127. MLet mlet=new MLet( new URL[0], this.getClass().getClassLoader());
  128. server.registerMBean(mlet, defaultLoader);
  129. loaderLoaded=true;
  130. }
  131. // Process nodes
  132. for (Node mbeanN = firstMbeanN; mbeanN != null;
  133. mbeanN= DomUtil.getNext(mbeanN, null, Node.ELEMENT_NODE))
  134. {
  135. String nodeName=mbeanN.getNodeName();
  136. // mbean is the "official" name
  137. if( "mbean".equals(nodeName) || "MLET".equals(nodeName) )
  138. {
  139. String code=DomUtil.getAttribute( mbeanN, "code" );
  140. String objectName=DomUtil.getAttribute( mbeanN, "objectName" );
  141. if( objectName==null ) {
  142. objectName=DomUtil.getAttribute( mbeanN, "name" );
  143. }
  144. if( log.isDebugEnabled())
  145. log.debug( "Processing mbean objectName=" + objectName +
  146. " code=" + code);
  147. // args can be grouped in constructor or direct childs
  148. Node constructorN=DomUtil.getChild(mbeanN, "constructor");
  149. if( constructorN == null ) constructorN=mbeanN;
  150. processArg(constructorN);
  151. try {
  152. ObjectName oname=new ObjectName(objectName);
  153. if( ! server.isRegistered( oname )) {
  154. // We wrap everything in a model mbean.
  155. // XXX need to support "StandardMBeanDescriptorsSource"
  156. String modelMBean=BaseModelMBean.class.getName();
  157. server.createMBean(modelMBean, oname,
  158. new Object[] { code, this},
  159. new String[] { String.class.getName(),
  160. ModelerSource.class.getName() }
  161. );
  162. mbeans.add(oname);
  163. }
  164. object2Node.put( oname, mbeanN );
  165. // XXX Arguments, loader !!!
  166. } catch( Exception ex ) {
  167. log.error( "Error creating mbean " + objectName, ex);
  168. }
  169. Node firstAttN=DomUtil.getChild(mbeanN, "attribute");
  170. for (Node descN = firstAttN; descN != null;
  171. descN = DomUtil.getNext( descN ))
  172. {
  173. processAttribute(server, descN, objectName);
  174. }
  175. } else if("jmx-operation".equals(nodeName) ) {
  176. String name=DomUtil.getAttribute(mbeanN, "objectName");
  177. if( name==null )
  178. name=DomUtil.getAttribute(mbeanN, "name");
  179. String operation=DomUtil.getAttribute(mbeanN, "operation");
  180. if( log.isDebugEnabled())
  181. log.debug( "Processing invoke objectName=" + name +
  182. " code=" + operation);
  183. try {
  184. ObjectName oname=new ObjectName(name);
  185. processArg( mbeanN );
  186. server.invoke( oname, operation, null, null);
  187. } catch (Exception e) {
  188. log.error( "Error in invoke " + name + " " + operation);
  189. }
  190. }
  191. ManagedBean managed=new ManagedBean();
  192. DomUtil.setAttributes(managed, mbeanN);
  193. Node firstN;
  194. // process attribute info
  195. firstN=DomUtil.getChild( mbeanN, "attribute");
  196. for (Node descN = firstN; descN != null;
  197. descN = DomUtil.getNext( descN ))
  198. {
  199. AttributeInfo ci=new AttributeInfo();
  200. DomUtil.setAttributes(ci, descN);
  201. managed.addAttribute( ci );
  202. }
  203. }
  204. long t2=System.currentTimeMillis();
  205. log.info( "Reading mbeans " + (t2-t1));
  206. loading=false;
  207. } catch( Exception ex ) {
  208. log.error( "Error reading mbeans ", ex);
  209. }
  210. }
  211. public void updateField( ObjectName oname, String name,
  212. Object value )
  213. {
  214. if( loading ) return;
  215. // nothing by default
  216. //log.info( "XXX UpdateField " + oname + " " + name + " " + value);
  217. Node n=(Node)object2Node.get( oname );
  218. if( n == null ) {
  219. log.info( "Node not found " + oname );
  220. return;
  221. }
  222. Node attNode=DomUtil.findChildWithAtt(n, "attribute", "name", name);
  223. if( attNode == null ) {
  224. // found no existing attribute with this name
  225. attNode=n.getOwnerDocument().createElement("attribute");
  226. DomUtil.setAttribute(attNode, "name", name);
  227. n.appendChild(attNode);
  228. }
  229. String oldValue=DomUtil.getAttribute(attNode, "value");
  230. if( oldValue != null ) {
  231. // we'll convert all values to text content
  232. DomUtil.removeAttribute( attNode, "value");
  233. }
  234. DomUtil.setText(attNode, value.toString());
  235. //store();
  236. }
  237. /** Store the mbeans.
  238. * XXX add a background thread to store it periodically
  239. */
  240. public void save() {
  241. // XXX customize no often than ( based on standard descriptor ), etc.
  242. // It doesn't work very well if we call this on each set att -
  243. // the triger will work for the first att, but all others will be delayed
  244. long time=System.currentTimeMillis();
  245. if( location!=null &&
  246. time - lastUpdate > updateInterval ) {
  247. lastUpdate=time;
  248. try {
  249. FileOutputStream fos=new FileOutputStream(location);
  250. DomUtil.writeXml(document, fos);
  251. } catch (TransformerException e) {
  252. log.error( "Error writing");
  253. } catch (FileNotFoundException e) {
  254. log.error( "Error writing" ,e );
  255. }
  256. }
  257. }
  258. private void processAttribute(MBeanServer server,
  259. Node descN, String objectName ) {
  260. String attName=DomUtil.getAttribute(descN, "name");
  261. String value=DomUtil.getAttribute(descN, "value");
  262. String type=null; // DomUtil.getAttribute(descN, "type");
  263. if( value==null ) {
  264. // The value may be specified as CDATA
  265. value=DomUtil.getContent(descN);
  266. }
  267. try {
  268. if( log.isDebugEnabled())
  269. log.debug("Set attribute " + objectName + " " + attName +
  270. " " + value);
  271. ObjectName oname=new ObjectName(objectName);
  272. // find the type
  273. if( type==null )
  274. type=registry.getType( oname, attName );
  275. if( type==null ) {
  276. log.info("Can't find attribute " + objectName + " " + attName );
  277. } else {
  278. Object valueO=registry.convertValue( type, value);
  279. server.setAttribute(oname, new Attribute(attName, valueO));
  280. }
  281. } catch( Exception ex) {
  282. log.error("Error processing attribute " + objectName + " " +
  283. attName + " " + value, ex);
  284. }
  285. }
  286. private void processArg(Node mbeanN) {
  287. Node firstArgN=DomUtil.getChild(mbeanN, "arg" );
  288. // process all args
  289. for (Node argN = firstArgN; argN != null;
  290. argN = DomUtil.getNext( argN ))
  291. {
  292. String type=DomUtil.getAttribute(argN, "type");
  293. String value=DomUtil.getAttribute(argN, "value");
  294. if( value==null ) {
  295. // The value may be specified as CDATA
  296. value=DomUtil.getContent(argN);
  297. }
  298. }
  299. }
  300. }