/* * Copyright (C) 2011 Rhegium Team * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.rhegium; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Properties; public final class Starter { private static final String PROPERTIES_BOOTSTRAP_FIREWALLING_CLASSLOADER = "bootstrap.firewalling.classloader"; private static final String PROPERTIES_BOOTSTRAP_FRAMEWORK_CLASSLOADER = "bootstrap.framework.classloader"; private static final String PROPERTIES_BOOTSTRAP_FRAMEWORK_FOLDER = "bootstrap.framework.folder"; private static final String PROPERTIES_FRAMEWORK_ENTRY_POINT = "bootstrap.framework.entry.point"; private static final String PROPERTIES_FRAMEWORK_BOOTSTRAP_CLASS = "bootstrap.framework.bootstrap.class"; private static final String PROPERTIES_BOOT_DELEGATION_PACKAGES = "bootstrap.delegation.packages"; private static final String STANDARD_FIREWALLING_CLASS_LOADER_CLASS = "org.rhegium.FirewallingClassLoader"; private static final String STANDARD_FRAMEWORK_CLASS_LOADER_CLASS = "org.rhegium.FrameworkClassLoader"; private static final String STANDARD_FRAMEWORK_BOOTSTRAP_CLASS = "org.rhegium.api.bootstrap.Bootstrapper"; private static final String STANDARD_CONFIGURATION_FOLDER = "conf"; private static final String STANDARD_FRAMEWORK_LIBRARY_FOLDER = "lib/framework"; private static final String FIREWALLING_CLASS_LOADER_CLASS; private static final String FRAMEWORK_CLASS_LOADER_CLASS; private static final String FRAMEWORK_BOOTSTRAP_CLASS; private static final String FRAMEWORK_ENTRY_POINT; private static final String FRAMEWORK_LIBRARY_FOLDER; private static final String[] JRE_BOOT_DELEGATION_PACKAGES; static { try { System.out.println("Loading bootstrapping properties..."); final Properties properties = loadProperties(); final String jreBootDelegationPackages = properties.getProperty(PROPERTIES_BOOT_DELEGATION_PACKAGES); JRE_BOOT_DELEGATION_PACKAGES = trimPackages(jreBootDelegationPackages.split(",")); FIREWALLING_CLASS_LOADER_CLASS = getProperty(properties, PROPERTIES_BOOTSTRAP_FIREWALLING_CLASSLOADER, STANDARD_FIREWALLING_CLASS_LOADER_CLASS); FRAMEWORK_CLASS_LOADER_CLASS = getProperty(properties, PROPERTIES_BOOTSTRAP_FRAMEWORK_CLASSLOADER, STANDARD_FRAMEWORK_CLASS_LOADER_CLASS); FRAMEWORK_BOOTSTRAP_CLASS = getProperty(properties, PROPERTIES_FRAMEWORK_BOOTSTRAP_CLASS, STANDARD_FRAMEWORK_BOOTSTRAP_CLASS); FRAMEWORK_ENTRY_POINT = getProperty(properties, PROPERTIES_FRAMEWORK_ENTRY_POINT, null); FRAMEWORK_LIBRARY_FOLDER = getProperty(properties, PROPERTIES_BOOTSTRAP_FRAMEWORK_FOLDER, STANDARD_FRAMEWORK_LIBRARY_FOLDER); } catch (final Exception e) { throw new RuntimeException(e); } } public static final void main(String[] args) throws Exception { if (FRAMEWORK_ENTRY_POINT == null) { throw new IllegalStateException("Entry point in framework.properties must be set!"); } // Retrieve the Firewalling ClassLoader which is a child classloader of // the general applications classloader final ClassLoader firewallingClassLoader = loadFirewallingClassLoader(); // Retrieve the Framework ClassLoader which is a child of our // firewalling classloader final ClassLoader frameworkClassLoader = loadFrameworkClassLoader(firewallingClassLoader); Thread.currentThread().setContextClassLoader(frameworkClassLoader); // Load up base framework start class and kick of initialization kickOffFrameworkBootstrapping(args, frameworkClassLoader); } private static void kickOffFrameworkBootstrapping(String[] args, ClassLoader frameworkClassLoader) throws Exception { final Class<?> bootstrapClass = frameworkClassLoader.loadClass(FRAMEWORK_BOOTSTRAP_CLASS); final Class<?> kickOffClazz = frameworkClassLoader.loadClass(FRAMEWORK_ENTRY_POINT); if (!bootstrapClass.isAssignableFrom(kickOffClazz)) { throw new IllegalArgumentException(PROPERTIES_FRAMEWORK_ENTRY_POINT + " must be an implementation of " + "org.rhegium.api.bootstrap.Bootstrapper"); } final Method initializer = kickOffClazz.getMethod("start", String[].class, ClassLoader.class); final Object bootstrapper = kickOffClazz.newInstance(); System.out.println("Kicking off framework initialization..."); initializer.invoke(bootstrapper, args, frameworkClassLoader); } private static ClassLoader loadFirewallingClassLoader() throws Exception { final Class<ClassLoader> firewallingClassLoaderClass = loadFirewallingClassLoaderClass(); final Constructor<ClassLoader> constructor = firewallingClassLoaderClass.getConstructor(String[].class, ClassLoader.class); System.out.println("Building FirewallingClassLoader..."); return constructor.newInstance(JRE_BOOT_DELEGATION_PACKAGES, Starter.class.getClassLoader()); } @SuppressWarnings("unchecked") private static Class<ClassLoader> loadFirewallingClassLoaderClass() throws ClassNotFoundException { return (Class<ClassLoader>) Class.forName(FIREWALLING_CLASS_LOADER_CLASS); } private static ClassLoader loadFrameworkClassLoader(final ClassLoader firewallingClassLoader) throws Exception { final File frameworkDirectory = new File(FRAMEWORK_LIBRARY_FOLDER); final URL[] entries = buildFrameworkClasspath(frameworkDirectory); final Class<ClassLoader> frameworkClassLoaderClass = loadFrameworkClassLoaderClass(firewallingClassLoader); final Constructor<ClassLoader> constructor = frameworkClassLoaderClass.getConstructor(URL[].class, ClassLoader.class); System.out.println("Building FrameworkClassLoader..."); return constructor.newInstance(entries, firewallingClassLoader); } @SuppressWarnings("unchecked") private static Class<ClassLoader> loadFrameworkClassLoaderClass(final ClassLoader parent) throws ClassNotFoundException { return (Class<ClassLoader>) Class.forName(FRAMEWORK_CLASS_LOADER_CLASS); } private static URL[] buildFrameworkClasspath(final File directory) throws IOException { final List<URL> entries = new ArrayList<>(); // Add configuration directory entries.add(new File(getConfigurationBase()).toURI().toURL()); // Add JAR files entries.addAll(findAllJars(directory)); return entries.toArray(new URL[entries.size()]); } private static List<URL> findAllJars(final File directory) throws MalformedURLException { final List<URL> jars = new ArrayList<>(); if (!directory.exists()) { return jars; } for (final File entry : directory.listFiles()) { if (entry.isDirectory()) { jars.addAll(findAllJars(entry)); } else if (entry.isFile() && entry.getName().toLowerCase().endsWith(".jar")) { String override = System.getProperty("org.rhegium.override." + entry.getName()); if (override != null) { File overrideFile = new File(override); if (!overrideFile.exists()) { throw new MalformedURLException("Override for " + entry.getName() + "'" + override + "' is no legal file or directory"); } jars.add(overrideFile.toURI().toURL()); } else { jars.add(entry.toURI().toURL()); } } } return jars; } private static Properties loadProperties() throws IOException { final File configDirectory = new File(getConfigurationBase()); final Properties properties = new Properties(); properties.load(new FileReader(new File(configDirectory, "framework.properties"))); return properties; } private static String getConfigurationBase() { String configurationBase = System.getProperty("org.rhegium.configurationBase"); if (configurationBase == null) { configurationBase = STANDARD_CONFIGURATION_FOLDER; } return configurationBase; } private static String getProperty(final Properties properties, final String propertyName, final String defaultValue) { final String value = System.getProperty(propertyName); if (value != null && !value.isEmpty()) { return value; } return properties.getProperty(propertyName, defaultValue); } private static String[] trimPackages(final String[] packages) { final String[] temp = new String[packages.length]; for (int i = 0; i < packages.length; i++) { temp[i] = packages[i].trim(); } return temp; } }