| /******************************************************************************* |
| * Copyright (c) 2000, 2004 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.ant.internal.ui.editor.utils; |
| |
| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * Copyright (c) 2000-2003 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, if |
| * any, must include the following acknowlegement: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowlegement may appear in the software itself, |
| * if and wherever such third-party acknowlegements normally appear. |
| * |
| * 4. The names "The Jakarta Project", "Ant", and "Apache Software |
| * Foundation" must not be used to endorse or promote products derived |
| * from this software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache" |
| * nor may "Apache" appear in their names without prior written |
| * permission of the Apache Group. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| |
| import java.io.File; |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.Reader; |
| import java.io.StringReader; |
| import java.io.UnsupportedEncodingException; |
| |
| import org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.Location; |
| import org.apache.tools.ant.Project; |
| import org.apache.tools.ant.RuntimeConfigurable; |
| import org.apache.tools.ant.Target; |
| import org.apache.tools.ant.Task; |
| import org.apache.tools.ant.UnknownElement; |
| import org.apache.tools.ant.helper.AntXMLContext; |
| import org.apache.tools.ant.helper.ProjectHelper2; |
| import org.apache.tools.ant.util.FileUtils; |
| import org.apache.tools.ant.util.JAXPUtils; |
| import org.eclipse.ant.internal.ui.editor.outline.AntModel; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.InputSource; |
| import org.xml.sax.Locator; |
| import org.xml.sax.SAXException; |
| import org.xml.sax.SAXParseException; |
| import org.xml.sax.XMLReader; |
| |
| /** |
| * Derived from the original Ant ProjectHelper2 class |
| * This class provides parsing for using a String as a source and provides |
| * handlers that will continue parsing to completion upon hitting errors. |
| */ |
| public class ProjectHelper extends ProjectHelper2 { |
| |
| /** |
| * helper for path -> URI and URI -> path conversions. |
| */ |
| private static FileUtils fu = FileUtils.newFileUtils(); |
| |
| /** |
| * The buildfile that is to be parsed. Must be set if parsing is to |
| * be successful. |
| */ |
| private File buildFile= null; |
| |
| /** |
| * Helper for generating <code>IProblem</code>s |
| */ |
| private static AntModel fAntModel; |
| |
| private static AntHandler elementHandler = new ElementHandler(); |
| private static AntHandler projectHandler = new ProjectHandler(); |
| private static AntHandler targetHandler = new TargetHandler(); |
| private static AntHandler mainHandler= new MainHandler(); |
| |
| public static class ElementHandler extends ProjectHelper2.ElementHandler { |
| |
| private UnknownElement task= null; |
| private Task currentTask= null; |
| |
| /* (non-Javadoc) |
| * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onStartChild(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes, org.apache.tools.ant.helper.AntXMLContext) |
| */ |
| public AntHandler onStartChild(String uri, String tag, String qname, Attributes attrs, AntXMLContext context) { |
| return ProjectHelper.elementHandler; |
| } |
| /* (non-Javadoc) |
| * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onStartElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes, org.apache.tools.ant.helper.AntXMLContext) |
| */ |
| public void onStartElement(String uri, String tag, String qname, Attributes attrs, AntXMLContext context) { |
| try { |
| RuntimeConfigurable wrapper= context.currentWrapper(); |
| currentTask= null; |
| task= null; |
| if (wrapper != null) { |
| currentTask= (Task)wrapper.getProxy(); |
| } |
| onStartElement0(uri, tag, qname, attrs, context); |
| |
| Locator locator= context.getLocator(); |
| fAntModel.addTask(task, currentTask, attrs, locator.getLineNumber(), locator.getColumnNumber()); |
| |
| } catch (BuildException be) { |
| Locator locator= context.getLocator(); |
| fAntModel.addTask(task, currentTask, attrs, locator.getLineNumber(), locator.getColumnNumber()); |
| fAntModel.error(be); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onEndElement(java.lang.String, java.lang.String, org.apache.tools.ant.helper.AntXMLContext) |
| */ |
| public void onEndElement(String uri, String tag, AntXMLContext context) { |
| super.onEndElement(uri, tag, context); |
| |
| Locator locator= context.getLocator(); |
| fAntModel.setCurrentElementLength(locator.getLineNumber(), locator.getColumnNumber()); |
| } |
| |
| private void onStartElement0(String uri, String tag, String qname, Attributes attrs, AntXMLContext context) { |
| |
| RuntimeConfigurable parentWrapper = context.currentWrapper(); |
| Object parent = null; |
| |
| if (parentWrapper != null) { |
| parent = parentWrapper.getProxy(); |
| } |
| |
| /* UnknownElement is used for tasks and data types - with |
| delayed eval */ |
| task = new UnknownElement(tag); |
| task.setProject(context.getProject()); |
| task.setNamespace(uri); |
| task.setQName(qname); |
| task.setTaskType(org.apache.tools.ant.ProjectHelper.genComponentName(task.getNamespace(), tag)); |
| task.setTaskName(qname); |
| |
| Location location = new Location(context.getLocator().getSystemId(), |
| context.getLocator().getLineNumber(), |
| context.getLocator().getColumnNumber()); |
| task.setLocation(location); |
| task.setOwningTarget(context.getCurrentTarget()); |
| |
| context.configureId(task, attrs); |
| |
| if (parent != null) { |
| // Nested element |
| ((UnknownElement) parent).addChild(task); |
| } else { |
| // Task included in a target ( including the default one ). |
| context.getCurrentTarget().addTask(task); |
| } |
| |
| // container.addTask(task); |
| // This is a nop in UE: task.init(); |
| |
| RuntimeConfigurable wrapper |
| = new RuntimeConfigurable(task, task.getTaskName()); |
| |
| for (int i = 0; i < attrs.getLength(); i++) { |
| String attrUri = attrs.getURI(i); |
| if (attrUri != null |
| && !attrUri.equals("") //$NON-NLS-1$ |
| && !attrUri.equals(uri)) { |
| continue; // Ignore attributes from unknown uris |
| } |
| String name = attrs.getLocalName(i); |
| String value = attrs.getValue(i); |
| // PR: Hack for ant-type value |
| // an ant-type is a component name which can |
| // be namespaced, need to extract the name |
| // and convert from qualified name to uri/name |
| if (name.equals("ant-type")) { //$NON-NLS-1$ |
| int index = value.indexOf(':'); |
| if (index != -1) { |
| String prefix = value.substring(0, index); |
| String mappedUri = context.getPrefixMapping(prefix); |
| if (mappedUri == null) { |
| throw new BuildException( |
| "Unable to find XML NS prefix " + prefix); //$NON-NLS-1$ |
| } |
| value = org.apache.tools.ant.ProjectHelper.genComponentName(mappedUri, value.substring(index + 1)); |
| } |
| } |
| wrapper.setAttribute(name, value); |
| } |
| |
| if (parentWrapper != null) { |
| parentWrapper.addChild(wrapper); |
| } |
| |
| context.pushWrapper(wrapper); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#characters(char[], int, int, org.apache.tools.ant.helper.AntXMLContext) |
| */ |
| public void characters(char[] buf, int start, int count, AntXMLContext context) { |
| try { |
| super.characters(buf, start, count, context); |
| } catch (SAXParseException e) { |
| ErrorHelper.handleErrorFromElementText(start, count, context, e); |
| } catch (BuildException be) { |
| ErrorHelper.handleErrorFromElementText(start, count, context, be); |
| } |
| } |
| } |
| |
| public static class MainHandler extends ProjectHelper2.MainHandler { |
| |
| /* (non-Javadoc) |
| * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onStartChild(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes, org.apache.tools.ant.helper.AntXMLContext) |
| */ |
| public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs, AntXMLContext context) throws SAXParseException { |
| if (name.equals("project") //$NON-NLS-1$ |
| && (uri.equals("") || uri.equals(ANT_CORE_URI))) { //$NON-NLS-1$ |
| return ProjectHelper.projectHandler; |
| } else { |
| try { |
| return super.onStartChild(uri, name, qname, attrs, context); |
| } catch (SAXParseException e) { |
| fAntModel.error(e); |
| throw e; |
| } |
| } |
| } |
| } |
| |
| public static class ProjectHandler extends ProjectHelper2.ProjectHandler { |
| |
| /* (non-Javadoc) |
| * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onStartChild(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes, org.apache.tools.ant.helper.AntXMLContext) |
| */ |
| public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs, AntXMLContext context) { |
| if (name.equals("target") //$NON-NLS-1$ |
| && (uri.equals("") || uri.equals(ANT_CORE_URI))) { //$NON-NLS-1$ |
| return ProjectHelper.targetHandler; |
| } else { |
| return ProjectHelper.elementHandler; |
| } |
| } |
| /* (non-Javadoc) |
| * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onEndElement(java.lang.String, java.lang.String, org.apache.tools.ant.helper.AntXMLContext) |
| */ |
| public void onEndElement(String uri, String tag, AntXMLContext context) { |
| super.onEndElement(uri, tag, context); |
| |
| Locator locator= context.getLocator(); |
| fAntModel.setCurrentElementLength(locator.getLineNumber(), locator.getColumnNumber()); |
| } |
| /* (non-Javadoc) |
| * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onStartElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes, org.apache.tools.ant.helper.AntXMLContext) |
| */ |
| public void onStartElement(String uri, String tag, String qname, Attributes attrs, AntXMLContext context) { |
| try { |
| super.onStartElement(uri, tag, qname, attrs, context); |
| |
| Locator locator= context.getLocator(); |
| fAntModel.addProject(context.getProject(), locator.getLineNumber(), locator.getColumnNumber()); |
| |
| } catch (SAXParseException e) { |
| fAntModel.error(e); |
| } catch (BuildException be) { |
| fAntModel.error(be); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#characters(char[], int, int, org.apache.tools.ant.helper.AntXMLContext) |
| */ |
| public void characters(char[] buf, int start, int count, AntXMLContext context) { |
| try { |
| super.characters(buf, start, count, context); |
| } catch (SAXParseException e) { |
| ErrorHelper.handleErrorFromElementText(start, count, context, e); |
| } catch (BuildException be) { |
| ErrorHelper.handleErrorFromElementText(start, count, context, be); |
| } |
| } |
| } |
| |
| public static class TargetHandler extends ProjectHelper2.TargetHandler { |
| /* (non-Javadoc) |
| * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onStartChild(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes, org.apache.tools.ant.helper.AntXMLContext) |
| */ |
| public AntHandler onStartChild(String uri, String name, String qname, Attributes attrs, AntXMLContext context) { |
| return ProjectHelper.elementHandler; |
| } |
| /* (non-Javadoc) |
| * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onStartElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes, org.apache.tools.ant.helper.AntXMLContext) |
| */ |
| public void onStartElement(String uri, String tag, String qname, Attributes attrs, AntXMLContext context) { |
| try { |
| super.onStartElement(uri, tag, qname, attrs, context); |
| Target newTarget= context.getCurrentTarget(); |
| Locator locator= context.getLocator(); |
| fAntModel.addTarget(newTarget, locator.getLineNumber(), locator.getColumnNumber()); |
| } catch (SAXParseException e) { |
| handleErrorInTarget(context, e); |
| } catch (BuildException be) { |
| handleErrorInTarget(context, be); |
| } |
| } |
| |
| private void handleErrorInTarget(AntXMLContext context, Exception e) { |
| Target newTarget= context.getCurrentTarget(); |
| Locator locator= context.getLocator(); |
| fAntModel.addTarget(newTarget, locator.getLineNumber(), locator.getColumnNumber()); |
| fAntModel.errorFromElement(e, null, locator.getLineNumber(), locator.getColumnNumber()); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#onEndElement(java.lang.String, java.lang.String, org.apache.tools.ant.helper.AntXMLContext) |
| */ |
| public void onEndElement(String uri, String tag, AntXMLContext context) { |
| super.onEndElement(uri, tag, context); |
| Locator locator= context.getLocator(); |
| fAntModel.setCurrentElementLength(locator.getLineNumber(), locator.getColumnNumber()); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.tools.ant.helper.ProjectHelper2.AntHandler#characters(char[], int, int, org.apache.tools.ant.helper.AntXMLContext) |
| */ |
| public void characters(char[] buf, int start, int count, AntXMLContext context) { |
| try { |
| super.characters(buf, start, count, context); |
| } catch (SAXParseException e) { |
| ErrorHelper.handleErrorFromElementText(start, count, context, e); |
| } catch (BuildException be) { |
| ErrorHelper.handleErrorFromElementText(start, count, context, be); |
| } |
| } |
| } |
| |
| public static class RootHandler extends ProjectHelper2.RootHandler { |
| |
| public RootHandler(AntXMLContext context, AntHandler rootHandler) { |
| super(context, rootHandler); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException) |
| */ |
| public void error(SAXParseException e) { |
| fAntModel.error(e); |
| } |
| /* (non-Javadoc) |
| * @see org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException) |
| */ |
| public void fatalError(SAXParseException e) { |
| fAntModel.fatalError(e); |
| } |
| /* (non-Javadoc) |
| * @see org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException) |
| */ |
| public void warning(SAXParseException e) { |
| fAntModel.warning(e); |
| } |
| } |
| |
| private static class ErrorHelper { |
| public static void handleErrorFromElementText(int start, int count, AntXMLContext context, Exception e) { |
| Locator locator= context.getLocator(); |
| int columnNumber= locator.getColumnNumber(); |
| if (columnNumber > -1) { |
| int lineNumber= start; |
| try { |
| lineNumber= fAntModel.getOffset(locator.getLineNumber(), 1); |
| } catch (BadLocationException e1) { |
| } |
| fAntModel.errorFromElementText(e, lineNumber, locator.getColumnNumber()); |
| } else { |
| fAntModel.errorFromElementText(e, start, count); |
| } |
| } |
| } |
| |
| public ProjectHelper(AntModel model) { |
| fAntModel= model; |
| } |
| |
| /** |
| * Parses the project file, configuring the project as it goes. |
| * |
| * @param project the current project |
| * @param source the xml source |
| * @param handler the root handler to use (contains the current context) |
| * @exception BuildException if the configuration is invalid or cannot |
| * be read |
| */ |
| public void parse(Project project, Object source, org.apache.tools.ant.helper.ProjectHelper2.RootHandler handler) throws BuildException { |
| |
| if (!(source instanceof String)) { |
| super.parse(project, source, handler); |
| return; |
| } |
| |
| AntXMLContext context= (AntXMLContext)project.getReference("ant.parsing.context"); //$NON-NLS-1$ |
| //switch to using "our" handler so parsing will continue on hitting errors. |
| handler= new RootHandler(context, mainHandler); |
| |
| Reader stream= new StringReader((String)source); |
| |
| InputSource inputSource = null; |
| try { |
| /** |
| * SAX 2 style parser used to parse the given file. |
| */ |
| XMLReader parser = JAXPUtils.getNamespaceXMLReader(); |
| |
| String uri = null; |
| if (buildFile != null) { |
| uri = fu.toURI(buildFile.getAbsolutePath()); |
| } |
| |
| inputSource = new InputSource(stream); |
| if (uri != null) { |
| inputSource.setSystemId(uri); |
| } |
| |
| context.setBuildFile(buildFile); |
| |
| parser.setContentHandler(handler); |
| parser.setEntityResolver(handler); |
| parser.setErrorHandler(handler); |
| parser.setDTDHandler(handler); |
| parser.parse(inputSource); |
| } catch (SAXParseException exc) { |
| //ignore as we will be parsing incomplete source |
| } catch (SAXException exc) { |
| //ignore as we will be parsing incomplete source |
| } catch (FileNotFoundException exc) { |
| throw new BuildException(exc); |
| } catch (UnsupportedEncodingException exc) { |
| throw new BuildException(exc); |
| } catch (IOException exc) { |
| throw new BuildException(exc); |
| } finally { |
| if (stream != null) { |
| try { |
| stream.close(); |
| } catch (IOException ioe) { |
| // ignore this |
| } |
| } |
| } |
| } |
| |
| /** |
| * Sets the buildfile that is about to be parsed or <code>null</code> if |
| * parsing has completed. |
| * |
| * @param file The buildfile about to be parsed |
| */ |
| public void setBuildFile(File file) { |
| buildFile= file; |
| } |
| |
| /* (non-Javadoc) |
| * We override this method from ProjectHelper2 as we do not want to execute the implicit target or |
| * any other target for that matter as it could hang Eclipse. |
| * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=50795 for more details. |
| * |
| * @see org.apache.tools.ant.ProjectHelper#parse(org.apache.tools.ant.Project, java.lang.Object) |
| */ |
| public void parse(Project project, Object source) throws BuildException { |
| getImportStack().addElement(source); |
| AntXMLContext context = null; |
| context = (AntXMLContext) project.getReference("ant.parsing.context"); //$NON-NLS-1$ |
| if (context == null) { |
| context = new AntXMLContext(project); |
| project.addReference("ant.parsing.context", context); //$NON-NLS-1$ |
| project.addReference("ant.targets", context.getTargets()); //$NON-NLS-1$ |
| } |
| |
| if (getImportStack().size() > 1) { |
| // we are in an imported file. |
| context.setIgnoreProjectTag(true); |
| Target currentTarget = context.getCurrentTarget(); |
| try { |
| Target newCurrent = new Target(); |
| newCurrent.setProject(project); |
| newCurrent.setName(""); //$NON-NLS-1$ |
| context.setCurrentTarget(newCurrent); |
| parse(project, source, new RootHandler(context, mainHandler)); |
| } finally { |
| context.setCurrentTarget(currentTarget); |
| } |
| } else { |
| // top level file |
| parse(project, source, new RootHandler(context, mainHandler)); |
| } |
| } |
| } |