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.dynamic;
14  
15  import java.io.BufferedReader;
16  import java.io.IOException;
17  import java.io.InputStream;
18  import java.io.OutputStreamWriter;
19  import java.io.PrintWriter;
20  import java.net.MalformedURLException;
21  import java.net.URI;
22  import java.net.URISyntaxException;
23  import java.net.URL;
24  import java.util.ArrayList;
25  import java.util.Arrays;
26  import java.util.Enumeration;
27  import java.util.HashMap;
28  import java.util.LinkedHashSet;
29  import java.util.Set;
30  import java.util.jar.Manifest;
31  
32  import org.abstracthorizon.extend.repository.maven.MavenRepoModuleLoader;
33  import org.abstracthorizon.extend.server.deployment.DeploymentManager;
34  import org.abstracthorizon.extend.server.deployment.Module;
35  import org.abstracthorizon.extend.server.deployment.ModuleId;
36  import org.abstracthorizon.extend.server.deployment.ModuleLoader;
37  import org.abstracthorizon.extend.server.deployment.support.JarModuleLoader;
38  import org.abstracthorizon.extend.server.deployment.support.ModuleClassLoader;
39  import org.abstracthorizon.extend.server.support.Dump;
40  import org.abstracthorizon.extend.server.support.EnhancedMap;
41  
42  /**
43   * Bootstrap class that sets up Extend through maven style repository
44   *
45   * @author Daniel Sendula
46   */
47  public class Bootstrap {
48  
49      public static final String DEFAULT_VERSION = "0.5";
50  
51      public static final String BOOTSTRAP_MODULE = "repo:maven:org.abstracthorizon.extend.bootstrap:extend-bootstrap-second-stage:${version}:jar";
52  
53      protected static String bootstrap = BOOTSTRAP_MODULE;
54  
55      protected static boolean debug = false;
56  
57      public static void main(String[] args) throws Exception {
58          System.out.println("Bootstrapping Extend...");
59  
60          ArrayList<String> repositories = new ArrayList<String>();
61          
62          ArrayList<String> originalArguments = new ArrayList<String>();
63          originalArguments.addAll(Arrays.asList(args));
64  
65          if (args.length > 0) {
66              int i = 0;
67              int p = 0;
68              while (i < args.length) {
69                  if (args[i].equals("-b") || args[i].equals("--bootstrap")) {
70                      i++;
71                      if (i == args.length) {
72                          throw new IllegalArgumentException("Expected bootstrap module location after -b or --bootstrap switch");
73                      }
74                      bootstrap = args[i];
75                      originalArguments.remove(p);
76                      originalArguments.remove(p);
77                  } else if (args[i].equals("-r") || args[i].equals("--repository")) {
78                      i++;
79                      if (i == args.length) {
80                          throw new IllegalArgumentException("Expected repository url name after -r or --repository switch");
81                      }
82                      repositories.add(args[i]);
83                      i++;
84                  } else if (args[i].equals("-v") || args[i].equals("--version")) {
85                      i++;
86                      if (i == args.length) {
87                          throw new IllegalArgumentException("Expected version number after -v or --version switch");
88                      }
89                      String version = args[i];
90                      if (bootstrap.contains("${version}")) {
91                          bootstrap = bootstrap.replace("${version}", version);
92                      } else {
93                          throw new IllegalArgumentException("For version switch to work bootstrap module's location must include '${verison}' substring or bootstrap module must not be added (-b or --bootstrap switch).");
94                      }
95                      originalArguments.remove(p);
96                      originalArguments.remove(p);
97                  } else if (args[i].equals("--debug") || args[i].equals("-X")) {
98                      debug = true;
99                  }
100                 i++;
101                 p++;
102             }
103         }
104 
105 
106         DeploymentManagerStub deploymentManager = new DeploymentManagerStub();
107 
108         MavenRepoModuleLoader mavenRepoModuleLoader = new MavenRepoModuleLoader();
109         mavenRepoModuleLoader.setDeploymentManager(deploymentManager);
110         deploymentManager.getModuleLoaders().add(mavenRepoModuleLoader);
111 
112         int ri = 0;
113         for (String r : repositories) {
114             mavenRepoModuleLoader.getRepositories().put("anonymous_" + ri, new URL(r));
115             ri++;
116         }
117         
118         JarModuleLoader jarModuleLoader = new JarModuleLoader();
119         jarModuleLoader.setDeploymentManager(deploymentManager);
120         jarModuleLoader.getExtensions().add(".jar");
121         deploymentManager.getModuleLoaders().add(jarModuleLoader);
122 
123         if (bootstrap.contains("${version}")) {
124             bootstrap = bootstrap.replace("${version}", DEFAULT_VERSION);
125         }
126 
127         URI supportCoreURI = new URI(bootstrap);
128         Module module = deploymentManager.load(supportCoreURI);
129         deploy(supportCoreURI, module, deploymentManager);
130 
131         fixSpring(deploymentManager);
132 
133         String mainClassString = null;
134         ClassLoader cl = module.getClassLoader();
135         Enumeration<URL> manifests = cl.getResources("META-INF/MANIFEST.MF");
136         URL manifestURL = null;
137         String moduleLocation = module.getOriginalLocation().toString();
138         while ((manifestURL == null) && manifests.hasMoreElements()) {
139             URL url = manifests.nextElement();
140             String urlString = url.toString().substring(4);
141             if (urlString.startsWith(moduleLocation)) {
142                 manifestURL = url;
143             }
144         }
145 
146         if (manifestURL != null) {
147             InputStream manifestInputStream = manifestURL.openStream();
148             if (manifestInputStream != null) {
149                 try {
150                     Manifest manifest = new Manifest(manifestInputStream);
151                     mainClassString = manifest.getMainAttributes().getValue("Main-Class");
152                 } finally {
153                     manifestInputStream.close();
154                 }
155             }
156         }
157         if (mainClassString == null) {
158             throw new IllegalArgumentException("Bootstrap module '" + bootstrap + "' must have main class defined in META-INF/MANIFEST.MF file");
159         }
160 
161         ArrayList<String> arguments = new ArrayList<String>();
162 
163         String initialJar = obtainInitialJar();
164         arguments.add("-ij");
165         arguments.add(initialJar);
166 
167         String initialVersion = obtainInitialVersion();
168         if ((initialVersion != null) && (initialVersion.length() > 0)) {
169             arguments.add("-iv");
170             arguments.add(initialVersion);
171         }
172 
173         for (Module m : deploymentManager.getDeployedModules().values()) {
174             arguments.add("-ad");
175             arguments.add(m.getModuleId().toString());
176         }
177         
178         arguments.addAll(originalArguments);
179 
180         String[] argumentsArray = new String[arguments.size()];
181         argumentsArray = arguments.toArray(argumentsArray);
182 
183         updateModuleClassLoaders(deploymentManager);
184 
185         if (debug) {
186             System.out.println("Starting with ==================================================================");
187             Dump.outputCore(new PrintWriter(new OutputStreamWriter(System.out)), deploymentManager);
188             System.out.println("================================================================================");
189         }
190         Class<?> mainClass = cl.loadClass(mainClassString);
191         mainClass.getMethod("main", new Class[]{args.getClass()}).invoke(null, new Object[]{argumentsArray});
192     }
193 
194     public static void deploy(URI uri, Module module, DeploymentManager deploymentManager) {
195         ModuleId moduleId = module.getModuleId();
196         if (!deploymentManager.getDeployedModules().containsKey(moduleId)) {
197             deploymentManager.deploy(moduleId, module);
198         }
199     }
200 
201     protected static void updateModuleClassLoaders(DeploymentManager deploymentManager) {
202         for (Module m : deploymentManager.getDeployedModules().values()) {
203             ClassLoader c = m.getClassLoader();
204             while ((c != null) && !(c instanceof ModuleClassLoader)) {
205                 c = c.getParent();
206             }
207             if (c != null) {
208                 ModuleClassLoader mcl = (ModuleClassLoader)c;
209                 mcl.setUserThreadClassLoader(false);
210                 if (debug) { System.out.println("Updated module " + mcl.getModule().getModuleId()); }
211             }
212         }
213     }
214 
215     protected static void fixSpring(DeploymentManager deploymentManager) throws URISyntaxException {
216         ModuleId springCoreModuleId = new ModuleId("org.springframework:spring-core:2.0.5:jar");
217         
218         Module springCore = deploymentManager.getDeployedModules().get(springCoreModuleId);
219         
220         ModuleId springBeansModuleId = new ModuleId("org.springframework:spring-beans:2.0.5:jar");
221         Module springBeans = deploymentManager.getDeployedModules().get(springBeansModuleId);
222 
223         ModuleId springContextModuleId = new ModuleId("org.springframework:spring-context:2.0.5:jar");
224         Module springContext = deploymentManager.getDeployedModules().get(springContextModuleId);
225 
226         springCore.getDependOnThis().add(springBeans);
227         springCore.getDependOnThis().add(springContext);
228         springBeans.getDependOnThis().add(springContext);
229         springBeans.getDependsOn().add(springCore);
230         springContext.getDependsOn().add(springCore);
231         springContext.getDependsOn().add(springBeans);
232 
233         Module jcl104OverSlf4j = deploymentManager.getDeployedModules().get(new ModuleId("org.slf4j:jcl104-over-slf4j:1.4.0:jar"));
234         jcl104OverSlf4j.getDependOnThis().add(springCore);
235         jcl104OverSlf4j.getDependOnThis().add(springBeans);
236         jcl104OverSlf4j.getDependOnThis().add(springContext);
237 
238         springCore.getDependsOn().add(jcl104OverSlf4j);
239         springBeans.getDependsOn().add(jcl104OverSlf4j);
240         springContext.getDependsOn().add(jcl104OverSlf4j);
241     }
242 
243 
244     public static HashMap<String, String> processManifestFile(BufferedReader input) throws IOException {
245         HashMap<String, String> res = new HashMap<String, String>();
246         String key = null;
247         String line = input.readLine();
248         while (line != null) {
249             if ((key != null) && (line.length() > 0) && Character.isWhitespace(line.charAt(0))) {
250                 res.put(key, res.get(key) + line.substring(1).trim());
251             } else {
252                 int i = line.indexOf(':');
253                 if (i > 0) {
254                     key = line.substring(0, i).trim();
255                     String value = line.substring(i + 1).trim();
256                     res.put(key, value);
257                 }
258             }
259 
260             line = input.readLine();
261         }
262 
263         return res;
264     }
265 
266     public static class DeploymentManagerStub implements DeploymentManager {
267 
268         protected EnhancedMap<ModuleId, Module> deployedModules = new EnhancedMap<ModuleId, Module>();
269 
270         protected LinkedHashSet<ModuleLoader> moduleLoaders = new LinkedHashSet<ModuleLoader>();
271 
272         public void create(Module module) {
273             module.create();
274         }
275 
276         public void deploy(ModuleId moduleId, Module module) {
277             deployedModules.put(moduleId, module);
278             create(module);
279             if ((module.getState() == Module.CREATED) || (module.getState() == Module.WAITING_ON_CREATE)) {
280                 start(module);
281             }
282             if (debug) { System.out.println("Deployed " + moduleId); }
283         }
284 
285         public void destroy(Module module) {
286             throw new RuntimeException("Not implemented");
287         }
288 
289         public Module loadAndDeploy(URI uri) {
290             Module m = deployedModules.get(uri);
291             if (m == null) {
292                 m = load(uri);
293                 if (m != null) {
294                     ModuleId moduleId = m.getModuleId();
295                     if (!deployedModules.containsValue(m)) {
296                         deploy(moduleId, m);
297                     } else if (!deployedModules.containsKey(moduleId)) {
298                         deployedModules.put(moduleId, m);
299                     }
300                 }
301             }
302             return m;
303         }
304 
305         public EnhancedMap<ModuleId, Module> getDeployedModules() {
306             return deployedModules;
307         }
308 
309         public Set<ModuleLoader> getModuleLoaders() {
310             return moduleLoaders;
311         }
312 
313         public void redeploy(Module module) {
314             throw new RuntimeException("Not implemented");
315         }
316 
317         public void setModuleLoaders(Set<ModuleLoader> moduleLoaders) {
318             throw new RuntimeException("Not implemented");
319         }
320 
321         public void start(Module module) {
322             module.start();
323             if (debug) { System.out.println("Started " + module.getModuleId()); }
324         }
325 
326         public void stop(Module module) {
327             throw new RuntimeException("Not implemented");
328         }
329 
330         public void undeploy(Module module) {
331             throw new RuntimeException("Not implemented");
332         }
333 
334         public boolean canLoad(URI url) {
335             for (ModuleLoader loader : moduleLoaders) {
336                 if (loader.canLoad(url)) {
337                     return true;
338                 }
339             }
340             return false;
341         }
342         
343         /**
344          * Translates URI to moduleId
345          * @param uri uri
346          * @return module id or <code>null</code>
347          */
348         public ModuleId toModuleId(URI uri) {
349             String path = uri.getPath();
350             if (path != null) {
351                 ModuleId moduleId = new ModuleId();
352                 moduleId.setArtifactId(path);
353                 return moduleId;
354             } else {
355                 return null;
356             }
357         }
358 
359         public Module load(URI uri) {
360             Module module = null;
361             for (ModuleLoader loader : moduleLoaders) {
362                 if (loader.canLoad(uri)) {
363                     module = loader.load(uri);
364                     return module;
365                 }
366             }
367             return module;
368         }
369 
370         public Module loadAs(URI uri, ModuleId moduleId) {
371             Module module = null;
372             for (ModuleLoader loader : moduleLoaders) {
373                 if (loader.canLoad(uri)) {
374                     module = loader.loadAs(uri, moduleId);
375                     return module;
376                 }
377             }
378             return module;
379         }
380     }
381 
382     public static String obtainInitialJar() throws MalformedURLException {
383         ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
384         String className = Bootstrap.class.getName().replace('.', '/') + ".class";
385         URL root = contextClassLoader.getResource(className);
386         if ("jar".equals(root.getProtocol())) {
387             String file = root.getFile();
388             //if (!file.startsWith("file")) {
389             //    throw new RuntimeException("Cannot handle protocol from where this jar is loaded; " + root);
390             //}
391             int i = file.lastIndexOf('!');
392             file = file.substring(0, i);
393             i = file.lastIndexOf("/");
394             if (i >= 0) {
395             	file = file.substring(i + 1);
396             }
397             return file;
398         } else {
399         	return "extend.jar";
400         }
401     }
402 
403     public static String obtainInitialVersion() {
404     	try {
405 	    	ClassLoader cl = Bootstrap.class.getClassLoader();
406 	    	String name = Bootstrap.class.getName().replace('.', '/') + ".class";
407 	    	URL url = cl.getResource(name);
408 	    	String urlString = url.toString();
409 	    	urlString = urlString.substring(0, urlString.length() - name.length());
410 	    	Enumeration<URL> e = cl.getResources("META-INF/Extend-Version");
411 	    	while (e.hasMoreElements()) {
412 	    		URL u = e.nextElement();
413 	    		String s = u.toString();
414 	    		if (s.startsWith(urlString)) {
415 	    			InputStream is = u.openStream();
416 	    			try {
417 	    				Manifest manifest = new Manifest(is);
418 	    				return manifest.getMainAttributes().getValue("Version");
419 	    			} finally {
420 	    				is.close();
421 	    			}
422 	    		}
423 	    	}
424     	} catch (IOException e) {
425     		e.printStackTrace();
426     	}
427     	return "";
428     }
429 
430 }