+ All Categories
Home > Documents > Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer,...

Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer,...

Date post: 30-Apr-2020
Category:
Upload: others
View: 1 times
Download: 0 times
Share this document with a friend
24
Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network Scripting und Compilation
Transcript
Page 1: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer JOHANNES KEPLER UNIVERSITY LINZ Research and teaching network

Scripting und Compilation

Page 2: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2

Scripting und Compilation

Scripting in der Java VM

Compilation

Page 3: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 3

Scripting

Ab Java 6 Unterstützung von Script-Sprachen

Einfaches API für die Ausführung von Scripts innerhalb der Java VM

Basissystem für die Implementierung von Script-Engines

Installation von Script-Sprachen über Java Services

Mozilla Rhino JavaScript Engine bereits installiert

package javax.script

Page 4: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 4

Vorgehen

Erzeugen eines ScriptEngineManagers

Abrufen einer Script-Engine einer bestimmten (installierten) Script-Sprachen über ScriptEngineManager

Ausführen von Scripts

Behandlung von ScriptExceptions

oder Ausführen eines Script-Programms aus einem File (Verwendung eines Readers)

ScriptEngineManager factory = new ScriptEngineManager(); ScriptEngine engine = factory.getEngineByName( "JavaScript" ); try { engine.eval( "println('Hello World');" ); } catch (ScriptException e) { System.out.println( "Error in script: line " + e.getLineNumber() + ", colum " + e.getColumnNumber() + ", message " + e.getMessage() ); }

engine.eval(new java.io.FileReader( "SimpleGreeter.js" ));

Page 5: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 5

Verwendung von Variablen und Bindings

Binden von Variablen mit put

Abrufen von Variablenwerten mit get

Verwendung von Bindings

engine.put( "x" , 1); engine.eval( "x = x + 1;" ); engine.put( "frame" , new JFrame()); engine.eval( "frame.setVisible(true);" );

Object x = engine.get("x"); System.out.println(x); JFrame frame = (JFrame)engine.get( "frame" ); frame.setVisible(false);

Bindings scope = engine.createBindings(); scope.put( "x" , "xxx" ); engine.eval( "x = x + x;" , scope); Object xxx = scope.get( "x" ); System.out.println(xxx);

2

xxxxxx

x = engine.get( "x" ); System.out.println(x); 2

Wert im globalem Scope bleibt erhalten

Evaluierung im Scope

Page 6: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 6

Funktions- und Methodeaufrufe

Engines müssen Invocable implementieren

Aufruf von Script-Funktionen

Aufruf von Methoden (bei objekt-orientierten Script-Sprachen)

Invocalbe inv = (Invocable) engine;

engine.eval( "function greet(x) {return 'Hello, ' + x + '!'; }" );

String greeting = ((String)inv.invokeFunction( "greet" , "Franz" )); System.out.println(greeting); Hello, Franz!

engine.eval(new FileReader( "SimpleGreeter.js" )); Object goodbyeGreeter = engine.eval( "new SimpleGreeter('Goodbye')" );

System.out.println(inv.invokeMethod(goodbyeGreeter, "greet", "Ann" ));

function SimpleGreeter(salutation) {this.salutation = salutation; } SimpleGreeter.prototype.greet = function(whom) { return this.salutation + ", " + whom + "!" }

"SimpleGreeter.js"

Goodbye, Ann!

Page 7: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 7

Implementierung von Interfaces

Java-Interfaces können durch Script-Objekte implementiert werden

Mit getInterface(Object, Class<T>) von Invocable

engine.eval( "var obj = new Object(); obj.run = function() { println('run method called'); }" ); Object obj = engine.get( "obj" );

Invocalbe inv = (Invocable) engine; Runnable r = inv.getInterface(obj, Runnable.class); Thread thread = new Thread(r); thread.start();

run method called

Page 8: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 8

Compilation von Scripts

Scripts können compiliert werden

mit compile von Compilable

Engine muss Compilable implementieren

erzeugt CompiledScript

das mit eval ausgeführt werden kann

Compilable compEngine = (Compilable)engine; CompiledScript script = compEngine.compile( "println ('compiled script called')" ); script.eval();

compiled script called

Page 9: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 9

Beispiel

Interaktive Java-Script Anwendung

public class JSCalculator { private JTextArea scriptArea; private ScriptEngine jsEngine; privare execBtn; ... public JSCalculator() { ScriptEngineManager manager = new ScriptEngineManager(); jsEngine = manager.getEngineByExtension("js"); frame = new JFrame("JS Calculator"); execBtn = new Jbutton("Exec"); execBtn.addActionListener(execHandler); ... } private ActionListener execHandler = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String script = scriptArea.getText(); Object result; try { result = jsEngine.eval(script); scriptListModel.addElement(script); … scriptArea.setText(" "); } catch (ScriptException e) { resultLabel.setText("Error at column " + e.getColumnNumber() + ": " + e.getMessage()); } catch (Exception e) { resultLabel.setText("Exception occurred: " + e.getMessage()); } } };

TextArea mitJavaScript Code

Page 10: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 10

Installation von Script-Sprachen

Script-Engine werden als Jar-Libraries installiert

Müssen java.script.ScriptEngineFactory Service implementieren

Registrierung als Service in META-INF

Auffinden

ScriptEngineManager manager = new ScriptEngineManager(); System.out.println( "Available factories: " ); for (ScriptEngineFactory factory : manager.getEngineFactories()) { System.out.println(factory.getEngineName()); } final ScriptEngine engine = manager.getEngineByName( "groovy" ); Object result = engine.eval( "x = 1;" );

Service Discovery!

Page 11: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 11

Exkurs

Java Services

Page 12: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 12

Java Service und Service Loader

Implementierungen zur Laufzeit anfordern

Java Service Interface = Spezifikation des Service

Java Service Provider = Implementierung des Service

ServiceLoader = Mechanismus zu Auffinden und Laden der Service

Provider zur Laufzeit

Vorgehen:

Service Interface definieren

Service Provider

implementieren

registieren: in META-INF/services/<full-qualified-servicename>

in Jar-Datei verpacken

Mit ServiceLoader Provider laden

Page 13: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 13

Beispiel Java Services

Service Interface definieren

Service Provider implementieren

registieren: in META-INF/services/<full-qualified-servicename>

package services; public interface MyService { public void doService(); }

package services; public class FirstProvider implements MyService { @Override public void doService() { System.out.println("First Service"); } }

package services; public class SecondProvider implements MyService { @Override public void doService() { System.out.println(“Second Service"); } }

services.FirstProvider services.SecondProvider

Page 14: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 14

Beispiel Java Services

Mit ServiceLoader Provider laden

package services; import java.util.ServiceLoader; public class TestMyServices { public static void main(String[] args) { ServiceLoader<MyService> loader = ServiceLoader.load(MyService.class); for (MyService provider: loader) { provider.doService(); } } }

Page 15: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 15

Scripting und Compilation

Scripting in der Java VM

Compilation

Page 16: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 16

Compiler Tools API

Zugriff auf Javac-Compiler über Tools API

Ausführen des Java-Compilers durch run

int run(InputStream in, OutputStream out, OutputStream err, String... arguments);

JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

int r = compiler.run(null, null, null, "-sourcepath", ".", "SayHalloClass.java");

Streams für Ein-/Ausgabe (Meldungen etc.) Argumente wie bei Aufruf von javac

Standard Ein-/Ausgabe

0 für Erfolg

Page 17: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 17

CompilationTasks

CompliationTask erlaubt genaue Kontrolle über Compilation-Prozess

fileManager: Manager für Source- und Class-Files

diagnosticListeners: Behandlung von Fehlermeldungen

classes: Klassen für Annotations-Verarbeitung (hier nicht verwendet)

compilationUnits: Source-Code

Beispiel:

StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null); DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>(); Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjectsFromStrings(Arrays.asList( "SayHalloClass.java" )); JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits); boolean success = task.call();

CompilationTask getTask(Writer out, JavaFileManager fileManager, DiagnosticListener<? super JavaFileObject> diagnosticListener, Iterable<String> options, Iterable<String> classes, Iterable<? extends JavaFileObject> compilationUnits);

Stamdard: Lesen und Schreiben auf Filesystem

Page 18: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 18

Bsp: Generierung und Compilieren von generiertem Code

Basisklasse mit abstrakter Methode addEventHandlers

Genierierter Code

public abstract class ButtonFrame extends JFrame { public ButtonFrame() {

panel = new JPanel(); yellowButton = new JButton("Yellow"); blueButton = new JButton("Blue"); redButton = new JButton("Red"); ... addEventHandlers(); } protected abstract void addEventHandlers(); … }

yellowButton=panel.setBackground(java.awt.Color.YELLOW); blueButton=panel.setBackground(java.awt.Color.BLUE); redButton=panel.setBackground(java.awt.Color.RED);

Textfile action.properties mit Action-Code

für Buttons

package x; public class Frame extends com.horstmann.corejava.ButtonFrame { protected void addEventHandlers() { yellowButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent event) { panel.setBackground(java.awt.Color.YELLOW); } } ); redButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent event) { panel.setBackground(java.awt.Color.RED); } } ); blueButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent event) { panel.setBackground(java.awt.Color.BLUE); } } ); } }

Page 19: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 19

Bsp: Generierung und Compilieren von generiertem Code

1. Source-Code wird mit StringBuilder dynamisch erzeugt

2. Byte-Code wird in Byte-Array abgelegt

3. Code wird aus Byte-Array geladen und ausgeführt

Ad 1.) JavaFileObject mit StringBuilder als Quelle

public class StringBuilderJavaSource extends SimpleJavaFileObject { public StringBuilderJavaSource(String name) { super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE); code = new StringBuilder(); } public CharSequence getCharContent(boolean ignoreEncodingErrors) { return code; } public void append(String str) { code.append(str); code.append('\n'); } private StringBuilder code; }

Name des „FileObjects“

liefert Source-Code

für Erzeugung des Source-Codes

Page 20: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 20

Beispiel: Generierung und Compilieren von Code

Ad 1.) Erzeugen des Source-Codes aus Template

static JavaFileObject buildSource(String superclassName) throws IOException { StringBuilderJavaSource source = new StringBuilderJavaSource("x.Frame"); source.append("package x;\n"); source.append("public class Frame extends " + superclassName + " {"); source.append("protected void addEventHandlers() {"); Properties props = new Properties(); props.load(new FileReader("action.properties")); for (Map.Entry<Object, Object> e : props.entrySet()) { String beanName = (String) e.getKey(); String eventCode = (String) e.getValue(); source.append(" " + beanName + ".addActionListener(new java.awt.event.ActionListener() {"); source.append(" public void actionPerformed(java.awt.event.ActionEvent event) {"); source.append(" " + eventCode); source.append(" } } );"); } source.append("} }"); return source; } }

Event Code aus Datei action.properties wird in

actionPerformed von ActionsListener verpackt und

bei Komponenten angefügt!

Page 21: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 21

Beispiel: Generierung und Compilieren von Code

Ad 2.) JavaFileObject mit ByteArrayOutputStream für Byte-Code

public class ByteArrayJavaClass extends SimpleJavaFileObject { public ByteArrayJavaClass(String name) { super(URI.create("bytes:///" + name), Kind.CLASS); stream = new ByteArrayOutputStream(); } public OutputStream openOutputStream() throws IOException { return stream; } public byte[] getBytes() { return stream.toByteArray(); } private ByteArrayOutputStream stream; }

OutputStream für Compiler

liefert Byte-Code

Name des „FileObjects“

Page 22: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 22

Beispiel: Generierung und Compilieren von Code

Ad 2.) Erzeugen eines FileManagers, der entsprechende FileObjects

liefert

ForwardingJavaFileManager

JavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null); fileManager = new ForwardingJavaFileManager<JavaFileManager>(fileManager) { public JavaFileObject getJavaFileForOutput(Location location, final String className, Kind kind, FileObject sibling) throws IOException { if (className.startsWith("x.")) { ByteArrayJavaClass fileObject = new ByteArrayJavaClass(className);

classFileObjects.add(fileObject); return fileObject;

} else { return super.getJavaFileForOutput(location, className, kind, sibling);

} } };

Delegation aller nicht-

überschriebenen Aufrufe

zu diesem FileManager

Liefert ByteArrayJavaClass für alle Klassen im Package "x"

Page 23: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 23

Beispiel: Generierung und Compilieren von Code

Ad 3.) Compilation

Laden

Ausführen (über Reflection)

JavaFileObject source = buildSource("com.horstmann.corejava.ButtonFrame"); JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null, null, Arrays.asList(source)); Boolean result = task.call();

Map<String, byte[]> byteCodeMap = new HashMap<String, byte[]>(); for (ByteArrayJavaClass cl : classFileObjects) { byteCodeMap.put(cl.getName().substring(1), cl.getBytes()); } ClassLoader loader = new MapClassLoader(byteCodeMap); Class<?> cl = loader.loadClass("x.Frame");

JFrame frame = (JFrame) cl.newInstance(); frame.setTitle("CompilerTest"); frame.setVisible(true);

public class MapClassLoader extends ClassLoader { public MapClassLoader(Map<String, byte[]> classes) { this.classes = classes; } protected Class<?> findClass(String name) throws ClassNotFoundException { byte[] classBytes = classes.get(name); if (classBytes == null) throw new ClassNotFoundException(name); Class<?> cl = defineClass(name, classBytes, 0, classBytes.length); if (cl == null) throw new ClassNotFoundException(name); return cl; } private Map<String, byte[]> classes; }

Page 24: Scripting und Compilation€¦ · Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 2 Scripting und Compilation

Pratikum SWE 2 © M. Löberbauer, T. Kotzmann, H. Prähofer, Institut für Systemsoftware, Johannes Kepler Universität Linz 24

Zusammenfassung

Scripting API erlaubt Verwendung von Script-Sprachen in Java-

Anwendungen

Compiler Tool API erlaubt Verwendung des Java-Compilers in Java-

Anwendungen

Java Service API wird zum Auffinden von installierten Script-Sprachen

und Compilern verwendet


Recommended