package org.apache.felix.mishell; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; public class OSGiScriptEngineFinder { private BundleContext context; public OSGiScriptEngineFinder(BundleContext context) { this.context = context; } private List<String> getAllEngineFactoryCandidates() throws IOException{ Bundle[] bundles = context.getBundles(); List<String> factoryCandidates = new ArrayList<String>(); for (Bundle bundle : bundles) { System.out.println(bundle.getSymbolicName()); if(bundle.getSymbolicName().equals("system.bundle")) continue; Enumeration urls = bundle.findEntries("META-INF/services", "javax.script.ScriptEngineFactory", false); if (urls == null) continue; while (urls.hasMoreElements()) { URL u = (URL) urls.nextElement(); BufferedReader reader = new BufferedReader( new InputStreamReader(u.openStream())); String line; while ((line = reader.readLine()) != null) { factoryCandidates.add(line.trim()); //Just for testing: try { Class engineFactory=Class.forName(line.trim()); ScriptEngineManager manager=new ScriptEngineManager(engineFactory.getClassLoader()); for (ScriptEngineFactory f: manager.getEngineFactories()){ ClassLoader old=Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(engineFactory.getClassLoader()); ScriptEngine e=f.getScriptEngine();//.eval(f.getOutputStatement("Hello world")); Thread.currentThread().setContextClassLoader(old); e.eval("File.new(\"\")"); Thread.currentThread().sleep(1000); } } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ScriptException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } return factoryCandidates; } public ScriptEngineManager getManagerFor(String factoryName) throws ClassNotFoundException{ Class factory=Class.forName(factoryName); String a; ScriptEngineManager manager=new ScriptEngineManager(factory.getClassLoader()); //Does this manager know the factory? boolean flag=false; for (ScriptEngineFactory fac : manager.getEngineFactories()){ if(fac.getClass().equals(factory)) flag=true; } return manager; } /** * Adds Engine factories found in installed bundles. The resolution order is the following: * <ol> * <li>First, all the factories found by the manager are used. This includes all factories seen by * the class loader that instantiated the ScriptEngineManager * </li> * <li>Then, by order of installation, the rest of the bundles are seeked. Therefore, if an engine appears in * two bundles, only the first one is used. * </li> * </ol> * This should not be a problem, as this method is intended for sparse use (only when changing the language) * @param the manager to whom the factories are going to be added * @exception RuntimeException wrapper for IOException in case there is any problem with the bundle.findEntries methods * @exception RuntimeException wrapper for ClassNotFoundException and InstantiationException which are supposed not to happen */ public void addEngineFactories(ScriptEngineManager manager){ //TODO refactor all this to make it work. An option is to directly use System.out.println("calling add engine factories"); try{ List<String> factoryCandidates=this.getAllEngineFactoryCandidates(); for (String candidate: factoryCandidates){ System.out.println("Candidate: "+candidate); Class factoryClazz=this.getClass().getClassLoader().loadClass(candidate); ScriptEngineFactory factory=(ScriptEngineFactory) factoryClazz.newInstance(); ScriptEngine engine=factory.getScriptEngine(); try { engine.eval("puts 'Hello world'"); } catch (ScriptException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(manager.getEngineByName(factory.getLanguageName())!=null){ System.out.println("Engine already existing. Continuing"); continue; //This means that there already is a factory for that language } //Now we register the factory for all its names, extensions and mime types for(String name: factory.getNames()){ System.out.println("registering "+name); manager.registerEngineName(name, factory); } for (String type: factory.getMimeTypes()){ manager.registerEngineMimeType(type, factory); System.out.println(manager.getEngineByMimeType(type).equals(factory)); } for (String extension: factory.getExtensions()){ manager.registerEngineExtension(extension, factory); System.out.println(manager.getEngineByExtension(extension).equals(factory)); } } System.out.println("manager now has: "); System.out.println(manager.getEngineByName("jruby")); for (ScriptEngineFactory f : manager.getEngineFactories()){ System.out.println(f); } }catch (IOException ioe){ throw new RuntimeException(ioe); } catch (ClassNotFoundException cnfe) { } catch (InstantiationException iee) { throw new RuntimeException (iee); } catch (IllegalAccessException iae) { throw new RuntimeException(iae); } } }