630 likes | 784 Views
Polyglot alchemy: JSR 223 in action. Fabrice Matrat Marc Campora. Marc Campora Sr Manager Java Middleware mcampora@amadeus.com @ mcampora. Fabrice Matrat System Architect Technical Evangelist fmatrat@amadeus.com @ fabricematrat. Amadeus.
E N D
Polyglot alchemy: JSR 223 in action FabriceMatrat Marc Campora
Marc Campora • Sr Manager • Java Middleware • mcampora@amadeus.com • @mcampora
FabriceMatrat • System Architect • Technical Evangelist • fmatrat@amadeus.com • @fabricematrat
Amadeus • Leading provider of IT solutions for the travel industry • Connect Providers (ex. airlines) and Resellers (ex. TAs) • Provide IT solutions (ex. check-in or inventory system)
System Constraints 600k Terminals 1.6B Transactions/day <0.5s Response time 3.7M Bookings/day 100+ IT changes/day 99.99% Availability
Our products • Inventory • Departure control • Self Booking Tools • Point-of-sale • e-Commerce • Mobile companions
Technical platform • A clear technical strategy • RIA even for the mobile • Community products • SaaS, multi-tenants infrastructure
Problem statement • Community versus specific
From SaaS to PaaS Application UI Application logic Middleware & Framework
From SaaS to PaaS Application UI A P I Custom UI Custom UI Application logic Custom logic Script execution environment Middleware & Framework
Scripting on JVM Application UI A P I Script Script Script Application logic Script execution environment Middleware & Framework
Embed Groovy Binding binding = new Binding(); binding.setVariable("foo", new Integer(2)); GroovyShellshell = new GroovyShell(binding); shell.evaluate("println 'Hello World!'; x = 123; return foo * 10");
Embed Groovy ClassLoader parent = getClass().getClassLoader(); GroovyClassLoader loader = newGroovyClassLoader(parent); File script = new File("HelloWorld.groovy")Class<GroovyObject> groovyClass = loader.parseClass(script); GroovyObjectgroovyObject = groovyClass.newInstance(); groovyObject.invokeMethod("run", new Object[0]);
Embed Groovy String[] roots = new String[] { "/my/groovy/script/path" }; GroovyScriptEnginegse = newGroovyScriptEngine(roots); Binding binding = new Binding(); binding.setVariable("input", "world"); gse.run("hello.groovy", binding); System.out.println(binding.getVariable("output"));
Groovy vs. JSR 223 Bindingbinding = newBinding(); binding.setVariable("foo", newInteger(2)); GroovyShellshell = newGroovyShell(binding); shell.evaluate("println'Hello World!'; x = 123; return foo * 10"); ScriptEngineManagermgr = newScriptEngineManager(); ScriptEngineengine= mgr.getEngineByName("groovy"); Bindigs bindings = engine.createBindings(); bindings.put("foo", newInteger(2)); engine.eval("println'Hello World!'; x = 123; return foo * 10",bindings);
Multiple script technology ScriptEngineManagermgr = newScriptEngineManager(); ScriptEngineengine = mgr.getEngineByName( "freemarker"); engine.eval("Hello ${who}!"); ScriptEngineManagermgr = newScriptEngineManager(); ScriptEngineengine = mgr.getEngineByName( "groovy"); engine.eval("println'Hello World!'");
Availability • 800 languages on JVM • Around 60 are maintained • 20 have JSR 223 Implementation
Performance • Compilation Result • JSR 223 No Access • Storage Script Script Script Script Compilation Result
Performance • Cache Byte Code Custom classloader Cache
Hot swapping Groovy • Run 2 versions of the same script Passport.groovy got changed Custom classloader Passport.class new code 1110000011 new hash new code 1110000011 new hash
Sandbox • Script in JVM sharing platform and resources
Sandbox • Bad things can happen • Consume resources (CPU, disk, threads) • Java and Amadeus API is available • java.lang.System.exit(1)
Compile : How ? • Check every node in AST @ compile time • org.codehaus.groovy.control.customizers.CompilationCustomizer • org.codehaus.groovy.ast.GroovyCodeVisitor
Compile : Design • Deny/Allow/Deny • Blacklist Everything • Whitelist • Blacklist Methods granularity in whitelisted classes • java.lang.System java.lang.System.exit java.lang.System.currentTimeMillis
Compile : Implementation classSecureCodeCustomizerextendsCompilationCustomizer { publicSecureCodeCustomizer() { super(CompilePhase.CANONICALIZATION); } publicvoid call(…) { finalModuleNodeast = source.getAST(); ast.getStatementBlock().visit(new SecureCodeVisitor()); … } } classSecureCodeVisitorimplementsGroovyCodeVisitor { publicvoidvisitMethodCallExpression(MethodCallExpressioncall) { checkMethodAuthorized(call); … } publicvoidvisitStaticMethodCallExpression (…) {…} publicvoidvisitClassExpression (…) {…} … }
Runtime • Java Security • leverage the JVM's Security Managers • Wrap Primitive/Method • Add Wrapping ((Object)"ls").execute() defobj = ((Object)"ls") // Throw an exception if necessary authorizeStatement(obj, "execute") obj.execute();
Sandbox code (for stability) • Timeout enforcement • Protection against infinite loops and other patterns • Injected @ compile time via AST transformation @groovy.transform.TimedInterrupt( value = 10L, unit = TimeUnit.SECONDS ) defconfig = newCompilerConfiguration() def customizer = newASTTransformationCustomizer( [value:10L, unit:TimeUnit.SECONDS], TimedInterrupt) config.addCompilationCustomizers(customizer)
We are not alone • Oracle Application Developer Framework • https://github.com/sjurgemeyer/GR8ConfUS2013/tree/master/JimDriscoll • Jenkins • http://kohsuke.org/2012/04/27/groovy-secureastcustomizer-is-harmful/ • Call to the community for improvement !
Remoting • AST can optimize the Contextual information sent to the Execution Farm. REST/Json with application context Application farm Scripting farm(s)
Remoting • Isolation • SandBox Failure • Memory or IO contentions • No Resources Impact on Main application Farm • Customers or staging isolation • On demand provisioning • Fine grain usage reports • Billing Model