1 /*
2 * JBoss, the OpenSource J2EE webOS
3 *
4 * Distributable under LGPL license.
5 * See terms of license at gnu.org.
6 */
7
8 // $Id: AxisService.java,v 1.25.2.7 2003/11/06 15:36:05 cgjung Exp $
9
10 package org.jboss.net.axis.server;
11
12 import org.jboss.net.axis.XMLResourceProvider;
13 import org.jboss.net.axis.AttacheableService;
14 import org.jboss.net.axis.Deployment;
15
16 import org.jboss.net.DefaultResourceBundle;
17
18 import org.jboss.deployment.DeploymentException;
19 import org.jboss.deployment.DeploymentInfo;
20 import org.jboss.deployment.MainDeployerMBean;
21 import org.jboss.deployment.SubDeployer;
22 import org.jboss.deployment.SubDeployerSupport;
23 import org.jboss.logging.Log4jLoggerPlugin;
24 import org.jboss.mx.loading.UnifiedClassLoader;
25 import org.jboss.web.WebApplication;
26
27 import org.apache.log4j.Category;
28 import org.apache.log4j.Priority;
29
30 import org.apache.axis.MessageContext;
31 import org.apache.axis.utils.XMLUtils;
32 import org.apache.axis.AxisFault;
33 import org.apache.axis.server.AxisServer;
34 import org.apache.axis.AxisProperties;
35 import org.apache.axis.deployment.wsdd.WSDDProvider;
36 import org.apache.axis.deployment.wsdd.WSDDUndeployment;
37 import org.apache.axis.client.Service;
38 import org.apache.axis.EngineConfiguration;
39 import org.apache.axis.configuration.EngineConfigurationFactoryFinder;
40 import org.apache.axis.EngineConfigurationFactory;
41
42 import org.jboss.naming.Util;
43 import org.jboss.metadata.MetaData;
44 import org.jboss.system.server.ServerConfigLocator;
45
46 import org.w3c.dom.Document;
47 import org.w3c.dom.Element;
48 import org.w3c.dom.Attr;
49 import org.w3c.dom.Node;
50 import org.w3c.dom.NamedNodeMap;
51 import org.w3c.dom.NodeList;
52
53 import javax.management.MBeanRegistration;
54 import javax.management.MBeanServer;
55 import javax.management.MBeanServerFactory;
56 import javax.management.ObjectName;
57 import javax.management.MalformedObjectNameException;
58
59 import javax.naming.InitialContext;
60 import javax.naming.LinkRef;
61 import javax.naming.Context;
62 import javax.naming.NamingException;
63
64 import java.io.FilenameFilter;
65 import java.io.File;
66 import java.io.IOException;
67 import java.io.InputStream;
68 import java.io.OutputStream;
69 import java.io.FileOutputStream;
70 import java.io.PrintStream;
71
72 import java.net.URL;
73 import java.net.URLClassLoader;
74 import java.net.MalformedURLException;
75
76 import javax.xml.parsers.ParserConfigurationException;
77
78 import java.util.Map;
79 import java.util.Iterator;
80 import java.util.Collection;
81
82 import java.lang.reflect.Proxy;
83
84 /**
85 * A deployer service that installs Axis and manages Web-Services
86 * within JMX.
87 * @created 27. September 2001
88 * @author <a href="mailto:Christoph.Jung@infor.de">Christoph G. Jung</a>
89 * @version $Revision: 1.25.2.7 $
90 */
91
92 public class AxisService
93 extends SubDeployerSupport
94 implements AxisServiceMBean, MBeanRegistration
95 {
96
97 //
98 // Attributes
99 //
100
101 /**
102 * A map of current deployment names to the
103 * wsdd docs that created them.
104 */
105 protected Map deployments = new java.util.HashMap();
106
107 /** this is where the axis "web-application" has been installed */
108 protected DeploymentInfo myDeploymentInfo = null;
109
110 /** the engine belonging to this service */
111 protected AxisServer axisServer;
112
113 /** the client configuration belonging to this service*/
114 protected XMLResourceProvider clientConfiguration;
115
116 /** the server configuration belonging to this service*/
117 protected XMLResourceProvider serverConfiguration;
118
119 /** the web deployer that hosts our servlet */
120 protected SubDeployer webDeployer;
121
122 /** the initial context into which we bind external web-service proxies */
123 protected InitialContext initialContext;
124
125 //
126 // Constructors
127 //
128
129 /** default */
130 public AxisService()
131 {
132 // we fake internationalisation if it is not globally catered
133 Category cat = ((Log4jLoggerPlugin) log.getLoggerPlugin()).getCategory();
134 if (cat.getResourceBundle() == null)
135 cat.setResourceBundle(new DefaultResourceBundle());
136 }
137
138 //
139 // Some helper methods
140 //
141
142 /**
143 * deploy an external web service reference
144 */
145
146 protected synchronized void deployExternalWebService(Element deployElement)
147 throws DeploymentException
148 {
149
150 try
151 {
152 if (initialContext == null)
153 {
154 initialContext = new InitialContext();
155 }
156
157 NamedNodeMap attributes = deployElement.getAttributes();
158
159 String jndiName = attributes.getNamedItem("jndiName").getNodeValue();
160 String serviceClassName =
161 attributes.getNamedItem("serviceImplClass").getNodeValue();
162 Object factory =
163 new AttacheableService(
164 serviceClassName,
165 serviceName.getCanonicalName());
166 initialContext.bind(jndiName, factory);
167 }
168 catch (NamingException e)
169 {
170 throw new DeploymentException(
171 "Could not deploy item " + deployElement,
172 e);
173 }
174 }
175
176 /** undeploys an external web service reference */
177 protected synchronized void undeployExternalWebService(Element deployElement)
178 {
179 try
180 {
181 if (initialContext == null)
182 {
183 initialContext = new InitialContext();
184 }
185
186 NamedNodeMap attributes = deployElement.getAttributes();
187
188 String jndiName = attributes.getNamedItem("jndiName").getNodeValue();
189
190 if (jndiName != null)
191 {
192 initialContext.unbind(jndiName);
193 }
194 }
195 catch (NamingException e)
196 {
197
198 // what?
199
200 ((Log4jLoggerPlugin) log.getLoggerPlugin()).getCategory().l7dlog(
201 Priority.WARN,
202 "Could not undeploy " + deployElement,
203 new Object[0],
204 e);
205 }
206 }
207
208 //----------------------------------------------------------------------------
209 // 'service' interface
210 //----------------------------------------------------------------------------
211
212 /**
213 * start service means
214 * - initialise axis engine
215 * - register Axis servlet in WebContainer
216 * - contact the maindeployer
217 */
218 protected void startService() throws Exception
219 {
220
221 // find the global config file in classpath
222 URL resource =
223 getClass().getClassLoader().getResource(
224 Constants.AXIS_CONFIGURATION_FILE);
225
226 Category cat = ((Log4jLoggerPlugin) log.getLoggerPlugin()).getCategory();
227 if (resource == null)
228 {
229 cat.l7dlog(
230 Priority.WARN,
231 Constants.COULD_NOT_FIND_AXIS_CONFIGURATION_0,
232 new Object[]{Constants.AXIS_CONFIGURATION_FILE},
233 null);
234 throw new Exception(Constants.COULD_NOT_FIND_AXIS_CONFIGURATION_0);
235 }
236
237 serverConfiguration = new XMLResourceProvider(resource);
238
239 axisServer = new AxisServer(serverConfiguration);
240
241 // we annotate the server configuration with our serviceName
242 serverConfiguration.getGlobalOptions().put(
243 org.jboss.net.axis.Constants.CONFIGURATION_CONTEXT,
244 serviceName.toString());
245
246 // find the client config file in classpath
247 resource =
248 getClass().getClassLoader().getResource(
249 Constants.AXIS_CLIENT_CONFIGURATION_FILE);
250
251 if (resource == null)
252 {
253 cat.l7dlog(
254 Priority.WARN,
255 Constants.COULD_NOT_FIND_AXIS_CONFIGURATION_0,
256 new Object[]{Constants.AXIS_CONFIGURATION_FILE},
257 null);
258 throw new Exception(Constants.COULD_NOT_FIND_AXIS_CONFIGURATION_0);
259 }
260
261 clientConfiguration = new XMLResourceProvider(resource);
262
263 clientConfiguration.buildDeployment();
264
265 clientConfiguration.getGlobalOptions().put(
266 org.jboss.net.axis.Constants.CONFIGURATION_CONTEXT,
267 serviceName.toString());
268
269 // make sure that Axis/Discovery wont register any application classloaders for system lookup
270 AxisProperties.getNameDiscoverer();
271 // register our client configuration there
272 Class initializeThisFuckingStaticStuff =
273 EngineConfigurationFactoryFinder.class;
274 System.setProperty(
275 EngineConfigurationFactory.SYSTEM_PROPERTY_NAME,
276 JMXEngineConfigurationFactory.class.getName());
277 super.startService();
278 }
279
280 /** what to do to stop axis temporarily --> undeploy the servlet */
281 protected void stopService() throws Exception
282 {
283
284 super.stopService();
285
286 // tear down all running web services
287 //Is this really what you want to do? Not leave services running anyway?
288 for (Iterator apps =
289 new java.util.ArrayList(deployments.values()).iterator();
290 apps.hasNext();
291 )
292 {
293 DeploymentInfo info = (DeploymentInfo) apps.next();
294 try
295 {
296 //unregister through server so it's bookeeping is up to date.
297 server.invoke(
298 MainDeployerMBean.OBJECT_NAME,
299 "undeploy",
300 new Object[]{info},
301 new String[]{"org.jboss.deployment.DeploymentInfo"});
302 }
303 catch (Exception e)
304 {
305 log.error("Could not undeploy deployment " + info, e);
306 }
307 }
308
309 axisServer.stop();
310 super.stopService();
311 myDeploymentInfo = null;
312 }
313
314 //----------------------------------------------------------------------------
315 // Deployer interface
316 //----------------------------------------------------------------------------
317
318 /**
319 * Provides a filter that decides whether a file can be deployed by
320 * this deployer based on the filename. This is for the benefit of
321 * the {@link org.jboss.deployer.MainDeployer} service.
322 *
323 * @return a <tt>FilenameFilter</tt> that only
324 * <tt>accept</tt>s files with names that can be
325 * deployed by this deployer
326 */
327 public boolean accepts(DeploymentInfo sdi)
328 {
329 if (sdi.shortName.endsWith("-axis.xml")
330 || sdi.localCl.getResource(Constants.WEB_SERVICE_DESCRIPTOR) != null)
331 {
332 return true;
333 }
334 return false;
335 }
336
337 /*
338 * Init a deployment
339 *
340 * parse the XML MetaData. Init and deploy are separate steps allowing for subDeployment
341 * in between.
342 *
343 * @param url The URL to deploy.
344 *
345 * @throws MalformedURLException Invalid URL
346 * @throws IOException Failed to fetch content
347 * @throws DeploymentException Failed to deploy
348 */
349
350 public void init(DeploymentInfo sdi) throws DeploymentException
351 {
352 super.init(sdi);
353
354 try
355 {
356 URL metaInfos = null;
357
358 if (sdi.metaData == null)
359 {
360 metaInfos =
361 sdi.localCl.getResource(Constants.WEB_SERVICE_DESCRIPTOR);
362 }
363 else
364 {
365 metaInfos = (URL) sdi.metaData;
366 }
367
368 sdi.metaData = XMLUtils.newDocument(metaInfos.openStream());
369
370 // Resolve what to watch
371 if (sdi.url.getProtocol().equals("file"))
372 {
373 sdi.watch = metaInfos;
374 }
375 else
376 {
377 // We watch the top only, no directory support
378 sdi.watch = sdi.url;
379 }
380 }
381 catch (Exception e)
382 {
383 throw new DeploymentException(e);
384 }
385 }
386
387 /**
388 * Describe <code>create</code> method here.
389 *
390 * This step should include deployment steps that expose the existence of the unit being
391 * deployed to other units.
392 *
393 * @param sdi a <code>DeploymentInfo</code> value
394 * @exception DeploymentException if an error occurs
395 */
396 public void create(DeploymentInfo sdi) throws DeploymentException
397 {
398 ((Log4jLoggerPlugin) log.getLoggerPlugin()).getCategory().l7dlog(
399 Priority.DEBUG,
400 Constants.ABOUT_TO_CREATE_AXIS_0,
401 new Object[]{sdi},
402 null);
403
404 if (deployments.containsKey(sdi.url))
405 {
406 throw new DeploymentException(
407 "attempting to redeploy a depoyed module! " + sdi.url);
408 }
409 else
410 {
411 deployments.put(sdi.url, sdi);
412 }
413
414 }
415
416 /**
417 * Describe <code>start</code> method here.
418 *
419 * This should only include deployment activities that refer to resources
420 * outside the unit being deployed.
421 *
422 * @param sdi a <code>DeploymentInfo</code> value
423 * @exception DeploymentException if an error occurs
424 */
425 public void start(DeploymentInfo sdi) throws DeploymentException
426 {
427 ((Log4jLoggerPlugin) log.getLoggerPlugin()).getCategory().l7dlog(
428 Priority.DEBUG,
429 Constants.ABOUT_TO_START_AXIS_0,
430 new Object[]{sdi},
431 null);
432
433 // remember old classloader
434 ClassLoader previous = Thread.currentThread().getContextClassLoader();
435
436 // build new classloader for naming purposes
437 URLClassLoader serviceLoader =
438 URLClassLoader.newInstance(new URL[0], sdi.ucl);
439
440 try
441 {
442 InitialContext iniCtx = new InitialContext();
443 Context envCtx = null;
444
445 // create a new naming context java:comp/env
446 try
447 {
448 // enter the apartment
449 Thread.currentThread().setContextClassLoader(serviceLoader);
450 envCtx = (Context) iniCtx.lookup("java:comp");
451 envCtx = envCtx.createSubcontext("env");
452 }
453 finally
454 {
455 // enter the apartment
456 Thread.currentThread().setContextClassLoader(previous);
457 }
458
459 Document doc = (Document) sdi.metaData;
460 // the original command
461 Element root = doc.getDocumentElement();
462 // the deployment command document
463 Document deployDoc = XMLUtils.newDocument();
464 // the client deployment command document
465 Document deployClientDoc = XMLUtils.newDocument();
466 // create command
467 Element deploy =
468 deployDoc.createElementNS(root.getNamespaceURI(), "deployment");
469 // create command
470 Element deployClient =
471 deployClientDoc.createElementNS(
472 root.getNamespaceURI(),
473 "deployment");
474
475 NamedNodeMap attributes = root.getAttributes();
476 for (int count = 0; count < attributes.getLength(); count++)
477 {
478 Attr attribute = (Attr) attributes.item(count);
479 deploy.setAttributeNodeNS(
480 (Attr) deployDoc.importNode(attribute, true));
481 deployClient.setAttributeNodeNS(
482 (Attr) deployClientDoc.importNode(attribute, true));
483 }
484
485 // and insert the nodes from the original document
486 // and sort out the ejb-ref extensions
487 NodeList children = root.getChildNodes();
488 for (int count = 0; count < children.getLength(); count++)
489 {
490 Node actNode = children.item(count);
491 if (actNode instanceof Element)
492 {
493 Element actElement = (Element) actNode;
494
495 if (actElement.getTagName().equals("ejb-ref"))
496 {
497
498 String refName =
499 MetaData.getElementContent(
500 MetaData.getUniqueChild(
501 (Element) actNode,
502 "ejb-ref-name"));
503 String linkName =
504 MetaData.getElementContent(
505 MetaData.getUniqueChild((Element) actNode, "ejb-link"));
506
507 log.warn(
508 "Web Service Deployment "
509 + sdi
510 + " makes use of the deprecated ejb-ref feature. "
511 + "Please adjust any ejb-providing service tag inside your web-service.xml pointing to "
512 + refName
513 + " to use the absolute "
514 + linkName
515 + " instead.");
516
517 if (refName == null)
518 throw new DeploymentException(
519 Constants.EJB_REF_MUST_HAVE_UNIQUE_NAME);
520 if (linkName == null)
521 throw new DeploymentException(
522 Constants.EJB_REF_MUST_HAVE_UNIQUE_LINK);
523
524 Util.bind(envCtx, refName, new LinkRef(linkName));
525 }
526 else if (actElement.getTagName().equals("ext-service"))
527 {
528 deployExternalWebService(actElement);
529 }
530 else
531 {
532 if (!actElement.getTagName().equals("service"))
533 {
534 deployClient.appendChild(
535 deployClientDoc.importNode(actNode, true));
536 }
537 deploy.appendChild(deployDoc.importNode(actNode, true));
538 }
539 }
540 else
541 {
542 deployClient.appendChild(
543 deployClientDoc.importNode(actNode, true));
544 deploy.appendChild(deployDoc.importNode(actNode, true));
545 }
546 }
547
548 // insert command into document
549 deployDoc.appendChild(deploy);
550 deployClientDoc.appendChild(deployClient);
551
552 try
553 {
554 Thread.currentThread().setContextClassLoader(serviceLoader);
555 new Deployment(deploy).deployToRegistry(
556 ((XMLResourceProvider) axisServer.getConfig()).getDeployment());
557 new Deployment(deployClient).deployToRegistry(
558 clientConfiguration.buildDeployment());
559 axisServer.refreshGlobalOptions();
560 axisServer.saveConfiguration();
561 }
562 catch (Exception e)
563 {
564 throw new DeploymentException(
565 Constants.COULD_NOT_DEPLOY_DESCRIPTOR,
566 e);
567 }
568 finally
569 {
570 Thread.currentThread().setContextClassLoader(previous);
571 }
572 }
573 catch (NamingException e)
574 {
575 throw new DeploymentException(
576 Constants.COULD_NOT_DEPLOY_DESCRIPTOR,
577 e);
578 }
579 catch (ParserConfigurationException parserError)
580 {
581 throw new DeploymentException(Constants.COULD_NOT_DEPLOY_DESCRIPTOR,
582 parserError);
583 }
584
585 }
586
587 /**
588 * this tiny helper copies all children of the given element that
589 * are elements and match the given name to the other element
590 */
591 protected void copyChildren(Document sourceDoc, Element source, String match, Element target)
592 {
593 NodeList children = source.getChildNodes();
594 for (int count = 0; count < children.getLength(); count++)
595 {
596 Node actNode = children.item(count);
597 if (actNode instanceof Element)
598 {
599 if (((Element) actNode).getLocalName().equals(match))
600 {
601 target.appendChild(sourceDoc.importNode(actNode, true));
602 }
603 }
604 }
605 }
606
607 /** stop a given deployment */
608 public void stop(DeploymentInfo sdi) throws DeploymentException
609 {
610 ((Log4jLoggerPlugin) log.getLoggerPlugin()).getCategory().l7dlog(
611 Priority.DEBUG,
612 Constants.ABOUT_TO_STOP_AXIS_0,
613 new Object[]{sdi},
614 null);
615 if (!deployments.containsKey(sdi.url))
616 {
617 throw new DeploymentException(
618 "Attempting to undeploy a not-deployed unit! " + sdi.url);
619 }
620 // this was the deployment command
621 Element root = (Element) ((Document) sdi.metaData).getDocumentElement();
622 // from which we extract an undeployment counterpart
623 Document undeployDoc = null;
624 try
625 {
626 undeployDoc = XMLUtils.newDocument();
627 }
628 catch (ParserConfigurationException parserError)
629 {
630 throw new DeploymentException(Constants.COULD_NOT_DEPLOY_DESCRIPTOR,
631 parserError);
632 }
633 Element undeploy =
634 undeployDoc.createElementNS(root.getNamespaceURI(), "undeployment");
635
636 // copy over administrational attributes
637 NamedNodeMap attributes = root.getAttributes();
638 for (int count = 0; count < attributes.getLength(); count++)
639 {
640 Attr attribute = (Attr) attributes.item(count);
641 undeploy.setAttributeNodeNS(
642 (Attr) undeployDoc.importNode(attribute, true));
643 }
644
645 // external services are just a matter of us
646 NodeList children = root.getElementsByTagName("ext-service");
647 for (int count = 0; count < children.getLength(); count++)
648 {
649 Element actNode = (Element) children.item(count);
650 undeployExternalWebService(actNode);
651 }
652
653 // all service and handler entries are copied in the
654 // undeployment document
655 copyChildren(undeployDoc, root, "service", undeploy);
656 copyChildren(undeployDoc, root, "handler", undeploy);
657 copyChildren(undeployDoc, root, "typemapping", undeploy);
658 copyChildren(undeployDoc, root, "beanmapping", undeploy);
659
660 // put command into document
661 undeployDoc.appendChild(undeploy);
662
663 try
664 {
665 // and call the administrator
666 new WSDDUndeployment(undeploy).undeployFromRegistry(
667 ((XMLResourceProvider) axisServer.getConfig()).getDeployment());
668 // and call the administrator
669 new WSDDUndeployment(undeploy).undeployFromRegistry(
670 clientConfiguration.buildDeployment());
671 axisServer.refreshGlobalOptions();
672 axisServer.saveConfiguration();
673 }
674 catch (Exception e)
675 {
676 throw new DeploymentException(Constants.COULD_NOT_UNDEPLOY, e);
677 }
678 }
679
680 /** destroy a given deployment */
681 public void destroy(DeploymentInfo sdi) throws DeploymentException
682 {
683 ((Log4jLoggerPlugin) log.getLoggerPlugin()).getCategory().l7dlog(
684 Priority.DEBUG,
685 Constants.ABOUT_TO_DESTROY_AXIS_0,
686 new Object[]{sdi},
687 null);
688 deployments.remove(sdi.url);
689 }
690
691 /** return the associated client configuration */
692 public EngineConfiguration getClientEngineConfiguration()
693 {
694 return clientConfiguration;
695 }
696
697 /** return the associated server configuration */
698 public EngineConfiguration getServerEngineConfiguration()
699 {
700 return serverConfiguration;
701 }
702
703 /** return the associated server */
704 public AxisServer getAxisServer()
705 {
706 return axisServer;
707 }
708
709 }