001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: */package org.apache.cxf.tools.validator.internal;
019:
020: import java.io.File;
021: import java.io.FilenameFilter;
022: import java.io.IOException;
023: import java.io.InputStream;
024: import java.io.Reader;
025: import java.net.MalformedURLException;
026: import java.net.URL;
027: import java.net.URLConnection;
028: import java.util.ArrayList;
029: import java.util.HashMap;
030: import java.util.List;
031: import java.util.Map;
032: import java.util.logging.Level;
033: import java.util.logging.Logger;
034: import javax.xml.XMLConstants;
035: import javax.xml.parsers.DocumentBuilder;
036: import javax.xml.parsers.DocumentBuilderFactory;
037: import javax.xml.parsers.ParserConfigurationException;
038: import javax.xml.parsers.SAXParser;
039: import javax.xml.parsers.SAXParserFactory;
040: import javax.xml.transform.Source;
041: import javax.xml.transform.dom.DOMSource;
042: import javax.xml.transform.sax.SAXSource;
043: import javax.xml.validation.Schema;
044: import javax.xml.validation.SchemaFactory;
045: import javax.xml.validation.Validator;
046:
047: import org.w3c.dom.Document;
048: import org.w3c.dom.ls.LSInput;
049: import org.w3c.dom.ls.LSResourceResolver;
050: import org.xml.sax.ErrorHandler;
051: import org.xml.sax.InputSource;
052: import org.xml.sax.SAXException;
053: import org.xml.sax.SAXParseException;
054:
055: import org.apache.cxf.common.i18n.Message;
056: import org.apache.cxf.common.logging.LogUtils;
057: import org.apache.cxf.resource.URIResolver;
058: import org.apache.cxf.tools.common.ToolConstants;
059: import org.apache.cxf.tools.common.ToolException;
060: import org.apache.cxf.tools.util.URIParserUtil;
061:
062: public class SchemaValidator extends AbstractDefinitionValidator {
063: protected static final Logger LOG = LogUtils
064: .getL7dLogger(SchemaValidator.class);
065:
066: protected String[] defaultSchemas;
067:
068: protected String schemaLocation = "./";
069:
070: private String wsdlsrc;
071:
072: private String[] xsds;
073:
074: private List<InputSource> schemaFromJar;
075:
076: private DocumentBuilder docBuilder;
077:
078: private SAXParser saxParser;
079:
080: public SchemaValidator(String schemaDir) throws ToolException {
081: schemaLocation = schemaDir;
082: defaultSchemas = getDefaultSchemas();
083: }
084:
085: public SchemaValidator(String schemaDir, String wsdl,
086: String[] schemas) throws ToolException {
087: schemaLocation = schemaDir;
088: defaultSchemas = getDefaultSchemas();
089: wsdlsrc = wsdl;
090: xsds = schemas;
091: }
092:
093: public SchemaValidator(List<InputSource> defaultSchemas,
094: String wsdl, String[] schemas) {
095: schemaLocation = null;
096: schemaFromJar = defaultSchemas;
097: wsdlsrc = wsdl;
098: xsds = schemas;
099: }
100:
101: public boolean isValid() {
102: return validate(wsdlsrc, xsds);
103: }
104:
105: public boolean validate(String wsdlsource, String[] schemas)
106: throws ToolException {
107: DocumentBuilderFactory docFactory = DocumentBuilderFactory
108: .newInstance();
109: try {
110: docFactory.setNamespaceAware(true);
111: docBuilder = docFactory.newDocumentBuilder();
112: } catch (ParserConfigurationException e) {
113: throw new ToolException(e);
114: }
115:
116: String systemId = null;
117: systemId = URIParserUtil.getAbsoluteURI(wsdlsource);
118: InputSource is = new InputSource(systemId);
119:
120: return validate(is, schemas);
121:
122: }
123:
124: private Schema createSchema(List<InputSource> xsdsInJar,
125: String[] schemas) throws SAXException, IOException {
126:
127: SchemaFactory sf = SchemaFactory
128: .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
129:
130: SchemaResourceResolver resourceResolver = new SchemaResourceResolver();
131:
132: sf.setResourceResolver(resourceResolver);
133:
134: List<Source> sources = new ArrayList<Source>();
135:
136: for (InputSource is : xsdsInJar) {
137: Message msg = new Message("CREATE_SCHEMA_LOADED_FROM_JAR",
138: LOG, is.getSystemId());
139: LOG.log(Level.INFO, msg.toString());
140: Document doc = docBuilder.parse(is.getByteStream());
141: DOMSource stream = new DOMSource(doc, is.getSystemId());
142: stream.setSystemId(is.getSystemId());
143: sources.add(stream);
144: }
145:
146: if (schemas != null) {
147: for (int i = 0; i < schemas.length; i++) {
148: Document doc = docBuilder.parse(schemas[i]);
149: DOMSource stream = new DOMSource(doc, schemas[i]);
150: sources.add(stream);
151: }
152: }
153: Source[] args = new Source[sources.size()];
154: sources.toArray(args);
155: return sf.newSchema(args);
156:
157: }
158:
159: private Schema createSchema(String[] schemas) throws SAXException,
160: IOException {
161:
162: SchemaFactory sf = SchemaFactory
163: .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
164:
165: SchemaResourceResolver resourceResolver = new SchemaResourceResolver();
166:
167: sf.setResourceResolver(resourceResolver);
168:
169: Source[] sources = new Source[schemas.length];
170:
171: for (int i = 0; i < schemas.length; i++) {
172: // need to validate the schema file
173: Document doc = docBuilder.parse(schemas[i]);
174:
175: DOMSource stream = new DOMSource(doc, schemas[i]);
176:
177: sources[i] = stream;
178: }
179: return sf.newSchema(sources);
180:
181: }
182:
183: public boolean validate(InputSource wsdlsource, String[] schemas)
184: throws ToolException {
185: boolean isValid = false;
186: Schema schema;
187: try {
188: SAXParserFactory saxFactory = SAXParserFactory
189: .newInstance();
190: saxFactory.setFeature(
191: "http://xml.org/sax/features/namespaces", true);
192: saxParser = saxFactory.newSAXParser();
193:
194: if (defaultSchemas != null) {
195: schemas = addSchemas(defaultSchemas, schemas);
196: schema = createSchema(schemas);
197: } else {
198: schema = createSchema(schemaFromJar, schemas);
199: }
200:
201: Validator validator = schema.newValidator();
202:
203: NewStackTraceErrorHandler errHandler = new NewStackTraceErrorHandler();
204: validator.setErrorHandler(errHandler);
205: SAXSource saxSource = new SAXSource(saxParser
206: .getXMLReader(), wsdlsource);
207: validator.validate(saxSource);
208:
209: if (!errHandler.isValid()) {
210: throw new ToolException(errHandler.getErrorMessages());
211: }
212:
213: isValid = true;
214:
215: } catch (IOException ioe) {
216: throw new ToolException("Cannot get the wsdl "
217: + wsdlsource.getSystemId(), ioe);
218: } catch (SAXException saxEx) {
219: throw new ToolException(saxEx);
220: } catch (ParserConfigurationException e) {
221: throw new ToolException(e);
222: }
223: return isValid;
224: }
225:
226: private String[] addSchemas(String[] defaults, String[] schemas) {
227: if (schemas == null || schemas.length == 0) {
228: return defaultSchemas;
229: }
230: String[] ss = new String[schemas.length + defaults.length];
231: System.arraycopy(defaults, 0, ss, 0, defaults.length);
232: System.arraycopy(schemas, 0, ss, defaults.length,
233: schemas.length);
234: return ss;
235: }
236:
237: private String[] getDefaultSchemas() throws ToolException {
238:
239: String loc = schemaLocation;
240:
241: if (loc == null || "".equals(loc.trim())) {
242: loc = "./";
243: }
244: File f = new File(loc);
245:
246: if (f.exists() && f.isDirectory()) {
247: FilenameFilter filter = new FilenameFilter() {
248: public boolean accept(File dir, String name) {
249: if (name.toLowerCase().endsWith(".xsd")
250: && !new File(dir.getPath() + File.separator
251: + name).isDirectory()) {
252: return true;
253: }
254: return false;
255: }
256: };
257:
258: File[] files = f.listFiles(filter);
259:
260: List<String> xsdUrls = new ArrayList<String>(files.length);
261: for (File file : files) {
262: try {
263: String s = file.toURI().toURL().toString();
264: xsdUrls.add(s);
265: if (s.indexOf("http-conf") > 0) {
266: xsdUrls.add(0, s);
267: }
268: } catch (MalformedURLException e) {
269: throw new ToolException(e);
270: }
271: }
272: return xsdUrls.toArray(new String[xsdUrls.size()]);
273: }
274: return null;
275: }
276: }
277:
278: class NewStackTraceErrorHandler implements ErrorHandler {
279: protected boolean valid;
280:
281: private StringBuffer buffer;
282:
283: private int numErrors;
284:
285: private List<SAXParseException> errors;
286:
287: NewStackTraceErrorHandler() {
288: valid = true;
289: numErrors = 0;
290: buffer = new StringBuffer();
291: errors = new ArrayList<SAXParseException>();
292: }
293:
294: public void error(SAXParseException ex) throws SAXParseException {
295: addError(ex);
296: }
297:
298: public void fatalError(SAXParseException ex) {
299: addError(ex);
300: }
301:
302: public void warning(SAXParseException ex) {
303: // Warning messages are ignored.
304: // return;
305: }
306:
307: boolean isValid() {
308: return valid;
309: }
310:
311: int getTotalErrors() {
312: return numErrors;
313: }
314:
315: String getErrorMessages() {
316: return buffer.toString();
317: }
318:
319: SAXParseException[] getErrors() {
320: if (errors == null) {
321: return null;
322: }
323: return errors.toArray(new SAXParseException[errors.size()]);
324: }
325:
326: void addError(String msg, SAXParseException ex) {
327: valid = false;
328: if (numErrors == 0) {
329: buffer.append("\n");
330: } else {
331: buffer.append("\n\n");
332: }
333: buffer.append(msg);
334: numErrors++;
335: errors.add(ex);
336:
337: }
338:
339: private String getErrorMessage(SAXParseException ex) {
340: return "line " + ex.getLineNumber() + " column "
341: + ex.getColumnNumber() + " of " + ex.getSystemId()
342: + ": " + ex.getMessage();
343: }
344:
345: private void addError(SAXParseException ex) {
346: addError(getErrorMessage(ex), ex);
347: }
348:
349: }
350:
351: class SchemaResourceResolver implements LSResourceResolver {
352: private static final Logger LOG = LogUtils
353: .getL7dLogger(SchemaValidator.class);
354: private static final Map<String, String> NSFILEMAP = new HashMap<String, String>();
355: static {
356: NSFILEMAP.put(ToolConstants.XML_NAMESPACE_URI, "xml.xsd");
357: NSFILEMAP.put(ToolConstants.WSDL_NAMESPACE_URI, "wsdl.xsd");
358: NSFILEMAP.put(ToolConstants.SCHEMA_URI, "XMLSchema.xsd");
359: }
360:
361: private LSInput loadLSInput(String ns) {
362: String path = ToolConstants.CXF_SCHEMAS_DIR_INJAR
363: + NSFILEMAP.get(ns);
364: URL url = getClass().getClassLoader().getResource(path);
365: LSInput lsin = new LSInputImpl();
366: lsin.setSystemId(url.toString());
367: try {
368: lsin.setByteStream(url.openStream());
369: } catch (IOException e) {
370: return null;
371: }
372: return lsin;
373: }
374:
375: public LSInput resolveResource(String type, String namespaceURI,
376: String publicId, String systemId, String baseURI) {
377: Message msg = new Message("RESOLVE_SCHEMA", LOG, namespaceURI,
378: systemId, baseURI);
379: LOG.log(Level.INFO, msg.toString());
380: if (NSFILEMAP.containsKey(namespaceURI)) {
381: return loadLSInput(namespaceURI);
382: }
383:
384: LSInput lsin = null;
385: String resURL = null;
386: String localFile = null;
387: if (systemId != null) {
388: String schemaLocation = "";
389: if (baseURI != null) {
390: schemaLocation = baseURI.substring(0, baseURI
391: .lastIndexOf("/") + 1);
392: }
393: if (systemId.indexOf("http://") < 0) {
394: resURL = schemaLocation + systemId;
395: } else {
396: resURL = systemId;
397: }
398: } else if (namespaceURI != null) {
399: resURL = namespaceURI;
400: }
401:
402: if (resURL != null && resURL.startsWith("http://")) {
403: String filename = NSFILEMAP.get(resURL);
404: if (filename != null) {
405: localFile = ToolConstants.CXF_SCHEMAS_DIR_INJAR
406: + filename;
407: } else {
408: URL url;
409: URLConnection urlCon = null;
410: try {
411: url = new URL(resURL);
412: urlCon = url.openConnection();
413: urlCon.setUseCaches(false);
414: lsin = new LSInputImpl();
415: lsin.setSystemId(resURL);
416: lsin.setByteStream(urlCon.getInputStream());
417: msg = new Message("RESOLVE_FROM_REMOTE", LOG, url);
418: LOG.log(Level.INFO, msg.toString());
419: return lsin;
420: } catch (Exception e) {
421: e.printStackTrace();
422: return null;
423: }
424: }
425: } else if (resURL != null && !resURL.startsWith("http:")) {
426: localFile = resURL;
427: } else {
428: return null;
429: }
430:
431: URIResolver resolver;
432: try {
433: msg = new Message("RESOLVE_FROM_LOCAL", LOG, localFile);
434: LOG.log(Level.INFO, msg.toString());
435:
436: resolver = new URIResolver(localFile);
437: if (resolver.isResolved()) {
438: lsin = new LSInputImpl();
439: lsin.setSystemId(localFile);
440: lsin.setByteStream(resolver.getInputStream());
441: }
442: } catch (IOException e) {
443: return null;
444: }
445: return lsin;
446: }
447: }
448:
449: class LSInputImpl implements LSInput {
450:
451: protected String fPublicId;
452:
453: protected String fSystemId;
454:
455: protected String fBaseSystemId;
456:
457: protected InputStream fByteStream;
458:
459: protected Reader fCharStream;
460:
461: protected String fData;
462:
463: protected String fEncoding;
464:
465: protected boolean fCertifiedText;
466:
467: public LSInputImpl() {
468: }
469:
470: public LSInputImpl(String publicId, String systemId,
471: InputStream byteStream) {
472: fPublicId = publicId;
473: fSystemId = systemId;
474: fByteStream = byteStream;
475: }
476:
477: public InputStream getByteStream() {
478: return fByteStream;
479: }
480:
481: public void setByteStream(InputStream byteStream) {
482: fByteStream = byteStream;
483: }
484:
485: public Reader getCharacterStream() {
486: return fCharStream;
487: }
488:
489: public void setCharacterStream(Reader characterStream) {
490: fCharStream = characterStream;
491: }
492:
493: public String getStringData() {
494: return fData;
495: }
496:
497: public void setStringData(String stringData) {
498: fData = stringData;
499: }
500:
501: public String getEncoding() {
502: return fEncoding;
503: }
504:
505: public void setEncoding(String encoding) {
506: fEncoding = encoding;
507: }
508:
509: public String getPublicId() {
510: return fPublicId;
511: }
512:
513: public void setPublicId(String publicId) {
514: fPublicId = publicId;
515: }
516:
517: public String getSystemId() {
518: return fSystemId;
519: }
520:
521: public void setSystemId(String systemId) {
522: fSystemId = systemId;
523: }
524:
525: public String getBaseURI() {
526: return fBaseSystemId;
527: }
528:
529: public void setBaseURI(String baseURI) {
530: fBaseSystemId = baseURI;
531: }
532:
533: public boolean getCertifiedText() {
534: return fCertifiedText;
535: }
536:
537: public void setCertifiedText(boolean certifiedText) {
538: fCertifiedText = certifiedText;
539: }
540:
541: }
|