| /******************************************************************************* |
| * Copyright (c) 2004, 2008 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are 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: |
| * IBM Corporation - initial API and implementation |
| * Jesper Steen Moeller - added namespace support |
| *******************************************************************************/ |
| package org.eclipse.jpt.eclipselink.core.internal.resource.orm; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.Reader; |
| import java.util.ArrayList; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| import javax.xml.parsers.ParserConfigurationException; |
| import org.eclipse.core.internal.content.ContentMessages; |
| import org.eclipse.core.internal.runtime.RuntimeLog; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExecutableExtension; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.content.IContentDescription; |
| import org.eclipse.core.runtime.content.XMLContentDescriber; |
| import org.eclipse.osgi.util.NLS; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.SAXException; |
| |
| //TODO bug 263976 - copied from org.eclipse.core.runtime.content.XMLRootElementContentDescriber2 |
| /** |
| * A content describer for detecting the name of the top-level element, |
| * its namespace and the DTD system identifier in an XML file. |
| * <p> |
| * This executable extension supports "element" parameter, that |
| * can be specified more than once. If the |
| * <code>":-"</code> method is used, then the value is treated as |
| * "element" (always just one) |
| * </p> |
| * <p> |
| * The value of "element" is specified using such a format |
| * <code>{namespace}name/dtd:version</code>. The namespace or dtd part |
| * can be omitted and accepted are values like <code>name/dtd</code>, |
| * <code>{ns}name</code> and <code>name</code>. |
| * </p> |
| * <p> |
| * The describer will detect a document, if it matches at least one "element" |
| * what means, that dtd, namespace (if specified) and name in "element" |
| * match those in the document. |
| * </p> |
| * <p> |
| * If the "element" name part is "*", e.g. <code>{namespace}*</code>, |
| * it denotes a wildcard match. If the "element" namespace part is empty, |
| * e.g. <code>{}name</code>, only these documents with the root element |
| * that belong to the unnamed namespace <code><elem xmlns=""></code> |
| * will be detected. |
| * </p> |
| * <p> |
| * This class should be used instead of {@link XMLRootElementContentDescriber} |
| * which doesn't detect namespaces and doesn't allow to specify |
| * more than one set of dtds, root element names and namespaces which |
| * should be detected. |
| * </p> |
| * <p> |
| * This class is not intended to be subclassed or instantiated by clients, |
| * only to be referenced by the "describer" configuration element in |
| * extensions to the <code>org.eclipse.core.runtime.contentTypes</code> |
| * extension point. |
| * </p> |
| * |
| * @since org.eclipse.core.contenttype 3.3 |
| */ |
| public final class XMLRootElementContentDescriber2 extends XMLContentDescriber implements IExecutableExtension { |
| private static final String ELEMENT_TO_FIND = "element"; //$NON-NLS-1$ |
| |
| /* (Intentionally not included in javadoc) |
| * The top-level elements we are looking for. This value will be initialized |
| * by the <code>setInitializationData</code> method. If no value is |
| * provided, then this means that we don't care what the top-level element |
| * will be. The list is a collection of <code>QualifiedElement</code>. |
| */ |
| private QualifiedElement[] elementsToFind = null; |
| |
| /* (Intentionally not included in javadoc) |
| * Simple value holder for root element name, its namespace and dtd. |
| */ |
| private class QualifiedElement { |
| private String namespace; |
| private String element; |
| private String dtd; |
| private String version; |
| |
| public QualifiedElement(String namespace, String element, String dtd, String version) { |
| this.namespace = namespace; |
| this.element = element; |
| this.dtd = dtd; |
| this.version = version; |
| } |
| |
| public QualifiedElement(String qualifiedElement) { |
| // Extract namespace part |
| int openBrace = qualifiedElement.indexOf('{'); |
| int closeBrace = qualifiedElement.indexOf('}'); |
| if (openBrace == 0 && closeBrace >=1 ) { |
| namespace = qualifiedElement.substring(1, closeBrace); |
| qualifiedElement = qualifiedElement.substring(closeBrace+1); |
| } |
| // Extract dtd part |
| int dtdSlash = qualifiedElement.indexOf('/'); |
| if (dtdSlash > 0) { |
| dtd = qualifiedElement.substring(dtdSlash+1); |
| qualifiedElement = qualifiedElement.substring(0, dtdSlash); |
| } |
| // Extract version part |
| int versionSlash = qualifiedElement.indexOf(':'); |
| if (versionSlash > 0) { |
| version = qualifiedElement.substring(versionSlash + 1); |
| qualifiedElement = qualifiedElement.substring(0, versionSlash); |
| } |
| |
| // Check if the name is a wildcard |
| element = ("*".equals(qualifiedElement) ? null : qualifiedElement); |
| } |
| |
| public String getNamespace() { |
| return namespace; |
| } |
| |
| public String getElement() { |
| return element; |
| } |
| public String getDTD() { |
| return dtd; |
| } |
| |
| public String getVersion() { |
| return version; |
| } |
| |
| public boolean matches(String someNamespace, String someElement, String someDtd, String someVersion) { |
| boolean nsMatch = this.namespace != null ? this.namespace.equals(someNamespace) : true; |
| boolean elementEquals = this.element != null ? this.element.equals(someElement) : true; |
| boolean dtdEquals = this.dtd != null ? this.dtd.equals(someDtd) : true; |
| boolean versionEquals = this.version != null ? this.version.equals(someVersion) : true; |
| return nsMatch && elementEquals && dtdEquals && versionEquals; |
| } |
| } |
| |
| /* (Intentionally not included in javadoc) |
| * Determines the validation status for the given contents. |
| * |
| * @param contents the contents to be evaluated |
| * @return one of the following:<ul> |
| * <li><code>VALID</code></li>, |
| * <li><code>INVALID</code></li>, |
| * <li><code>INDETERMINATE</code></li> |
| * </ul> |
| * @throws IOException |
| */ |
| private int checkCriteria(InputSource contents) throws IOException { |
| XMLRootHandler xmlHandler = new XMLRootHandler(elementsToFind != null); |
| try { |
| if (!xmlHandler.parseContents(contents)) |
| return INDETERMINATE; |
| } catch (SAXException e) { |
| // we may be handed any kind of contents... it is normal we fail to parse |
| return INDETERMINATE; |
| } catch (ParserConfigurationException e) { |
| // some bad thing happened - force this describer to be disabled |
| String message = ContentMessages.content_parserConfiguration; |
| RuntimeLog.log(new Status(IStatus.ERROR, ContentMessages.OWNER_NAME, 0, message, e)); |
| throw new RuntimeException(message); |
| } |
| // Check to see if we matched our criteria. |
| if (elementsToFind != null) { |
| boolean foundOne = false; |
| for (int i = 0; i < elementsToFind.length && !foundOne; ++i) { |
| foundOne |= elementsToFind[i].matches(xmlHandler.getRootNamespace(), xmlHandler.getRootName(), xmlHandler.getDTD(), xmlHandler.getVersion()); |
| } |
| if (!foundOne) |
| return INDETERMINATE; |
| } |
| // We must be okay then. |
| return VALID; |
| } |
| |
| /* (Intentionally not included in javadoc) |
| * @see IContentDescriber#describe(InputStream, IContentDescription) |
| */ |
| @Override |
| public int describe(InputStream contents, IContentDescription description) throws IOException { |
| // call the basic XML describer to do basic recognition |
| if (super.describe(contents, description) == INVALID) |
| return INVALID; |
| // super.describe will have consumed some chars, need to rewind |
| contents.reset(); |
| // Check to see if we matched our criteria. |
| return checkCriteria(new InputSource(contents)); |
| } |
| |
| /* (Intentionally not included in javadoc) |
| * @see IContentDescriber#describe(Reader, IContentDescription) |
| */ |
| @Override |
| public int describe(Reader contents, IContentDescription description) throws IOException { |
| // call the basic XML describer to do basic recognition |
| if (super.describe(contents, description) == INVALID) |
| return INVALID; |
| // super.describe will have consumed some chars, need to rewind |
| contents.reset(); |
| // Check to see if we matched our criteria. |
| return checkCriteria(new InputSource(contents)); |
| } |
| |
| /* (Intentionally not included in javadoc) |
| * @see IExecutableExtension#setInitializationData |
| */ |
| public void setInitializationData(final IConfigurationElement config, final String propertyName, final Object data) throws CoreException { |
| if (data instanceof String) |
| elementsToFind = new QualifiedElement[] {new QualifiedElement((String) data)}; |
| else if (data instanceof Hashtable) { |
| List elements = null; |
| |
| // the describer parameters have to be read again, because "element" parameter can be specified multiple times |
| // and the given hashtable carries only one of them |
| IConfigurationElement describerElement = config.getChildren("describer")[0]; //$NON-NLS-1$ |
| IConfigurationElement[] params = describerElement.getChildren("parameter"); //$NON-NLS-1$ |
| String pname = null; |
| for (int i = 0; i < params.length; i++) { |
| pname = params[i].getAttribute("name"); //$NON-NLS-1$ |
| if (ELEMENT_TO_FIND.equals(pname)) { |
| if (elements == null) |
| elements = new LinkedList(); |
| elements.add(new QualifiedElement(params[i].getAttribute("value"))); //$NON-NLS-1$ |
| } |
| } |
| |
| List qualifiedElements = new ArrayList(); |
| |
| // create list of qualified elements |
| if (elements != null) { |
| for (Iterator it = elements.iterator(); it.hasNext();) { |
| qualifiedElements.add(it.next()); |
| } |
| } |
| elementsToFind = (QualifiedElement[]) qualifiedElements.toArray(new QualifiedElement[qualifiedElements.size()]); |
| } |
| |
| if (elementsToFind.length == 0) { |
| String message = NLS.bind(ContentMessages.content_badInitializationData, XMLRootElementContentDescriber2.class.getName()); |
| throw new CoreException(new Status(IStatus.ERROR, ContentMessages.OWNER_NAME, 0, message, null)); |
| } |
| } |
| } |