1
2
3
4
5
6
7
8
9
10
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
44
45
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
345
346
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
389
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 }