Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   package edu.mit.simile.butterfly;
   
   import java.io.File;
   import java.io.IOException;
  import java.net.URL;
  import java.util.Date;
  import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Locale;
  import java.util.Map;
  import java.util.Set;
  import java.util.Timer;
  
  
  import org.slf4j.Logger;
  
This is the Butterfly servlet and the main entry point for a Butterfly-powered web application. This servlet is responsible for loading, configuring and wire together the various modules that compose your webapp and then manages the dispatching of requests to the modules that are supposed to handle them.
  
  public class Butterfly extends HttpServlet {
  
      public static final String HOST_HEADER = "X-Forwarded-Host";
      public static final String CONTEXT_HEADER = "X-Context-Path";
      
      private static final long serialVersionUID = 1938797827088619577L;
  
      private static final long watcherDelay = 1000;
      
      public static final String NAME = "butterfly.name";
      public static final String APPENGINE = "butterfly.appengine";
      public static final String AUTORELOAD = "butterfly.autoreload";
      public static final String HOME = "butterfly.home";
      public static final String ZONE = "butterfly.zone";
      public static final String BASE_URL = "butterfly.url";
      public static final String DEFAULT_ZONE = "butterfly.default.zone";
      public static final String DEFAULT_MOUNTPOINT = "butterfly.default.mountpoint";
      public static final String MODULES_IGNORE = "butterfly.modules.ignore";
      public static final String MODULES_PATH = "butterfly.modules.path";
      
      public static final String MAIN_ZONE = "main";
  
      final static List<StringCONTROLLER;
      
      static {
           = new ArrayList<String>();
          .add("controller.js");
      }
      
      // --------------------- static ----------------------------------
      
      public static String getTrueHost(HttpServletRequest request) {
          String host = request.getHeader();
          if (host != null) {
              String[] hosts = host.split(",");
              host = hosts[hosts.length - 1];
          }
          return host;
      }
 
     public static String getTrueContextPath(HttpServletRequest requestboolean absolute) {
         String context = request.getHeader();
         if (context != null) {
             if (context.charAt(context.length() - 1) == '/'context = context.substring(0, context.length() - 1);
         } else {
             context = request.getContextPath();
         }
         if (absolute) {
             return getFullHost(request) + context;
         } else {
             return context;
         }
     }
 
     public static String getTrueRequestURI(HttpServletRequest requestboolean absolute) {
         return getTrueContextPath(request,absolute) + request.getPathInfo();
     }
     
     public static String getFullHost(HttpServletRequest request) {
         StringBuffer prefix = new StringBuffer();
         String protocol = request.getScheme();
         prefix.append(protocol);
         prefix.append("://");
         String proxy = getTrueHost(request);
         if (proxy != null) {
             prefix.append(proxy);
         } else {
             prefix.append(request.getServerName());
             int port = request.getServerPort();
             if (!((protocol.equals("http") && port == 80) || (protocol.equals("https") && port == 443))) {
                 prefix.append(':');
                 prefix.append(port);
             }
         }
         return prefix.toString();
     }    
 
     public static boolean isGAE(ServletConfig config) {
         return (config.getServletContext().getServerInfo().indexOf("Google App Engine") != -1);
     }
     
     // ---------------------------------------------------------------
 
     transient private Logger _logger;
 
     private boolean _autoreload;
     private boolean _appengine;
     private String _name;
     private String _default_mountpoint;
     private int _routingCookieMaxAge;
     
     private String[] _ignores;
     
     transient protected Timer _timer;
     transient protected ButterflyClassLoader _classLoader;
     transient protected ButterflyScriptWatcher _scriptWatcher;
     transient protected ServletConfig _config;
     transient protected ServletContext _context;
     transient protected ButterflyMounter _mounter;
 
     protected ExtendedProperties _properties;
     protected File _contextDir;
     protected File _homeDir;
     protected File _webInfDir;
     protected Exception _configurationException;
 
     protected boolean _configured = false;
 
     protected ContextFactory contextFactory;
     
     class ButterflyContextFactory extends ContextFactory {
         protected void onContextCreated(Context cx) {
             cx.setOptimizationLevel(9);
             super.onContextCreated(cx);
         }
     }    
     
     @Override
     public void init(ServletConfig configthrows ServletException {
         super.init(config);
          = config;
 
          = isGAE(config);
         
          = System.getProperty("butterfly");
 
          = config.getServletContext();
         .setAttribute();
                 
          = new File(.getRealPath("/"));
          = new File("WEB-INF");
          = new ExtendedProperties();
          = new ButterflyMounter();
 
         // Load the butterfly properties
         String props = System.getProperty("butterfly.properties");
         File butterflyProperties = (props == null) ? new File("butterfly.properties") : new File(props);
 
         BufferedInputStream is = null;
         try {
             is = new BufferedInputStream(new FileInputStream(butterflyProperties)); 
             .load(is);
         } catch (FileNotFoundException e) {
             throw new ServletException("Could not find butterfly properties file",e);
         } catch (IOException e) {
             throw new ServletException("Could not read butterfly properties file",e);
         } finally {
             try {
                 is.close();
             } catch (Exception e) {
                 // ignore
             }
         }
 
         // Process eventual properties includes
         String includes = .getString("butterfly.includes");
         if (includes != null) {
             for (String prop : includes.split(",")) {
                 File prop_file = (prop.startsWith("/")) ? new File(prop) : new File(prop);
                 try {
                     is = new BufferedInputStream(new FileInputStream(prop_file));
                     ExtendedProperties p = new ExtendedProperties();
                     p.load(is);
                     .combine(p);
                 } catch (Exception e) {
                     // ignore 
                 } finally {
                     try {
                         is.close();
                     } catch (Exception e) {
                         // ignore
                     }
                 }
             }
         }
         // Overload with properties set from the command line 
         // using the -Dkey=value parameters to the JVM
         Properties systemProperties = System.getProperties();
         for (Iterator<Objecti = systemProperties.keySet().iterator(); i.hasNext(); ) {
             String key = (Stringi.next();
             String value = systemProperties.getProperty(key);
             .setProperty(keyvalue);
         }
 
          = .getString("/modules");
          = .getString("").split(",");
         
          = .getBoolean(false);
         
         if (!) {
             String log4j = System.getProperty("butterfly.log4j");
             File logProperties = (log4j == null) ? new File("log4j.properties") : new File(log4j);
             if (logProperties.exists()) {
                 if () {
                     PropertyConfigurator.configureAndWatch(logProperties.getAbsolutePath(), );
                 } else {
                     PropertyConfigurator.configure(logProperties.getAbsolutePath());
                 }
             }
         }
 
          = LoggerFactory.getLogger();
         
         .info("Starting {} ...");
 
         .info("Properties loaded from {}"butterflyProperties);
 
         if (.info("Autoreloading is enabled");
         if (.info("Running in Google App Engine");
 
         .debug("> init");
         
         .debug("> initialize classloader");
         try {
              = AccessController.doPrivileged (
                 new PrivilegedAction<ButterflyClassLoader>() {
                     public ButterflyClassLoader run() {
                         return new ButterflyClassLoader(this.getClass().getClassLoader());
                     }
                 }
             );
             
             Thread.currentThread().setContextClassLoader();
             .watch(butterflyProperties); // reload if the butterfly properties change
              = new ButterflyContextFactory();
             .initApplicationClassLoader(); // tell rhino to use this classloader as well
 
             ContextFactory.initGlobal();
             
             if ( && !) {
                  = new Timer(true);
                 TimerTask classloaderWatcher = .getClassLoaderWatcher(new Trigger());
                 .schedule(classloaderWatcher);
             }
         } catch (Exception e) {
             throw new ServletException("Failed to load butterfly classloader"e);
         }
         .debug("< initialize classloader");
 
         if ( && !) {
             .debug("> initialize script watcher");
              = new ButterflyScriptWatcher();
             .debug("< initialize script watcher");
         }
 
         this.configure();
         
         .debug("< init");
     }
     
     @Override
     public void destroy() {
         .info("Stopping Butterfly...");
         
         for (ButterflyModule m : .values()) {
             try {
                 .debug("> destroying {}"m);
                 m.destroy();
                 .debug("< destroying {}"m);
             } catch (Exception e) {
                 .error("Exception caught while destroying '" + m + "'"e);
             }
         }
         
         if ( != null) {
             .cancel();
         }
         
         .info("done.");
     }
     
     @SuppressWarnings("unchecked")
     public void configure() {
         .debug("> configure");
 
         .info("> process properties");
         try {
 
             String homePath = .getString();
             if (homePath == null) {
                  = ;
             } else {
                  = new File(homePath);
             }
             .info("Butterfly home: {}");
             
             Iterator<Stringi = .getKeys();
             while (i.hasNext()) {
                 String zone = i.next();
                 String path = .getString(zone);
                 zone = zone.substring(.length() + 1);
                 .info("Zone path: [{}] -> {}"zonepath);
                 .registerZone(zonepath);
             }
 
             String defaultZone = .getString();
             if (defaultZone != null) {
                 .info("Default zone is: '{}'"defaultZone);
                 .setDefaultZone(defaultZone);
             } else {
                 String baseURL = .getString(,"/");
                 .registerZone(baseURL);
                 .setDefaultZone();
             }
             
             String language = .getString("butterfly.locale.language");
             String country =  .getString("butterfly.locale.country");
             String variant =  .getString("butterfly.locale.variant");
             if (language != null) {
                 if (country != null) {
                     if (variant != null) {
                         Locale.setDefault(new Locale(languagecountryvariant));
                     } else {
                         Locale.setDefault(new Locale(languagecountry));
                     }
                 } else {
                     Locale.setDefault(new Locale(language));
                 }
             }
 
             String timeZone = .getString("butterfly.timeZone");
             if (timeZone != null) {
                 TimeZone.setDefault(TimeZone.getTimeZone(timeZone));
             }
             
              = .getInt("butterfly.routing.cookie.maxage",-1);
         } catch (Exception e) {
              = new Exception("Failed to load butterfly properties"e);
         }
         .info("< process properties");
 
         .info("> load modules");
         // load modules from the properties found in the butterfly.properties
         List<Stringpaths = .getList();
         for (String path : paths) {
             findModulesIn(absolutize(path.trim()));
         }
 
         // load modules from the path found in the servlet init properties
         String servlet_paths = this..getInitParameter();
         if (servlet_paths != null) {
             for (String path : servlet_paths.split(",")) {
                 findModulesIn(absolutize(path.trim()));
             }
         }
         .info("< load modules");
         
         .info("> create modules");
         for (String name : .keySet()) {
             createModule(name);
         }
         .info("< create modules");
         
         .info("> load module wirings");
         ExtendedProperties wirings = new ExtendedProperties();
         try {
             // Load the wiring properties
             File moduleWirings = absolutize(.getString("butterfly.modules.wirings","WEB-INF/modules.properties"));
             .info("Loaded module wirings from: {}"moduleWirings);
             .watch(moduleWirings); // reload if the module wirings change
             FileInputStream fis = new FileInputStream(moduleWirings);
             wirings.load(fis);
             fis.close();
         } catch (Exception e) {
              = new Exception("Failed to load module wirings"e);
         }
         .info("< load module wirings");
 
         .info("> wire modules");
         try {
             wireModules(wirings);
         } catch (Exception e) {
              = new Exception("Failed to wire modules"e);
         }
         .info("< wire modules");
 
         .info("> configure modules");
         try {
             configureModules();
         } catch (Exception e) {
              = new Exception("Failed to configure modules"e);
         }
         .info("< configure modules");
                 
         .info("> initialize modules");
         Set<Stringinitialized = new HashSet<String>();
         Set<Stringinitializing = new HashSet<String>();
         for (String name : .keySet()) {
             initializeModule(nameinitializedinitializing);
         }
         .info("< initialize modules");
         
          = true;
         
         .debug("< configure");
     }
     
     protected void initializeModule(String nameSet<StringinitializedSet<Stringinitializing) {
         ButterflyModule m = .get(name);
         if (m != null && !initialized.contains(name)) {
             .debug("> initialize " + m.getName());
             
             if (initializing.contains(name)) {
                 .warn("Circular dependencies detected involving module " + m);
             } else {
                 initializing.add(name);
                 for (String depends : m.getDependencies().keySet()) {
                     initializeModule(dependsinitializedinitializing);
                 }
                 initializing.remove(name);
             }
             
             try {
                 m.init(getServletConfig());
             } catch (Exception e) {
                  = new Exception("Failed to initialize module " + me);
             }
             
             .debug("< initialize " + m.getName());
             initialized.add(name);
         }
     }
     
     @Override
     @SuppressWarnings("unchecked")
     public void service(HttpServletRequest requestHttpServletResponse responsethrows ServletExceptionIOException {
         String method = request.getMethod();
         String path = request.getPathInfo();
         String urlQuery = request.getQueryString();
 
         if ( != null) {
             Zone zone = .getZone(request);
             
             if (.isDebugEnabled()) {
                 .debug("> " + method + " [" + zone.getName() + "] " + path + ((urlQuery != null) ? "?" + urlQuery : ""));
                 Enumeration<Stringen = request.getHeaderNames();
                 while (en.hasMoreElements()) {
                     String header = en.nextElement();
                     .trace("{}: {}"headerrequest.getHeader(header));
                 }
             } else if (.isInfoEnabled()) {
                 String zoneName = (zone != null) ? zone.getName() : "";
                 .info("{} {} [{}]"new String[] { method,path,zoneName });
             }
     
             setRoutingCookie(requestresponse);
             
             try {
                 if () {
                     if ( == null) {
                         ButterflyModule module = .getModule(path,zone);
                         .debug("Module '{}' will handle the request"module.getName());
                         String localPath = module.getRelativePath(request);
                         if (!module.process(localPathrequestresponse)) {
                             response.sendError(.);
                         }
                     } else {
                         error(response"Butterfly Error""Butterfly incurred in the following errors while initializing:");
                     }
                 } else {
                     delay(response"Butterfly is still initializing...");
                 }
             } catch (FileNotFoundException e) {
                 response.sendError(.);
             } catch (Exception e) {
                 error(response"Butterfly Error""Butterfly caught the following error while processing the request:"e);
             }
     
             response.flushBuffer();
             if (.isDebugEnabled()) .debug("< " + method + " [" + zone.getName() + "] " + path + ((urlQuery != null) ? "?" + urlQuery : ""));
 
         } else {
             response.sendError(.);
         }
     }
     
     // ---------------------------- private -----------------------------------
     
     final static private String dependencyPrefix = "requires";
     final static private String implementsProperty = "implements";
     final static private String extendsProperty = "extends";
     
     protected Map<String,Boolean_created = new HashMap<String,Boolean>();
 
     final static private String routingCookie = "host";
     
     /*
      * This method adds a cookie to the response that will be used by mod_proxy_balancer
      * to know what server is supposed to be handling all the requests of this user agent. 
      */
     protected void setRoutingCookie(HttpServletRequest requestHttpServletResponse response) {
         Cookie[] cookies = request.getCookies();
         if (cookies != null) {
             for (Cookie cookie : cookies) {
                 if (.equals(cookie.getName())) {
                     return;
                 }
             }
         }
         
         Cookie cookie = new Cookie("." + ); // IMPORTANT: the initial dot is required by mod_proxy_balancer!
         cookie.setMaxAge(); // delete at end of browser session
         cookie.setPath("/");
         response.addCookie(cookie);
     }
     
     protected File absolutize(File baseString location) {
         if (location == null || location.length() == 0) { // we got an empty location
             return base;
         } else if (location.indexOf(':') > 0) { // we got an absolute windows location (ie c:\blah)
             return new File(location);
         } else if (location.charAt(0) == '/' || location.charAt(0) == '\\') { // we got an absolute location
             return new File(location);
         } else { // we got a relative location
             return new File(baselocation);
         }
     }
 
     protected static final String PATH_PROP = "__path__";
     
     protected void findModulesIn(File f) {
         .debug("look for modules in {}"f);
         File modFile = new File(f,"MOD-INF");
         if (modFile.exists()) {
             .trace("> findModulesIn({})"f);
             try {
                 String name = f.getName();
 
                 ExtendedProperties p  = new ExtendedProperties();
                 File propFile = new File(modFile,"module.properties");
                 if (propFile.exists()) {
                     .watch(propFile); // reload if the the module properties change
                     BufferedInputStream stream = new BufferedInputStream(new FileInputStream(propFile));
                     p.load(stream);
                     stream.close();
                 }
 
                 p.addProperty(f.getAbsolutePath());
                 
                 if (p.containsKey("name")) {
                     name = p.getString("name");
                 }
                 
                 boolean load = true;
                 
                 for (String s : ) {
                     if (name.matches(s)) {
                         load = false;
                         break;
                     }
                 }
                 
                 if (load) {
                     .put(namep);
                 }
             } catch (Exception e) {
                 .error("Error finding module wirings"e);
             }
             .trace("< findModulesIn({})"f);
         } else {
             File[] files = f.listFiles();
             if (files != null) {
                 for (int i = 0; i < files.lengthi++) {
                     File file = files[i];
                     try {
                         if (file.isDirectory()) {
                             findModulesIn(file);
                         }
                     } catch (AccessControlException e) {
                         // skip
                         // NOTE: this is needed for Google App Engine that doesn't like us snooping around the internal file system
                     }
                 }
             }
         }
     }
 
     protected ButterflyModule createModule(String name) {
         .trace("> Creating module: {}"name);
 
         if (.containsKey(name)) {
             .trace("< Module '{}' already exists"name);
             return .get(name);
         }
 
         ExtendedProperties p = .get(name);
         File path = new File(p.getString());
         .debug("Module path: {}"path);
             
         File classes = new File(path,"MOD-INF/classes");
         if (classes.exists()) {
             .addRepository(classes);
         }
         
         File libs = new File(path,"MOD-INF/lib");
         if (libs.exists()) {
             .addRepository(libs);
         }
 
         ButterflyModule m = new ButterflyModuleImpl();
         
         // process module's controller
         String manager = p.getString("module-impl");
         if (manager != null && !manager.equals(m.getClass().getName())) {
             try {
                 Class<?> c = .loadClass(manager);
                 m = (ButterflyModulec.newInstance();
             } catch (Exception e) {
                 .error("Error loading special module manager"e);
             }
         }
         
         m.setName(name);
         m.setPath(path);
         m.setModules();
         m.setMounter();
         m.setClassLoader();
         m.setTimer();
             
         .put(name,m);
             
         // process inheritance
         ButterflyModule parentModule = null;
         String parentName = p.getString();
         if (parentName != null) {
             if (.containsKey(parentName)) {
                 if (.containsKey(parentName)) {
                     parentModule = .get(parentName);
                 } else {
                     parentModule = createModule(parentName);
                 }
             } else {
                 throw new RuntimeException("Cannot wire module '" + name + "' because the extended module '" + parentName + "' is not defined.");
             }
         }
 
         if (parentModule != null) {
             m.setExtended(parentModule);
             parentModule.addExtendedBy(m);
         }
             
         .trace("< Creating module: {}"name);
         
         return m
     }
 
     @SuppressWarnings("unchecked")
 	protected void wireModules(ExtendedProperties wirings) {
         .trace("> wireModules()");
 
         .info("mounting modules");
         
         for (String name : .keySet()) {
             .trace("> Mounting module: {}"name);
             ButterflyModule m = .get(name);
             String mountPointStr = wirings.getString(m.getName());
             if (mountPointStr == null) {
             	String moduleName = m.getName(); 
             	String mountPoint =  + "/" + m.getName();
                 .info("No mount point defined for module '" + moduleName + "', mounting to '" + mountPoint + "'");
             	mountPointStr = mountPoint;
             }
             
             MountPoint mountPoint = new MountPoint(mountPointStr);
             if (.isRegistered(mountPoint)) {
                 throw new RuntimeException("Cannot have two different modules with the same mount point '" + mountPoint + "'.");
             } else {
                 .register(mountPointm);
             }
             .trace("< Mounting module: {}"name);
         }
         
         for (String name : .keySet()) {
             .trace("> Expanding properties for module: {}"name);
             ButterflyModule m = .get(name);
             ExtendedProperties p = .get(name);
             ButterflyModule extended = m.getExtendedModule();
 
             while (extended != null) {
                 .trace("> Merging properties from extended module: {}"name);
                 ExtendedProperties temp = p;
                 p = .get(extended.getName());
                 p.combine(temp);
                 .trace("< Merging properties from extended module: {} -> {}"namep);
                 extended = extended.getExtendedModule();
             }
             
             .put(name,p);
             
             List<Stringimplementations = p.getList();
             if (implementations != null) {
                 for (String i : implementations) {
                     Map<StringButterflyModulemap = .get(i);
                     if (map == null) {
                         map = new HashMap<String,ButterflyModule>();
                         .put(imap);
                     }
                     map.put(namem);
                     m.setImplementation(i);
                 }
             }
             .trace("< Expanding properties for module: {}"name);
         }
         
         for (String name : .keySet()) {
             .trace("> Inject dependencies in module: {}"name);
             ExtendedProperties p = .get(name);
             ButterflyModule m = .get(name);
 
             for (Object o : p.keySet()) {
                 String s = (Stringo;
                 if (s.equals()) {
                     for (Object oo : p.getList(s)) {
                         String dep = (Stringoo;
                         .trace("> Processing dependency: {}"dep);
                         dep = dep.trim();
                         Map<String,ButterflyModulemodules = .get(dep);
                         if (modules != null) {
                             if (modules.size() == 1) {
                                 // if there's only one module implementing that interface, wiring is automatic
                                 setDependency(mdepmodules.values().iterator().next());
                             } else {
                                 ButterflyModule parent = m.getExtendedModule();
                                 do {
                                     String wiredDependency = wirings.getString(name + "." + dep);
                                     if (wiredDependency != null) {
                                         setDependency(mdep.get(wiredDependency));
                                         break;
                                     } else {
                                         if (parent != null) {
                                             name = parent.getName();
                                         }
                                     }
                                 } while (parent != null);
                             }
                         } else {
                             throw new RuntimeException("Cannot wire module '" + name + "' because no module implements the required interface '" + dep + "'");
                         }
                         .trace("< Processing dependency: {}"dep);
                     }
                 }
             }
             
             .trace("< Inject dependencies in module: {}"name);
         }
         
         ButterflyModule rootModule = .getRootModule();
         
         // in case nothing defined the root mount point use the default one
         if (rootModule == null) {
             rootModule = .get("main");
         }
         
         // in case not even the 'main' module is available, give up
         if (rootModule == null) {
             throw new RuntimeException("Cannot initialize the modules because I can't guess which module to mount to '/'");
         }
         
         .trace("< wireModules()");
     }    
         
     @SuppressWarnings("unchecked")
     protected void configureModules() {
         .trace("> configureModules()");
         for (String name : .keySet()) {
             .trace("> Configuring module: {}"name);
             ExtendedProperties p = .get(name);
             ButterflyModule m = .get(name);
             
             // make the system properties accessible to the modules
             m.setProperties();
             
             try {
                 if (p.getBoolean("templating".)) {
                     .trace("> enabling templating");
                     // load the default velocity properties
                     Properties properties = new Properties();
                     File velocityProperties = new File("velocity.properties");
                     .watch(velocityProperties); // reload if the velocity properties change
                     FileInputStream fis = new FileInputStream(velocityProperties);
                     properties.load(fis);
                     fis.close();
         
                     // set properties for resource loading
                     properties.setProperty("resource.loader""butterfly");
                     properties.setProperty("butterfly.resource.loader.class"ButterflyResourceLoader.class.getName());
                     properties.setProperty("butterfly.resource.loader.cache""true");
                     properties.setProperty("butterfly.resource.loader.modificationCheckInterval""1");
                     properties.setProperty("butterfly.resource.loader.description""Butterfly Resource Loader");
                         
                     // set properties for macros
                     properties.setProperty("velocimacro.library"p.getString("templating.macros"""));
         
                     // Set our special parent injection directive
                     properties.setProperty("userdirective"Super.class.getName());
         
                     // Set logging properties
                     if () {
                         properties.setProperty(."org.apache.velocity.runtime.log.JdkLogChute");
                     } else {
                         properties.setProperty(."org.apache.velocity.runtime.log.Log4JLogChute");
                         properties.setProperty("runtime.log.logsystem.log4j.logger""velocity");
                     }
 
                     // create a module-specific velocity engine
                     VelocityEngine velocity = new VelocityEngine();
                     velocity.setApplicationAttribute("module"m); // this is how we pass the module to the resource loader
                     velocity.init(properties);
                     
                     // inject the template engine in the module
                     m.setTemplateEngine(velocity);
                     .trace("< enabling templating");
                 }
 
                 List<Stringscriptables = p.getList("scriptables");
                 if (scriptables.size() > 0) {
                     Context context = Context.enter();
 
                     BufferedReader initializerReader = null
 
                     for (String scriptable : scriptables) {
                         if (!scriptable.equals("")) {
                             try {
                                 .trace("> adding scriptable object: {}"scriptable);
                                 @SuppressWarnings("rawtypes")
 								Class c  = .loadClass(scriptable);
                                 ButterflyScriptableObject o = (ButterflyScriptableObjectc.newInstance();
                                 setScriptable(mo);
                                 URL initializer = c.getResource("init.js");
                                 if (initializer != null) {
                                     initializerReader = new BufferedReader(new InputStreamReader(initializer.openStream()));
                                     setScript(minitializercontext.compileReader(initializerReader"init.js", 1, null));
                                     .watch(initializer,m);
                                     .trace("Parsed scriptable javascript initializer successfully");
                                 }
                                 .trace("< adding scriptable object: {}"scriptable);
                             } catch (Exception e) {
                                 .trace("Error initializing scriptable object '{}': {}"scriptablee);
                             } finally {
                                 if (initializerReader != nullinitializerReader.close();
                             }
                         }
                     }
 
                     Context.exit();
                 }
                 
                 List<Stringcontrollers = p.getList("controller");
                 Set<URLcontrollerURLs = new HashSet<URL>(controllers.size());
                 for (String controller : controllers) {
                     URL controllerURL = m.getResource("MOD-INF/" + controller);
                     if (controllerURL != null) {
                         controllerURLs.add(controllerURL);
                     }
                 }
                 
                 if (controllerURLs.size() > 0) {
                     .trace("> enabling javascript control");
                     
                     Context context = Context.enter();
 
                     BufferedReader initializerReader = null
                     
                     try {
                         URL initializer = this.getClass().getClassLoader().getResource("edu/mit/simile/butterfly/Butterfly.js");
                         initializerReader = new BufferedReader(new InputStreamReader(initializer.openStream()));
                         setScript(minitializercontext.compileReader(initializerReader"Butterfly.js", 1, null));
                         watch(initializer,m);
                         .trace("Parsed javascript initializer successfully");
                     } finally {
                         if (initializerReader != nullinitializerReader.close();
                     }
                     
                     BufferedReader controllerReader = null;
 
                     for (URL controllerURL : controllerURLs) {
                         try{
                             controllerReader = new BufferedReader(new InputStreamReader(controllerURL.openStream()));
                             setScript(mcontrollerURLcontext.compileReader(controllerReadercontrollerURL.toString(), 1, null));
                             watch(controllerURL,m);
                             .trace("Parsed javascript controller successfully: {}"controllerURL);
                         } finally {
                             if (controllerReader != nullcontrollerReader.close();
                         }
                     }
                     
                     Context.exit();
     
                     .trace("< enabling javascript control");
                 }
             } catch (Exception e) {
                 .error("Error enabling javascript control",e);
             }
             .trace("< Configuring module: {}"name);
         }
         .trace("< configureModules()");
     }
 
     protected void setDependency(ButterflyModule subjString depButterflyModule obj) {
         subj.setDependency(depobj);
         ButterflyModule extended = subj.getExtendedModule();
         if (extended != null) {
             setDependency(extendeddepobj);
         }
     }
 
     protected void setScriptable(ButterflyModule modButterflyScriptableObject scriptable) {
         mod.setScriptable(scriptable);
         ButterflyModule extended = mod.getExtendedModule();
         if (extended != null) {
             setScriptable(extendedscriptable);
         }
     }
     
     protected void watch(URL scriptButterflyModule modulethrows IOException {
         if ( != null) {
             .watch(scriptmodule);
         }