Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content')
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomFileContentDescriber.java96
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomHandler.java166
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/TextContentDescriber.java89
-rw-r--r--org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/XMLContentDescriber.java128
4 files changed, 479 insertions, 0 deletions
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomFileContentDescriber.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomFileContentDescriber.java
new file mode 100644
index 00000000..49c9a868
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomFileContentDescriber.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.content;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+import org.eclipse.core.runtime.content.IContentDescription;
+
+import org.eclipse.m2e.core.internal.Messages;
+
+
+/**
+ * A content describer for POM files.
+ *
+ * @see org.eclipse.ant.internal.core.contentDescriber.AntBuildfileContentDescriber
+ * @author Herve Boutemy
+ * @since 0.9.6
+ */
+public final class PomFileContentDescriber extends XMLContentDescriber {
+ /**
+ * 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 {
+ PomHandler pomHandler = new PomHandler();
+ try {
+ if(!pomHandler.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
+ throw new RuntimeException(Messages.PomFileContentDescriber_error);
+ }
+
+ // Check to see if we matched our criteria.
+ if(pomHandler.hasRootProjectElement()) {
+ if(pomHandler.hasArtifactIdElement()) {
+ //project and artifactId element
+ return VALID;
+ }
+ //only a top level project element: maybe a POM file, but maybe an Ant buildfile, a site descriptor, ...
+ return INDETERMINATE;
+ }
+ return INDETERMINATE;
+ }
+
+ @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));
+ }
+
+ @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));
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomHandler.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomHandler.java
new file mode 100644
index 00000000..3ff2db65
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/PomHandler.java
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.content;
+
+import java.io.IOException;
+import java.io.StringReader;
+
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+
+/**
+ * An xml event handler for detecting the project top-level element in a POM file. Also records whether a default
+ * attribute is present for the project and if any typical Maven elements are present.
+ *
+ * @see org.eclipse.ant.internal.core.contentDescriber.AntHandler
+ * @author Herve Boutemy
+ * @since 0.9.6
+ */
+public final class PomHandler extends DefaultHandler {
+ /**
+ * An exception indicating that the parsing should stop.
+ */
+ private class StopParsingException extends SAXException {
+ /**
+ * All serializable objects should have a stable serialVersionUID
+ */
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Constructs an instance of <code>StopParsingException</code> with a <code>null</code> detail message.
+ */
+ public StopParsingException() {
+ super((String) null);
+ }
+ }
+
+ private static final String PROJECT = "project"; //$NON-NLS-1$
+
+ private static final String ARTIFACTID = "artifactId"; //$NON-NLS-1$
+
+ /**
+ * This is the name of the top-level element found in the XML file. This member variable is <code>null</code> unless
+ * the file has been parsed successful to the point of finding the top-level element.
+ */
+ private String fTopElementFound = null;
+
+ private SAXParserFactory fFactory;
+
+ private boolean fArtifactIdFound = false;
+
+ private int fLevel = -1;
+
+ /**
+ * Creates a new SAX parser for use within this instance.
+ *
+ * @return The newly created parser.
+ * @throws ParserConfigurationException If a parser of the given configuration cannot be created.
+ * @throws SAXException If something in general goes wrong when creating the parser.
+ */
+ private final SAXParser createParser(SAXParserFactory parserFactory) throws ParserConfigurationException,
+ SAXException, SAXNotRecognizedException, SAXNotSupportedException {
+ // Initialize the parser.
+ final SAXParser parser = parserFactory.newSAXParser();
+ final XMLReader reader = parser.getXMLReader();
+ // disable DTD validation
+ try {
+ // be sure validation is "off" or the feature to ignore DTD's will not apply
+ reader.setFeature("http://xml.org/sax/features/validation", false); //$NON-NLS-1$
+ reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); //$NON-NLS-1$
+ } catch(SAXNotRecognizedException e) {
+ // not a big deal if the parser does not recognize the features
+ } catch(SAXNotSupportedException e) {
+ // not a big deal if the parser does not support the features
+ }
+ return parser;
+ }
+
+ private SAXParserFactory getFactory() {
+ synchronized(this) {
+ if(fFactory != null) {
+ return fFactory;
+ }
+ fFactory = SAXParserFactory.newInstance();
+ fFactory.setNamespaceAware(true);
+ }
+ return fFactory;
+ }
+
+ protected boolean parseContents(InputSource contents) throws IOException, ParserConfigurationException, SAXException {
+ // Parse the file into we have what we need (or an error occurs).
+ try {
+ fFactory = getFactory();
+ if(fFactory == null) {
+ return false;
+ }
+ final SAXParser parser = createParser(fFactory);
+ // to support external entities specified as relative URIs (see bug 63298)
+ contents.setSystemId("/"); //$NON-NLS-1$
+ parser.parse(contents, this);
+ } catch(StopParsingException e) {
+ // Abort the parsing normally. Fall through...
+ }
+ return true;
+ }
+
+ /*
+ * Resolve external entity definitions to an empty string. This is to speed
+ * up processing of files with external DTDs. Not resolving the contents
+ * of the DTD is ok, as only the System ID of the DTD declaration is used.
+ * @see org.xml.sax.helpers.DefaultHandler#resolveEntity(java.lang.String, java.lang.String)
+ */
+ @Override
+ public InputSource resolveEntity(String publicId, String systemId) {
+ return new InputSource(new StringReader("")); //$NON-NLS-1$
+ }
+
+
+ @Override
+ public final void startElement(final String uri, final String elementName, final String qualifiedName,
+ final Attributes attributes) throws SAXException {
+ fLevel++ ;
+ if(fTopElementFound == null) {
+ fTopElementFound = elementName;
+ if(!hasRootProjectElement()) {
+ throw new StopParsingException();
+ }
+ }
+ if(fLevel == 1 && ARTIFACTID.equals(elementName)) {
+ fArtifactIdFound = true;
+ throw new StopParsingException();
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ super.endElement(uri, localName, qName);
+ fLevel-- ;
+ }
+
+ protected boolean hasRootProjectElement() {
+ return PROJECT.equals(fTopElementFound);
+ }
+
+ protected boolean hasArtifactIdElement() {
+ return fArtifactIdFound;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/TextContentDescriber.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/TextContentDescriber.java
new file mode 100644
index 00000000..bfe4da15
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/TextContentDescriber.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.content;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.core.runtime.content.IContentDescription;
+import org.eclipse.core.runtime.content.ITextContentDescriber;
+
+/**
+ * A copy of org.eclipse.core.internal.content.TextContentDescriber to avoid internal API use.
+ *
+ * This class provides internal basis for text-based content describers.
+ *
+ * <p>
+ * Note: do not add protected/public members to this class if you don't intend to
+ * make them public API.
+ * </p>
+ *
+ * @see org.eclipse.core.runtime.content.XMLRootElementContentDescriber2
+ * @since 3.0
+ */
+class TextContentDescriber implements ITextContentDescriber {
+
+ private final static QualifiedName[] SUPPORTED_OPTIONS = {IContentDescription.BYTE_ORDER_MARK};
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.content.ITextContentDescriber#describe(java.io.Reader, org.eclipse.core.runtime.content.IContentDescription)
+ */
+ @SuppressWarnings("unused")
+ public int describe(Reader contents, IContentDescription description) throws IOException {
+ // we want to be pretty loose on detecting the text content type
+ return INDETERMINATE;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.content.IContentDescriber#describe(java.io.InputStream, org.eclipse.core.runtime.content.IContentDescription)
+ */
+ public int describe(InputStream contents, IContentDescription description) throws IOException {
+ if (description == null || !description.isRequested(IContentDescription.BYTE_ORDER_MARK))
+ return INDETERMINATE;
+ byte[] bom = getByteOrderMark(contents);
+ if (bom != null)
+ description.setProperty(IContentDescription.BYTE_ORDER_MARK, bom);
+ // we want to be pretty loose on detecting the text content type
+ return INDETERMINATE;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.content.IContentDescriber#getSupportedOptions()
+ */
+ public QualifiedName[] getSupportedOptions() {
+ return SUPPORTED_OPTIONS;
+ }
+
+ byte[] getByteOrderMark(InputStream input) throws IOException {
+ int first = input.read();
+ if (first == 0xEF) {
+ //look for the UTF-8 Byte Order Mark (BOM)
+ int second = input.read();
+ int third = input.read();
+ if (second == 0xBB && third == 0xBF)
+ return IContentDescription.BOM_UTF_8;
+ } else if (first == 0xFE) {
+ //look for the UTF-16 BOM
+ if (input.read() == 0xFF)
+ return IContentDescription.BOM_UTF_16BE;
+ } else if (first == 0xFF) {
+ if (input.read() == 0xFE)
+ return IContentDescription.BOM_UTF_16LE;
+ }
+ return null;
+ }
+}
diff --git a/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/XMLContentDescriber.java b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/XMLContentDescriber.java
new file mode 100644
index 00000000..ed115a0a
--- /dev/null
+++ b/org.eclipse.m2e.core/src/org/eclipse/m2e/core/internal/content/XMLContentDescriber.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.core.internal.content;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+import org.eclipse.core.runtime.QualifiedName;
+import org.eclipse.core.runtime.content.IContentDescription;
+import org.eclipse.core.runtime.content.ITextContentDescriber;
+
+/**
+ * A copy of org.eclipse.core.internal.content.XMLContentDescriber to avoid internal API use.
+ *
+ * A content interpreter for XML files.
+ * This class provides internal basis for XML-based content describers.
+ * <p>
+ * Note: do not add protected/public members to this class if you don't intend to
+ * make them public API.
+ * </p>
+ *
+ * @see org.eclipse.core.runtime.content.XMLRootElementContentDescriber2
+ * @see "http://www.w3.org/TR/REC-xml *"
+ */
+class XMLContentDescriber extends TextContentDescriber implements ITextContentDescriber {
+ private static final QualifiedName[] SUPPORTED_OPTIONS = new QualifiedName[] {IContentDescription.CHARSET, IContentDescription.BYTE_ORDER_MARK};
+ private static final String ENCODING = "encoding="; //$NON-NLS-1$
+ private static final String XML_PREFIX = "<?xml "; //$NON-NLS-1$
+
+ public int describe(InputStream input, IContentDescription description) throws IOException {
+ byte[] bom = getByteOrderMark(input);
+ String xmlDeclEncoding = "UTF-8"; //$NON-NLS-1$
+ input.reset();
+ if (bom != null) {
+ if (bom == IContentDescription.BOM_UTF_16BE)
+ xmlDeclEncoding = "UTF-16BE"; //$NON-NLS-1$
+ else if (bom == IContentDescription.BOM_UTF_16LE)
+ xmlDeclEncoding = "UTF-16LE"; //$NON-NLS-1$
+ // skip BOM to make comparison simpler
+ input.skip(bom.length);
+ // set the BOM in the description if requested
+ if (description != null && description.isRequested(IContentDescription.BYTE_ORDER_MARK))
+ description.setProperty(IContentDescription.BYTE_ORDER_MARK, bom);
+ }
+ byte[] xmlPrefixBytes = XML_PREFIX.getBytes(xmlDeclEncoding);
+ byte[] prefix = new byte[xmlPrefixBytes.length];
+ if (input.read(prefix) < prefix.length)
+ // there is not enough info to say anything
+ return INDETERMINATE;
+ for (int i = 0; i < prefix.length; i++)
+ if (prefix[i] != xmlPrefixBytes[i])
+ // we don't have a XMLDecl... there is not enough info to say anything
+ return INDETERMINATE;
+ if (description == null)
+ return VALID;
+ // describe charset if requested
+ if (description.isRequested(IContentDescription.CHARSET)) {
+ String fullXMLDecl = readFullXMLDecl(input, xmlDeclEncoding);
+ if (fullXMLDecl != null) {
+ String charset = getCharset(fullXMLDecl);
+ if (charset != null && !"UTF-8".equalsIgnoreCase(charset)) //$NON-NLS-1$
+ // only set property if value is not default (avoid using a non-default content description)
+ description.setProperty(IContentDescription.CHARSET, getCharset(fullXMLDecl));
+ }
+ }
+ return VALID;
+ }
+
+ private String readFullXMLDecl(InputStream input, String unicodeEncoding) throws IOException {
+ byte[] xmlDecl = new byte[100];
+ int c = 0;
+ // looks for XMLDecl ending char (?)
+ int read = 0;
+ while (read < xmlDecl.length && (c = input.read()) != -1 && c != '?')
+ xmlDecl[read++] = (byte) c;
+ return c == '?' ? new String(xmlDecl, 0, read, unicodeEncoding) : null;
+ }
+
+ public int describe(Reader input, IContentDescription description) throws IOException {
+ BufferedReader reader = new BufferedReader(input);
+ String line = reader.readLine();
+ // end of stream
+ if (line == null)
+ return INDETERMINATE;
+ // XMLDecl should be the first string (no blanks allowed)
+ if (!line.startsWith(XML_PREFIX))
+ return INDETERMINATE;
+ if (description == null)
+ return VALID;
+ // describe charset if requested
+ if ((description.isRequested(IContentDescription.CHARSET)))
+ description.setProperty(IContentDescription.CHARSET, getCharset(line));
+ return VALID;
+ }
+
+ private String getCharset(String firstLine) {
+ int encodingPos = firstLine.indexOf(ENCODING);
+ if (encodingPos == -1)
+ return null;
+ char quoteChar = '"';
+ int firstQuote = firstLine.indexOf(quoteChar, encodingPos);
+ if (firstQuote == -1) {
+ quoteChar = '\'';
+ firstQuote = firstLine.indexOf(quoteChar, encodingPos);
+ }
+ if (firstQuote == -1 || firstLine.length() == firstQuote - 1)
+ return null;
+ int secondQuote = firstLine.indexOf(quoteChar, firstQuote + 1);
+ if (secondQuote == -1)
+ return null;
+ return firstLine.substring(firstQuote + 1, secondQuote);
+ }
+
+ public QualifiedName[] getSupportedOptions() {
+ return SUPPORTED_OPTIONS;
+ }
+}

Back to the top