1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.catalina.connector;
18
19 import java.util.Iterator;
20 import java.util.Set;
21
22 import javax.management.MBeanServer;
23 import javax.management.MBeanServerNotification;
24 import javax.management.Notification;
25 import javax.management.NotificationListener;
26 import javax.management.ObjectInstance;
27 import javax.management.ObjectName;
28
29 import org.apache.juli.logging.Log;
30 import org.apache.juli.logging.LogFactory;
31
32
33 import org.apache.tomcat.util.http.mapper.Mapper;
34 import org.apache.tomcat.util.modeler.Registry;
35
36 import org.apache.tomcat.util.res.StringManager;
37
38
39 /**
40 * Mapper listener.
41 *
42 * @author Remy Maucherat
43 * @author Costin Manolache
44 */
45 public class MapperListener
46 implements NotificationListener
47 {
48 private static Log log = LogFactory.getLog(MapperListener.class);
49
50
51 // ----------------------------------------------------- Instance Variables
52 /**
53 * Associated mapper.
54 */
55 protected Mapper mapper = null;
56
57 /**
58 * MBean server.
59 */
60 protected MBeanServer mBeanServer = null;
61
62
63 /**
64 * The string manager for this package.
65 */
66 private StringManager sm =
67 StringManager.getManager(Constants.Package);
68
69 // It should be null - and fail if not set
70 private String domain="*";
71 private String engine="*";
72
73 // ----------------------------------------------------------- Constructors
74
75
76 /**
77 * Create mapper listener.
78 */
79 public MapperListener(Mapper mapper) {
80 this.mapper = mapper;
81 }
82
83
84 // --------------------------------------------------------- Public Methods
85
86 public String getDomain() {
87 return domain;
88 }
89
90 public void setDomain(String domain) {
91 this.domain = domain;
92 }
93
94 public String getEngine() {
95 return engine;
96 }
97
98 public void setEngine(String engine) {
99 this.engine = engine;
100 }
101
102 /**
103 * Initialize associated mapper.
104 */
105 public void init() {
106
107 try {
108
109 mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
110
111 registerEngine();
112
113 // Query hosts
114 String onStr = domain + ":type=Host,*";
115 ObjectName objectName = new ObjectName(onStr);
116 Set set = mBeanServer.queryMBeans(objectName, null);
117 Iterator iterator = set.iterator();
118 while (iterator.hasNext()) {
119 ObjectInstance oi = (ObjectInstance) iterator.next();
120 registerHost(oi.getObjectName());
121 }
122
123
124 // Query contexts
125 onStr = "*:j2eeType=WebModule,*";
126 objectName = new ObjectName(onStr);
127 set = mBeanServer.queryMBeans(objectName, null);
128 iterator = set.iterator();
129 while (iterator.hasNext()) {
130 ObjectInstance oi = (ObjectInstance) iterator.next();
131 registerContext(oi.getObjectName());
132 }
133
134 // Query wrappers
135 onStr = "*:j2eeType=Servlet,*";
136 objectName = new ObjectName(onStr);
137 set = mBeanServer.queryMBeans(objectName, null);
138 iterator = set.iterator();
139 while (iterator.hasNext()) {
140 ObjectInstance oi = (ObjectInstance) iterator.next();
141 registerWrapper(oi.getObjectName());
142 }
143
144 onStr = "JMImplementation:type=MBeanServerDelegate";
145 objectName = new ObjectName(onStr);
146 mBeanServer.addNotificationListener(objectName, this, null, null);
147
148 } catch (Exception e) {
149 log.warn("Error registering contexts",e);
150 }
151
152 }
153
154 /**
155 * unregister this from JMImplementation:type=MBeanServerDelegate
156 */
157 public void destroy() {
158 try {
159
160 ObjectName objectName = new ObjectName(
161 "JMImplementation:type=MBeanServerDelegate");
162 mBeanServer.removeNotificationListener(objectName, this);
163 } catch (Exception e) {
164 log.warn("Error unregistering MBeanServerDelegate", e);
165 }
166 }
167
168 // ------------------------------------------- NotificationListener Methods
169
170
171 public void handleNotification(Notification notification,
172 java.lang.Object handback) {
173
174 if (notification instanceof MBeanServerNotification) {
175 ObjectName objectName =
176 ((MBeanServerNotification) notification).getMBeanName();
177 String j2eeType = objectName.getKeyProperty("j2eeType");
178 String engineName = null;
179 if (j2eeType != null) {
180 if ((j2eeType.equals("WebModule")) ||
181 (j2eeType.equals("Servlet"))) {
182 if (mBeanServer.isRegistered(objectName)) {
183 try {
184 engineName = (String)
185 mBeanServer.getAttribute(objectName, "engineName");
186 } catch (Exception e) {
187 // Ignore
188 }
189 }
190 }
191 }
192
193 // At deployment time, engineName is always = null.
194 if ( (!"*".equals(domain)) &&
195 ( !domain.equals(objectName.getDomain()) ) &&
196 ( (!domain.equals(engineName) ) &&
197 (engineName != null) ) ) {
198 return;
199 }
200 if(log.isDebugEnabled())
201 log.debug( "Handle " + objectName + " type : " + notification.getType());
202 if (notification.getType().equals
203 (MBeanServerNotification.REGISTRATION_NOTIFICATION)) {
204 String type=objectName.getKeyProperty("type");
205 if( "Host".equals( type ) && domain.equals(objectName.getDomain())) {
206 try {
207 registerHost(objectName);
208 } catch (Exception e) {
209 log.warn("Error registering Host " + objectName, e);
210 }
211 }
212
213 if (j2eeType != null) {
214 if (j2eeType.equals("WebModule")) {
215 try {
216 registerContext(objectName);
217 } catch (Throwable t) {
218 log.warn("Error registering Context " + objectName,t);
219 }
220 } else if (j2eeType.equals("Servlet")) {
221 try {
222 registerWrapper(objectName);
223 } catch (Throwable t) {
224 log.warn("Error registering Wrapper " + objectName,t);
225 }
226 }
227 }
228 } else if (notification.getType().equals
229 (MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) {
230 String type=objectName.getKeyProperty("type");
231 if( "Host".equals( type )&& domain.equals(objectName.getDomain())) {
232 try {
233 unregisterHost(objectName);
234 } catch (Exception e) {
235 log.warn("Error unregistering Host " + objectName,e);
236 }
237 }
238
239 if (j2eeType != null) {
240 if (j2eeType.equals("WebModule")) {
241 try {
242 unregisterContext(objectName);
243 } catch (Throwable t) {
244 log.warn("Error unregistering webapp " + objectName,t);
245 }
246 }
247 }
248 }
249 }
250
251 }
252
253
254 // ------------------------------------------------------ Protected Methods
255
256 private void registerEngine()
257 throws Exception
258 {
259 ObjectName engineName = new ObjectName
260 (domain + ":type=Engine");
261 if ( ! mBeanServer.isRegistered(engineName)) return;
262 String defaultHost =
263 (String) mBeanServer.getAttribute(engineName, "defaultHost");
264 ObjectName hostName = new ObjectName
265 (domain + ":type=Host," + "host=" + defaultHost);
266 if (!mBeanServer.isRegistered(hostName)) {
267
268 // Get the hosts' list
269 String onStr = domain + ":type=Host,*";
270 ObjectName objectName = new ObjectName(onStr);
271 Set set = mBeanServer.queryMBeans(objectName, null);
272 Iterator iterator = set.iterator();
273 String[] aliases;
274 boolean isRegisteredWithAlias = false;
275
276 while (iterator.hasNext()) {
277
278 if (isRegisteredWithAlias) break;
279
280 ObjectInstance oi = (ObjectInstance) iterator.next();
281 hostName = oi.getObjectName();
282 aliases = (String[])
283 mBeanServer.invoke(hostName, "findAliases", null, null);
284
285 for (int i=0; i < aliases.length; i++){
286 if (aliases[i].equalsIgnoreCase(defaultHost)){
287 isRegisteredWithAlias = true;
288 break;
289 }
290 }
291 }
292
293 if (!isRegisteredWithAlias && log.isWarnEnabled())
294 log.warn(sm.getString("mapperListener.unknownDefaultHost", defaultHost));
295 }
296 // This should probablt be called later
297 if( defaultHost != null ) {
298 mapper.setDefaultHostName(defaultHost);
299 }
300 }
301
302 /**
303 * Register host.
304 */
305 private void registerHost(ObjectName objectName)
306 throws Exception {
307 String name=objectName.getKeyProperty("host");
308 if( name != null ) {
309 String[] aliases = (String[])
310 mBeanServer.invoke(objectName, "findAliases", null, null);
311 mapper.addHost(name, aliases, objectName);
312 if(log.isDebugEnabled())
313 log.debug(sm.getString
314 ("mapperListener.registerHost", name, domain));
315
316 }
317 }
318
319
320 /**
321 * Unregister host.
322 */
323 private void unregisterHost(ObjectName objectName)
324 throws Exception {
325 String name=objectName.getKeyProperty("host");
326 mapper.removeHost(name);
327 if(log.isDebugEnabled())
328 log.debug(sm.getString
329 ("mapperListener.unregisterHost", name, domain));
330 }
331
332
333 /**
334 * Register context.
335 */
336 private void registerContext(ObjectName objectName)
337 throws Exception {
338
339 String name = objectName.getKeyProperty("name");
340
341 // If the domain is the same with ours or the engine
342 // name attribute is the same... - then it's ours
343 String targetDomain=objectName.getDomain();
344 if( ! domain.equals( targetDomain )) {
345 try {
346 targetDomain = (String) mBeanServer.getAttribute
347 (objectName, "engineName");
348 } catch (Exception e) {
349 // Ignore
350 }
351 if( ! domain.equals( targetDomain )) {
352 // not ours
353 return;
354 }
355 }
356
357 String hostName = null;
358 String contextName = null;
359 if (name.startsWith("//")) {
360 name = name.substring(2);
361 }
362 int slash = name.indexOf("/");
363 if (slash != -1) {
364 hostName = name.substring(0, slash);
365 contextName = name.substring(slash);
366 } else {
367 return;
368 }
369 // Special case for the root context
370 if (contextName.equals("/")) {
371 contextName = "";
372 }
373
374 if(log.isDebugEnabled())
375 log.debug(sm.getString
376 ("mapperListener.registerContext", contextName));
377
378 Object context =
379 mBeanServer.invoke(objectName, "findMappingObject", null, null);
380 //mBeanServer.getAttribute(objectName, "mappingObject");
381 javax.naming.Context resources = (javax.naming.Context)
382 mBeanServer.invoke(objectName, "findStaticResources", null, null);
383 //mBeanServer.getAttribute(objectName, "staticResources");
384 String[] welcomeFiles = (String[])
385 mBeanServer.getAttribute(objectName, "welcomeFiles");
386
387 mapper.addContext(hostName, contextName, context,
388 welcomeFiles, resources);
389
390 }
391
392
393 /**
394 * Unregister context.
395 */
396 private void unregisterContext(ObjectName objectName)
397 throws Exception {
398
399 String name = objectName.getKeyProperty("name");
400
401 // If the domain is the same with ours or the engine
402 // name attribute is the same... - then it's ours
403 String targetDomain=objectName.getDomain();
404 if( ! domain.equals( targetDomain )) {
405 try {
406 targetDomain = (String) mBeanServer.getAttribute
407 (objectName, "engineName");
408 } catch (Exception e) {
409 // Ignore
410 }
411 if( ! domain.equals( targetDomain )) {
412 // not ours
413 return;
414 }
415 }
416
417 String hostName = null;
418 String contextName = null;
419 if (name.startsWith("//")) {
420 name = name.substring(2);
421 }
422 int slash = name.indexOf("/");
423 if (slash != -1) {
424 hostName = name.substring(0, slash);
425 contextName = name.substring(slash);
426 } else {
427 return;
428 }
429 // Special case for the root context
430 if (contextName.equals("/")) {
431 contextName = "";
432 }
433 if(log.isDebugEnabled())
434 log.debug(sm.getString
435 ("mapperListener.unregisterContext", contextName));
436
437 mapper.removeContext(hostName, contextName);
438
439 }
440
441
442 /**
443 * Register wrapper.
444 */
445 private void registerWrapper(ObjectName objectName)
446 throws Exception {
447
448 // If the domain is the same with ours or the engine
449 // name attribute is the same... - then it's ours
450 String targetDomain=objectName.getDomain();
451 if( ! domain.equals( targetDomain )) {
452 try {
453 targetDomain=(String) mBeanServer.getAttribute(objectName, "engineName");
454 } catch (Exception e) {
455 // Ignore
456 }
457 if( ! domain.equals( targetDomain )) {
458 // not ours
459 return;
460 }
461
462 }
463
464 String wrapperName = objectName.getKeyProperty("name");
465 String name = objectName.getKeyProperty("WebModule");
466
467 String hostName = null;
468 String contextName = null;
469 if (name.startsWith("//")) {
470 name = name.substring(2);
471 }
472 int slash = name.indexOf("/");
473 if (slash != -1) {
474 hostName = name.substring(0, slash);
475 contextName = name.substring(slash);
476 } else {
477 return;
478 }
479 // Special case for the root context
480 if (contextName.equals("/")) {
481 contextName = "";
482 }
483 if(log.isDebugEnabled())
484 log.debug(sm.getString
485 ("mapperListener.registerWrapper",
486 wrapperName, contextName));
487
488 String[] mappings = (String[])
489 mBeanServer.invoke(objectName, "findMappings", null, null);
490 Object wrapper =
491 mBeanServer.invoke(objectName, "findMappingObject", null, null);
492
493 for (int i = 0; i < mappings.length; i++) {
494 boolean jspWildCard = (wrapperName.equals("jsp")
495 && mappings[i].endsWith("/*"));
496 mapper.addWrapper(hostName, contextName, mappings[i], wrapper,
497 jspWildCard);
498 }
499
500 }
501
502
503
504
505 }