Return-Path: Delivered-To: apmail-jakarta-ant-dev-archive@jakarta.apache.org Received: (qmail 83984 invoked by uid 500); 15 Oct 2001 12:38:21 -0000 Mailing-List: contact ant-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk Reply-To: ant-dev@jakarta.apache.org list-help: list-unsubscribe: list-post: Delivered-To: mailing list ant-dev@jakarta.apache.org Received: (qmail 83973 invoked from network); 15 Oct 2001 12:38:17 -0000 Message-ID: <00af01c15575$f4f16580$0100a8c0@jose> From: "Jose Alberto Fernandez" To: References: Subject: Re: SUMMARY: loading tasks from jars for Ant 1.5 summary feedback Date: Mon, 15 Oct 2001 13:36:03 +0100 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----=_NextPart_000_00AD_01C1557E.55DCD2A0" X-Priority: 3 X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook Express 5.00.3018.1300 X-MimeOLE: Produced By Microsoft MimeOLE V5.00.3018.1300 X-Spam-Rating: daedalus.apache.org 1.6.2 0/1000/N This is a multi-part message in MIME format. ------=_NextPart_000_00AD_01C1557E.55DCD2A0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable From: "Tim Dawson" > > From: Jose Alberto Fernandez [mailto:j_a_fernandez@yahoo.com] > >=20 >=20 > ok... then how do we get the DD? (I've only ever used getResources() > to grab a resource other than a properties file from a jar) >=20 > I'm gonna need a few implementation pointers here... You could just extracted from the library using the Zip classes.=20 >=20 > I can agree with that 100%. Is using "Class-Path" controversial? > I haven't read any threads related to that. >=20 The problem that I see here is that ANT is using its own 1.1 able = ClassLoader which do not understant Class-Path. Which it is a problem. I think we = would have to retrofit the details of the 1.2 spec into AntClassLoader to make it work = right. Notice that 1.2 provides URLClassLoader which knows how to do all the = work. I think. > I could see how it would be for the optional jar, because there > are so many different dependencies locked up in there, you'd have > to break it out into many smaller jars or else I'd have to have > the starteam.jar even though all I want is to use the junit task. >=20 In my understading, not everything in Class-Path needs to exest. Same as = with CLASSPATH. I think though that is would be a very good idea to break up = optional.jar into a bunch of smaller libraries for each particular usage. For example an AntCVS.jar, = AntPCVS.jar, AntJunit.jar ans so on. Each with its limited dependencies. So in your buildfile you = would say: and we will just need to have junit.jar is you want this library to = work. > >=20 > > But that would mean there is no way to start ANT, just because=20 > > you put one too many jars in the system. That sounds really bad to = me. >=20 > ah, I see what you mean. if I dropped the jar file in I'd still get an > error whether or not I was planning to use it. that would be = confusing. >=20 > the best approach is just to unsupport autoloading. I'm in support of = that, > but can we get consensus around it? >=20 Agreed. Tim, I have been working on an implementation which I think is all coded = but I have not tested yet. Before sending a patch submission I also want to have an task = to package=20 the libraries and verify the descriptor. Only after that, I would try to = submit a patch of core to reorganize it in libraries, and adopt it during initial loading. I am attaching the code I have to hear your suggestions or anyone elses = on the code I have. My goal at the end of the day is for the core to load its core tasks by = just executing the equivalent of . One of the problems I am trying to dealt with is how to bootstrap ANT in = this new model.=20 During bootstrapping (when building from scratch) there is no "ant.jar" = and hence the problem. If there is no /org/apache/tools/ant/defaults.properties, but instead = one of several META-INF/antlib.xml=20 we will need some way to tell ANT to use the unjared file located = somewhere. I was thinking on adding a property during bootstrap: -Dant.bootxml=3D"filename"=20 which will be used by the core instead of the mentioned above. = You will see some methods in the code providing what it is needed for this to work. I would like your opinionsand improvements. This code depends on the = patch for project-level tasks (DeclaringTasks) that I sent last week. Hope to hear comments, concerns, additions, etc. Jose Alberto ------=_NextPart_000_00AD_01C1557E.55DCD2A0 Content-Type: application/octet-stream; name="Antlib.java" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="Antlib.java" /* * The Apache Software License, Version 1.1 * * Copyright (c) 1999 The Apache Software Foundation. All rights=20 * 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.=20 * * 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: =20 * "This product includes software developed by the=20 * 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=20 * 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. * = =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D * * 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 * . */ package org.apache.tools.ant.taskdefs; import org.apache.tools.ant.*; import org.apache.tools.ant.types.*; import org.xml.sax.*; import javax.xml.parsers.*; import java.util.*; import java.util.zip.*; import java.io.*; /** * Make available the tasks and types from an Ant library. * *
 * <antlib library=3D"libname.jar" >
 *   <alias name=3D"nameOnLib" as=3D"newName" />
 * </antlib>
 *=20
 * <antlib file=3D"libname.jar" override=3D"true" />
 * 
* @author Jose Alberto = Fernandez */ public class Antlib extends Task implements DeclaringTask { /** Location of destriptor in library */ public static String XML_DESCRIPTOR =3D "META-INF/antlib.xml"; /** Prefix name for DTD of descriptor */ public static String ANTLIB_DTD_PREFIX =3D "Antlib-V"; public static String ANTLIB_DTD_EXT =3D ".dtd"; private String library =3D null; private File file =3D null; private boolean override =3D false; private boolean onCurrent =3D false; private SAXParserFactory saxFactory; private Vector aliases =3D new Vector(); public class Alias { private String name; private String as; public void setName(String name) { this.name =3D name; } public void setAs(String as) { this.as =3D as; } } public Antlib() { super(); saxFactory =3D SAXParserFactory.newInstance(); saxFactory.setValidating(true); } public Antlib(Project p) { this(); setProject(p); } /**=20 * Set name of library to load. The library is located in = $ANT_HOME/lib. * @param lib the name of library relative to $ANT_HOME/lib. */ public void setLibrary(String lib) { this.library =3D lib; } /** * Set file location of library to load. * @param file the jar file for the library. */ public void setFile(File file) { this.file =3D file; } /** * Set whether to override any existing definitions. * @param override if true new definitions will replace existing = ones. */ public void setOverride(boolean override) { this.override =3D override; } /** * Set whether to use a new classloader or not.=20 * Default is false. * This property is mostly used by the core when loading core tasks. * @param onCurrent if true the current classloader will be used to * load the definitions. */ public void setOnCurrent(boolean onCurrent) { this.onCurrent =3D onCurrent; } /** Create new Alias element. */ public Alias createAlias() { Alias als =3D new Alias(); aliases.add(als); return als; } public void execute() throws BuildException { File realFile =3D file; if (library !=3D null) { if (file !=3D null) { String msg =3D "You cannot specify both file and library."; throw new BuildException(msg, location); } // For the time being libraries live in $ANT_HOME/lib. // The idea being that we would not load all the jar there anymore String home =3D project.getProperty("ant.home"); =20 if (home =3D=3D null) throw new BuildException("ANT_HOME not set as required."); realFile =3D new File(new File(home, "lib"), library); } else if (file =3D=3D null) { String msg =3D "Must specify either library or file attribute."; throw new BuildException(msg, location); } if (!realFile.exists()) { String msg =3D "Cannot find library: " + realFile; throw new BuildException(msg, location); } InputStream is =3D getDescriptor(realFile); =09 if (is =3D=3D null) { String msg =3D "Missing descriptor on library: " + realFile; throw new BuildException(msg, location); } evaluateDescriptor(onCurrent? null : makeClassLoader(realFile),=20 processAliases(), is); } /** * Load definitions directly from an external XML file. * @param xmlfile XML file in the Antlib format. */ public void loadDefinitions(File xmlfile) throws BuildException { try { InputStream is =3D new FileInputStream(xmlfile); loadDefinitions(is); } catch (IOException io) { throw new BuildException("Cannot read file: " + file, io); } } /** * Load definitions directly from InputStream. * @param is InputStream for the Antlib descriptor. */ public void loadDefinitions(InputStream is) throws BuildException { evaluateDescriptor(null, processAliases(), is); } private InputStream getDescriptor(File file) { try { final ZipFile zipfile =3D new ZipFile(file); ZipEntry entry =3D zipfile.getEntry(XML_DESCRIPTOR); =20 if (entry =3D=3D null) return null; =20 // Guarantee that when Entry is close so does the zipfile instance. return new FilterInputStream(zipfile.getInputStream(entry)){ public void close() throws IOException { super.close(); zipfile.close(); } }; } catch(ZipException ze) { throw new BuildException("Not a library file.", ze, location); } catch(IOException ioe) { throw new BuildException("Cannot read library content.", ioe, location); } } private Properties processAliases() { Properties p =3D new Properties(); for(Enumeration e =3D aliases.elements(); e.hasMoreElements();) { Alias a =3D (Alias)e.nextElement(); p.put(a.name, a.as); } return p; } protected ClassLoader makeClassLoader(File fl) throws BuildException = { Path clspath =3D new Path(project); clspath.setLocation(fl); AntClassLoader al =3D new AntClassLoader(project, clspath, true); return al; } protected void evaluateDescriptor(ClassLoader cl,=20 Properties als, InputStream is) throws BuildException { try { SAXParser saxParser =3D saxFactory.newSAXParser(); Parser parser =3D saxParser.getParser(); InputSource inputSource =3D new InputSource(is); //inputSource.setSystemId(uri); //URI is nasty for jar = entries project.log("parsing descriptor for library: " + file,=20 Project.MSG_VERBOSE); saxParser.parse(inputSource, new AntLibraryHandler(cl, = als)); } catch(ParserConfigurationException exc) { throw new BuildException("Parser has not been configured = correctly", exc); } catch(SAXParseException exc) { Location location =3D new Location(XML_DESCRIPTOR,=20 exc.getLineNumber(), exc.getColumnNumber()); Throwable t =3D exc.getException(); if (t instanceof BuildException) { BuildException be =3D (BuildException) t; if (be.getLocation() =3D=3D Location.UNKNOWN_LOCATION) { be.setLocation(location); } throw be; } =20 throw new BuildException(exc.getMessage(), t, location); } catch(SAXException exc) { Throwable t =3D exc.getException(); if (t instanceof BuildException) { throw (BuildException) t; } throw new BuildException(exc.getMessage(), t); } catch(IOException exc) { throw new BuildException("Error reading library descriptor", = exc); } finally { if (is !=3D null) { try { is.close(); } catch (IOException ioe) { // ignore this } } } } /** * Parses the document describing the content of the library. */ private class AntLibraryHandler extends HandlerBase { =09 private final ClassLoader cl; private final Properties aliasMap; private Locator locator =3D null; AntLibraryHandler(ClassLoader cl, Properties als) { this.cl =3D cl; this.aliasMap =3D als; } public void setDocumentLocator(Locator locator) { this.locator =3D locator; } public void startElement(String tag, AttributeList attrs) throws SAXParseException=20 { if ("antlib".equals(tag)) { // No attributes to worry about return; } if ("task".equals(tag) || "type".equals(tag)) { String name =3D null; String className =3D null; for (int i =3D 0, last =3D attrs.getLength(); i < last; i++) { String key =3D attrs.getName(i); String value =3D attrs.getValue(i); if (key.equals("name")) { name =3D value; } else if (key.equals("class")) { className =3D value; } else { throw new SAXParseException("Unexpected attribute \""=20 + key + "\"", locator); } } if (name =3D=3D null || className =3D=3D null) { String msg =3D "Underspecified " + tag + " declaration."; throw new SAXParseException(msg, locator); } =09 try { String alias =3D aliasMap.getProperty(name); if (alias !=3D null) name =3D alias; if (!override && inUse(name)) { String msg =3D "Cannot override " + tag + ": " + name; log(msg, Project.MSG_WARN); return; } Class cls =3D (cl !=3D null)?=20 cl.loadClass(className) : Class.forName(className); if (tag.equals("task")) { project.addTaskDefinition(name, cls); } else { project.addDataTypeDefinition(name, cls); } } catch (ClassNotFoundException cnfe) { String msg =3D "Class " + className + " cannot be found"; throw new SAXParseException(msg, locator, cnfe); } catch (NoClassDefFoundError ncdfe) { String msg =3D "Class " + className + " cannot be found"; throw new SAXParseException(msg, locator); } }=20 else { throw new SAXParseException("Unexpected element \"" +=20 tag + "\"",=20 locator); } } private boolean inUse(String name) { return (project.getTaskDefinitions().get(name) !=3D null || project.getDataTypeDefinitions().get(name) !=3D null); } /** * Recognizes the DTD declaration for antlib and returns * the corresponding DTD definition from a resource. *

* To allow for future versions of the DTD format it will * search for any DTDs of the form "Antlib-V.*\.dtd". */ public InputSource resolveEntity(String publicId, String systemId) { =20 if (systemId !=3D null && systemId.startsWith(ANTLIB_DTD_PREFIX) && systemId.endsWith(ANTLIB_DTD_EXT)) { InputSource is =3D new InputSource(getClass().getResourceAsStream(systemId)); is.setSystemId(systemId); return is; } return null; } } } ------=_NextPart_000_00AD_01C1557E.55DCD2A0 Content-Type: application/octet-stream; name="Antlib-V1_0.dtd" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="Antlib-V1_0.dtd" ------=_NextPart_000_00AD_01C1557E.55DCD2A0--