Source Code Cross Referenced for SelfModifier.java in  » Installer » IzPack » com » izforge » izpack » uninstaller » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Installer » IzPack » com.izforge.izpack.uninstaller 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * IzPack - Copyright 2001-2008 Julien Ponge, All Rights Reserved.
003:         * 
004:         * http://izpack.org/
005:         * http://izpack.codehaus.org/
006:         * 
007:         * Copyright 2004 Chadwick McHenry
008:         * 
009:         * Licensed under the Apache License, Version 2.0 (the "License");
010:         * you may not use this file except in compliance with the License.
011:         * You may obtain a copy of the License at
012:         * 
013:         *     http://www.apache.org/licenses/LICENSE-2.0
014:         *     
015:         * Unless required by applicable law or agreed to in writing, software
016:         * distributed under the License is distributed on an "AS IS" BASIS,
017:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018:         * See the License for the specific language governing permissions and
019:         * limitations under the License.
020:         */
021:
022:        package com.izforge.izpack.uninstaller;
023:
024:        import java.io.BufferedOutputStream;
025:        import java.io.BufferedReader;
026:        import java.io.File;
027:        import java.io.FileOutputStream;
028:        import java.io.IOException;
029:        import java.io.InputStream;
030:        import java.io.InputStreamReader;
031:        import java.io.OutputStream;
032:        import java.io.PrintStream;
033:        import java.io.PrintWriter;
034:        import java.io.RandomAccessFile;
035:        import java.lang.reflect.Method;
036:        import java.lang.reflect.Modifier;
037:        import java.net.URI;
038:        import java.net.URL;
039:        import java.text.CharacterIterator;
040:        import java.text.SimpleDateFormat;
041:        import java.text.StringCharacterIterator;
042:        import java.util.Date;
043:        import java.util.Enumeration;
044:        import java.util.jar.JarFile;
045:        import java.util.jar.JarEntry;
046:        import java.util.zip.ZipEntry;
047:
048:        import com.izforge.izpack.util.OsVersion;
049:        import com.izforge.izpack.installer.MultiVolumeInstaller;
050:
051:        /**
052:         * Allows an application to modify the jar file from which it came, including outright deletion. The
053:         * jar file of an app is usually locked when java is run so this is normally not possible.
054:         * <p>
055:         * 
056:         * Create a SelfModifier with a target method, then invoke the SelfModifier with arguments to be
057:         * passed to the target method. The jar file containing the target method's class (obtained by
058:         * reflection) will be extracted to a temporary directory, and a new java process will be spawned to
059:         * invoke the target method. The original jar file may now be modified.
060:         * <p>
061:         * 
062:         * If the constructor or invoke() methods fail, it is generally because secondary java processes
063:         * could not be started.
064:         * 
065:         * <b>Requirements</b>
066:         * <ul>
067:         * <li>The target method, and all it's required classes must be in a jar file.
068:         * <li>The Self Modifier, and its inner classes must also be in the jar file.
069:         * </ul>
070:         * 
071:         * There are three system processes (or "phases") involved, the first invoked by the user, the
072:         * second and third by the SelfModifier.
073:         * <p>
074:         * 
075:         * <b>Phase 1:</b>
076:         * <ol>
077:         * <li>Program is launched, SelfModifier is created, invoke(String[]) is called
078:         * <li>A temporary directory (or "sandbox") is created in the default temp directory, and the jar
079:         * file contents ar extracted into it
080:         * <li>Phase 2 is spawned using the sandbox as it's classpath, SelfModifier as the main class, the
081:         * arguments to "invoke(String[])" as the main arguments, and the <a
082:         * href="#selfmodsysprops">SelfModifier system properties</a> set.
083:         * <li>Immidiately exit so the system unlocks the jar file
084:         * </ol>
085:         * 
086:         * <b>Phase 2:</b>
087:         * <ol>
088:         * <li>Initializes from system properties.
089:         * <li>Spawn phase 3 exactly as phase 2 except the self.modifier.phase system properties set to 3.
090:         * <li>Wait for phase 3 to die
091:         * <li>Delete the temporary sandbox
092:         * </ol>
093:         * 
094:         * <b>Phase 3:</b>
095:         * <ol>
096:         * <li>Initializes from system properties.
097:         * <li>Redirect std err stream to the log
098:         * <li>Invoke the target method with arguments we were given
099:         * <li>The target method is expected to call exit(), or to not start any looping threads (e.g. AWT
100:         * thread). In other words, the target is the new "main" method.
101:         * </ol>
102:         * 
103:         * <a name="selfmodsysprops"><b>SelfModifier system properties</b></a> used to pass information
104:         * between processes. <table border="1">
105:         * <tr>
106:         * <th>Constant
107:         * <th>System property
108:         * <th>description</tr>
109:         * <tr>
110:         * <td><a href="#BASE_KEY">BASE_KEY</a>
111:         * <td>self.mod.jar
112:         * <td>base path to log file and sandbox dir</tr>
113:         * <tr>
114:         * <td><a href="#JAR_KEY">JAR_KEY</a>
115:         * <td>self.mod.class
116:         * <td>path to original jar file</tr>
117:         * <tr>
118:         * <td><a href="#CLASS_KEY">CLASS_KEY</a>
119:         * <td>self.mod.method
120:         * <td>class of target method</tr>
121:         * <tr>
122:         * <td><a href="#METHOD_KEY">METHOD_KEY</a>
123:         * <td>self.mod.phase
124:         * <td>name of method to be invoked in sandbox</tr>
125:         * <tr>
126:         * <td><a href="#PHASE_KEY">PHASE_KEY</a>
127:         * <td>self.mod.base
128:         * <td>phase of operation to run</tr>
129:         * </table>
130:         * 
131:         * @author Chadwick McHenry
132:         * @version 1.0
133:         */
134:        public class SelfModifier {
135:
136:            /** System property name of base for log and sandbox of secondary processes. */
137:            public static final String BASE_KEY = "self.mod.base";
138:
139:            /** System property name of original jar file containing application. */
140:            public static final String JAR_KEY = "self.mod.jar";
141:
142:            /** System property name of class declaring target method. */
143:            public static final String CLASS_KEY = "self.mod.class";
144:
145:            /** System property name of target method to invoke in secondary process. */
146:            public static final String METHOD_KEY = "self.mod.method";
147:
148:            /** System property name of phase (1, 2, or 3) indicator. */
149:            public static final String PHASE_KEY = "self.mod.phase";
150:
151:            /** Base prefix name for sandbox and log, used only in phase 1. */
152:            private String prefix = "izpack";
153:
154:            /** Target method to be invoked in sandbox. */
155:            private Method method = null;
156:
157:            /** Log for phase 2 and 3, because we can't capture the stdio from them. */
158:            private File logFile = null;
159:
160:            /** Directory which we extract too, invoke from, and finally delete. */
161:            private File sandbox = null;
162:
163:            /** Original jar file program was launched from. */
164:            private File jarFile = null;
165:
166:            /** Current phase of execution: 1, 2, or 3. */
167:            private int phase = 0;
168:
169:            /** For logging time. */
170:            private SimpleDateFormat isoPoint = new SimpleDateFormat(
171:                    "yyyy-MM-dd'T'HH:mm:ss.SSS");
172:
173:            private Date date = new Date();
174:
175:            public static void test(String[] args) {
176:                // open a File for random access in the sandbox, which will cause
177:                // deletion
178:                // of the file and its parent directories to fail until it is closed (by
179:                // virtue of this java process halting)
180:                try {
181:                    File sandbox = new File(System.getProperty(BASE_KEY) + ".d");
182:                    File randFile = new File(sandbox, "RandomAccess.tmp");
183:                    RandomAccessFile rand = new RandomAccessFile(randFile, "rw");
184:                    rand
185:                            .writeChars("Just a test: The jvm has to close 'cuz I won't!\n");
186:
187:                    System.err.print("Deleting sandbox: ");
188:                    deleteTree(sandbox);
189:                    System.err.println(sandbox.exists() ? "FAILED"
190:                            : "SUCCEEDED");
191:                } catch (Exception x) {
192:                    System.err.println(x.getMessage());
193:                    x.printStackTrace();
194:                }
195:            }
196:
197:            public static void main(String[] args) {
198:                // phase 1 already set up the sandbox and spawned phase 2.
199:                // phase 2 creates the log, spawns phase 3 and waits
200:                // phase 3 invokes method and returns. method must kill all it's threads
201:
202:                try {
203:                    // all it's attributes are retrieved from system properties
204:                    SelfModifier selfModifier = new SelfModifier();
205:
206:                    // phase 2: invoke a process for phase 3, wait, and clean up
207:                    if (selfModifier.phase == 2)
208:                        selfModifier.invoke2(args);
209:
210:                    // phase 3: invoke method and die
211:                    else if (selfModifier.phase == 3)
212:                        selfModifier.invoke3(args);
213:                } catch (IOException ioe) {
214:                    System.err.println("Error invoking a secondary phase");
215:                    System.err
216:                            .println("Note that this program is only intended as a secondary process");
217:                    ioe.printStackTrace();
218:                }
219:            }
220:
221:            /**
222:             * Internal constructor where target class and method are obtained from system properties.
223:             * 
224:             * @throws IOException for errors getting to the sandbox.
225:             * @throws SecurityException if access to the target method is denied
226:             */
227:            private SelfModifier() throws IOException {
228:                phase = Integer.parseInt(System.getProperty(PHASE_KEY));
229:
230:                String cName = System.getProperty(CLASS_KEY);
231:                String tName = System.getProperty(METHOD_KEY);
232:
233:                jarFile = new File(System.getProperty(JAR_KEY));
234:                logFile = new File(System.getProperty(BASE_KEY) + ".log");
235:                sandbox = new File(System.getProperty(BASE_KEY) + ".d");
236:
237:                // retrieve refrence to target method
238:                try {
239:                    Class clazz = Class.forName(cName);
240:                    Method method = clazz.getMethod(tName,
241:                            new Class[] { String[].class });
242:
243:                    initMethod(method);
244:                } catch (ClassNotFoundException x1) {
245:                    log("No class found for " + cName);
246:                } catch (NoSuchMethodException x2) {
247:                    log("No method " + tName + " found in " + cName);
248:                }
249:            }
250:
251:            /**
252:             * Creates a SelfModifier which will invoke the target method in a separate process from which
253:             * it may modify it's own jar file.
254:             * 
255:             * The target method must be public, static, and take a single array of strings as its only
256:             * parameter. The class which declares the method must also be public. Reflection is used to
257:             * ensure this.
258:             * 
259:             * @param method a public, static method that accepts a String array as it's only parameter. Any
260:             * return value is ignored.
261:             * 
262:             * @throws NullPointerException if <code>method</code> is null
263:             * @throws IllegalArgumentException if <code>method</code> is not public, static, and take a
264:             * String array as it's only argument, or of it's declaring class is not public.
265:             * @throws IllegalStateException if process was not invoked from a jar file, or an IOExceptioin
266:             * occured while accessing it
267:             * @throws IOException if java is unable to be executed as a separte process
268:             * @throws SecurityException if access to the method, or creation of a subprocess is denied
269:             */
270:            public SelfModifier(Method method) throws IOException {
271:                phase = 1;
272:                initJavaExec();
273:                initMethod(method);
274:            }
275:
276:            /**
277:             * Check the method for the required properties (public, static, params:(String[])).
278:             * 
279:             * @throws NullPointerException if <code>method</code> is null
280:             * @throws IllegalArgumentException if <code>method</code> is not public, static, and take a
281:             * String array as it's only argument, or of it's declaring class is not public.
282:             * @throws SecurityException if access to the method is denied
283:             */
284:            private void initMethod(Method method) {
285:                int mod = method.getModifiers();
286:                if ((mod & Modifier.PUBLIC) == 0
287:                        || (mod & Modifier.STATIC) == 0)
288:                    throw new IllegalArgumentException(
289:                            "Method not public and static");
290:
291:                Class[] params = method.getParameterTypes();
292:                if (params.length != 1
293:                        || !params[0].isArray()
294:                        || !"java.lang.String".equals(params[0]
295:                                .getComponentType().getName()))
296:                    throw new IllegalArgumentException(
297:                            "Method must accept String array");
298:
299:                Class clazz = method.getDeclaringClass();
300:                mod = clazz.getModifiers();
301:                if ((mod & Modifier.PUBLIC) == 0
302:                        || (mod & Modifier.INTERFACE) != 0)
303:                    throw new IllegalArgumentException(
304:                            "Method must be in a public class");
305:
306:                this .method = method;
307:            }
308:
309:            /**
310:             * This call ensures that java can be exec'd in a separate process.
311:             * 
312:             * @throws IOException if an I/O error occurs, indicating java is unable to be exec'd
313:             * @throws SecurityException if a security manager exists and doesn't allow creation of a
314:             * subprocess
315:             */
316:            private void initJavaExec() throws IOException {
317:                try {
318:                    Process p = Runtime.getRuntime().exec(javaCommand());
319:
320:                    new StreamProxy(p.getErrorStream(), "err").start();
321:                    new StreamProxy(p.getInputStream(), "out").start();
322:                    p.getOutputStream().close();
323:
324:                    // even if it returns an error code, it was at least found
325:                    p.waitFor();
326:                } catch (InterruptedException ie) {
327:                    throw new IOException("Unable to create a java subprocess");
328:                }
329:            }
330:
331:            /***********************************************************************************************
332:             * --------------------------------------------------------------------- Phase 1 (call from
333:             * external spawn phase 2) ---------------------------------------------------------------------
334:             */
335:
336:            /**
337:             * Invoke the target method in a separate process from which it may modify it's own jar file.
338:             * This method does not normally return. After spawning the secondary process, the current
339:             * process must die before the jar file is unlocked, therefore calling this method is akin to
340:             * calling {@link System#exit(int)}.
341:             * <p>
342:             * 
343:             * The contents of the current jar file are extracted copied to a 'sandbox' directory from which
344:             * the method is invoked. The path to the original jar file is placed in the system property
345:             * {@link #JAR_KEY}.
346:             * <p>
347:             * 
348:             * @param args arguments to pass to the target method. May be empty or null to indicate no
349:             * arguments.
350:             * 
351:             * @throws IOException for lots of things
352:             * @throws IllegalStateException if method's class was not loaded from a jar
353:             */
354:            public void invoke(String[] args) throws IOException {
355:                // Initialize sandbox and log file to be unique, but similarly named
356:                while (true) {
357:                    logFile = File.createTempFile(prefix, ".log");
358:                    String f = logFile.toString();
359:                    sandbox = new File(f.substring(0, f.length() - 4) + ".d");
360:
361:                    // check if the similarly named directory is free
362:                    if (!sandbox.exists())
363:                        break;
364:
365:                    logFile.delete();
366:                }
367:                if (!sandbox.mkdir())
368:                    throw new RuntimeException("Failed to create temp dir: "
369:                            + sandbox);
370:
371:                sandbox = sandbox.getCanonicalFile();
372:                logFile = logFile.getCanonicalFile();
373:
374:                jarFile = findJarFile(
375:                        (Class<MultiVolumeInstaller>) method
376:                                .getDeclaringClass()).getCanonicalFile();
377:                if (jarFile == null)
378:                    throw new IllegalStateException(
379:                            "SelfModifier must be in a jar file");
380:                log("JarFile: " + jarFile);
381:
382:                extractJarFile();
383:
384:                if (args == null)
385:                    args = new String[0];
386:                spawn(args, 2);
387:
388:                // finally, if all went well, the invoking process must exit
389:                log("Exit");
390:                System.exit(0);
391:            }
392:
393:            /**
394:             * Run a new jvm with all the system parameters needed for phases 2 and 3.
395:             * 
396:             * @throws IOException if there is an error getting the cononical name of a path
397:             */
398:            private Process spawn(String[] args, int nextPhase)
399:                    throws IOException {
400:                String base = logFile.getAbsolutePath();
401:                base = base.substring(0, base.length() - 4);
402:
403:                // invoke from tmpdir, passing target method arguments as args, and
404:                // SelfModifier parameters as sustem properties
405:                String[] javaCmd = new String[] {
406:                        javaCommand(),
407:                        "-classpath",
408:                        sandbox.getAbsolutePath(),
409:                        "-D" + BASE_KEY + "=" + base,
410:                        "-D" + JAR_KEY + "=" + jarFile.getPath(),
411:                        "-D" + CLASS_KEY + "="
412:                                + method.getDeclaringClass().getName(),
413:                        "-D" + METHOD_KEY + "=" + method.getName(),
414:                        "-D" + PHASE_KEY + "=" + nextPhase,
415:                        getClass().getName() };
416:
417:                String[] entireCmd = new String[javaCmd.length + args.length];
418:                System.arraycopy(javaCmd, 0, entireCmd, 0, javaCmd.length);
419:                System.arraycopy(args, 0, entireCmd, javaCmd.length,
420:                        args.length);
421:
422:                StringBuffer sb = new StringBuffer("Spawning phase ");
423:                sb.append(nextPhase).append(": ");
424:                for (String anEntireCmd : entireCmd) {
425:                    sb.append("\n\t").append(anEntireCmd);
426:                }
427:                log(sb.toString());
428:
429:                // Just invoke it and let it go, the exception will be caught above
430:                // Won't compile on < jdk1.3, but will run on jre1.2
431:                if (JAVA_SPECIFICATION_VERSION < 1.3)
432:                    return Runtime.getRuntime().exec(entireCmd, null);
433:                else
434:                    return Runtime.getRuntime().exec(entireCmd, null, null); // workDir);
435:            }
436:
437:            /**
438:             * Retrieve the jar file the specified class was loaded from.
439:             * 
440:             * @return null if file was not loaded from a jar file
441:             * @throws SecurityException if access to is denied by SecurityManager
442:             */
443:            public static File findJarFile(Class<MultiVolumeInstaller> clazz) {
444:                String resource = clazz.getName().replace('.', '/') + ".class";
445:
446:                URL url = ClassLoader.getSystemResource(resource);
447:                if (!"jar".equals(url.getProtocol()))
448:                    return null;
449:
450:                String path = url.getFile();
451:                // starts at "file:..." (use getPath() as of 1.3)
452:                path = path.substring(0, path.lastIndexOf('!'));
453:
454:                File file;
455:
456:                // getSystemResource() returns a valid URL (eg. spaces are %20), but a
457:                // file
458:                // Constructed w/ it will expect "%20" in path. URI and File(URI)
459:                // properly
460:                // deal with escaping back and forth, but didn't exist until 1.4
461:                if (JAVA_SPECIFICATION_VERSION < 1.4)
462:                    file = new File(fromURI(path));
463:                else
464:                    file = new File(URI.create(path));
465:
466:                return file;
467:            }
468:
469:            /**
470:             * @throws IOException
471:             */
472:            private void extractJarFile() throws IOException {
473:                byte[] buf = new byte[5120];
474:                int extracted = 0;
475:                InputStream in = null;
476:                OutputStream out = null;
477:                String MANIFEST = "META-INF/MANIFEST.MF";
478:
479:                JarFile jar = new JarFile(jarFile, true);
480:
481:                try {
482:                    Enumeration<JarEntry> entries = jar.entries();
483:                    while (entries.hasMoreElements()) {
484:                        ZipEntry entry = entries.nextElement();
485:                        if (entry.isDirectory())
486:                            continue;
487:
488:                        String pathname = entry.getName();
489:                        if (MANIFEST.equals(pathname.toUpperCase()))
490:                            continue;
491:
492:                        in = jar.getInputStream(entry);
493:
494:                        File outFile = new File(sandbox, pathname);
495:                        File parent = outFile.getParentFile();
496:                        if (parent != null && !parent.exists())
497:                            parent.mkdirs();
498:
499:                        out = new BufferedOutputStream(new FileOutputStream(
500:                                outFile));
501:
502:                        int n;
503:                        while ((n = in.read(buf, 0, buf.length)) > 0)
504:                            out.write(buf, 0, n);
505:
506:                        out.close();
507:                        extracted++;
508:                    }
509:                    jar.close();
510:
511:                    log("Extracted " + extracted + " file"
512:                            + (extracted > 1 ? "s" : "") + " into "
513:                            + sandbox.getPath());
514:                } finally {
515:                    try {
516:                        jar.close();
517:                    } catch (IOException ioe) {
518:                    }
519:                    if (out != null) {
520:                        try {
521:                            out.close();
522:                        } catch (IOException ioe) {
523:                        }
524:                    }
525:                    if (in != null) {
526:                        try {
527:                            in.close();
528:                        } catch (IOException ioe) {
529:                        }
530:                    }
531:                }
532:            }
533:
534:            /***********************************************************************************************
535:             * --------------------------------------------------------------------- Phase 2 (spawn the
536:             * phase 3 and clean up) ---------------------------------------------------------------------
537:             */
538:
539:            /**
540:             * Invoke phase 2, which starts phase 3, then cleans up the sandbox. This is needed because
541:             * GUI's often call the exit() method to kill the AWT thread, and early versions of java did not
542:             * have exit hooks. In order to delete the sandbox on exit we invoke method in separate process
543:             * and wait for that process to complete. Even worse, resources in the jar may be locked by the
544:             * target process, which would prevent the sandbox from being deleted as well.
545:             */
546:            private void invoke2(String[] args) {
547:
548:                int retVal = -1;
549:                try {
550:                    // TODO: in jre 1.2, Phs1 consistently needs more time to unlock the
551:                    // original jar. Phs2 should wait to invoke Phs3 until it knows its
552:                    // parent (Phs1) has died, but Process.waitFor() only works on
553:                    // children. Can we see when a parent dies, or /this/ Process
554:                    // becomes
555:                    // orphaned?
556:                    try {
557:                        Thread.sleep(1000);
558:                    } catch (Exception x) {
559:                    }
560:
561:                    // spawn phase 3, capture its stdio and wait for it to exit
562:                    Process p = spawn(args, 3);
563:
564:                    new StreamProxy(p.getErrorStream(), "err", log).start();
565:                    new StreamProxy(p.getInputStream(), "out", log).start();
566:                    p.getOutputStream().close();
567:
568:                    try {
569:                        retVal = p.waitFor();
570:                    } catch (InterruptedException e) {
571:                        log(e);
572:                    }
573:
574:                    // clean up and go
575:                    log("deleteing sandbox");
576:                    deleteTree(sandbox);
577:                } catch (Exception e) {
578:                    log(e);
579:                }
580:                log("Phase 3 return value = " + retVal);
581:            }
582:
583:            /** Recursively delete a file structure. */
584:            public static boolean deleteTree(File file) {
585:                if (file.isDirectory()) {
586:                    File[] files = file.listFiles();
587:                    for (File file1 : files) {
588:                        deleteTree(file1);
589:                    }
590:                }
591:                return file.delete();
592:            }
593:
594:            /***********************************************************************************************
595:             * --------------------------------------------------------------------- Phase 3 (invoke method,
596:             * let it go as long as it likes)
597:             * ---------------------------------------------------------------------
598:             */
599:
600:            /**
601:             * Invoke the target method and let it run free!
602:             */
603:            private void invoke3(String[] args) {
604:                // std io is being redirected to the log
605:                try {
606:                    errlog("Invoking method: "
607:                            + method.getDeclaringClass().getName() + "."
608:                            + method.getName() + "(String[] args)");
609:
610:                    method.invoke(null, new Object[] { args });
611:                } catch (Throwable t) {
612:                    errlog(t.getMessage());
613:                    t.printStackTrace();
614:                    errlog("exiting");
615:                    System.err.flush();
616:                    System.exit(31);
617:                }
618:
619:                errlog("Method returned, waiting for other threads");
620:                System.err.flush();
621:                // now let the method call exit...
622:            }
623:
624:            /***********************************************************************************************
625:             * --------------------------------------------------------------------- Logging
626:             * ---------------------------------------------------------------------
627:             */
628:
629:            PrintStream log = null;
630:
631:            private void errlog(String msg) {
632:                date.setTime(System.currentTimeMillis());
633:                System.err.println(isoPoint.format(date) + " Phase " + phase
634:                        + ": " + msg);
635:            }
636:
637:            private PrintStream checkLog() {
638:                try {
639:                    if (log == null)
640:                        log = new PrintStream(new FileOutputStream(logFile
641:                                .toString(), true));
642:                } catch (IOException x) {
643:                    System.err.println("Phase " + phase + " log err: "
644:                            + x.getMessage());
645:                    x.printStackTrace();
646:                }
647:                date.setTime(System.currentTimeMillis());
648:                return log;
649:            }
650:
651:            private void log(Throwable t) {
652:                if (checkLog() != null) {
653:                    log.println(isoPoint.format(date) + " Phase " + phase
654:                            + ": " + t.getMessage());
655:                    t.printStackTrace(log);
656:                }
657:            }
658:
659:            private void log(String msg) {
660:                if (checkLog() != null)
661:                    log.println(isoPoint.format(date) + " Phase " + phase
662:                            + ": " + msg);
663:            }
664:
665:            public static class StreamProxy extends Thread {
666:
667:                InputStream in;
668:
669:                String name;
670:
671:                OutputStream out;
672:
673:                public StreamProxy(InputStream in, String name) {
674:                    this (in, name, null);
675:                }
676:
677:                public StreamProxy(InputStream in, String name, OutputStream out) {
678:                    this .in = in;
679:                    this .name = name;
680:                    this .out = out;
681:                }
682:
683:                public void run() {
684:                    try {
685:                        PrintWriter pw = null;
686:                        if (out != null)
687:                            pw = new PrintWriter(out);
688:
689:                        BufferedReader br = new BufferedReader(
690:                                new InputStreamReader(in));
691:                        String line;
692:                        while ((line = br.readLine()) != null) {
693:                            if (pw != null)
694:                                pw.println(line);
695:                            // System.out.println(name + ">" + line);
696:                        }
697:                        if (pw != null)
698:                            pw.flush();
699:                    } catch (IOException ioe) {
700:                        ioe.printStackTrace();
701:                    }
702:                }
703:            }
704:
705:            /***********************************************************************************************
706:             * --------------------------------------------------------------------- Apache ant code
707:             * ---------------------------------------------------------------------
708:             */
709:            // This was stolen (and specialized from much more modular code) from the
710:            // jakarta ant class org.apache.tools.ant.taskdefs.condition.Os
711:            // See the javaCommand() method.
712:            private static final float JAVA_SPECIFICATION_VERSION = Float
713:                    .parseFloat(System
714:                            .getProperty("java.specification.version"));
715:
716:            private static final String JAVA_HOME = System
717:                    .getProperty("java.home");
718:
719:            /**
720:             * Constructs a file path from a <code>file:</code> URI.
721:             * 
722:             * <p>
723:             * Will be an absolute path if the given URI is absolute.
724:             * </p>
725:             * 
726:             * <p>
727:             * Swallows '%' that are not followed by two characters, doesn't deal with non-ASCII characters.
728:             * </p>
729:             * 
730:             * @param uri the URI designating a file in the local filesystem.
731:             * @return the local file system path for the file.
732:             */
733:            public static String fromURI(String uri) {
734:                if (!uri.startsWith("file:"))
735:                    throw new IllegalArgumentException(
736:                            "Can only handle file: URIs");
737:
738:                if (uri.startsWith("file://"))
739:                    uri = uri.substring(7);
740:                else
741:                    uri = uri.substring(5);
742:
743:                uri = uri.replace('/', File.separatorChar);
744:                if (File.pathSeparatorChar == ';' && uri.startsWith("\\")
745:                        && uri.length() > 2
746:                        && Character.isLetter(uri.charAt(1))
747:                        && uri.lastIndexOf(':') > -1) {
748:                    uri = uri.substring(1);
749:                }
750:
751:                StringBuffer sb = new StringBuffer();
752:                CharacterIterator iter = new StringCharacterIterator(uri);
753:                for (char c = iter.first(); c != CharacterIterator.DONE; c = iter
754:                        .next()) {
755:                    if (c == '%') {
756:                        char c1 = iter.next();
757:                        if (c1 != CharacterIterator.DONE) {
758:                            int i1 = Character.digit(c1, 16);
759:                            char c2 = iter.next();
760:                            if (c2 != CharacterIterator.DONE) {
761:                                int i2 = Character.digit(c2, 16);
762:                                sb.append((char) ((i1 << 4) + i2));
763:                            }
764:                        }
765:                    } else {
766:                        sb.append(c);
767:                    }
768:                }
769:
770:                String path = sb.toString();
771:                return path;
772:            }
773:
774:            private static String addExtension(String command) {
775:                // This is the most common extension case - exe for windows and OS/2,
776:                // nothing for *nix.
777:                return command
778:                        + (OsVersion.IS_WINDOWS || OsVersion.IS_OS2 ? ".exe"
779:                                : "");
780:            }
781:
782:            private static String javaCommand() {
783:                // This was stolen (and specialized from much more modular code) from
784:                // the
785:                // jakarta ant classes Os & JavaEnvUtils. Also see the following
786:                // org.apache.tools.ant.taskdefs.Java
787:                // org.apache.tools.ant.taskdefs.Execute
788:                // org.apache.tools.ant.taskdefs.condition.Os
789:                // org.apache.tools.ant.util.CommandlineJava
790:                // org.apache.tools.ant.util.JavaEnvUtils
791:                // org.apache.tools.ant.util.FileUtils
792:                // TODO: I didn't copy nearly all of their conditions
793:                String executable = addExtension("java");
794:                String dir = new File(JAVA_HOME + "/bin").getAbsolutePath();
795:                File jExecutable = new File(dir, executable);
796:
797:                // Unfortunately on Windows java.home doesn't always refer
798:                // to the correct location, so we need to fall back to
799:                // assuming java is somewhere on the PATH.
800:                if (!jExecutable.exists())
801:                    return executable;
802:                return jExecutable.getAbsolutePath();
803:            }
804:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.