001    /**
002     *
003     * Licensed to the Apache Software Foundation (ASF) under one or more
004     * contributor license agreements.  See the NOTICE file distributed with
005     * this work for additional information regarding copyright ownership.
006     * The ASF licenses this file to You under the Apache License, Version 2.0
007     * (the "License"); you may not use this file except in compliance with
008     * the License.  You may obtain a copy of the License at
009     *
010     * http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    package com.hs.mail.container;
019    
020    import java.io.File;
021    import java.lang.reflect.InvocationTargetException;
022    import java.lang.reflect.Method;
023    import java.net.JarURLConnection;
024    import java.net.MalformedURLException;
025    import java.net.URI;
026    import java.net.URL;
027    import java.net.URLClassLoader;
028    import java.util.ArrayList;
029    import java.util.Arrays;
030    import java.util.Comparator;
031    import java.util.Iterator;
032    import java.util.LinkedList;
033    import java.util.List;
034    
035    public class Main {
036    
037        private File appHome;
038            private ClassLoader classLoader;
039            private List classpaths = new ArrayList(5);
040    
041            public static void main(String[] args) {
042                    Main app = new Main();
043    
044                    if (args.length < 1) {
045                            System.out.println("Main class was not specified");
046                            System.exit(0);
047                    }
048                    
049                    // Convert arguments to collection for easier management
050                    List tokens = new LinkedList(Arrays.asList(args));
051                    String taskClass = (String) tokens.remove(0);
052            
053                    // Add the following to the classpath:
054                    // ${app.home}/lib
055                    //
056                    app.addClassPath(new File(app.getAppHome(), "lib"));
057                    
058                    try {
059                            app.runTaskClass(taskClass, tokens);
060                    } catch (ClassNotFoundException e) {
061                            System.out.println("Could not load class: " + e.getMessage());
062                            try {
063                                    ClassLoader cl = app.getClassLoader();
064                                    if (cl != null) {
065                                            System.out.println("Class loader setup: ");
066                                            printClassLoaderTree(cl);
067                                    }
068                            } catch (MalformedURLException me) {
069                            }
070                    } catch (Throwable e) {
071                            System.out.println("Failed to execute main task. Reason: " + e);
072                    }
073            }
074    
075            /**
076             * Print out what's in the classloader tree being used. 
077             */
078            private static int printClassLoaderTree(ClassLoader cl) {
079                    int depth = 0;
080                    if (cl.getParent() != null) {
081                            depth = printClassLoaderTree(cl.getParent()) + 1;
082                    }
083                    
084                    StringBuffer indent = new StringBuffer();
085                    for (int i = 0; i < depth; i++) {
086                            indent.append("  ");
087                    }
088                    
089                    if (cl instanceof URLClassLoader) {
090                            URLClassLoader ucl = (URLClassLoader) cl;
091                            System.out.println(indent + cl.getClass().getName() + " {");
092                            URL[] urls = ucl.getURLs();
093                            for (int i = 0; i < urls.length; i++) {
094                                    System.out.println(indent + "  " + urls[i]);
095                            }
096                            System.out.println(indent + "}");
097                    } else {
098                            System.out.println(indent + cl.getClass().getName());
099                    }
100                    return depth;
101            }
102    
103            public void runTaskClass(String taskClass, List tokens) throws Throwable {
104                    ClassLoader cl = getClassLoader();
105    
106                    // Use reflection to run the task.
107                    try {
108                            String[] args = (String[]) tokens.toArray(new String[tokens.size()]);
109                            Class task = cl.loadClass(taskClass);
110                            Method runTask = task.getMethod("main", new Class[] { String[].class });
111                            runTask.invoke(task.newInstance(), new Object[] { args });
112                    } catch (InvocationTargetException e) {
113                            throw e.getCause();
114                    }
115            }
116            
117        private void addClassPath(File file) {
118            classpaths.add(file);
119            }
120    
121            public ClassLoader getClassLoader() throws MalformedURLException {
122                    if (classLoader == null) {
123                            // Setup the ClassLoader
124                            classLoader = Main.class.getClassLoader();
125                            if (!classpaths.isEmpty()) {
126                                    ArrayList urls = new ArrayList();
127                                    for (Iterator iter = classpaths.iterator(); iter.hasNext();) {
128                                            File dir = (File) iter.next();
129                                            if (dir.isDirectory()) {
130                                                    File[] files = dir.listFiles();
131                                                    if (files != null) {
132                                                            // Sort the jars so that classpath built is
133                                                            // consistently in the same order. Also allows us to
134                                                            // use jar names to control classpath order.
135                                                            Arrays.sort(files, new Comparator() {
136                                                                    public int compare(Object o1, Object o2) {
137                                                                            File f1 = (File) o1;
138                                                                            File f2 = (File) o2;
139                                                                            return f1.getName().compareTo(f2.getName());
140                                                                    }
141                                                            });
142                                                            for (int j = 0; j < files.length; j++) {
143                                                                    if (files[j].getName().endsWith(".zip")
144                                                                                    || files[j].getName().endsWith(".jar")) {
145                                                                            urls.add(files[j].toURL());
146                                                                    }
147                                                            }
148                                                    }
149                                            }
150                                    }
151                                    URL u[] = new URL[urls.size()];
152                                    urls.toArray(u);
153                                    classLoader = new URLClassLoader(u, classLoader);
154                            }
155                            Thread.currentThread().setContextClassLoader(classLoader);
156                    }
157                    return classLoader;
158            }
159            
160            public void setAppHome(File appHome) {
161                    this.appHome = appHome;
162            }
163    
164            public File getAppHome() {
165                    if (appHome == null) {
166                            if (System.getProperty("app.home") != null) {
167                                    appHome = new File(System.getProperty("app.home"));
168                            }
169                            if (appHome == null) {
170                                    // guess from the location of the jar
171                                    URL url = Main.class.getClassLoader().getResource("com/hs/mail/container/Main.class");
172                                    if (url != null) {
173                                            try {
174                                                    JarURLConnection jarConnection = (JarURLConnection) url.openConnection();
175                                                    url = jarConnection.getJarFileURL();
176                                                    URI baseURI = new URI(url.toString()).resolve("..");
177                                                    appHome = new File(baseURI).getCanonicalFile();
178                                                    System.setProperty("app.home", appHome.getAbsolutePath());
179                                            } catch (Exception ignored) {
180                                            }
181                                    }
182                            }
183                            if (appHome == null) {
184                                    appHome = new File("../.");
185                                    System.setProperty("app.home", appHome.getAbsolutePath());
186                            }
187                    }
188                    return appHome;
189            }
190    
191    }