/******************************************************************************* * Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc. * Distributed under license by Red Hat, Inc. All rights reserved. * This program is made available under the terms of the * Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Exadel, Inc. and Red Hat, Inc. - initial API and implementation ******************************************************************************/ package org.jboss.tools.common.meta.impl; import org.xml.sax.ContentHandler; import java.io.*; import java.util.*; import java.net.*; import org.w3c.dom.*; import org.xml.sax.Attributes; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; import org.apache.xerces.xni.XMLResourceIdentifier; import org.apache.xerces.xni.XNIException; import org.apache.xerces.xni.parser.XMLInputSource; import org.jboss.tools.common.CommonPlugin; import org.jboss.tools.common.model.plugin.ModelPlugin; import org.jboss.tools.common.model.util.*; import org.jboss.tools.common.xml.SAXValidator; import org.jboss.tools.common.xml.XMLEntityResolver; import org.jboss.tools.common.xml.XMLEntityResolverImpl; import org.jboss.tools.common.xml.XMLUtilities; public class MetaLibLoader { public static String DOC_PUBLICID = "-//Red Hat, Inc.//DTD Meta 1.0//EN"; //$NON-NLS-1$ public static boolean validateMetaXML = false; static { try { Class<?> c = MetaLibLoader.class; XMLEntityResolver.registerPublicEntity(DOC_PUBLICID, c, "/meta/meta.dtd"); //$NON-NLS-1$ } catch (IOException e) { ModelPlugin.getPluginLog().logError(e); } } private XModelMetaDataImpl meta = null; private HashSet<String> metas = new HashSet<String>(); private ArrayList<ModuleRef> metarefs = new ArrayList<ModuleRef>(); private Element root = XMLUtilities.createDocumentElement("meta"); //$NON-NLS-1$ public MetaLibLoader() {} public void load(XModelMetaDataImpl meta) { this.meta = meta; Map<String,URL> resources = MetaResourceLoader.getMetaResources(); Iterator<String> it = resources.keySet().iterator(); while(it.hasNext()) { String path = it.next(); URL url = resources.get(path); load(path, url); } for (int i = 0; i < metarefs.size(); i++) { ModuleRef r = metarefs.get(i); load(r.element, r.name, r.info); } } void sift(Set modules) { boolean b = true; while(b) { b = false; for (int i = metarefs.size() - 1; i >= 0; i--) { ModuleRef r = metarefs.get(i); if(r.acceptable(modules)) continue; b = true; metarefs.remove(i); } } } void load(String name, URL url) { if(url == null) return; // long t = System.currentTimeMillis(); InputStream stream1 = null; InputStream stream2 = null; try { stream1 = url.openStream(); stream2 = new BufferedInputStream(stream1, 16384); Element g = parse(stream2); if(g == null) { ModelPlugin.getPluginLog().logError("SAX parser failed to load meta resource " + name); stream1 = url.openStream(); stream2 = new BufferedInputStream(stream1, 16384); g = XMLUtilities.getElement(stream2, new EmptyResolver()); } if(g == null) { ModelPlugin.getPluginLog().logInfo("Corrupted meta resource " + name); //$NON-NLS-1$ } else { load0(g, name, url.toString()); } } catch (IOException e) { ModelPlugin.getPluginLog().logError("MetaLoader: Cannot read resource " + url.toString()); //$NON-NLS-1$ return; } finally { if(stream2!=null) { try { stream2.close(); } catch (IOException e) { // ignore } } } if(validateMetaXML) { InputStream stream3 = null; try { stream3 = url.openStream(); InputSource is = new InputSource(stream3); String[] errors = XMLUtil.getXMLErrors(is, true); if(errors != null && errors.length > 0) { ModelPlugin.getPluginLog().logInfo("Errors in " + name); //$NON-NLS-1$ for (int i = 0; i < errors.length && i < 5; i++) { ModelPlugin.getPluginLog().logInfo(errors[i]); } } } catch (IOException e) { ModelPlugin.getPluginLog().logError(e); }finally { if(stream3!=null) { try { stream3.close(); } catch (IOException e) { // ignore } } } } } Element parse(InputStream stream) { Parser p = new Parser(); p.documentElement = root; p.current = root; p.parse(stream); Element g = p.documentElement; g = XMLUtilities.getUniqueChild(g, "XModelEntityGroup"); //$NON-NLS-1$ if(g != null) { p.documentElement.removeChild(g); } return g; } void load0(Element g, String name, String source) { metarefs.add(new ModuleRef(g, name, source)); } void load(Element g, String name, String source) { source = source.substring(0, source.length() - name.length()); if(metas.contains(name)) { // ModelPlugin.log("Can't load module " + name + " second time from " + source); } else if(g == null) { //ModelPlugin.log("Can't load module " + name + " from " + source); } else { XMetaDataLoader.loadEntityGroup(meta, g); metas.add(name); //ModelPlugin.log("Module " + name + " loaded from " + source); meta.getLoadedModules().put(name, source); } } } class ModuleRef { Element element; String name; String info; String key = ""; //$NON-NLS-1$ ArrayList<String> depends = new ArrayList<String>(); public ModuleRef(Element e, String name, String info) { this.element = e; Element v = XMLUtil.getUniqueChild(e, "VERSION"); //$NON-NLS-1$ this.name = name; this.info = info; if(v == null) return; if(v.hasAttribute("MODULE") && v.hasAttribute("VERSION")) { //$NON-NLS-1$ //$NON-NLS-2$ key = v.getAttribute("MODULE") + ":" + v.getAttribute("VERSION"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } if(v.hasAttribute("DEPENDS")) { //$NON-NLS-1$ String s = v.getAttribute("DEPENDS"); //$NON-NLS-1$ StringTokenizer st = new StringTokenizer(s, ","); //$NON-NLS-1$ while(st.hasMoreTokens()) depends.add(st.nextToken()); } } public boolean acceptable(Set modules) { return (true || key.endsWith("1.0")); //$NON-NLS-1$ } } class Parser implements ContentHandler { protected static final String FATAL_ERROR_PROCESSING_FEATURE_ID = "http://apache.org/xml/features/continue-after-fatal-error"; //$NON-NLS-1$ protected static final String ENTITY_RESOLVER_PROPERTY_ID = "http://apache.org/xml/properties/internal/entity-resolver"; //$NON-NLS-1$ protected static final String NAMESPACES_FEATURE_ID = "http://xml.org/sax/features/namespaces"; //$NON-NLS-1$ protected static final String NAMESPACE_PREFIXES_FEATURE_ID = "http://xml.org/sax/features/namespace-prefixes"; //$NON-NLS-1$ protected static final String VALIDATION_FEATURE_ID = "http://xml.org/sax/features/validation"; //$NON-NLS-1$ protected static final String VALIDATION_SCHEMA_FEATURE_ID = "http://apache.org/xml/features/validation/schema"; //$NON-NLS-1$ protected static final String VALIDATION_SCHEMA_CHECKING_FEATURE_ID = "http://apache.org/xml/features/validation/schema-full-checking"; //$NON-NLS-1$ protected static final String VALIDATION_DYNAMIC_FEATURE_ID = "http://apache.org/xml/features/validation/dynamic"; //$NON-NLS-1$ protected static final String DEFAULT_SAX_PARSER_CLASS_NAME = "org.apache.xerces.parsers.SAXParser"; //$NON-NLS-1$ Element documentElement = null; Element current = null; public void parse(InputStream is) { parse(new InputSource(is)); } public void parse(org.xml.sax.InputSource is) { XMLReader parser = createParser(); if(parser == null) return; try { parser.parse(is); } catch (SAXException e) { ModelPlugin.getPluginLog().logError(e); } catch (IOException e) { ModelPlugin.getPluginLog().logError(e); } } XMLReader newInstance() throws SAXException { try { return (XMLReader) ModelPlugin.getDefault().getBundle().loadClass(DEFAULT_SAX_PARSER_CLASS_NAME).newInstance(); } catch (ClassNotFoundException e1) { throw new SAXException("SAX2 driver class " + DEFAULT_SAX_PARSER_CLASS_NAME + " not found", e1); } catch (IllegalAccessException e2) { throw new SAXException("SAX2 driver class " + DEFAULT_SAX_PARSER_CLASS_NAME + " found but cannot be loaded", e2); } catch (InstantiationException e3) { throw new SAXException("SAX2 driver class " + DEFAULT_SAX_PARSER_CLASS_NAME + " loaded but cannot be instantiated (no empty public constructor?)", e3); } catch (ClassCastException e4) { throw new SAXException("SAX2 driver class " + DEFAULT_SAX_PARSER_CLASS_NAME + " does not implement XMLReader", e4); } } XMLReader createParser() { DefaultHandler handler = new DefaultHandler(); XMLReader parserInstance = null; try { parserInstance = newInstance(); //XMLReaderFactory.createXMLReader(DEFAULT_SAX_PARSER_CLASS_NAME); } catch (SAXException e) { ModelPlugin.getPluginLog().logError("default parser failed: " + e.getMessage()); return null; } SAXValidator.setFeature(parserInstance, NAMESPACES_FEATURE_ID, false); SAXValidator.setFeature(parserInstance, NAMESPACE_PREFIXES_FEATURE_ID, false); SAXValidator.setFeature(parserInstance, VALIDATION_FEATURE_ID, false); SAXValidator.setFeature(parserInstance, VALIDATION_SCHEMA_FEATURE_ID, false); SAXValidator.setFeature(parserInstance, VALIDATION_SCHEMA_CHECKING_FEATURE_ID, false); SAXValidator.setFeature(parserInstance, VALIDATION_DYNAMIC_FEATURE_ID, false); SAXValidator.setFeature(parserInstance, FATAL_ERROR_PROCESSING_FEATURE_ID, false); try { if(MetaLibLoader.validateMetaXML) { parserInstance.setProperty(ENTITY_RESOLVER_PROPERTY_ID, new XMLEntityResolverImpl()); } else { parserInstance.setProperty(ENTITY_RESOLVER_PROPERTY_ID, new EmptyHandler()); } } catch (SAXException e1) { CommonPlugin.getPluginLog().logError( e1.getMessage()+"", e1); //$NON-NLS-1$ } parserInstance.setContentHandler(handler); parserInstance.setErrorHandler(handler); parserInstance.setContentHandler(this); return parserInstance; } //SAXParser public void characters(char[] ch, int start, int length) throws SAXException { } public void endDocument() throws SAXException { } public void endElement(String uri, String localName, String name) throws SAXException { Node p = current.getParentNode(); if(p instanceof Element) { current = (Element)p; } } public void endPrefixMapping(String prefix) throws SAXException {} public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {} public void processingInstruction(String target, String data) throws SAXException { } public void setDocumentLocator(Locator locator) {} public void skippedEntity(String name) throws SAXException {} public void startDocument() throws SAXException { } public void startElement(String uri, String localName, String name, Attributes atts) throws SAXException { if(current == null) { current = XMLUtilities.createDocumentElement(name); documentElement = current; } else { current = XMLUtilities.createElement(current, name); } int l = atts.getLength(); for (int i = 0; i < l; i++) { String n = atts.getQName(i); String v = atts.getValue(i); current.setAttribute(n, v); } } public void startPrefixMapping(String prefix, String uri) throws SAXException {} } class EmptyHandler implements org.apache.xerces.xni.parser.XMLEntityResolver { public XMLInputSource resolveEntity(XMLResourceIdentifier id) throws XNIException, IOException { return new XMLInputSource(id.getPublicId(), id.getBaseSystemId(), id.getBaseSystemId(), new StringReader(""), null); } } class EmptyResolver implements EntityResolver { public InputSource resolveEntity(String publicID, String systemID) throws SAXException, IOException { return new InputSource(new StringReader("")); //$NON-NLS-1$ } }