001: /*
002: * Copyright 2005 Paul Hinds
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.tp23.antinstaller.runtime.exe;
017:
018: import java.io.File;
019: import java.io.FileOutputStream;
020: import java.io.IOException;
021: import java.io.InputStream;
022: import java.io.PrintStream;
023: import java.net.MalformedURLException;
024: import java.net.URL;
025: import java.net.URLClassLoader;
026: import java.util.Iterator;
027: import java.util.Map;
028: import java.util.Properties;
029:
030: import org.apache.tools.ant.BuildException;
031: import org.apache.tools.ant.BuildListener;
032: import org.apache.tools.ant.DefaultLogger;
033: import org.apache.tools.ant.Diagnostics;
034: import org.apache.tools.ant.Project;
035: import org.apache.tools.ant.ProjectHelper;
036: import org.apache.tools.ant.input.DefaultInputHandler;
037: import org.apache.tools.ant.launch.Locator;
038: import org.tp23.antinstaller.InstallException;
039: import org.tp23.antinstaller.InstallerContext;
040: import org.tp23.antinstaller.antmod.ProjectHelper3;
041: import org.tp23.antinstaller.antmod.RuntimeLauncher;
042: import org.tp23.antinstaller.antmod.taskdefs.CallTargetTask;
043: import org.tp23.antinstaller.antmod.taskdefs.GetResourceTask;
044: import org.tp23.antinstaller.antmod.taskdefs.TickTask;
045: import org.tp23.antinstaller.selfextract.NonExtractor;
046: import org.tp23.antinstaller.selfextract.SelfExtractor;
047:
048: /**
049: *
050: * <p>This AntRunner runs Ant builds directly from a Jar without having to extract
051: * the build.xml to temporary space.</p>
052: * <p> </p>
053: * <p>Copyright: Copyright (c) 2004</p>
054: * <p>Company: tp23</p>
055: * @author Paul Hinds
056: * @version $Id: AntProjectFilter.java,v 1.10 2007/01/28 08:44:39 teknopaul Exp $
057: */
058: public class AntProjectFilter implements ExecuteFilter {
059:
060: //TODO certain jars are added from Ant default directories that are probably not needed
061:
062: private static String antVersion = null;
063:
064: /** The Ant Home property - from default Launcher */
065: public static final String ANTHOME_PROPERTY = "ant.home";
066:
067: /** The location of a per-user library directory - from default Launcher */
068: public static final String USER_LIBDIR = ".ant/lib";
069:
070: public AntProjectFilter() {
071: }
072:
073: /**
074: * run Ant
075: *
076: * @param ctx InstallerContext
077: * @throws InstallException
078: * @todo Implement this org.tp23.antinstaller.runtime.AntRunner method
079: */
080: public void exec(InstallerContext ctx) throws InstallException {
081: if (ctx.getInstaller().isVerbose()) {
082: ctx.log("Starting Ant Project");
083: }
084:
085: try {
086:
087: Project project = new Project();
088: ctx
089: .log("N.B. Ignore missing tools.jar message if you dont run javac");
090: appendClassPath();
091: setAntHome(ctx);
092: project.setCoreLoader(this .getClass().getClassLoader());
093:
094: DefaultLogger antLogger = new DefaultLogger();
095: antLogger.setOutputPrintStream(ctx.getAntOutputRenderer()
096: .getOut());
097: antLogger.setErrorPrintStream(ctx.getAntOutputRenderer()
098: .getErr());
099: antLogger.setMessageOutputLevel(Project.MSG_INFO);
100: BuildListener bl = ctx.getBuildListener();
101: if (bl != null) {
102: project.addBuildListener(bl);
103: }
104: project.addBuildListener(antLogger);
105:
106: /*
107: * Log useful ant task output to the log file to help debugging
108: * and for customer support
109: */
110: final String logFileName = ctx.getLogger().getFileName();
111: if (logFileName != null && logFileName.length() > 0) {
112: PrintStream stream = new PrintStream(
113: new FileOutputStream(logFileName, true), true);
114: DefaultLogger antFileLogger = new DefaultLogger();
115: antFileLogger.setOutputPrintStream(stream);
116: antFileLogger.setErrorPrintStream(stream);
117: int logLevel = (ctx.getInstaller().isVerbose()) ? Project.MSG_VERBOSE
118: : Project.MSG_INFO;
119: antFileLogger.setMessageOutputLevel(logLevel);
120:
121: project.addBuildListener(antFileLogger);
122: }
123:
124: // irrelevant really but might help someone on a command line
125: project.setInputHandler(new DefaultInputHandler());
126: project.fireBuildStarted();
127:
128: project.init();
129: project.setUserProperty("ant.version", getAntVersion());
130:
131: // add properties
132: // N.B. properties are not loaded from the file it exists for debugging installers
133: String arg;
134: String value;
135: Map properties = ctx.getInstaller().getResultContainer()
136: .getAllProperties();
137: Iterator iter = properties.keySet().iterator();
138: while (iter.hasNext()) {
139: arg = (String) iter.next();
140: value = (String) properties.get(arg);
141: project.setUserProperty(arg, value);
142: }
143:
144: // From here we immitate Main
145: try {
146: Diagnostics.validateVersion();
147: } catch (Throwable exc) {
148: // minimal messages for the benefit of the command line install
149: System.err.println("Version error:" + exc.getClass()
150: + "," + exc.getMessage());
151: return;
152: }
153:
154: ProjectHelper helper = new ProjectHelper3();
155: project.addReference("ant.projectHelper", helper);
156: project
157: .addReference(RuntimeLauncher.CONTEXT_REFERENCE,
158: ctx);
159:
160: project.setBaseDir(ctx.getFileRoot());
161: File buildXml = new File(ctx.getFileRoot(), ctx
162: .getAntBuildFile());
163: if (buildXml.exists()) {
164: helper.parse(project, buildXml);
165: project.setUserProperty("ant.file", buildXml
166: .getAbsolutePath());
167: } else {
168: URL buildIS = this .getClass().getResource(
169: "/" + ctx.getAntBuildFile());
170: helper.parse(project, buildIS);
171: project.setUserProperty("ant.file", buildIS
172: .toExternalForm());
173: }
174:
175: File enclosingJar = SelfExtractor.getEnclosingJar(this );
176: if (enclosingJar != null) {
177: project.setUserProperty(
178: NonExtractor.ANTINSTALLER_JAR_PROPERTY,
179: enclosingJar.getAbsolutePath());
180: System.out
181: .println(NonExtractor.ANTINSTALLER_JAR_PROPERTY
182: + enclosingJar.getAbsolutePath());
183: }
184: project.addTaskDefinition("antinstaller-calltarget",
185: CallTargetTask.class);
186: project.addTaskDefinition("antinstaller-tick",
187: TickTask.class);
188: project.addTaskDefinition("antinstaller-getresource",
189: GetResourceTask.class);
190:
191: //what is this !?! project.setKeepGoingMode(keepGoingMode);
192:
193: project.executeTargets(ctx.getInstaller().getTargets(ctx));
194: project.fireBuildFinished(null);
195: ctx.setInstallSucceded(true);
196: ctx.log("Ant finished");
197: } catch (Throwable e) {
198: throw new InstallException("Error running the install, "
199: + e.getMessage(), e);
200: } finally {
201: ctx.getRunner().antFinished();
202: }
203: }
204:
205: public static synchronized String getAntVersion()
206: throws BuildException {
207: if (antVersion == null) {
208: try {
209: Properties props = new Properties();
210: InputStream in = AntProjectFilter.class
211: .getResourceAsStream("/org/apache/tools/ant/version.txt");
212: props.load(in);
213: in.close();
214:
215: StringBuffer msg = new StringBuffer();
216: msg.append("Apache Ant version ");
217: msg.append(props.getProperty("VERSION"));
218: msg.append(" compiled on ");
219: msg.append(props.getProperty("DATE"));
220: antVersion = msg.toString();
221: } catch (IOException ioe) {
222: throw new BuildException(
223: "Could not load the version information:"
224: + ioe.getMessage());
225: } catch (NullPointerException npe) {
226: throw new BuildException(
227: "Could not load the version information.");
228: }
229: }
230: return antVersion;
231: }
232:
233: /**
234: * Append extra Ant jars to the classpath the original classpath
235: * is not removed incase the installer is launched from a script
236: *
237: */
238: private static void appendClassPath() {
239: try {
240: // now update the class.path property
241: StringBuffer baseClassPath = new StringBuffer(System
242: .getProperty("java.class.path"));
243: if (baseClassPath.charAt(baseClassPath.length() - 1) == File.pathSeparatorChar) {
244: baseClassPath.setLength(baseClassPath.length() - 1);
245: }
246: URL[] jars = getLibPaths();
247: for (int i = 0; i < jars.length; ++i) {
248: baseClassPath.append(File.pathSeparatorChar);
249: baseClassPath.append(Locator
250: .fromURI(jars[i].toString()));
251: }
252:
253: System.setProperty("java.class.path", baseClassPath
254: .toString());
255:
256: URLClassLoader loader = new URLClassLoader(jars);
257: Thread.currentThread().setContextClassLoader(loader);
258: } catch (MalformedURLException e) {
259: // swallow exception, normally all resources are already loaded
260: System.err.println("Invalid Jar path");
261: }
262: }
263:
264: /**
265: * Ant home is not a requirement but can exist prior to loading
266: * the default Ant mechanism of using the current Jars parent
267: * is consipicuously absent, do not rely on ANT_HOME out side of a
268: * controlled environment (e.g. a normal install)
269: */
270: private static void setAntHome(InstallerContext ctx) {
271: String antHomeProperty = System.getProperty(ANTHOME_PROPERTY);
272: if (antHomeProperty == null) {
273: System.setProperty(ANTHOME_PROPERTY, ctx.getFileRoot()
274: .getAbsolutePath());
275: }
276: }
277:
278: /**
279: * To maintain compatability with previous verisons currently the only
280: * Ant command line argument supported is the -lib parameter with the value
281: * "antlib"
282: * @TODO this should probably be removed
283: * @throws MalformedURLException
284: */
285: private static URL[] getLibPaths() throws MalformedURLException {
286:
287: // add all Jars from the ./antlib directory at the time of the build
288: // this is NOT based on ANT_HOME
289: URL[] libJars = Locator.getLocationURLs(new File("antlib"));
290:
291: // add all the Jars from ~/.ant/lib
292: // this is probably irrelevant for a normal install
293: URL[] userJars = Locator.getLocationURLs(new File(USER_LIBDIR));
294:
295: // Now try and find JAVA_HOME
296: File toolsJar = Locator.getToolsJar();
297:
298: int jarsLength = libJars.length + userJars.length
299: + (toolsJar != null ? 1 : 0);
300: URL[] allJars = new URL[jarsLength];
301: int i = 0;
302: if (toolsJar != null) {
303: allJars[i++] = toolsJar.toURL();
304: }
305: if (libJars.length != 0) {
306: System.arraycopy(libJars, 0, allJars, i, libJars.length);
307: i += libJars.length;
308: }
309: if (userJars.length != 0) {
310: System.arraycopy(userJars, 0, allJars, i, userJars.length);
311: //i+=userJars.length;
312: //assert(allJars.length=i-1);
313: }
314: return libJars;
315: }
316:
317: }
|