NetBeans IDE
NetBeans Platform
Plugins
Docs & Support
Community
Partners
HOME
/ Bugzilla
[?]
|
New
|
Browse
|
Search
|
Reports
|
Help
|
Log In
Please use the Apache issue tracking system for new NetBeans issues (
https://issues.apache.org/jira/projects/NETBEANS0/issues
) !!
[patch]
ant project api changes
ant-project-93509.diff (text/plain), 49.65 KB, created by
Milos Kleint
on 2007-04-06 14:59 UTC
(
hide
)
Description:
ant project api changes
Filename:
MIME Type:
Creator:
Milos Kleint
Created:
2007-04-06 14:59 UTC
Size:
49.65 KB
patch
obsolete
>Index: ant/project/apichanges.xml >=================================================================== >RCS file: /cvs/ant/project/apichanges.xml,v >retrieving revision 1.15 >diff -u -r1.15 apichanges.xml >--- ant/project/apichanges.xml 2 Mar 2007 03:34:19 -0000 1.15 >+++ ant/project/apichanges.xml 6 Apr 2007 13:50:17 -0000 >@@ -81,6 +81,26 @@ > <!-- ACTUAL CHANGES BEGIN HERE: --> > > <changes> >+ >+ <change id="build-extender"> >+ <api name="general"/> >+ <summary>Support for externally extending the project's build script</summary> >+ <version major="1" minor="16"/> >+ <date day="10" month="4" year="2007"/> >+ <author login="mkleint"/> >+ <compatibility addition="yes"/> >+ <description> >+ <p> >+ Add framework for extending the project's build script with 3rd party snippets, >+ allowing automated extensions to the build process. >+ </p> >+ </description> >+ <class package="org.netbeans.api.project.support.ant" name="AntBuildExtender"/> >+ <class package="org.netbeans.spi.project.support.ant" name="GeneratedFileHelper"/> >+ <class package="org.netbeans.spi.project.support.ant" name="AntBuildExtenderImplementation"/> >+ <class package="org.netbeans.spi.project.support.ant" name="AntBuildExtenderSupport"/> >+ <issue number="93509"/> >+ </change> > > <change id="includes-excludes"> > <api name="general"/> >Index: ant/project/manifest.mf >=================================================================== >RCS file: /cvs/ant/project/manifest.mf,v >retrieving revision 1.19 >diff -u -r1.19 manifest.mf >--- ant/project/manifest.mf 2 Mar 2007 03:34:19 -0000 1.19 >+++ ant/project/manifest.mf 6 Apr 2007 13:50:17 -0000 >@@ -1,6 +1,6 @@ > Manifest-Version: 1.0 > OpenIDE-Module: org.netbeans.modules.project.ant/1 >-OpenIDE-Module-Specification-Version: 1.15 >+OpenIDE-Module-Specification-Version: 1.16 > OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/project/ant/Bundle.properties > OpenIDE-Module-Install: org/netbeans/modules/project/ant/AntProjectModule.class > >Index: ant/project/nbproject/project.xml >=================================================================== >RCS file: /cvs/ant/project/nbproject/project.xml,v >retrieving revision 1.21 >diff -u -r1.21 project.xml >--- ant/project/nbproject/project.xml 27 Mar 2007 00:01:23 -0000 1.21 >+++ ant/project/nbproject/project.xml 6 Apr 2007 13:50:17 -0000 >@@ -165,5 +165,6 @@ > <built-to>build/tasks.jar</built-to> > </extra-compilation-unit> > </data> >+ <junit-version xmlns="http://www.netbeans.org/ns/junit/1" value="junit3"/> > </configuration> > </project> >Index: ant/project/src/org/netbeans/api/project/ant/AntBuildExtender.java >=================================================================== >RCS file: ant/project/src/org/netbeans/api/project/ant/AntBuildExtender.java >diff -N ant/project/src/org/netbeans/api/project/ant/AntBuildExtender.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ ant/project/src/org/netbeans/api/project/ant/AntBuildExtender.java 6 Apr 2007 13:50:18 -0000 >@@ -0,0 +1,304 @@ >+/* >+ * The contents of this file are subject to the terms of the Common Development >+ * and Distribution License (the License). You may not use this file except in >+ * compliance with the License. >+ * >+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html >+ * or http://www.netbeans.org/cddl.txt. >+ * >+ * When distributing Covered Code, include this CDDL Header Notice in each file >+ * and include the License file at http://www.netbeans.org/cddl.txt. >+ * If applicable, add the following below the CDDL Header, with the fields >+ * enclosed by brackets [] replaced by your own identifying information: >+ * "Portions Copyrighted [year] [name of copyright owner]" >+ * >+ * The Original Software is NetBeans. The Initial Developer of the Original >+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun >+ * Microsystems, Inc. All Rights Reserved. >+ */ >+ >+package org.netbeans.api.project.ant; >+ >+import org.netbeans.spi.project.ant.AntBuildExtenderImplementation; >+import java.util.ArrayList; >+import java.util.Collection; >+import java.util.Collections; >+import java.util.HashMap; >+import java.util.HashSet; >+import java.util.List; >+import java.util.Map; >+import java.util.Set; >+import java.util.TreeMap; >+import javax.xml.parsers.DocumentBuilder; >+import javax.xml.parsers.DocumentBuilderFactory; >+import javax.xml.parsers.ParserConfigurationException; >+import org.netbeans.api.project.FileOwnerQuery; >+import org.netbeans.spi.project.ant.AntBuildExtenderImplementation; >+import org.netbeans.spi.project.support.ant.AntProjectHelper; >+import org.openide.filesystems.FileObject; >+import org.openide.filesystems.FileUtil; >+import org.w3c.dom.Document; >+import org.w3c.dom.Element; >+import org.w3c.dom.NodeList; >+ >+/** >+ * Allows extending the project's build script with 3rd party additions. >+ * Check the Project's lookup to see if the feature is supported by a given Ant project type. >+ * Typical usage: >+ * <ul> >+ * <li>Lookup the instance of AntBuildExtender in the project at hand</li> >+ * <li>Create the external build script file with your targets and configuration</li> >+ * <li>Use the AntBuildExtender to wire your script and targets into the main build lifecycle</li> >+ * <li>Call {@link org.netbeans.api.project.ProjectManager#saveProject} to persist the changes and >+ * regenerate the main build script</li> >+ * </ul> >+ * >+ * Please note that it's easy to break the build script functionality and any script extensions >+ * shall be done with care. A few rules to follow: >+ * <ul> >+ * <li>Pick a reasonably unique extension id</li> >+ * <li>Prefix target names and properties you define in your extension with the extension id to prevent clashes.</li> >+ * </ul> >+ * @author mkleint >+ * @since org.netbeans.modules.project.ant 1.16 >+ */ >+public final class AntBuildExtender { >+ private HashMap<String, Extension> extensions; >+ private AntBuildExtenderImplementation implementation; >+ >+ static { >+ AntBuildExtenderAccessorImpl.createAccesor(); >+ } >+ >+ AntBuildExtender(AntBuildExtenderImplementation implementation) { >+ this.implementation = implementation; >+ } >+ >+ /** >+ * Get a list of target names in the main build script that are allowed to be >+ * extended by adding the "depends" attribute definition to them. >+ * @return list of target names >+ */ >+ public List<String> getExtendableTargets() { >+ List<String> targets = new ArrayList<String>(); >+ targets.addAll(implementation.getExtendableTargets()); >+ targets = Collections.unmodifiableList(targets); >+ return targets; >+ } >+ >+ /** >+ * Adds a new build script extension. >+ * @param id identification of the extension >+ * @param extensionXml fileobject referencing the build script for the extension, >+ * needs to be located in nbproject directory or below. >+ * @return the newly created extension. >+ */ >+ public synchronized Extension addExtension(String id, FileObject extensionXml) { >+ assert extensionXml != null; >+ assert extensionXml.isValid() && extensionXml.isData(); >+ //TODO assert the owner is the same as the owner of this instance of entender. >+ assert FileOwnerQuery.getOwner(extensionXml) == implementation.getOwningProject(); >+ FileObject nbproj = implementation.getOwningProject().getProjectDirectory().getFileObject(AntProjectHelper.PROJECT_XML_PATH).getParent(); >+ assert FileUtil.isParentOf(nbproj, extensionXml); >+ if (extensions == null) { >+ readProjectMetadata(); >+ } >+ if (extensions.get(id) != null) { >+ throw new IllegalStateException("Extension with id '" + id + "' already exists."); >+ } >+ Extension ex = new Extension(id, extensionXml, FileUtil.getRelativePath(nbproj, extensionXml)); >+ extensions.put(id, ex); >+ updateProjectMetadata(); >+ return ex; >+ } >+ /** >+ * Remove an existing build script extension. Make sure to remove the extension's script file >+ * before/after removing the extension. >+ * @param id identification of the extension >+ */ >+ public synchronized void removeExtension(String id) { >+ if (extensions == null) { >+ readProjectMetadata(); >+ } >+ if (extensions.get(id) == null) { >+ // oh well, just ignore. >+ return; >+ } >+ extensions.remove(id); >+ updateProjectMetadata(); >+ } >+ >+ /** >+ * Get an extension by the id. >+ * @param id identification token >+ * @return Extention with the given id or null if not found. >+ */ >+ public synchronized Extension getExtension(String id) { >+ if (extensions == null) { >+ readProjectMetadata(); >+ } >+ return extensions.get(id); >+ } >+ >+ >+ synchronized Set<Extension> getExtensions() { >+ Set<Extension> ext = new HashSet<Extension>(); >+ if (extensions == null) { >+ readProjectMetadata(); >+ } >+ ext.addAll(extensions.values()); >+ return ext; >+ } >+ >+ private static final DocumentBuilder db; >+ static { >+ try { >+ db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); >+ } catch (ParserConfigurationException e) { >+ throw new AssertionError(e); >+ } >+ } >+ private static Document createNewDocument() { >+ // #50198: for thread safety, use a separate document. >+ // Using XMLUtil.createDocument is much too slow. >+ synchronized (db) { >+ return db.newDocument(); >+ } >+ } >+ >+ >+ private void updateProjectMetadata() { >+ Document doc = createNewDocument(); >+ Element root = doc.createElement(AntBuildExtenderImplementation.ELEMENT_ROOT); >+ if (extensions != null) { >+ FileObject nbproj = implementation.getOwningProject().getProjectDirectory().getFileObject(AntProjectHelper.PROJECT_XML_PATH).getParent(); >+ for (Extension ext : extensions.values()) { >+ Element child = doc.createElement(AntBuildExtenderImplementation.ELEMENT_EXTENSION); >+ child.setAttribute(AntBuildExtenderImplementation.ATTR_ID, ext.id); >+ String relPath = FileUtil.getRelativePath(nbproj, ext.file); >+ assert relPath != null; >+ child.setAttribute(AntBuildExtenderImplementation.ATTR_FILE, relPath); >+ root.appendChild(child); >+ for (String target : ext.dependencies.keySet()) { >+ for (String depTarget : ext.dependencies.get(target)) { >+ Element dep = doc.createElement(AntBuildExtenderImplementation.ELEMENT_DEPENDENCY); >+ dep.setAttribute(AntBuildExtenderImplementation.ATTR_TARGET, target); >+ dep.setAttribute(AntBuildExtenderImplementation.ATTR_DEPENDSON, depTarget); >+ child.appendChild(dep); >+ } >+ } >+ } >+ } >+ implementation.updateBuildExtensionMetadata(root); >+ } >+ >+ private void readProjectMetadata() { >+ Element cfgEl = implementation.getBuildExtensionMetadata(); >+ List<String> rootIds = new ArrayList<String>(); >+ FileObject nbproj = implementation.getOwningProject().getProjectDirectory().getFileObject(AntProjectHelper.PROJECT_XML_PATH).getParent(); >+ extensions = new HashMap<String, Extension>(); >+ if (cfgEl != null) { >+ String namespace = cfgEl.getNamespaceURI(); >+ NodeList roots = cfgEl.getElementsByTagNameNS(namespace, AntBuildExtenderImplementation.ELEMENT_EXTENSION); >+ for (int i=0; i <roots.getLength(); i++) { >+ Element root = (Element) roots.item(i); >+ String id = root.getAttribute(AntBuildExtenderImplementation.ATTR_ID); >+ assert id.length() > 0 : "Illegal project.xml"; >+ String value = root.getAttribute(AntBuildExtenderImplementation.ATTR_FILE); >+ FileObject script = nbproj.getFileObject(value); >+ assert script != null : "Missing file " + script; >+ Extension ext = new Extension(id, script, value); >+ extensions.put(id, ext); >+ NodeList deps = root.getElementsByTagNameNS(namespace, AntBuildExtenderImplementation.ELEMENT_DEPENDENCY); >+ for (int j = 0; j < deps.getLength(); j++) { >+ Element dep = (Element)deps.item(j); >+ String target = dep.getAttribute(AntBuildExtenderImplementation.ATTR_TARGET); >+ String dependsOn = dep.getAttribute(AntBuildExtenderImplementation.ATTR_DEPENDSON); >+ assert target != null; >+ assert dependsOn != null; >+ ext.loadDependency(target, dependsOn); >+ } >+ } >+ } >+ } >+ >+ /** >+ * Describes and allows to manipulate the build script extension and it's links to the main build script >+ * of the project. >+ */ >+ public final class Extension { >+ String id; >+ FileObject file; >+ String path; >+ TreeMap<String, Collection<String>> dependencies; >+ >+ Extension(String id, FileObject script, String relPath) { >+ this.id = id; >+ file = script; >+ path = relPath; >+ dependencies = new TreeMap<String, Collection<String>>(); >+ } >+ >+ String getPath() { >+ return path; >+ } >+ >+ /** >+ * Add a dependency of a main build script target on the target in the extension's script. >+ * @param mainBuildTarget name of target in the main build script (see {@link org.netbeans.api.project.ant.AntBuildExtender#getExtendableTargets}) >+ * @param extensionTarget name of target in the extention script >+ */ >+ public void addDependency(String mainBuildTarget, String extensionTarget) { >+ assert implementation.getExtendableTargets().contains(mainBuildTarget) : >+ "The target '" + mainBuildTarget + "' is not designated by the project type as extensible."; >+ synchronized (AntBuildExtender.class) { >+ loadDependency(mainBuildTarget, extensionTarget); >+ updateProjectMetadata(); >+ } >+ } >+ >+ private void loadDependency(String mainBuildTarget, String extensionTarget) { >+ synchronized (AntBuildExtender.class) { >+ Collection<String> tars = dependencies.get(mainBuildTarget); >+ if (tars == null) { >+ tars = new ArrayList<String>(); >+ dependencies.put(mainBuildTarget, tars); >+ } >+ if (!tars.contains(extensionTarget)) { >+ tars.add(extensionTarget); >+ } else { >+ //log? >+ } >+ } >+ } >+ >+ >+ /** >+ * Remove a dependency of a main build script target on the target in the extension's script. >+ * >+ * @param mainBuildTarget name of target in the main build script (see {@link org.netbeans.api.project.ant.AntBuildExtender#getExtendableTargets}) >+ * @param extensionTarget name of target in the extention script >+ */ >+ public void removeDependency(String mainBuildTarget, String extensionTarget) { >+ Collection<String> str = dependencies.get(mainBuildTarget); >+ if (str != null) { >+ str.remove(extensionTarget); >+ updateProjectMetadata(); >+ } else { >+ //oh well, just ignore, nothing to update anyway.. >+ } >+ } >+ >+ Map<String, Collection<String>> getDependencies() { >+ TreeMap<String, Collection<String>> toRet = new TreeMap<String, Collection<String>>(); >+ synchronized (AntBuildExtender.class) { >+ for (String str : dependencies.keySet()) { >+ ArrayList<String> col = new ArrayList<String>(); >+ col.addAll(dependencies.get(str)); >+ toRet.put(str, col); >+ } >+ } >+ return toRet; >+ } >+ } >+} >Index: ant/project/src/org/netbeans/api/project/ant/AntBuildExtenderAccessorImpl.java >=================================================================== >RCS file: ant/project/src/org/netbeans/api/project/ant/AntBuildExtenderAccessorImpl.java >diff -N ant/project/src/org/netbeans/api/project/ant/AntBuildExtenderAccessorImpl.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ ant/project/src/org/netbeans/api/project/ant/AntBuildExtenderAccessorImpl.java 6 Apr 2007 13:50:18 -0000 >@@ -0,0 +1,60 @@ >+/* >+ * The contents of this file are subject to the terms of the Common Development >+ * and Distribution License (the License). You may not use this file except in >+ * compliance with the License. >+ * >+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html >+ * or http://www.netbeans.org/cddl.txt. >+ * >+ * When distributing Covered Code, include this CDDL Header Notice in each file >+ * and include the License file at http://www.netbeans.org/cddl.txt. >+ * If applicable, add the following below the CDDL Header, with the fields >+ * enclosed by brackets [] replaced by your own identifying information: >+ * "Portions Copyrighted [year] [name of copyright owner]" >+ * >+ * To change this template, choose Tools | Template Manager >+ * and open the template in the editor. >+ */ >+package org.netbeans.api.project.ant; >+ >+import org.netbeans.spi.project.ant.AntBuildExtenderImplementation; >+import java.util.Collection; >+import java.util.Map; >+import java.util.Set; >+import org.netbeans.api.project.ant.AntBuildExtender.Extension; >+import org.netbeans.modules.project.ant.AntBuildExtenderAccessor; >+import org.netbeans.spi.project.ant.AntBuildExtenderImplementation; >+ >+/** >+ * >+ * @author mkleint >+ */ >+class AntBuildExtenderAccessorImpl extends AntBuildExtenderAccessor { >+ >+ static void createAccesor() { >+ if (DEFAULT == null) { >+ DEFAULT= new AntBuildExtenderAccessorImpl(); >+ } >+ } >+ >+ private AntBuildExtenderAccessorImpl() { >+ } >+ >+ >+ public AntBuildExtender createExtender(AntBuildExtenderImplementation impl) { >+ return new AntBuildExtender(impl); >+ } >+ >+ public Set<Extension> getExtensions(AntBuildExtender ext) { >+ return ext.getExtensions(); >+ } >+ >+ public String getPath(Extension extension) { >+ return extension.getPath(); >+ } >+ >+ public Map<String, Collection<String>> getDependencies(Extension extension) { >+ return extension.getDependencies(); >+ } >+ >+} >Index: ant/project/src/org/netbeans/modules/project/ant/AntBuildExtenderAccessor.java >=================================================================== >RCS file: ant/project/src/org/netbeans/modules/project/ant/AntBuildExtenderAccessor.java >diff -N ant/project/src/org/netbeans/modules/project/ant/AntBuildExtenderAccessor.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ ant/project/src/org/netbeans/modules/project/ant/AntBuildExtenderAccessor.java 6 Apr 2007 13:50:18 -0000 >@@ -0,0 +1,57 @@ >+/* >+ * The contents of this file are subject to the terms of the Common Development >+ * and Distribution License (the License). You may not use this file except in >+ * compliance with the License. >+ * >+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html >+ * or http://www.netbeans.org/cddl.txt. >+ * >+ * When distributing Covered Code, include this CDDL Header Notice in each file >+ * and include the License file at http://www.netbeans.org/cddl.txt. >+ * If applicable, add the following below the CDDL Header, with the fields >+ * enclosed by brackets [] replaced by your own identifying information: >+ * "Portions Copyrighted [year] [name of copyright owner]" >+ * >+ * The Original Software is NetBeans. The Initial Developer of the Original >+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun >+ * Microsystems, Inc. All Rights Reserved. >+ */ >+ >+package org.netbeans.modules.project.ant; >+ >+import org.netbeans.spi.project.ant.AntBuildExtenderImplementation; >+import java.util.Collection; >+import java.util.Map; >+import java.util.Set; >+import org.netbeans.api.project.ant.AntBuildExtender; >+import org.netbeans.spi.project.ant.AntBuildExtenderImplementation; >+ >+ >+/** >+ * @author mkleint >+ */ >+public abstract class AntBuildExtenderAccessor { >+ >+ public static AntBuildExtenderAccessor DEFAULT = null; >+ >+ static { >+ // invokes static initializer of Item.class >+ // that will assign value to the DEFAULT field above >+ Class c = AntBuildExtender.class; >+ try { >+ Class.forName(c.getName(), true, c.getClassLoader()); >+ } catch (Exception ex) { >+ ex.printStackTrace(); >+ } >+ } >+ >+ public abstract AntBuildExtender createExtender(AntBuildExtenderImplementation impl); >+ >+ public abstract Set<AntBuildExtender.Extension> getExtensions(AntBuildExtender ext); >+ >+ public abstract String getPath(AntBuildExtender.Extension extension); >+ >+ public abstract Map<String, Collection<String>> getDependencies(AntBuildExtender.Extension extension); >+ >+ >+} >Index: ant/project/src/org/netbeans/spi/project/ant/AntBuildExtenderImplementation.java >=================================================================== >RCS file: ant/project/src/org/netbeans/spi/project/ant/AntBuildExtenderImplementation.java >diff -N ant/project/src/org/netbeans/spi/project/ant/AntBuildExtenderImplementation.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ ant/project/src/org/netbeans/spi/project/ant/AntBuildExtenderImplementation.java 6 Apr 2007 13:50:18 -0000 >@@ -0,0 +1,104 @@ >+/* >+ * The contents of this file are subject to the terms of the Common Development >+ * and Distribution License (the License). You may not use this file except in >+ * compliance with the License. >+ * >+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html >+ * or http://www.netbeans.org/cddl.txt. >+ * >+ * When distributing Covered Code, include this CDDL Header Notice in each file >+ * and include the License file at http://www.netbeans.org/cddl.txt. >+ * If applicable, add the following below the CDDL Header, with the fields >+ * enclosed by brackets [] replaced by your own identifying information: >+ * "Portions Copyrighted [year] [name of copyright owner]" >+ * >+ * The Original Software is NetBeans. The Initial Developer of the Original >+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun >+ * Microsystems, Inc. All Rights Reserved. >+ */ >+ >+package org.netbeans.spi.project.ant; >+ >+import java.util.List; >+import org.netbeans.api.project.Project; >+import org.w3c.dom.Element; >+ >+/** >+ * A project type's spi for {@link org.netbeans.api.project.ant.AntBuildExtender}'s wiring. >+ * A typical setup in the project type includes: >+ * <ul> >+ * <li>Enhance the Project's metadata schema with the build extensibility content.</<li> >+ * <li>Provide lookup and storage of the metadata content by implementing this interface</<li> >+ * <li>Provide an instance of {@link org.netbeans.api.project.ant.AntBuildExtender} in project's lookup for use by 3rd >+ * party modules.</<li> >+ * <li>Use the new {@link org.netbeans.spi.project.support.ant.GeneratedFilesHelper#GeneratedFilesHelper(AntProjectHelper,AntBuildExtender)} constructor to >+ * create the helper for generating build related files.</<li> >+ * </ul> >+ * @author mkleint >+ * @since org.netbeans.modules.project.ant 1.16 >+ */ >+public interface AntBuildExtenderImplementation { >+ >+ /** >+ * >+ */ >+ public static final String ELEMENT_ROOT = "buildExtensions"; //NOI18N >+ >+ /** >+ * >+ */ >+ public static final String ELEMENT_EXTENSION = "extension"; //NOI18N >+ >+ /** >+ * >+ */ >+ public static final String ELEMENT_DEPENDENCY = "dependency"; //NOI18N >+ >+ /** >+ * >+ */ >+ public static final String ATTR_TARGET = "target"; >+ /** >+ * >+ */ >+ public static final String ATTR_DEPENDSON = "dependsOn"; >+ /** >+ * >+ */ >+ public static final String ATTR_ID = "id"; >+ /** >+ * >+ */ >+ public static final String ATTR_FILE = "file"; >+ >+ >+ /** >+ * A declarative list of targets that are intended by the project type to be used >+ * for extensions to plug into. >+ * @return list of target names >+ */ >+ List<String> getExtendableTargets(); >+ >+ /** >+ * Requests an update of build extensibility metadata by the implementation. >+ * A usual implementation takes the content of <code>root</code> parameter and >+ * copies it into the correct place in the primary project configuration space in project.xml >+ * >+ * @param root the root element for extensibility metadata (See {@link org.netbeans.spi.project.ant.AntBuildExtenderImplementation#ELEMENT_ROOT}) */ >+ void updateBuildExtensionMetadata(Element root); >+ >+ /** >+ * Returns the project build script extensibility configuration from a known location in project.xml. >+ * (As defined by the project type's schema). Usual implementation will use the primary project configuration >+ * space in project.xml. >+ * @return project metadata element, the root for project extensions (See {@link org.netbeans.spi.project.ant.AntBuildExtenderImplementation#ELEMENT_ROOT}), or null if not >+ * configured. >+ */ >+ Element getBuildExtensionMetadata(); >+ >+ /** >+ * Returns Ant Project instance. >+ * @return The project that this instance of AntBuildExtenderImplementation describes >+ */ >+ Project getOwningProject(); >+} >Index: ant/project/src/org/netbeans/spi/project/support/ant/AntBuildExtenderSupport.java >=================================================================== >RCS file: ant/project/src/org/netbeans/spi/project/support/ant/AntBuildExtenderSupport.java >diff -N ant/project/src/org/netbeans/spi/project/support/ant/AntBuildExtenderSupport.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ ant/project/src/org/netbeans/spi/project/support/ant/AntBuildExtenderSupport.java 6 Apr 2007 13:50:18 -0000 >@@ -0,0 +1,46 @@ >+/* >+ * The contents of this file are subject to the terms of the Common Development >+ * and Distribution License (the License). You may not use this file except in >+ * compliance with the License. >+ * >+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html >+ * or http://www.netbeans.org/cddl.txt. >+ * >+ * When distributing Covered Code, include this CDDL Header Notice in each file >+ * and include the License file at http://www.netbeans.org/cddl.txt. >+ * If applicable, add the following below the CDDL Header, with the fields >+ * enclosed by brackets [] replaced by your own identifying information: >+ * "Portions Copyrighted [year] [name of copyright owner]" >+ * >+ * The Original Software is NetBeans. The Initial Developer of the Original >+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun >+ * Microsystems, Inc. All Rights Reserved. >+ */ >+ >+package org.netbeans.spi.project.support.ant; >+ >+import org.netbeans.spi.project.ant.AntBuildExtenderImplementation; >+import org.netbeans.api.project.ant.AntBuildExtender; >+import org.netbeans.modules.project.ant.AntBuildExtenderAccessor; >+ >+/** >+ * Factory class for creation of AntBuildExtender instances >+ * @author mkleint >+ * @since org.netbeans.modules.project.ant 1.16 >+ */ >+public final class AntBuildExtenderSupport { >+ >+ /** Creates a new instance of AntBuildExtenderSupport */ >+ private AntBuildExtenderSupport() { >+ } >+ >+ /** >+ * >+ * @param implementation >+ * @return >+ */ >+ public static AntBuildExtender createAntExtender(AntBuildExtenderImplementation implementation) { >+ return AntBuildExtenderAccessor.DEFAULT.createExtender(implementation); >+ } >+ >+} >Index: ant/project/src/org/netbeans/spi/project/support/ant/GeneratedFilesHelper.java >=================================================================== >RCS file: /cvs/ant/project/src/org/netbeans/spi/project/support/ant/GeneratedFilesHelper.java,v >retrieving revision 1.17 >diff -u -r1.17 GeneratedFilesHelper.java >--- ant/project/src/org/netbeans/spi/project/support/ant/GeneratedFilesHelper.java 3 Aug 2006 19:21:06 -0000 1.17 >+++ ant/project/src/org/netbeans/spi/project/support/ant/GeneratedFilesHelper.java 6 Apr 2007 13:50:20 -0000 >@@ -29,6 +29,7 @@ > import java.io.OutputStream; > import java.net.URI; > import java.net.URL; >+import java.util.Collection; > import java.util.HashMap; > import java.util.Map; > import java.util.Properties; >@@ -40,17 +41,30 @@ > import javax.xml.transform.stream.StreamResult; > import javax.xml.transform.stream.StreamSource; > import org.netbeans.api.project.ProjectManager; >+import org.netbeans.api.project.ant.AntBuildExtender; >+import org.netbeans.api.project.ant.AntBuildExtender.Extension; >+import org.netbeans.modules.project.ant.AntBuildExtenderAccessor; > import org.netbeans.modules.project.ant.UserQuestionHandler; > import org.openide.ErrorManager; > import org.openide.filesystems.FileLock; > import org.openide.filesystems.FileObject; > import org.openide.filesystems.FileSystem; > import org.openide.filesystems.FileUtil; >+import org.openide.util.Exceptions; > import org.openide.util.Mutex; > import org.openide.util.MutexException; > import org.openide.util.NbBundle; > import org.openide.util.UserQuestionException; > import org.openide.util.Utilities; >+import org.openide.xml.XMLUtil; >+import org.w3c.dom.Attr; >+import org.w3c.dom.Document; >+import org.w3c.dom.Element; >+import org.w3c.dom.Node; >+import org.w3c.dom.NodeList; >+import org.w3c.dom.Text; >+import org.xml.sax.InputSource; >+import org.xml.sax.SAXException; > > /** > * Helps a project type (re-)generate, and manage the state and versioning of, >@@ -160,6 +174,8 @@ > /** Project directory. */ > private final FileObject dir; > >+ private AntBuildExtender extender; >+ > /** > * Create a helper based on the supplied project helper handle. > * @param h an Ant-based project helper supplied to the project type provider >@@ -168,6 +184,19 @@ > this.h = h; > dir = h.getProjectDirectory(); > } >+ >+ /** >+ * Create a helper based on the supplied project helper handle. The created >+ * instance is capable of extending the generated files with 3rd party content. >+ * @param h an Ant-based project helper supplied to the project type provider >+ * @param ex build extensibility support >+ * @since org.netbeans.modules.project.ant 1.16 >+ * >+ */ >+ public GeneratedFilesHelper(AntProjectHelper h, AntBuildExtender ex) { >+ this(h); >+ extender = ex; >+ } > > /** > * Create a helper based only on a project directory. >@@ -255,7 +284,11 @@ > new ByteArrayInputStream(projectXmlData), projectXmlF.toURI().toString()); > ByteArrayOutputStream result = new ByteArrayOutputStream(); > t.transform(projectXmlSource, new StreamResult(result)); >- resultData = result.toByteArray(); >+ if (BUILD_IMPL_XML_PATH.equals(path)) { >+ resultData = applyBuildExtensions(result.toByteArray(), extender); >+ } else { >+ resultData = result.toByteArray(); >+ } > } catch (TransformerException e) { > throw (IOException)new IOException(e.toString()).initCause(e); > } >@@ -369,6 +402,83 @@ > } > } > >+ private byte[] applyBuildExtensions(byte[] resultData, AntBuildExtender ext) { >+ if (ext == null) { >+ return resultData; >+ } >+ try { >+ ByteArrayInputStream in2 = new ByteArrayInputStream(resultData); >+ InputSource is = new InputSource(in2); >+ >+ Document doc = XMLUtil.parse(is, false, true, null, null); >+ Element el = doc.getDocumentElement(); >+ Node firstSubnode = el.getFirstChild(); >+ //TODO check if first one is text and use it as indentation.. >+ for (Extension extension : AntBuildExtenderAccessor.DEFAULT.getExtensions(ext)) { >+ Text after = doc.createTextNode("\n"); >+ el.insertBefore(after, firstSubnode); >+ Element imp = createImportElement(AntBuildExtenderAccessor.DEFAULT.getPath(extension), doc); >+ el.insertBefore(imp, after); >+ Text before = doc.createTextNode(" "); >+ el.insertBefore(before, imp); >+ firstSubnode = before; >+ NodeList nl = el.getElementsByTagName("target"); >+ Map<String, Collection<String>> deps = AntBuildExtenderAccessor.DEFAULT.getDependencies(extension); >+ for (String targetName : deps.keySet()) { >+ Element targetEl = null; >+ for (int i = 0; i < nl.getLength(); i++) { >+ Element elem = (Element)nl.item(i); >+ String at = elem.getAttribute("name"); >+ if (at != null && at.equals(targetName)) { >+ targetEl = elem; >+ break; >+ } >+ } >+// System.out.println("target name=" + targetName); >+// System.out.println("target elem=" + targetEl); >+ if (targetEl != null) { >+ Attr depend = targetEl.getAttributeNode("depends"); >+ if (depend == null) { >+ depend = doc.createAttribute("depends"); >+ depend.setValue(""); >+ targetEl.setAttributeNode(depend); >+ } >+ String oldVal = depend.getValue(); >+ for (String targ : deps.get(targetName)) { >+ oldVal = oldVal + "," + targ; >+ } >+ if (oldVal.startsWith(",")) { >+ oldVal = oldVal.substring(1); >+ } >+ depend.setValue(oldVal); >+ } else { >+ //TODO log?? >+ } >+ } >+ } >+ >+ ByteArrayOutputStream out = new ByteArrayOutputStream(); >+ XMLUtil.write(doc, out, "UTF-8"); >+ return out.toByteArray(); >+ } >+ catch (IOException ex) { >+ ex.printStackTrace(); >+ Exceptions.printStackTrace(ex); >+ return resultData; >+ } >+ catch (SAXException ex) { >+ ex.printStackTrace(); >+ Exceptions.printStackTrace(ex); >+ return resultData; >+ } >+ } >+ >+ private Element createImportElement(String path, Document doc) { >+ Element el = doc.createElement("import"); >+ el.setAttribute("file", path); >+ return el; >+ } >+ > /** > * Load data from a stream into a buffer. > */ >Index: ant/project/src/org/netbeans/spi/project/support/ant/package.html >=================================================================== >RCS file: /cvs/ant/project/src/org/netbeans/spi/project/support/ant/package.html,v >retrieving revision 1.3 >diff -u -r1.3 package.html >--- ant/project/src/org/netbeans/spi/project/support/ant/package.html 30 Jun 2006 18:05:51 -0000 1.3 >+++ ant/project/src/org/netbeans/spi/project/support/ant/package.html 6 Apr 2007 13:50:20 -0000 >@@ -130,6 +130,10 @@ > {@link org.netbeans.spi.project.support.ant.ProjectXmlSavedHook} to be told when > to recreate them.</p> > >+<p>To allow 3rd party extensions to build scripts, use {@link org.netbeans.spi.project.ant.AntBuildExtenderImplementation} and >+{@link org.netbeans.spi.project.support.ant.AntBuildExtenderSupport}. >+</p> >+ > <p>{@link org.netbeans.spi.project.support.ant.EditableProperties} is a > VCS-friendly alternative to {@link java.util.Properties}. > {@link org.netbeans.spi.project.support.ant.PropertyUtils} also provides various >Index: ant/project/test/unit/src/org/netbeans/spi/project/support/ant/AntBasedTestUtil.java >=================================================================== >RCS file: /cvs/ant/project/test/unit/src/org/netbeans/spi/project/support/ant/AntBasedTestUtil.java,v >retrieving revision 1.21 >diff -u -r1.21 AntBasedTestUtil.java >--- ant/project/test/unit/src/org/netbeans/spi/project/support/ant/AntBasedTestUtil.java 27 Mar 2007 00:01:31 -0000 1.21 >+++ ant/project/test/unit/src/org/netbeans/spi/project/support/ant/AntBasedTestUtil.java 6 Apr 2007 13:50:21 -0000 >@@ -19,6 +19,7 @@ > > package org.netbeans.spi.project.support.ant; > >+import org.netbeans.spi.project.ant.AntBuildExtenderImplementation; > import java.beans.PropertyChangeEvent; > import java.beans.PropertyChangeListener; > import java.io.File; >@@ -56,6 +57,7 @@ > import org.netbeans.spi.project.AuxiliaryConfiguration; > import org.netbeans.api.project.ProjectInformation; > import org.netbeans.api.project.ProjectManager; >+import org.netbeans.api.project.ant.AntBuildExtender; > import org.netbeans.spi.project.ant.AntArtifactProvider; > import org.netbeans.spi.queries.CollocationQueryImplementation; > import org.openide.filesystems.FileObject; >@@ -100,6 +102,9 @@ > return new TestAntBasedProjectType(); > } > >+ public static AntBasedProjectType testAntBasedProjectType(AntBuildExtenderImplementation extender) { >+ return new TestAntBasedProjectType(extender); >+ } > /** > * You can adjust which artifacts are supplied. > */ >@@ -108,15 +113,20 @@ > } > > private static final class TestAntBasedProjectType implements AntBasedProjectType { >+ private AntBuildExtenderImplementation ext; > > TestAntBasedProjectType() {} > >+ TestAntBasedProjectType(AntBuildExtenderImplementation ext) { >+ this.ext = ext; >+ } >+ > public String getType() { > return "test"; > } > > public Project createProject(AntProjectHelper helper) throws IOException { >- return new TestAntBasedProject(helper); >+ return new TestAntBasedProject(helper, ext); > } > > public String getPrimaryConfigurationDataElementName(boolean shared) { >@@ -136,14 +146,22 @@ > private final GeneratedFilesHelper genFilesHelper; > private final Lookup l; > >- TestAntBasedProject(AntProjectHelper helper) throws IOException { >+ TestAntBasedProject(AntProjectHelper helper, AntBuildExtenderImplementation ext) throws IOException { > if (helper.getProjectDirectory().getFileObject("nbproject/broken") != null) { > throw new IOException("broken"); > } > this.helper = helper; > AuxiliaryConfiguration aux = helper.createAuxiliaryConfiguration(); > refHelper = new ReferenceHelper(helper, aux, helper.getStandardPropertyEvaluator()); >- genFilesHelper = new GeneratedFilesHelper(helper); >+ Object extContent; >+ if (ext !=null) { >+ AntBuildExtender e = AntBuildExtenderSupport.createAntExtender(ext); >+ genFilesHelper = new GeneratedFilesHelper(helper, e); >+ extContent = e; >+ } else { >+ genFilesHelper = new GeneratedFilesHelper(helper); >+ extContent = new Object(); >+ } > l = Lookups.fixed(new Object[] { > new TestInfo(), > helper, >@@ -166,6 +184,7 @@ > } > }, > "hello", >+ extContent > }); > } > >@@ -218,6 +237,7 @@ > public void removePropertyChangeListener(PropertyChangeListener listener) {} > > } >+ > > private final class TestAntArtifactProvider implements AntArtifactProviderMutable { > >Index: ant/project/test/unit/src/org/netbeans/spi/project/support/ant/AntBuildExtenderTest.java >=================================================================== >RCS file: ant/project/test/unit/src/org/netbeans/spi/project/support/ant/AntBuildExtenderTest.java >diff -N ant/project/test/unit/src/org/netbeans/spi/project/support/ant/AntBuildExtenderTest.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ ant/project/test/unit/src/org/netbeans/spi/project/support/ant/AntBuildExtenderTest.java 6 Apr 2007 13:50:21 -0000 >@@ -0,0 +1,135 @@ >+/* >+ * The contents of this file are subject to the terms of the Common Development >+ * and Distribution License (the License). You may not use this file except in >+ * compliance with the License. >+ * >+ * You can obtain a copy of the License at http://www.netbeans.org/cddl.html >+ * or http://www.netbeans.org/cddl.txt. >+ * >+ * When distributing Covered Code, include this CDDL Header Notice in each file >+ * and include the License file at http://www.netbeans.org/cddl.txt. >+ * If applicable, add the following below the CDDL Header, with the fields >+ * enclosed by brackets [] replaced by your own identifying information: >+ * "Portions Copyrighted [year] [name of copyright owner]" >+ * >+ * The Original Software is NetBeans. The Initial Developer of the Original >+ * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun >+ * Microsystems, Inc. All Rights Reserved. >+ */ >+ >+package org.netbeans.spi.project.support.ant; >+ >+import org.netbeans.spi.project.ant.AntBuildExtenderImplementation; >+import java.util.Collections; >+import java.util.List; >+import org.netbeans.api.project.Project; >+import org.netbeans.api.project.ProjectManager; >+import org.netbeans.api.project.TestUtil; >+import org.netbeans.api.project.ant.AntBuildExtender; >+import org.netbeans.junit.NbTestCase; >+import org.openide.filesystems.FileObject; >+import org.w3c.dom.Element; >+import org.w3c.dom.NodeList; >+ >+/** >+ * Test functionality of AntBuildExtender. >+ * @author mkleint >+ */ >+public class AntBuildExtenderTest extends NbTestCase { >+ >+ public AntBuildExtenderTest(String name) { >+ super(name); >+ } >+ >+ private FileObject scratch; >+ private FileObject projdir; >+ private FileObject extension1; >+ private ProjectManager pm; >+ private Project p; >+ private AntProjectHelper h; >+ private GeneratedFilesHelper gfh; >+ private ExtImpl extenderImpl; >+ >+ protected void setUp() throws Exception { >+ super.setUp(); >+ scratch = TestUtil.makeScratchDir(this); >+ projdir = scratch.createFolder("proj"); >+ TestUtil.createFileFromContent(GeneratedFilesHelperTest.class.getResource("data/project.xml"), projdir, "nbproject/project.xml"); >+ extension1 = TestUtil.createFileFromContent(GeneratedFilesHelperTest.class.getResource("data/extension1.xml"), projdir, "nbproject/extension1.xml"); >+ extenderImpl = new ExtImpl(); >+ TestUtil.setLookup(new Object[] { >+ AntBasedTestUtil.testAntBasedProjectType(extenderImpl), >+ }); >+ pm = ProjectManager.getDefault(); >+ p = pm.findProject(projdir); >+ extenderImpl.project = p; >+ h = p.getLookup().lookup(AntProjectHelper.class); >+ gfh = p.getLookup().lookup(GeneratedFilesHelper.class); >+ assertNotNull(gfh); >+ } >+ >+ public void testGetExtendableTargets() { >+ AntBuildExtender instance = p.getLookup().lookup(AntBuildExtender.class); >+ >+ List<String> result = instance.getExtendableTargets(); >+ >+ assertEquals(1, result.size()); >+ assertEquals("all", result.get(0)); >+ } >+ >+ public void testAddExtension() { >+ AntBuildExtender instance = p.getLookup().lookup(AntBuildExtender.class); >+ instance.addExtension("milos", extension1); >+ Element el = extenderImpl.newElement; >+ assertNotNull(el); >+ NodeList nl = el.getElementsByTagName(AntBuildExtenderImplementation.ELEMENT_EXTENSION); >+ assertEquals(1, nl.getLength()); >+ Element extens = (Element) nl.item(0); >+ assertEquals("milos", extens.getAttribute(AntBuildExtenderImplementation.ATTR_ID)); >+ assertEquals("extension1.xml", extens.getAttribute(AntBuildExtenderImplementation.ATTR_FILE)); >+ } >+ >+ public void testRemoveExtension() { >+ AntBuildExtender instance = p.getLookup().lookup(AntBuildExtender.class); >+ testAddExtension(); >+ Element el = extenderImpl.newElement; >+ extenderImpl.oldElement = el; >+ instance.removeExtension("milos"); >+ el = extenderImpl.newElement; >+ assertNotNull(el); >+ NodeList nl = el.getElementsByTagName(AntBuildExtenderImplementation.ELEMENT_EXTENSION); >+ assertEquals(0, nl.getLength()); >+ } >+ >+ public void testGetExtension() { >+ AntBuildExtender instance = p.getLookup().lookup(AntBuildExtender.class); >+ testAddExtension(); >+ AntBuildExtender.Extension ext = instance.getExtension("milos"); >+ assertNotNull(ext); >+ } >+ >+ private class ExtImpl implements AntBuildExtenderImplementation { >+ Project project; >+ Element newElement; >+ Element oldElement; >+ List<String> targets = Collections.singletonList("all"); >+ >+ public List<String> getExtendableTargets() { >+ return targets; >+ } >+ >+ public void updateBuildExtensionMetadata(Element element) { >+ newElement = element; >+ } >+ >+ public Element getBuildExtensionMetadata() { >+ return oldElement; >+ } >+ >+ public Project getOwningProject() { >+ return project; >+ } >+ >+ } >+ >+} >Index: ant/project/test/unit/src/org/netbeans/spi/project/support/ant/GeneratedFilesHelperTest.java >=================================================================== >RCS file: /cvs/ant/project/test/unit/src/org/netbeans/spi/project/support/ant/GeneratedFilesHelperTest.java,v >retrieving revision 1.9 >diff -u -r1.9 GeneratedFilesHelperTest.java >--- ant/project/test/unit/src/org/netbeans/spi/project/support/ant/GeneratedFilesHelperTest.java 3 Aug 2006 19:21:08 -0000 1.9 >+++ ant/project/test/unit/src/org/netbeans/spi/project/support/ant/GeneratedFilesHelperTest.java 6 Apr 2007 13:50:21 -0000 >@@ -19,14 +19,18 @@ > > package org.netbeans.spi.project.support.ant; > >+import org.netbeans.spi.project.ant.AntBuildExtenderImplementation; > import java.io.ByteArrayInputStream; > import java.io.File; > import java.net.URL; >+import java.util.Collections; >+import java.util.List; > import org.netbeans.api.project.Project; > import org.netbeans.api.project.ProjectManager; > import org.netbeans.api.project.TestUtil; > import org.netbeans.junit.NbTestCase; > import org.netbeans.modules.project.ant.Util; >+import org.netbeans.spi.project.AuxiliaryConfiguration; > import org.openide.filesystems.FileObject; > import org.openide.filesystems.FileUtil; > import org.openide.util.Utilities; >@@ -46,21 +50,26 @@ > > private FileObject scratch; > private FileObject projdir; >+ private FileObject extension1; > private ProjectManager pm; > private Project p; > private AntProjectHelper h; > private GeneratedFilesHelper gfh; >+ private ExtImpl extenderImpl; > > protected void setUp() throws Exception { > super.setUp(); > scratch = TestUtil.makeScratchDir(this); > projdir = scratch.createFolder("proj"); > TestUtil.createFileFromContent(GeneratedFilesHelperTest.class.getResource("data/project.xml"), projdir, "nbproject/project.xml"); >+ extension1 = TestUtil.createFileFromContent(GeneratedFilesHelperTest.class.getResource("data/extension1.xml"), projdir, "nbproject/extension1.xml"); >+ extenderImpl = new ExtImpl(); > TestUtil.setLookup(new Object[] { >- AntBasedTestUtil.testAntBasedProjectType(), >+ AntBasedTestUtil.testAntBasedProjectType(extenderImpl), > }); > pm = ProjectManager.getDefault(); > p = pm.findProject(projdir); >+ extenderImpl.project = p; > h = p.getLookup().lookup(AntProjectHelper.class); > gfh = p.getLookup().lookup(GeneratedFilesHelper.class); > assertNotNull(gfh); >@@ -198,6 +207,36 @@ > } > assertTrue("generated file has platform line endings", ok); > } >+ } >+ >+ private class ExtImpl implements AntBuildExtenderImplementation { >+ Project project; >+ Element newElement; >+ Element oldElement; >+ >+ public List<String> getExtendableTargets() { >+ return Collections.singletonList("all"); >+ } >+ >+ public void updateBuildExtensionMetadata(Element element) { >+ newElement = element; >+ } >+ >+ public Element getBuildExtensionMetadata() { >+ Element el = project.getLookup().lookup(AuxiliaryConfiguration.class).getConfigurationFragment(ELEMENT_ROOT, "urn:test:extension", true); >+ if (el != null) { >+ NodeList nl = el.getElementsByTagName(AntBuildExtenderImplementation.ELEMENT_ROOT); >+ if (nl.getLength() == 1) { >+ return (Element) nl.item(0); >+ } >+ } >+ return null; >+ } >+ >+ public Project getOwningProject() { >+ return project; >+ } >+ > } > > } >Index: ant/project/test/unit/src/org/netbeans/spi/project/support/ant/data/extension1.xml >=================================================================== >RCS file: ant/project/test/unit/src/org/netbeans/spi/project/support/ant/data/extension1.xml >diff -N ant/project/test/unit/src/org/netbeans/spi/project/support/ant/data/extension1.xml >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ ant/project/test/unit/src/org/netbeans/spi/project/support/ant/data/extension1.xml 6 Apr 2007 13:50:21 -0000 >@@ -0,0 +1,13 @@ >+<?xml version="1.0" encoding="UTF-8"?> >+ >+<!-- >+ Document : extension1.xml.xml >+ Created on : March 28, 2007, 3:56 PM >+ Author : mkleint >+ Description: >+ Purpose of the document follows. >+--> >+ >+<root> >+ >+</root>
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Actions:
View
|
Diff
Attachments on
bug 93509
: 40555 |
40557
|
40558
|
40559
|
41230
SiteMap
About Us
Contact
Legal & Licences
By use of this website, you agree to the
NetBeans Policies and Terms of Use
. © 2014, Oracle Corporation and/or its affiliates. Sponsored by