1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.modeler.mbeans;
18
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.net.URL;
22 import java.net.URLConnection;
23 import java.util.HashMap;
24 import java.util.Iterator;
25 import java.util.Map;
26 import java.util.jar.Attributes;
27 import java.util.jar.Manifest;
28
29 import javax.management.Attribute;
30 import javax.management.AttributeNotFoundException;
31 import javax.management.MBeanException;
32 import javax.management.MBeanServer;
33 import javax.management.ObjectName;
34 import javax.management.ReflectionException;
35
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38 import org.apache.commons.modeler.Registry;
39
40 /***
41 * Based on jk2 proxy.
42 *
43 * Proxy using a very simple HTTP based protocol.
44 *
45 * For efficiency, it'll get bulk results and cache them - you
46 * can force an update by calling the refreshAttributes and refreshMetadata
47 * operations on this mbean.
48 *
49 * TODO: implement the user/pass auth ( right now you must use IP based security )
50 * TODO: eventually support https
51 * TODO: support for metadata ( mbean-descriptors ) for description and type conversions
52 * TODO: filter out trivial components ( mutexes, etc )
53 *
54 * @author Costin Manolache
55 */
56 public class SimpleRemoteConnector
57 {
58 private static Log log = LogFactory.getLog(SimpleRemoteConnector.class);
59
60
61 String webServerHost="localhost";
62 int webServerPort=8080;
63
64
65 String statusPath="/jkstatus";
66
67
68 String user;
69 String pass;
70
71
72 String domain;
73
74
75 String localDomain;
76 String filter;
77
78
79 long lastRefresh=0;
80 long updateInterval=5000;
81
82 String prefix="";
83
84 Registry reg;
85
86 MBeanServer mserver;
87
88
89 HashMap mbeans=new HashMap();
90
91 public SimpleRemoteConnector()
92 {
93 }
94
95
96
97 public String getWebServerHost() {
98 return webServerHost;
99 }
100
101 public void setWebServerHost(String webServerHost) {
102 this.webServerHost = webServerHost;
103 }
104
105 public int getWebServerPort() {
106 return webServerPort;
107 }
108
109 public void setWebServerPort(int webServerPort) {
110 this.webServerPort = webServerPort;
111 }
112
113 public long getUpdateInterval() {
114 return updateInterval;
115 }
116
117 public void setUpdateInterval(long updateInterval) {
118 this.updateInterval = updateInterval;
119 }
120
121 public String getUser() {
122 return user;
123 }
124
125 public void setUser(String user) {
126 this.user = user;
127 }
128
129 public String getPass() {
130 return pass;
131 }
132
133 public String getDomain() {
134 return domain;
135 }
136
137 public void setDomain(String domain) {
138 this.domain = domain;
139 }
140
141 public void setPass(String pass) {
142 this.pass = pass;
143 }
144
145 public String getStatusPath() {
146 return statusPath;
147 }
148
149 public void setStatusPath(String statusPath) {
150 this.statusPath = statusPath;
151 }
152
153 public String getFilter() {
154 return filter;
155 }
156
157 public void setFilter(String filter) {
158 this.filter = filter;
159 }
160
161
162
163 public void destroy() {
164 try {
165
166
167 Iterator mbeansIt=mbeans.values().iterator();
168 while( mbeansIt.hasNext()) {
169 MBeanProxy proxy=(MBeanProxy)mbeansIt.next();
170 ObjectName oname=proxy.getJmxName();
171 Registry.getRegistry().getMBeanServer().unregisterMBean(oname);
172 }
173 } catch( Throwable t ) {
174 log.error( "Destroy error", t );
175 }
176 }
177
178 public void init() throws IOException {
179 try {
180
181 log.info("init " + webServerHost + " " + webServerPort);
182 reg=Registry.getRegistry();
183
184
185
186 refreshAttributes();
187 } catch( Throwable t ) {
188 log.error( "Init error", t );
189 }
190 }
191
192 public void start() throws IOException {
193 System.out.println("XXX start");
194 if( reg==null)
195 init();
196 }
197
198 /*** Refresh the proxies, if updateInterval passed
199 *
200 */
201 public void refresh() {
202 long time=System.currentTimeMillis();
203 if( time - lastRefresh < updateInterval ) {
204 return;
205 }
206 System.out.println("refresh... ");
207 lastRefresh=time;
208
209 refreshAttributes();
210 }
211
212 public void refreshAttributes() {
213 try {
214 int cnt=0;
215
216 if( filter==null ) {
217 filter=domain + ":*";
218 }
219
220 InputStream is=getStream( "qry=" + filter);
221 if( is==null ) return;
222
223 Manifest mf=new Manifest(is);
224
225 HashMap currentObjects=new HashMap();
226 Map entries=mf.getEntries();
227 Iterator it=entries.keySet().iterator();
228 while( it.hasNext() ) {
229 String name=(String)it.next();
230 Attributes attrs=(Attributes)entries.get( name );
231
232 ObjectName oname=new ObjectName(name);
233 currentObjects.put( oname, "");
234 MBeanProxy proxy=(MBeanProxy)mbeans.get(oname);
235 if( proxy==null ) {
236 log.debug( "New object " + name);
237 String code=attrs.getValue("modelerType");
238 if(log.isDebugEnabled())
239 log.debug("Register " + name + " " + code );
240
241 proxy= new MBeanProxy(this, code);
242 mbeans.put( oname, proxy );
243
244
245 MBeanServer mserver=Registry.getRegistry().getMBeanServer();
246 if( ! mserver.isRegistered(oname ) ) {
247 mserver.registerMBean(proxy, oname);
248 }
249 }
250 Iterator it2=attrs.keySet().iterator();
251 while( it2.hasNext() ) {
252 Object o=it2.next();
253 String att=(o==null) ? null : o.toString();
254 if( "modelerType".equals( att )) continue;
255 String val=attrs.getValue(att);
256 proxy.update(att, val);
257 cnt++;
258 }
259 }
260
261
262 Iterator existingIt=mbeans.keySet().iterator();
263 while( existingIt.hasNext() ) {
264 ObjectName on=(ObjectName)existingIt.next();
265 if(currentObjects.get( on ) != null )
266 continue;
267 if( log.isDebugEnabled() )
268 log.debug("No longer alive " + on);
269 try {
270 mserver.unregisterMBean(on);
271 } catch( Throwable t ) {
272 log.info("Error unregistering " + on + " " + t.toString());
273 }
274 }
275
276 log.info( "Refreshing attributes " + cnt);
277 } catch( Exception ex ) {
278 log.info("Error ", ex);
279 }
280 }
281
282
283
284
285 public void refreshMetadata() {
286 try {
287 int cnt=0;
288 int newCnt=0;
289 InputStream is=getStream("getMetadata=" + domain + ":*");
290 if( is==null ) return;
291
292 log.info( "Refreshing metadata " + cnt + " " + newCnt);
293 } catch( Exception ex ) {
294 log.info("Error ", ex);
295 }
296 }
297
298 public Object invoke(Object oname, String name, Object params[], String signature[])
299 throws MBeanException, ReflectionException {
300 try {
301
302 InputStream is=this.getStream("invoke=" + name + "&name=" + oname.toString() );
303 if( is==null ) return null;
304
305
306
307
308
309 this.refreshAttributes();
310 } catch( Exception ex ) {
311 throw new MBeanException(ex);
312 }
313 return null;
314 }
315
316
317 public void setAttribute(ObjectName oname, Attribute attribute)
318 throws AttributeNotFoundException, MBeanException,
319 ReflectionException
320 {
321 try {
322
323 String val=(String)attribute.getValue();
324 String name=attribute.getName();
325 InputStream is=this.getStream("set=" + name + "&name=" + oname.toString()
326 + "&value=" + val);
327 if( is==null ) return;
328
329
330
331
332
333 this.refreshAttributes();
334 } catch( Exception ex ) {
335 throw new MBeanException(ex);
336 }
337 }
338
339 /*** connect to apache using http, get a list of mbeans. Can be
340 * overriten to support different protocols ( jk/Unix domain sockets, etc )
341 */
342 protected InputStream getStream(String qry) throws Exception {
343 try {
344 String path=statusPath + "?" + qry;
345 URL url=new URL( "http", webServerHost, webServerPort, path);
346 log.debug( "Connecting to " + url);
347 URLConnection urlc=url.openConnection();
348 InputStream is=urlc.getInputStream();
349 return is;
350 } catch (IOException e) {
351 log.info( "Can't connect to jkstatus " + webServerHost + ":" + webServerPort
352 + " " + e.toString());
353 return null;
354 }
355 }
356
357
358 }
359