View Javadoc

1   /*
2    * Copyright (c) 2005-2007 Creative Sphere Limited.
3    * All rights reserved. This program and the accompanying materials
4    * are made available under the terms of the Eclipse Public License v1.0
5    * which accompanies this distribution, and is available at
6    * http://www.eclipse.org/legal/epl-v10.html
7    *
8    * Contributors:
9    *
10   *   Creative Sphere - initial API and implementation
11   *
12   */
13  package org.abstracthorizon.extend.server;
14  
15  import java.io.BufferedReader;
16  import java.io.File;
17  import java.io.IOException;
18  import java.io.InputStream;
19  import java.io.InputStreamReader;
20  import java.lang.reflect.Constructor;
21  import java.lang.reflect.InvocationTargetException;
22  import java.lang.reflect.Method;
23  import java.net.JarURLConnection;
24  import java.net.MalformedURLException;
25  import java.net.URL;
26  import java.net.URLClassLoader;
27  import java.util.ArrayList;
28  import java.util.Collection;
29  import java.util.Enumeration;
30  import java.util.jar.JarEntry;
31  import java.util.jar.JarFile;
32  
33  /**
34   * <p>Bootstrap class.
35   *
36   * This class first tries to find home directory of the server:
37   *
38   * <ul>
39   * <li>URL of this class is found</li>
40   * <li>then root of class path is taken where this class is in</li>
41   * <li>if url is jar then directory jar is in is taken</li>
42   * <li>directory's name is checked if it is &quot;bin&quot;, if so - parent is taken</li>
43   * </ul>
44   * </p>
45   * <p>
46   *   Then class loader with class path is created with all jar files from lib subdirectory (of the home directory),
47   *   and lib directory itself is added to the class path.
48   * </p>
49   * <p>
50   *   After that server directory is determined from arguments (TODO) or if none present from
51   *   &quit;server/default&quot; directory of the home directory.
52   * </p>
53   * <p>
54   *   Last part is to load {@link Server} class (using reflection), pass home and server's urls to it
55   *   (in constructor) and then to invoke it calling <code>create()</code> and <code>start()</code> methods.
56   * </p>
57   *
58   * @author Daniel Sendula
59   */
60  public class Bootstrap {
61  
62      /**
63       * Main method
64       * @param args arguments
65       * @throws Exception
66       */
67      public static void main(String[] args) throws Exception {
68          URL homeURL = getHomeLocation();
69          URL libURL = new URL(homeURL.getProtocol(), homeURL.getHost(), homeURL.getPort(), homeURL.getFile() + "lib/");
70  
71          String serverDir = "default";
72  
73          int i = 0;
74          while (i < args.length) {
75              if ("-c".equals(args[i])) {
76                  i = i + 1;
77                  if (i >= args.length) {
78                      throw new IllegalArgumentException("-c must be followed with name of sub-directory from server directory");
79                  }
80                  serverDir = args[i];
81              }
82  
83              i = i + 1;
84          }
85  
86          URL serverURL = null;
87          File local = new File(homeURL.getFile() + "server/" + serverDir);
88          if (local.exists()) {
89              serverURL = new URL(homeURL.getProtocol(), homeURL.getHost(), homeURL.getPort(), homeURL.getFile() + "server/" + serverDir + "/");
90          } else {
91              serverURL = new URL(homeURL.getProtocol(), homeURL.getHost(), homeURL.getPort(), serverDir + "/");
92          }
93  
94          System.out.println("home = " + homeURL);
95          System.out.println("lib = " + libURL);
96  
97          URLClassLoader classLoader = createClassLoader(Thread.currentThread().getContextClassLoader(), libURL);
98  
99          Class<?> serverClass = classLoader.loadClass("org.abstracthorizon.extend.support.spring.server.SpringBasedServer");
100 
101         Constructor<?> constructor = serverClass.getConstructor(new Class[]{URL.class, URL.class});
102         Object server = constructor.newInstance(new Object[]{homeURL, serverURL});
103 
104         invokeMethod(server, "create", true);
105         invokeMethod(server, "start", true);
106 
107     }
108 
109     /**
110      * Gets home location.
111      * @return home location
112      * @throws MalformedURLException
113      */
114     public static URL getHomeLocation() throws MalformedURLException {
115         ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
116         String className = Bootstrap.class.getName().replace('.', '/') + ".class";
117         URL root = contextClassLoader.getResource(className);
118         if ("file".equals(root.getProtocol())) {
119             String file = root.getFile();
120             file = file.substring(0, file.length() - className.length() - 1);
121             if (file.endsWith("bin")) {
122                 file = file.substring(0, file.length() - 3);
123             }
124             return new File(file).toURI().toURL();
125         } else if ("jar".equals(root.getProtocol())) {
126             String file = root.getFile();
127             //if (!file.startsWith("file")) {
128             //    throw new RuntimeException("Cannot handle protocol from where this jar is loaded; " + root);
129             //}
130             int i = file.lastIndexOf('!');
131             file = file.substring(0, i);
132             File f = new File(file);
133             file = f.getParent();
134             if (file.endsWith("bin")) {
135                 file = file.substring(0, file.length() - 3);
136             }
137             return new URL(file);
138             // return new File(file).toURL();
139         } else {
140             throw new RuntimeException("Cannot handle protocol from where this class is loaded; " + root);
141         }
142     }
143 
144     /**
145      * Creates class loader for given url. If url is directory then it is scanned
146      * and all jar files from it added to classpath.
147      *
148      * @param parent parent class loader or <code>null</code>
149      * @param lib url class loader to be created for.
150      * @return {@link URLClassLoader} instance
151      */
152     public static URLClassLoader createClassLoader(ClassLoader parent, URL lib) throws IOException {
153         Collection<URL> urls = collectFiles(lib);
154         urls.add(lib);
155         URL[] us = new URL[urls.size()];
156         us = urls.toArray(us);
157         URLClassLoader classLoader = new URLClassLoader(us, parent);
158         return classLoader;
159     }
160 
161     /**
162      * Collects files from given url.
163      * @param url url
164      * @return collection of urls
165      * @throws IOException
166      */
167     public static Collection<URL> collectFiles(URL url) throws IOException {
168         String protocol = url.getProtocol();
169         if ("file".equals(protocol)) {
170             return collectFilesFromPath(new File(url.getFile()));
171         } else if ("jar".equals(protocol)) {
172             JarURLConnection jarURLConnection = (JarURLConnection)url.openConnection();
173             return collectFilesFromJar(url, jarURLConnection.getJarFile());
174         } else {
175             return collectFilesFromURL(url);
176         }
177     }
178 
179     /**
180      * Collects files from given path
181      * @param path directory
182      * @return collection of urls
183      * @throws IOException
184      */
185     public static Collection<URL> collectFilesFromPath(File path) throws IOException {
186         ArrayList<URL> urls = new ArrayList<URL>();
187         if (path.exists()) {
188             if (path.isDirectory()) {
189                 File[] files = path.listFiles();
190                 for (File file : files) {
191                     if (file.isFile()) {
192                         urls.add(file.toURI().toURL());
193                     }
194                 }
195             }
196         }
197         return urls;
198      }
199 
200     /**
201      * Collects files from jar file (root of)
202      * @param original original url
203      * @param jarFile jar file
204      * @return collection of urls
205      * @throws IOException
206      */
207     public static Collection<URL> collectFilesFromJar(URL original, JarFile jarFile) throws IOException {
208         ArrayList<URL> urls = new ArrayList<URL>();
209 
210         String originalFile = original.getFile();
211         String prefix = originalFile.substring(originalFile.lastIndexOf('!') + 1);
212         if (prefix.endsWith("/")) {
213             if (prefix.startsWith("/")) {
214                 prefix = prefix.substring(1);
215             }
216             Enumeration<JarEntry> en = jarFile.entries();
217             while (en.hasMoreElements()) {
218                 JarEntry entry = en.nextElement();
219                 String path = entry.getName();
220                 if (path.startsWith(prefix)) {
221                     path = path.substring(prefix.length());
222                     if (path.length() > 0) {
223                         int i = path.indexOf('/');
224                         if ((i < 0) /*|| (i == (path.length() - 1))*/) {
225                             URL url = new URL(original.getProtocol(), original.getHost(), original.getPort(), originalFile + path);
226                             urls.add(url);
227                         }
228                     }
229                 }
230             }
231         }
232         return urls;
233      }
234 
235     /**
236      * Collects files from give (generic) url
237      * @param url url
238      * @return collection of files
239      * @throws IOException
240      */
241     public static Collection<URL> collectFilesFromURL(URL url) throws IOException {
242         ArrayList<URL> urls = new ArrayList<URL>();
243         InputStream is = url.openStream();
244         try {
245             BufferedReader input = new BufferedReader(new InputStreamReader(is));
246             String file = input.readLine();
247             while (file != null) {
248                 if (file.length() > 0) {
249                     URL newUrl = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile() + "/" + file);
250                     urls.add(newUrl);
251                 }
252                 file = input.readLine();
253             }
254         } finally {
255             is.close();
256         }
257         return urls;
258      }
259 
260     /**
261      * Invokes parametherless method with given name. If <code>mustBePresent</code>
262      * is set to <code>true</code> {@link NoSuchMethodException} is propagated wrapped in
263      * {@link RuntimeException}.
264      *
265      * @param object instance on which method is going to be executed
266      * @param methodName method name
267      * @param mustBePresent if set then method must be present or {@link NoSuchMethodError} is thrown
268      * @throws RuntimeException if {@link NoSuchMethodException}, {@link IllegalArgumentException},
269      * {@link IllegalAccessException} or {@link InvocationTargetException} is thrown.
270      */
271     public static void invokeMethod(Object object, String methodName, boolean mustBePresent) {
272         try {
273             Method method = object.getClass().getMethod(methodName, new Class[]{});
274             method.invoke(object, new Object[]{});
275         } catch (NoSuchMethodException e) {
276             if (mustBePresent) {
277                 throw new RuntimeException(e);
278             }
279         } catch (IllegalArgumentException e) {
280             throw new RuntimeException(e);
281         } catch (IllegalAccessException e) {
282             throw new RuntimeException(e);
283         } catch (InvocationTargetException e) {
284             throw new RuntimeException(e);
285         }
286     }
287 }