1 package org.apache.commons.modeler.modules;
2
3 import java.io.FileNotFoundException;
4 import java.io.FileOutputStream;
5 import java.io.InputStream;
6 import java.net.URL;
7 import java.util.ArrayList;
8 import java.util.HashMap;
9 import java.util.List;
10
11 import javax.management.Attribute;
12 import javax.management.MBeanServer;
13 import javax.management.ObjectName;
14 import javax.management.loading.MLet;
15 import javax.xml.transform.TransformerException;
16
17 import org.apache.commons.logging.Log;
18 import org.apache.commons.logging.LogFactory;
19 import org.apache.commons.modeler.AttributeInfo;
20 import org.apache.commons.modeler.BaseModelMBean;
21 import org.apache.commons.modeler.ManagedBean;
22 import org.apache.commons.modeler.Registry;
23 import org.apache.commons.modeler.util.DomUtil;
24 import org.w3c.dom.Document;
25 import org.w3c.dom.Node;
26
27
28 /*** This will create mbeans based on a config file.
29 * The format is an extended version of MLET.
30 *
31 * Classloading. We don't support any explicit classloader tag.
32 * A ClassLoader is just an mbean ( it can be the standard MLetMBean or
33 * a custom one ).
34 *
35 * XXX add a special attribute to reference the loader mbean,
36 * XXX figure out how to deal with private loaders
37 */
38 public class MbeansSource extends ModelerSource implements MbeansSourceMBean
39 {
40 private static Log log = LogFactory.getLog(MbeansSource.class);
41 Registry registry;
42 String type;
43
44
45 boolean loading=true;
46 List mbeans=new ArrayList();
47 static boolean loaderLoaded=false;
48 private Document document;
49 private HashMap object2Node = new HashMap();
50
51 long lastUpdate;
52 long updateInterval=10000;
53
54 public void setRegistry(Registry reg) {
55 this.registry=reg;
56 }
57
58 public void setLocation( String loc ) {
59 this.location=loc;
60 }
61
62 /*** Used if a single component is loaded
63 *
64 * @param type
65 */
66 public void setType( String type ) {
67 this.type=type;
68 }
69
70 public void setSource( Object source ) {
71 this.source=source;
72 }
73
74 public Object getSource() {
75 return source;
76 }
77
78 public String getLocation() {
79 return location;
80 }
81
82 /*** Return the list of mbeans created by this source.
83 * It can be used to implement runtime services.
84 */
85 public List getMBeans() {
86 return mbeans;
87 }
88
89 public List loadDescriptors( Registry registry, String location,
90 String type, Object source)
91 throws Exception
92 {
93 setRegistry(registry);
94 setLocation(location);
95 setType(type);
96 setSource(source);
97 execute();
98 return mbeans;
99 }
100
101 public void start() throws Exception {
102 registry.invoke(mbeans, "start", false);
103 }
104
105 public void stop() throws Exception {
106 registry.invoke(mbeans, "stop", false);
107 }
108
109 public void init() throws Exception {
110 if( mbeans==null) execute();
111 if( registry==null ) registry=Registry.getRegistry();
112
113 registry.invoke(mbeans, "init", false);
114 }
115
116 public void destroy() throws Exception {
117 registry.invoke(mbeans, "destroy", false);
118 }
119
120 public void load() throws Exception {
121 execute();
122 }
123
124 public void execute() throws Exception {
125 if( registry==null ) registry=Registry.getRegistry();
126 try {
127 InputStream stream=getInputStream();
128 long t1=System.currentTimeMillis();
129 document = DomUtil.readXml(stream);
130
131
132 Node descriptorsN=document.getDocumentElement();
133
134 if( descriptorsN == null ) {
135 log.error("No descriptors found");
136 return;
137 }
138
139 Node firstMbeanN=DomUtil.getChild(descriptorsN, null);
140
141 if( firstMbeanN==null ) {
142
143 if( log.isDebugEnabled() )
144 log.debug("No child " + descriptorsN);
145 firstMbeanN=descriptorsN;
146 }
147
148 MBeanServer server=(MBeanServer)Registry.getServer();
149
150
151 if( ! loaderLoaded ) {
152
153 ObjectName defaultLoader= new ObjectName("modeler",
154 "loader", "modeler");
155 MLet mlet=new MLet( new URL[0], this.getClass().getClassLoader());
156 server.registerMBean(mlet, defaultLoader);
157 loaderLoaded=true;
158 }
159
160
161 for (Node mbeanN = firstMbeanN; mbeanN != null;
162 mbeanN= DomUtil.getNext(mbeanN, null, Node.ELEMENT_NODE))
163 {
164 String nodeName=mbeanN.getNodeName();
165
166
167 if( "mbean".equals(nodeName) || "MLET".equals(nodeName) )
168 {
169 String code=DomUtil.getAttribute( mbeanN, "code" );
170 String objectName=DomUtil.getAttribute( mbeanN, "objectName" );
171 if( objectName==null ) {
172 objectName=DomUtil.getAttribute( mbeanN, "name" );
173 }
174
175 if( log.isDebugEnabled())
176 log.debug( "Processing mbean objectName=" + objectName +
177 " code=" + code);
178
179
180 Node constructorN=DomUtil.getChild(mbeanN, "constructor");
181 if( constructorN == null ) constructorN=mbeanN;
182
183 ArgsInfo info = processArg(constructorN);
184
185 try {
186 ObjectName oname=new ObjectName(objectName);
187 if( ! server.isRegistered( oname )) {
188
189
190 String modelMBean=BaseModelMBean.class.getName();
191 if(info == null) {
192 server.createMBean(modelMBean, oname,
193 new Object[] { code, this},
194 new String[] { String.class.getName(),
195 ModelerSource.class.getName() }
196 );
197 } else {
198 server.createMBean(modelMBean, oname,
199 new Object[] { code, this,
200 info.getValues(),
201 info.getSigs()
202 },
203 new String[] { String.class.getName(),
204 ModelerSource.class.getName(),
205 Object[].class.getName(),
206 String[].class.getName()
207 }
208 );
209 }
210
211 mbeans.add(oname);
212 }
213 object2Node.put( oname, mbeanN );
214
215 } catch( Exception ex ) {
216 log.error( "Error creating mbean " + objectName, ex);
217 }
218
219 Node firstAttN=DomUtil.getChild(mbeanN, "attribute");
220 for (Node descN = firstAttN; descN != null;
221 descN = DomUtil.getNext( descN ))
222 {
223 processAttribute(server, descN, objectName);
224 }
225 } else if("jmx-operation".equals(nodeName) ) {
226 String name=DomUtil.getAttribute(mbeanN, "objectName");
227 if( name==null )
228 name=DomUtil.getAttribute(mbeanN, "name");
229
230 String operation=DomUtil.getAttribute(mbeanN, "operation");
231
232 if( log.isDebugEnabled())
233 log.debug( "Processing invoke objectName=" + name +
234 " code=" + operation);
235 try {
236 ObjectName oname=new ObjectName(name);
237
238 ArgsInfo info = processArg( mbeanN );
239 if(info == null) {
240 server.invoke( oname, operation, null, null);
241 } else {
242 server.invoke( oname, operation, info.getValues(), info.getSigs());
243 }
244 } catch (Exception e) {
245 log.error( "Error in invoke " + name + " " + operation);
246 }
247 }
248
249 ManagedBean managed=new ManagedBean();
250 DomUtil.setAttributes(managed, mbeanN);
251 Node firstN;
252
253
254 firstN=DomUtil.getChild( mbeanN, "attribute");
255 for (Node descN = firstN; descN != null;
256 descN = DomUtil.getNext( descN ))
257 {
258 AttributeInfo ci=new AttributeInfo();
259 DomUtil.setAttributes(ci, descN);
260 managed.addAttribute( ci );
261 }
262
263 }
264
265 long t2=System.currentTimeMillis();
266 log.info( "Reading mbeans " + (t2-t1));
267 loading=false;
268 } catch( Exception ex ) {
269 log.error( "Error reading mbeans ", ex);
270 }
271 }
272
273 public void updateField( ObjectName oname, String name,
274 Object value )
275 {
276 if( loading ) return;
277
278
279 Node n=(Node)object2Node.get( oname );
280 if( n == null ) {
281 log.info( "Node not found " + oname );
282 return;
283 }
284 Node attNode=DomUtil.findChildWithAtt(n, "attribute", "name", name);
285 if( attNode == null ) {
286
287 attNode=n.getOwnerDocument().createElement("attribute");
288 DomUtil.setAttribute(attNode, "name", name);
289 n.appendChild(attNode);
290 }
291 String oldValue=DomUtil.getAttribute(attNode, "value");
292 if( oldValue != null ) {
293
294 DomUtil.removeAttribute( attNode, "value");
295 }
296 DomUtil.setText(attNode, value.toString());
297
298
299 }
300
301 /*** Store the mbeans.
302 * XXX add a background thread to store it periodically
303 */
304 public void save() {
305
306
307
308 long time=System.currentTimeMillis();
309 if( location!=null &&
310 time - lastUpdate > updateInterval ) {
311 lastUpdate=time;
312 try {
313 FileOutputStream fos=new FileOutputStream(location);
314 DomUtil.writeXml(document, fos);
315 } catch (TransformerException e) {
316 log.error( "Error writing");
317 } catch (FileNotFoundException e) {
318 log.error( "Error writing" ,e );
319 }
320 }
321 }
322
323 private void processAttribute(MBeanServer server,
324 Node descN, String objectName ) {
325 String attName=DomUtil.getAttribute(descN, "name");
326 String value=DomUtil.getAttribute(descN, "value");
327 String type=null;
328 if( value==null ) {
329
330 value=DomUtil.getContent(descN);
331 }
332 try {
333 if( log.isDebugEnabled())
334 log.debug("Set attribute " + objectName + " " + attName +
335 " " + value);
336 ObjectName oname=new ObjectName(objectName);
337
338 if( type==null )
339 type=registry.getType( oname, attName );
340
341 if( type==null ) {
342 log.info("Can't find attribute " + objectName + " " + attName );
343
344 } else {
345 Object valueO=registry.convertValue( type, value);
346 server.setAttribute(oname, new Attribute(attName, valueO));
347 }
348 } catch( Exception ex) {
349 log.error("Error processing attribute " + objectName + " " +
350 attName + " " + value, ex);
351 }
352
353 }
354
355 private ArgsInfo processArg(Node mbeanN) {
356 Node firstArgN=DomUtil.getChild(mbeanN, "arg" );
357 if(firstArgN == null) {
358 return null;
359 }
360 ArgsInfo info = new ArgsInfo();
361
362 for (Node argN = firstArgN; argN != null;
363 argN = DomUtil.getNext( argN ))
364 {
365 String type=DomUtil.getAttribute(argN, "type");
366 String value=DomUtil.getAttribute(argN, "value");
367 if( value==null ) {
368
369 value=DomUtil.getContent(argN);
370 }
371 info.addArgPair(type, registry.convertValue(type,value));
372 }
373 return info;
374 }
375
376 private static class ArgsInfo {
377 private List sigs = new ArrayList();
378 private List values = new ArrayList();
379
380 ArgsInfo() {
381 }
382
383 public String [] getSigs() {
384 return (String [])sigs.toArray(new String[sigs.size()]);
385 }
386
387 public Object[] getValues () {
388 return values.toArray(new Object[values.size()]);
389 }
390
391 public void addArgPair(String name, Object val) {
392 sigs.add(name);
393 values.add(val);
394 }
395 }
396 }