001: /**
002: * JOnAS : Java(TM) OpenSource Application Server
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
017: * USA
018: *
019: * Initial Developer : Guillaume Sauthier
020: * --------------------------------------------------------------------------
021: * $Id: XMLUtils.java 7513 2005-10-17 15:45:34Z sauthieg $
022: * --------------------------------------------------------------------------
023: */package org.objectweb.jonas_lib.genbase.utils;
024:
025: import java.io.IOException;
026: import java.io.InputStream;
027:
028: import javax.xml.parsers.DocumentBuilder;
029: import javax.xml.parsers.DocumentBuilderFactory;
030: import javax.xml.parsers.ParserConfigurationException;
031:
032: import org.w3c.dom.Attr;
033: import org.w3c.dom.Document;
034: import org.w3c.dom.Element;
035: import org.w3c.dom.NodeList;
036: import org.w3c.dom.Text;
037: import org.xml.sax.SAXException;
038:
039: import org.objectweb.jonas_client.deployment.api.JonasAppClientDTDs;
040: import org.objectweb.jonas_client.deployment.api.JonasAppClientSchemas;
041:
042: import org.objectweb.jonas_ear.deployment.api.EarDTDs;
043: import org.objectweb.jonas_ear.deployment.api.EarSchemas;
044:
045: import org.objectweb.jonas_ejb.deployment.api.JonasEjbjarDTDs;
046: import org.objectweb.jonas_ejb.deployment.api.JonasEjbjarSchemas;
047:
048: import org.objectweb.jonas_lib.deployment.validation.JEntityResolver;
049: import org.objectweb.jonas_lib.genbase.archive.Archive;
050:
051: import org.objectweb.jonas_web.deployment.api.JonasWebAppDTDs;
052: import org.objectweb.jonas_web.deployment.api.JonasWebAppSchemas;
053: import org.objectweb.jonas_web.deployment.api.WebAppDTDs;
054: import org.objectweb.jonas_web.deployment.api.WebAppSchemas;
055:
056: import org.objectweb.jonas_ws.deployment.api.JonasWsSchemas;
057: import org.objectweb.jonas_ws.deployment.api.WsSchemas;
058: import org.objectweb.jonas_ws.wsgen.NoJ2EEWebservicesException;
059:
060: /**
061: * XML Utils Class. Holds methods for easier DOM parsing, XML modifications, ...
062: * @author Guillaume Sauthier
063: */
064: public class XMLUtils {
065:
066: /** DOM factory */
067: private static DocumentBuilderFactory factory = null;
068:
069: /**
070: * J2EE namespace
071: */
072: private static final String J2EE_NS = "http://java.sun.com/xml/ns/j2ee";
073:
074: /**
075: * JONAS namespace
076: */
077: private static final String JONAS_NS = "http://www.objectweb.org/jonas/ns";
078:
079: /**
080: * XML NS namespace
081: */
082: private static final String XMLNS_NS = "http://www.w3.org/2000/xmlns/";
083:
084: /**
085: * XML Schema instance namespace
086: */
087: private static final String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";
088:
089: /**
090: * jonas-session tag name
091: */
092: private static final String SESSION_BEAN = "jonas-session";
093:
094: /**
095: * jonas-entity tag name
096: */
097: private static final String ENTITY_BEAN = "jonas-entity";
098:
099: /**
100: * jonas-message-driven tag name
101: */
102: private static final String MESSAGE_BEAN = "jonas-message-driven";
103:
104: /**
105: * ejb-name tag name
106: */
107: private static final String EJB_NAME = "ejb-name";
108:
109: /**
110: * servlet tag name
111: */
112: private static final String SERVLET = "servlet";
113:
114: /**
115: * servlet-name tag name
116: */
117: private static final String SERVLET_NAME = "servlet-name";
118:
119: /**
120: * jonas-service-ref tag name
121: */
122: private static final String JONAS_SERVICE_REF = "jonas-service-ref";
123:
124: /**
125: * service-ref-name tag name
126: */
127: private static final String SR_NAME = "service-ref-name";
128:
129: /**
130: * Empty private constructor for Utility Class
131: */
132: private XMLUtils() {
133: }
134:
135: /**
136: * Returns a new DocumentBuilderFactory.
137: * @param validating set the parser validating or not
138: * @return a new DocumentBuilderFactory.
139: */
140: private static DocumentBuilderFactory newFactory(boolean validating) {
141: DocumentBuilderFactory factory = DocumentBuilderFactory
142: .newInstance();
143: factory.setNamespaceAware(true);
144: factory.setValidating(validating);
145: setFactoryValidation(factory, validating);
146:
147: return factory;
148: }
149:
150: /**
151: * Sets the validation for the factory
152: *
153: * @param factory the factory
154: * @param validating to turn on or off validation
155: */
156: private static void setFactoryValidation(
157: DocumentBuilderFactory factory, boolean validating) {
158: factory.setValidating(validating);
159: // ignore white space can only be set if parser is validating
160: factory.setIgnoringElementContentWhitespace(validating);
161: factory.setAttribute(
162: "http://apache.org/xml/features/validation/schema",
163: new Boolean(validating));
164: }
165:
166: /**
167: * Creates a new Document from a given InputStream. Validate the file.
168: *
169: * @param is the InputStream to be parsed
170: * @param name filename
171: * @param isDTDsAllowed if false, throw exception on DTD Doctype
172: *
173: * @return the Document instance.
174: *
175: * @throws ParserConfigurationException ParserConfigurationException
176: * @throws SAXException SAXException
177: * @throws IOException IOException
178: * @throws NoJ2EEWebservicesException NoJ2EEWebservicesException
179: */
180: public static Document newDocument(InputStream is, String name,
181: boolean isDTDsAllowed) throws ParserConfigurationException,
182: SAXException, IOException, NoJ2EEWebservicesException {
183:
184: return newDocument(is, name, isDTDsAllowed, true);
185: }
186:
187: /**
188: * Creates a new Document from a given InputStream.
189: *
190: * @param is the InputStream to be parsed
191: * @param name filename
192: * @param isDTDsAllowed if false, throw exception on DTD Doctype
193: * @param validate if the file is to be validated
194: *
195: * @return the Document instance.
196: *
197: * @throws ParserConfigurationException ParserConfigurationException
198: * @throws SAXException SAXException
199: * @throws IOException IOException
200: * @throws NoJ2EEWebservicesException NoJ2EEWebservicesException
201: */
202: public static Document newDocument(InputStream is, String name,
203: boolean isDTDsAllowed, boolean validate)
204: throws NoJ2EEWebservicesException,
205: ParserConfigurationException, SAXException, IOException {
206:
207: if (factory == null) {
208: factory = newFactory(validate);
209: }
210:
211: if (factory.isValidating() != validate) {
212: setFactoryValidation(factory, validate);
213: }
214:
215: DocumentBuilder builder = factory.newDocumentBuilder();
216:
217: // add entity resolver
218: if (factory.isValidating()) {
219: JEntityResolver jer = new JEntityResolver();
220: // add Schemas
221: jer.addSchemas(new WebAppSchemas());
222: jer.addSchemas(new JonasWebAppSchemas());
223: jer.addSchemas(new JonasEjbjarSchemas());
224: jer.addSchemas(new JonasAppClientSchemas());
225: jer.addSchemas(new EarSchemas());
226: jer.addSchemas(new WsSchemas());
227: jer.addSchemas(new JonasWsSchemas());
228:
229: // add DTDs
230: jer.addDtds(new WebAppDTDs());
231: jer.addDtds(new JonasWebAppDTDs());
232: jer.addDtds(new JonasEjbjarDTDs());
233: jer.addDtds(new JonasAppClientDTDs());
234: jer.addDtds(new EarDTDs());
235:
236: builder.setEntityResolver(jer);
237: }
238: Document doc = builder.parse(is);
239: // close InputStream when finished parsing
240: is.close();
241: if (doc.getDoctype() != null && !isDTDsAllowed) {
242: // DTD case
243: // -> Throw Exception
244: throw new NoJ2EEWebservicesException(
245: name
246: + " use a DTD. Only XML Schema are accepted for J2EE 1.4 webservices");
247: }
248: return doc;
249: }
250:
251: /**
252: * Returns the <code>session</code>/<code>entity</code>/
253: * <code>message-driven</code> XML Element with given name.
254: * @param base <code>jonas-ejb-jar</code> Element.
255: * @param bName the bean name to be found.
256: * @return the <code>session</code>/<code>entity</code>/
257: * <code>message-driven</code> XML Element.
258: */
259: public static Element getBeanElement(Element base, String bName) {
260: Element found = null;
261:
262: // try Session Bean
263: NodeList sessions = base.getElementsByTagNameNS(JONAS_NS,
264: SESSION_BEAN);
265:
266: for (int i = 0; (i < sessions.getLength()) && (found == null); i++) {
267: Element session = (Element) sessions.item(i);
268: NodeList names = session.getElementsByTagNameNS(JONAS_NS,
269: EJB_NAME);
270:
271: // ejb-name mandatory and unique
272: Element name = (Element) names.item(0);
273:
274: if (name.getFirstChild().getNodeValue().equals(bName)) {
275: found = session;
276: }
277: }
278:
279: // try Entity Bean
280: NodeList entities = base.getElementsByTagNameNS(JONAS_NS,
281: ENTITY_BEAN);
282:
283: for (int i = 0; (i < entities.getLength()) && (found == null); i++) {
284: Element entity = (Element) entities.item(i);
285: NodeList names = entity.getElementsByTagNameNS(JONAS_NS,
286: EJB_NAME);
287:
288: // ejb-name mandatory and unique
289: Element name = (Element) names.item(0);
290:
291: if (name.getFirstChild().getNodeValue().equals(bName)) {
292: found = entity;
293: }
294: }
295:
296: // try Message Driven Bean
297: NodeList messages = base.getElementsByTagNameNS(JONAS_NS,
298: MESSAGE_BEAN);
299:
300: for (int i = 0; (i < messages.getLength()) && (found == null); i++) {
301: Element message = (Element) messages.item(i);
302: NodeList names = message.getElementsByTagNameNS(JONAS_NS,
303: EJB_NAME);
304:
305: // ejb-name mandatory and unique
306: Element name = (Element) names.item(0);
307:
308: if (name.getFirstChild().getNodeValue().equals(bName)) {
309: found = message;
310: }
311: }
312:
313: return found;
314: }
315:
316: /**
317: * Returns the matching <code>servlet</code> XML Element with given name.
318: * @param base <code>web-app</code> Element.
319: * @param sName the servlet name to be found.
320: * @return the matching <code>servlet</code> XML Element.
321: */
322: public static Element getServletElement(Element base, String sName) {
323: Element found = null;
324:
325: // Search servlet List
326: NodeList servlets = base.getElementsByTagNameNS(J2EE_NS,
327: SERVLET);
328:
329: for (int i = 0; (i < servlets.getLength()) && (found == null); i++) {
330: Element servlet = (Element) servlets.item(i);
331: NodeList names = servlet.getElementsByTagNameNS(J2EE_NS,
332: SERVLET_NAME);
333:
334: // servlet-name mandatory and unique
335: Element name = (Element) names.item(0);
336:
337: if (name.getFirstChild().getNodeValue().equals(sName)) {
338: found = servlet;
339: }
340: }
341:
342: return found;
343: }
344:
345: /**
346: * Returns the <code>jonas-service-ref</code> XML Element with given name.
347: * @param base <code>web-app</code>/ bean Element containing
348: * <code>jonas-service-ref</code> Element(s).
349: * @param srName the service-ref name to be found.
350: * @return the <code>jonas-service-ref</code> XML Element.
351: */
352: public static Element getJonasServiceRef(Element base, String srName) {
353: Element found = null;
354:
355: // Search jonas-service-ref list
356: if (base != null) {
357: NodeList jsrs = base.getElementsByTagNameNS(JONAS_NS,
358: JONAS_SERVICE_REF);
359:
360: for (int i = 0; (i < jsrs.getLength()) && (found == null); i++) {
361: Element jsr = (Element) jsrs.item(i);
362:
363: NodeList names = jsr.getElementsByTagNameNS(JONAS_NS,
364: SR_NAME);
365:
366: // service-ref-name mandatory and unique
367: Element name = (Element) names.item(0);
368:
369: if (name != null) {
370: // found jonas:service-ref-name
371: if (name.getFirstChild().getNodeValue().equals(
372: srName)) {
373: found = jsr;
374: }
375: }
376: }
377: }
378:
379: return found;
380: }
381:
382: /**
383: * default application.xml contains a fake ejb module needed to be parsed
384: * without error but not needed for a normal application. Than we remove it.
385: * @param doc application.xml document
386: */
387: public static void cleanDummyApplication(Document doc) {
388: Element root = doc.getDocumentElement();
389: NodeList nl = root.getElementsByTagNameNS(J2EE_NS, "module");
390: root.removeChild(nl.item(0));
391: }
392:
393: /**
394: * Add an ejb module in an application Document
395: * @param app application.xml Document
396: * @param ejbjar EJBJar archive
397: */
398: public static void addEjb(Document app, Archive ejbjar) {
399: Element module = app.createElementNS(J2EE_NS, "module");
400: Element ejb = app.createElementNS(J2EE_NS, "ejb");
401: Text ejbText = app.createTextNode(ejbjar.getRootFile()
402: .getName());
403: ejb.appendChild(ejbText);
404: module.appendChild(ejb);
405:
406: insertModule(app, module);
407: }
408:
409: /**
410: * Add a client module in an application Document
411: * @param app application.xml Document
412: * @param client Client archive
413: */
414: public static void addClient(Document app, Archive client) {
415: Element module = app.createElementNS(J2EE_NS, "module");
416: Element clt = app.createElementNS(J2EE_NS, "java");
417: Text cltText = app.createTextNode(client.getRootFile()
418: .getName());
419: clt.appendChild(cltText);
420: module.appendChild(clt);
421:
422: insertModule(app, module);
423: }
424:
425: /**
426: * Add an web module in an application Document
427: * @param app application.xml Document
428: * @param webapp WebApp archive
429: * @param ctx context-root
430: */
431: public static void addWebApp(Document app, Archive webapp,
432: String ctx) {
433: Element module = app.createElementNS(J2EE_NS, "module");
434: Element web = app.createElementNS(J2EE_NS, "web");
435: Element webUri = app.createElementNS(J2EE_NS, "web-uri");
436: Element context = app.createElementNS(J2EE_NS, "context-root");
437:
438: Text webText = app.createTextNode(webapp.getName());
439: Text ctxText = app.createTextNode(ctx);
440: webUri.appendChild(webText);
441: context.appendChild(ctxText);
442:
443: web.appendChild(webUri);
444: web.appendChild(context);
445:
446: module.appendChild(web);
447:
448: insertModule(app, module);
449: }
450:
451: /**
452: * Insert a module in application Document
453: * @param app application.xml Document
454: * @param module module Element
455: */
456: private static void insertModule(Document app, Element module) {
457: Element application = app.getDocumentElement();
458: Element first = findFirstSecurityRole(application);
459: application.insertBefore(module, first);
460: }
461:
462: /**
463: * return the first found security-role Element (or null if not found)
464: * @param app application.xml Document
465: * @return the first found security-role Element (or null if not found)
466: */
467: private static Element findFirstSecurityRole(Element app) {
468: NodeList nl = app.getElementsByTagNameNS(J2EE_NS,
469: "security-role");
470:
471: if (nl.getLength() == 0) {
472: return null;
473: } else {
474: return (Element) nl.item(0);
475: }
476: }
477:
478: /**
479: * Creates a new XML Document for an empty jonas-client.xml.
480: * @return Returns a new XML Document for an empty jonas-client.xml.
481: */
482: public static Document newJonasClient() {
483:
484: Document root = createDocument();
485:
486: // jonas-client
487: Element jonasClient = root.createElementNS(JONAS_NS,
488: "jonas-client");
489:
490: // Automatically retrieve latest schema name
491: int index = JonasAppClientSchemas.JONAS_APPCLIENT_SCHEMAS.length - 1;
492: String schema = JonasAppClientSchemas.JONAS_APPCLIENT_SCHEMAS[index];
493: addNamespaces(jonasClient, schema);
494: root.appendChild(jonasClient);
495:
496: return root;
497: }
498:
499: /**
500: * @return Returns an empty jonas-web-app Document
501: */
502: public static Document newJonasWeb() {
503:
504: Document root = createDocument();
505:
506: // jonas-web-app
507: Element jonasWebApp = root.createElementNS(JONAS_NS,
508: "jonas-web-app");
509:
510: // Automatically retrieve latest schema name
511: int index = JonasWebAppSchemas.JONAS_WEBAPP_SCHEMAS.length - 1;
512: String schema = JonasWebAppSchemas.JONAS_WEBAPP_SCHEMAS[index];
513: addNamespaces(jonasWebApp, schema);
514: root.appendChild(jonasWebApp);
515:
516: return root;
517: }
518:
519: /**
520: * @return Returns an empty Document.
521: */
522: private static Document createDocument() {
523: DocumentBuilderFactory factory = DocumentBuilderFactory
524: .newInstance();
525: factory.setNamespaceAware(true);
526: DocumentBuilder builder;
527: try {
528: builder = factory.newDocumentBuilder();
529: } catch (ParserConfigurationException e) {
530: throw new RuntimeException(e);
531: }
532: return builder.newDocument();
533: }
534:
535: /**
536: * Add common namespaces to the given element and add schemaLocation
537: * @param e the Element to be updated
538: * @param schema the schema location value
539: */
540: private static void addNamespaces(Element e, String schema) {
541: Document root = e.getOwnerDocument();
542: // create xmlns="http://www.w3.org/XML/1998/namespace"
543: Attr xmlns = root.createAttributeNS(XMLNS_NS, "xmlns");
544: xmlns.setValue(JONAS_NS);
545:
546: // create xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
547: Attr xsi = root.createAttributeNS(XMLNS_NS, "xmlns:xsi");
548: xsi.setValue(XSI_NS);
549:
550: // create xsi:schemaLocation="http://www.objectweb.org/jonas/ns
551: // http://www.objectweb.org/jonas/ns/<schema>"
552: Attr schemaLocation = root.createAttributeNS(XSI_NS,
553: "xsi:schemaLocation");
554: schemaLocation.setValue(JONAS_NS + " " + JONAS_NS + "/"
555: + schema);
556:
557: e.setAttributeNodeNS(xmlns);
558: e.setAttributeNodeNS(xsi);
559: e.setAttributeNodeNS(schemaLocation);
560:
561: }
562:
563: /**
564: * Check if the web module name is already declared in the application.xml Document
565: * @param app the application.xml Doc
566: * @param name web application name
567: * @return Returns <code>true</code> if the module is already declared, <code>false</code> otherwise.
568: */
569: public static boolean isWebModuleAlreadyDeclared(Document app,
570: String name) {
571: // Corresponding Xpath expression : //j2ee:module/j2ee:web/j2ee:web-uri == name
572:
573: Element found = null;
574: NodeList modules = app
575: .getElementsByTagNameNS(J2EE_NS, "module");
576: for (int i = 0; (i < modules.getLength()) && (found == null); i++) {
577:
578: // we check each module to see if it is a web module
579: Element module = (Element) modules.item(i);
580: NodeList webModules = module.getElementsByTagNameNS(
581: J2EE_NS, "web");
582: for (int j = 0; (j < webModules.getLength())
583: && (found == null); j++) {
584:
585: // We should only have 0..1 web module in a j2ee:module
586: Element webModule = (Element) webModules.item(j);
587: NodeList weburiModules = webModule
588: .getElementsByTagNameNS(J2EE_NS, "web-uri");
589: // web-uri is mandatory and is the first element under j2ee:web
590: Element webUri = (Element) weburiModules.item(0);
591: if (webUri.getFirstChild().getNodeValue().equals(name)) {
592: found = webUri;
593: }
594: }
595: }
596: // "true" if element was found
597: return (found != null);
598: }
599:
600: }
|