/** Intercepts all messages sent from the client */ @Override public String handle(ClientImpl client, Transport transport, Message message) throws IOException { if (!message.getChannel().startsWith("/meta")) { // These are published messages Persistable target = (Persistable) Identification.idForString((String) message.getChannel()).getTarget(); Function messageFunc = (Function) target.get("message"); messageFunc.call( PersevereContextFactory.getContext(), GlobalData.getGlobalScope(), target, new Object[] {message.getData()}); // don't actually publish it, let Persevere handle it return null; } if (message.getChannel().startsWith("/meta/subscribe")) { // A subscription request, we just need to make sure the global listener // object is subscribed to the given resource String id = (String) message.get("subscription"); while (id.endsWith("*")) { id = id.substring(0, id.length() - 1); } Object target = Identification.idForString(id).getTarget(); if (target instanceof ObservablePersistable) ((ObservablePersistable) target).subscribe(); PersistableObject.addListener(jettyBayeuxRestListener); } return super.handle(client, transport, message); }
public class ModuleLoader extends PersevereNativeFunction { String currentJslibPath = ""; // create the require function so dependencies can be done in proper order Map<String, ScriptableObject> exports = new HashMap<String, ScriptableObject>(); Map<String, File> jslibFiles = new HashMap<String, File>(); Scriptable global = GlobalData.getGlobalScope(); Log log = LogFactory.getLog(ModuleLoader.class); Map<String, Long> lastTimeStamps = new HashMap<String, Long>(); File jslibDirectory; public ModuleLoader() { global.put("require", global, this); } public void scanForFiles(File jslibDirectory) { this.jslibDirectory = jslibDirectory; scanForFiles(); } public void scanForFiles() { try { if (jslibDirectory.exists()) for (File file : DataSourceManager.getConfigFiles(jslibDirectory)) { String path = file.getCanonicalPath(); path = path.replace(File.separatorChar, '/'); path = path.split("\\/jslib\\/")[1]; jslibFiles.put(path, file); } } catch (IOException e) { throw new RuntimeException(e); } } public void loadFiles() { for (String filename : new HashSet<String>(jslibFiles.keySet())) { try { call(PersevereContextFactory.getContext(), global, global, new Object[] {filename}); } catch (RhinoException e) { log.error( e.details() + " on line " + e.lineNumber() + " in " + e.sourceName() + '\n' + e.getScriptStackTrace()); } catch (Throwable e) { throw new RuntimeException("Trying to load " + filename, e); } } } @Override public synchronized Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { Transaction previousTransaction = Transaction.currentTransaction(); Transaction.startTransaction(); String filename = (String) args[0]; if (filename.startsWith(".")) filename = currentJslibPath + filename; filename = Pattern.compile("\\.\\./[^.]*/").matcher(filename).replaceAll("/"); filename = filename.replace("./", ""); InputStream inStream; ScriptableObject exportObject; String oldJsLibPath = currentJslibPath; try { File jslibFile = jslibFiles.get(filename); if (jslibFile == null && !filename.endsWith(".js")) { filename += ".js"; jslibFile = jslibFiles.get(filename); } if (jslibFile == null) throw ScriptRuntime.constructError("Error", "File not found " + filename); exportObject = exports.get(filename); Long lastTimeStamp = lastTimeStamps.get(filename); if (lastTimeStamp == null || lastTimeStamp < jslibFile.lastModified()) { lastTimeStamps.put(filename, jslibFile.lastModified()); inStream = new FileInputStream(jslibFile); exportObject = new NativeObject(); ScriptRuntime.setObjectProtoAndParent((ScriptableObject) exportObject, global); // setup the module scope ScriptableObject moduleScope = new NativeObject(); moduleScope.setParentScope(global); int lastSlash = filename.lastIndexOf('/'); currentJslibPath = lastSlash == -1 ? "" : filename.substring(0, lastSlash + 1); moduleScope.put("exports", moduleScope, exportObject); // memoize exports.put(filename, exportObject); // evaluate the script try { cx.evaluateString(moduleScope, IOUtils.toString(inStream, "UTF-8"), filename, 1, null); } catch (RuntimeException e) { // revert exports.remove(filename); jslibFiles.put(filename, jslibFile); throw e; } // re-retrieve it in case the library changed it exportObject = (ScriptableObject) moduleScope.get("exports", moduleScope); exports.put(filename, exportObject); if ("jsgi-app.js".equals(filename)) { // handle jackconfig.js, setting up the app if it is there global.put("app", global, exportObject.get("app", exportObject)); } // freeze it // exportObject.sealObject(); } Transaction.currentTransaction().commit(); } catch (IOException e) { throw ScriptRuntime.constructError("Error", e.getMessage()); } finally { currentJslibPath = oldJsLibPath; previousTransaction.enterTransaction(); } return exportObject; } public void freezeExports() { for (String filename : new HashSet<String>(jslibFiles.keySet())) { try { ScriptableObject exportObject = (ScriptableObject) call(PersevereContextFactory.getContext(), global, global, new Object[] {filename}); exportObject.sealObject(); } catch (RhinoException e) { log.error( e.details() + " on line " + e.lineNumber() + " in " + e.sourceName() + '\n' + e.getScriptStackTrace()); } } } public void startTimer() { GlobalData.jsTimer.schedule( new TimerTask() { @Override public void run() { try { scanForFiles(); loadFiles(); } catch (Throwable e) { log.error(e); } } }, 1000, 500); } }