001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mx.metadata;
023:
024: // $Id: XMLMetaData.java 57200 2006-09-26 12:10:47Z dimitris@jboss.org $
025:
026: import java.net.MalformedURLException;
027: import java.net.URL;
028: import java.util.Map;
029:
030: import javax.management.MBeanInfo;
031: import javax.management.NotCompliantMBeanException;
032:
033: import org.jboss.dom4j.Document;
034: import org.jboss.dom4j.DocumentException;
035: import org.jboss.dom4j.DocumentType;
036: import org.jboss.dom4j.Element;
037: import org.jboss.dom4j.io.SAXReader;
038: import org.jboss.mx.modelmbean.XMBeanConstants;
039: import org.jboss.mx.service.ServiceConstants;
040: import org.jboss.mx.util.JBossNotCompliantMBeanException;
041: import org.jboss.util.xml.JBossEntityResolver;
042: import org.xml.sax.SAXException;
043:
044: /**
045: * Aggregate builder for XML schemas. This builder implementation is used
046: * as an aggregate for all XML based builder implementations. The correct
047: * XML parser is picked based on the schema declaration of the XML file.
048: *
049: * @author <a href="mailto:juha@jboss.org">Juha Lindfors</a>.
050: * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>.
051: * @author Matt Munz
052: */
053: public class XMLMetaData extends AbstractBuilder implements
054: ServiceConstants, XMBeanConstants {
055:
056: // Attributes ----------------------------------------------------
057: private static final int NO_VERSION = -1;
058: private static final int JBOSS_XMBEAN_1_0 = 0;
059: private static final int JBOSS_XMBEAN_1_1 = 1;
060: private static final int JBOSS_XMBEAN_1_2 = 2;
061:
062: /**
063: * The URL for the XML file.
064: */
065: private URL url = null;
066:
067: private Element element;
068:
069: private String versionString;
070:
071: /**
072: * The class name of the resource class this Model MBean represents.
073: */
074: private String resourceClassName = null;
075:
076: /**
077: * The class name of the Model MBean implementation class.
078: */
079: private String mmbClassName = null;
080:
081: // Constructors --------------------------------------------------
082:
083: /**
084: * Constructs an aggregate XML builder implementation.
085: *
086: * @param mmbClassName the class name of the Model MBean
087: * implementation
088: * @param resourceClassName the class name of the resource object the
089: * Model MBean represents
090: * @param url the URL for the XML definition of the
091: * management interface
092: */
093: public XMLMetaData(String mmbClassName, String resourceClassName,
094: URL url) {
095: super ();
096:
097: this .url = url;
098: this .mmbClassName = mmbClassName;
099: this .resourceClassName = resourceClassName;
100: }
101:
102: /**
103: * Constructs an aggregate XML builder implementation.
104: *
105: * @param mmbClassName the class name of the Model MBean
106: * implementation
107: * @param resourceClassName the class name of the resource object the
108: * Model MBean represents
109: * @param url the URL for the XML definition of the
110: * management interface
111: *
112: * @throws MalformedURLException if the URL string could not be resolved
113: */
114: public XMLMetaData(String mmbClassName, String resourceClassName,
115: String url) throws MalformedURLException {
116: this (mmbClassName, resourceClassName, new URL(url));
117: }
118:
119: /**
120: * Constructs an aggregate XML builder implementation.
121: *
122: * @param mmbClassName the class name of the Model MBean
123: * implementation
124: * @param resourceClassName the class name of the resource object the
125: * Model MBean represents
126: * @param url the URL for the XML definition of the
127: * management interface
128: * @param properties Map of configuration properties for this
129: * builder. These properties will be passed
130: * to the appropriate XML schema specific builder
131: * when it is created.
132: */
133: public XMLMetaData(String mmbClassName, String resourceClassName,
134: URL url, Map properties) {
135: this (mmbClassName, resourceClassName, url);
136: setProperties(properties);
137: }
138:
139: /**
140: * Constructs an aggregate XML builder implementation.
141: *
142: * @param mmbClassName the class name of the Model MBean
143: * implementation
144: * @param resourceClassName the class name of the resource object the
145: * Model MBean represents
146: * @param url the URL for the XML definition of the
147: * management interface
148: * @param properties Map of configuration properties for this
149: * builder. These properties will be passed
150: * to the appropriate XML schema specific builder
151: * when it is created.
152: *
153: * @throws MalformedURLException if the URL string could not be resolved
154: */
155: public XMLMetaData(String mmbClassName, String resourceClassName,
156: String url, Map properties) throws MalformedURLException {
157: this (mmbClassName, resourceClassName, new URL(url), properties);
158: }
159:
160: /**
161: * Creates a new <code>XMLMetaData</code> instance using an explicit DOM element
162: * as the configuration source, and requiring an explicit version indicator.
163: * The version should be the PublicID for the dtd or (worse) the dtd url.
164: *
165: * @param mmbClassName a <code>String</code> value
166: * @param resourceClassName a <code>String</code> value
167: * @param element an <code>org.w3c.dom.Element</code> value
168: * @param version a <code>String</code> value
169: */
170: public XMLMetaData(String mmbClassName, String resourceClassName,
171: Element element, String version) {
172: super ();
173: this .mmbClassName = mmbClassName;
174: this .resourceClassName = resourceClassName;
175: this .element = element;
176: versionString = version;
177: }
178:
179: // MetaDataBuilder implementation --------------------------------
180: /**
181: * Constructs the Model MBean metadata. This implementation reads the
182: * document type definition from the beginning of the XML file and picks
183: * a corresponding XML builder based on the schema name. In case no
184: * document type is defined the latest schema builder for this JBossMX
185: * release is used. <p>
186: *
187: * The SAX parser implementation is selected by default based on JAXP
188: * configuration. If you want to use JAXP to select the parser, you can
189: * set the system property <tt>"javax.xml.parsers.SAXParserFactory"</tt>.
190: * For example, to use Xerces you might define: <br><pre>
191: *
192: * java -Djavax.xml.parsers.SAXParserFactory=org.apache.xerces.jaxp.SAXParserFactoryImpl ...
193: *
194: * </pre>
195: *
196: * In case you can't or don't want to use JAXP to configure the SAX parser
197: * implementation you can override the SAX parser implementation by setting
198: * an MBean descriptor field {@link XMBeanConstants#SAX_PARSER} to the
199: * parser class string value.
200: *
201: * @return initialized MBean info
202: * @throws NotCompliantMBeanException if there were errors building the
203: * MBean info from the given XML file.
204: */
205: public MBeanInfo build() throws NotCompliantMBeanException {
206: try {
207: int version = NO_VERSION;
208:
209: if (versionString == null) {
210: // by default, let JAXP pick the SAX parser
211: SAXReader reader = new SAXReader();
212:
213: // check if user wants to override the SAX parser property
214: if (properties.get(SAX_PARSER) != null) {
215: try {
216: reader
217: .setXMLReaderClassName(getStringProperty(SAX_PARSER));
218: }
219:
220: catch (SAXException e) {
221: //Should log and ignore, I guess
222: } // end of try-catch
223: }
224: // by default we validate
225: reader.setValidation(true);
226:
227: // the user can override the validation by setting the VALIDATE property
228: try {
229: boolean validate = getBooleanProperty(XML_VALIDATION);
230: reader.setValidation(validate);
231: } catch (IllegalPropertyException e) {
232: // FIXME: log the exception (warning)
233:
234: // fall through, use the default value
235: }
236:
237: //supply it with our dtd locally.
238: reader.setEntityResolver(new JBossEntityResolver());
239:
240: // get the element and start parsing...
241: Document doc = reader.read(url);
242: element = doc.getRootElement();
243: DocumentType type = doc.getDocType();
244:
245: version = validateVersionString(type.getPublicID());
246: if (version == NO_VERSION) {
247: version = validateVersionString(type.getSystemID());
248: } // end of if ()
249:
250: } else {
251: version = validateVersionString(versionString);
252: } // end of else
253:
254: if (element == null) {
255: throw new IllegalStateException(
256: "No element supplied with explict version!");
257: }
258: // These are the known schemas for us. Pick the correct one based on
259: // schema or default to the latest.docURL.endsWith(JBOSSMX_XMBEAN_DTD_1_0)
260: if (version == JBOSS_XMBEAN_1_0
261: || version == JBOSS_XMBEAN_1_1
262: || version == JBOSS_XMBEAN_1_2) {
263: // jboss_xmbean_1_0.dtd is the only implemented useful xmbean
264: return new JBossXMBean10(mmbClassName,
265: resourceClassName, element, properties).build();
266: } else {
267: throw new NotCompliantMBeanException(
268: "Unknown xmbean type " + versionString);
269: } // end of else
270:
271: } catch (DocumentException e) {
272: throw new JBossNotCompliantMBeanException(
273: "Error parsing the XML file, from XMLMetaData: ", e);
274: }
275: }
276:
277: private int validateVersionString(String versionString) {
278: if (PUBLIC_JBOSSMX_XMBEAN_DTD_1_0.equals(versionString)) {
279: return JBOSS_XMBEAN_1_0;
280: } // end of if ()
281: if (versionString != null
282: && versionString.endsWith(JBOSSMX_XMBEAN_DTD_1_0)) {
283: return JBOSS_XMBEAN_1_0;
284: } // end of if ()
285: if (PUBLIC_JBOSSMX_XMBEAN_DTD_1_1.equals(versionString)) {
286: return JBOSS_XMBEAN_1_1;
287: } // end of if ()
288: if (versionString != null
289: && versionString.endsWith(JBOSSMX_XMBEAN_DTD_1_1)) {
290: return JBOSS_XMBEAN_1_1;
291: } // end of if ()
292: if (PUBLIC_JBOSSMX_XMBEAN_DTD_1_2.equals(versionString)) {
293: return JBOSS_XMBEAN_1_2;
294: } // end of if ()
295: if (versionString != null
296: && versionString.endsWith(JBOSSMX_XMBEAN_DTD_1_2)) {
297: return JBOSS_XMBEAN_1_2;
298: } // end of if ()
299:
300: //There is nothing defined for jboss xmbean 1.2, so we can't recognize it.
301: return NO_VERSION;
302: }
303:
304: }
|