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