Monday, May 2, 2016

JDK 9'da Stream Arayüzündeki Yenilikler

JDK'nın yeni sürümü SE 9'un çıkışına henüz yaklaşık bir yıllık bir süre var. Takvim ise aşağıdaki gibi işliyor. Bu takvime göre çıkış zamanı Mart 2017: 
2016/05/26Feature Complete
2016/08/11All Tests Run
2016/09/01Rampdown Start
2016/10/20Zero Bug Bounce
2016/12/01Rampdown Phase 2
2017/01/26Final Release Candidate
2017/03/23General Availability
Ancak ön deneme sürümü yayınladı. Ön deneme sürümüne bu bağlantıdan ulaşabilirsiniz. Bu sürümde desteklenen özelliklerin listesini aşağıda bulabilirsiniz:
Process API Updates
HTTP 2 Client
Improve Contended Locking
Unified JVM Logging
Compiler Control
Variable Handles
Segmented Code Cache
Smart Java Compilation, Phase Two
The Modular JDK
Modular Source Code
Elide Deprecation Warnings on Import Statements
Resolve Lint and Doclint Warnings
Milling Project Coin
Remove GC Combinations Deprecated in JDK 8
Tiered Attribution for javac
Process Import Statements Correctly
Annotations Pipeline 2.0
Datagram Transport Layer Security (DTLS)
Modular Run-Time Images
Simplified Doclet API
jshell: The Java Shell (Read-Eval-Print Loop)
New Version-String Scheme
HTML5 Javadoc
Javadoc Search
UTF-8 Property Files
Unicode 7.0
Add More Diagnostic Commands
Create PKCS12 Keystores by Default
Remove Launch-Time JRE Version Selection
Improve Secure Application Performance
Generate Run-Time Compiler Tests Automatically
Test Class-File Attributes Generated by javac
Parser API for Nashorn
Linux/AArch64 Port
Multi-Release JAR Files
Remove the JVM TI hprof Agent
Remove the jhat Tool
Java-Level JVM Compiler Interface
TLS Application-Layer Protocol Negotiation Extension
Validate JVM Command-Line Flag Arguments
Leverage CPU Instructions for GHASH and RSA
Compile for Older Platform Versions
Make G1 the Default Garbage Collector
OCSP Stapling for TLS
Store Interned Strings in CDS Archives
Multi-Resolution Images
Use CLDR Locale Data by Default
Prepare JavaFX UI Controls & CSS APIs for Modularization
Compact Strings
Merge Selected Xerces 2.11.0 Updates into JAXP
BeanInfo Annotations
Update JavaFX/Media to Newer Version of GStreamer
HarfBuzz Font-Layout Engine
Stack-Walking API
Encapsulate Most Internal APIs
Module System
TIFF Image I/O
HiDPI Graphics on Windows and Linux
Platform Logging API and Service
Marlin Graphics Renderer
More Concurrency Updates
Unicode 8.0
XML Catalogs
Convenience Factory Methods for Collections
Reserved Stack Areas for Critical Sections
Unified GC Logging
Platform-Specific Desktop Features
DRBG-Based SecureRandom Implementations
Enhanced Method Handles
Modular Java Application Packaging
Dynamic Linking of Language-Defined Object Models
Enhanced Deprecation
Additional Tests for Humongous Objects in G1
Improve Test-Failure Troubleshooting
Indify String Concatenation
HotSpot C++ Unit-Test Framework
jlink: The Java Linker
Enable GTK 3 on Linux
New HotSpot Build System
Spin-Wait Hints

Artık Garbage First Çöp Toplayıcısı (G1GC)  varsayılan çöp toplayıcı:
bool UseG1GC                              := true                             {product}
Ayrıca pek kullanılmayan aşağıdaki çöp toplayıcı birleşimleri Java Sanal Makinasından çıkarıldı:
  • DefNew + CMS
  • ParNew + SerialOld
  • Incremental CMS
Stream Arayüzündeki Yenilikler

   Stream API ile birlikte torbalar üzerinde seri ya da paralel çalışabilen iç döngü oluşturabiliyoruz. Bu döngülerde neler yapılacığını ise Stream arayüzünün metodları ve bu metodlara parametre olarak geçtiğimiz fonksiyonlar aracılığı tanımlıyoruz. Fonksiyonları ise Lambda ifadeleri ya da Metod referansları ile tanımlıyoruz. Java 9'da Stream arayüzünde yeni misafirlerimiz var: takeWhile ve dropWhile. Scala ya da C# programlama dilini kullanarak uygulama geliştirenlerin bildikleri metodlar bunlar. Şimdi bu iki metodun davranışını örnek uygulama üzerinden çalışalım. Elimizde her bir satırında bir Türkçe kelimenin olduğu yirmi beş bin satırdan oluşan dictionary.txt isimli bir dosya bulunuyor. Şimdi sadece A harfinden M harfine kadar olan harflerle başlayan kelimeleri listeleyelim:
Files.lines(Paths.get("src","dictionary.txt"))
     .takeWhile( line -> line.matches("^[a-m].*$") )
     .forEach(System.out::println);
takeWhile metoduna parametre olarak bir Predicate<T> tipinde bir fonksiyon veriyoruz. Bu fonksiyon T'ye karşılık bir boolean değer döndürür. takeWhile bu boolean değer döndüren fonksiyon true değer döndürdüğü sürece akımı devam ettirir, false döndüğü ilk durumda ise akımı keser. 
   Şimdi ise N harfinden itibaren sözlüğün sonuna kadar tüm kelimeleri listeleyelim:
Files.lines(Paths.get("src","dictionary.txt"))
     .dropWhile( line -> line.matches("[a-m].*$") )
     .forEach(System.out::println);
   Şimdi ise birden (1) yüze (100) kadar olan tek sayıların toplamını bulalım. Aslında hesaplama yapmadan 2500 cevabını kolaylıkla verebiliriz. Java'da çözüm için Stream arayüzüne 9 sürümü ile gelen iterator isimli bir metodu kullanacağız:
Stream<Integer> oddNumbers = Stream.iterate(1, n -> n <= 100, n -> n + 2 );
System.out.println(oddNumbers.reduce(0, (acc,num) -> acc + num ));

Stream API Örnekleri

Şimdi dilerseniz, elimizdeki problem için Stream API, Lambda ifadeleri ve Java 8+ ile gelen yenilikleri çalışacağımız bir kaç problem çözelim. 

Topaklanmış İndeks

İlk olarak sözlükteki kelimeleri ilk üç karakterine göre gruplayalım. Bu işleme ilişkisel veri tabanlarında "indeks topaklama" (=clustered index) adını veriyoruz. Bu teknik, karakter katarı (=String) alanlar üzerinde yapılan aramaları indeks boyunu sabit ve aynı indeks değerine sahip kayıtları aynı sayfada tutarak hızlandırmayı amaçlıyor. Java 8+'da bu indekslemeyi aşağıdaki gibi gerçekleştiriyoruz:
Stream<String> words
        = Files.lines(Paths.get("src", "dictionary.txt"));
final Function<String, String> first3CharsLambda = word -> word.length() >= 3 ? word.substring(0, 3) : word.substring(0, word.length());
final Collector<String, ?, Map<String, List<String>>> groupByFirstThreeChars 
        = Collectors.groupingBy(first3CharsLambda);
Map<String,List<String>> clusteredIndex=
        words.collect(groupByFirstThreeChars);        
for (Entry<String,List<String>> entry: clusteredIndex.entrySet()){
    System.out.println(entry.getKey()+": "+entry.getValue());
}

Palindrom

Tersten okunuşu aynı olan kelimelere palindrom adını veriyoruz. Şimdi
sözlüğümüzdeki palindormların listesini veren çözümü Java 8+'de kodlayalım:

package com.example.java9;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.function.Function;

/**
 *
 * @author bkurt
 */
public class Palindrome {

    public static void main(String[] args) throws IOException {
        List<String> words
                = Files.readAllLines(Paths.get("src", "dictionary.txt"));
        Function<String, String> reverse
                = word -> new StringBuilder(word).reverse().toString();
        words.stream().filter(word -> words.contains(reverse.apply(word)))
                .distinct()
                .forEach(System.out::println);
    }

}


Sesli Harf Sayma

Bu örnek uygulamada hangi sesli harf kelimelerde toplam kaç defa kullanılıyor? bunu bulmaya çalışalım:
package com.example.java9;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.AbstractMap;
import java.util.List;
import static java.util.Map.Entry;
import java.util.stream.Collectors;
import static java.util.stream.Collectors.groupingBy;

/**
 *
 * @author Binnur Kurt (binnur.kurt@gmail.com)
 */
public class Vowel {

    public static void main(String[] args) throws IOException {
        List<String> words
                = Files.readAllLines(Paths.get("src", "dictionary.txt"));
        words.stream().flatMap(word -> word.chars().boxed().map(c -> pair(c, word)))
                .collect(groupingBy(Entry::getKey, Collectors.mapping(Entry::getValue, Collectors.toList())))
                .forEach((key, value) -> System.out.format("%c : %d\n", key, value.size()));
    }

    private static <T, U> AbstractMap.SimpleEntry<T, U> pair(T t, U u) {
        return new AbstractMap.SimpleEntry<T, U>(t, u);
    }
}

Düzenli İfade Arama

Bu örnek uygulamada ise sözlükte düzenli ifade arayacağız. a ile başlayan z ile biten ilk kelimeyi bulmaya çalışalım:
Stream<String> words
        = Files.lines(Paths.get("src", "dictionary.txt"));
Optional<String> found= words.filter(word -> word.matches("^a.*z$"))
     .findFirst();
System.out.println(found.orElse("Not found!"));
Şimde ise a ile başlayan z ile biten tüm kelimeleri bulmaya çalışalım:
Stream<String> words
        = Files.lines(Paths.get("src", "dictionary.txt"));
List<String> searchResult= words.filter(word -> word.matches("^a.*z$"))
     .collect(Collectors.toList());
System.out.println(searchResult);
Aynı problemi Java 9'da Scanner sınıfına gelen findAll() metodunu kullanarak da basitçe çözebiliriz:
package com.example.java9;

import java.io.IOException;
import java.nio.file.Paths;
import java.util.List;
import java.util.Scanner;
import java.util.regex.MatchResult;
import java.util.stream.Collectors;

/**
 *
 * @author binnur kurt (binnur.kurt@gmail.com)
 */
public class SearchInFile {
    
    public static void main(String[] args) throws IOException {
        List<String> searchResult = new Scanner(Paths.get("src", "dictionary.txt"))
                .findAll("\\ba.*z\\b")
                .map(MatchResult::group)
                .collect(Collectors.toList());
        searchResult.forEach(System.out::println);
    }
    
}

Wednesday, April 20, 2016

Java Uygulamalarının Windows Servisi Olarak Yönetilmesi

Servis rolünde çalışacak Java uygulamalarını Windows işletim sisteminde Windows servisi olarak tanımlamak isteriz. Windows servisine eklenen uygulamaları, Windows servisi olarak yönetmek, otomatik olarak başlatmak, durdurmak, devre dışı bırakmak, yeniden başlatmak ve eğer varsa bağımlı olduğu diğer servisleri tanımlamak mümkündür. Windows servisi olarak çalıştıracağımız Java uygulaması Java SE'de yazılmış bir web servisi olacak:
package com.example.ws;

import java.util.Collection;
import java.util.Random;
import java.util.stream.Collectors;

import javax.jws.WebService;

@WebService
public class LotteryWS {
 public Collection<Integer> draw() {
  return new Random().ints(1, 50).distinct().limit(6).sorted().boxed()
    .collect(Collectors.toList());
 }
}
Bu web servisini Windows servisi olarak başlatmak ve durdurmak istiyoruz. Bu amaçla Apache Commons'da ye alan Daemon kütüphanesinden yararlanacağız: https://commons.apache.org/proper/commons-daemon. İlk olarak servisi başlatma ve durdurma metodlarını içerecek bir sınıf kodlayacağız:
package com.example.daemon;

import java.util.Scanner;

import javax.xml.ws.Endpoint;

import org.apache.commons.daemon.Daemon;
import org.apache.commons.daemon.DaemonContext;
import org.apache.commons.daemon.DaemonInitException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.example.ws.LotteryWS;

public class SimpleService implements Daemon {
 static final Logger LOG = LoggerFactory.getLogger(SimpleService.class);
 private static LotteryWS ws = new LotteryWS();
 private static Endpoint ep= null;
 private static boolean isRunning = false;

 public static void main(String[] args) {

  Scanner sc = new Scanner(System.in);
  // wait until receive stop command from keyboard
  System.out.printf("Enter 'stop' to halt: ");
  while (!sc.nextLine().toLowerCase().equals("stop"))
   ;

  if (isRunning) {
   terminate();
  }
  sc.close();
 }

 public static void windowsService(String args[]) {
  String cmd = "start";
  if (args.length > 0) {
   cmd = args[0];
  }

  if ("start".equals(cmd)) {
   windowsStart(args);
  } else {
   windowsStop(args);
  }
 }

 public static void windowsStart(String[] args) {
  LOG.info("windowsStart called");
  initialize();
  while (isRunning) {
   synchronized (SimpleService.class) {
    try {
     SimpleService.class.wait(60000);
    } catch (InterruptedException ie) {
    }
   }
  }
 }

 public static void windowsStop(String[] args) {
  LOG.info("windowsStop is called");
  terminate();
  synchronized (SimpleService.class) {
   SimpleService.class.notify();
  }
 }

 public static void initialize() {
  if (ws != null) {
   LOG.info("Starting the WS");
   ep = Endpoint.publish("http://localhost:7001/lottery", ws);
   isRunning=true;   
  }
 }

 public static void terminate() {
  if (ws != null) {
   LOG.info("Stopping the WS");
   ep.stop();
   LOG.info("Web service is stopped.");
   isRunning= false;
  }
 }

 @Override
 public void destroy() {
  LOG.info("Destroying the service...");
 }

 @Override
 public void init(DaemonContext context) throws DaemonInitException,
   Exception {
  LOG.info("Initializing the service...");
 }

 @Override
 public void start() throws Exception {
  LOG.info("Starting the service...");
 }

 @Override
 public void stop() throws Exception {
  LOG.info("Stoping the service...");
 }

}
Her ne kadar bu yazıda Windows işletim sistemini ele almış olsak da bu çözüm Daemon arayüzünü gerçeklediği için Unix işletim sisteminde de kullanılabilir. SimpleService sınıfı ve Java uygulamamız aslında doğrudan Windows servisi ile karşılaşmıyor. SimpleService sınıfını prunsrv.exe için tanımlıyoruz. Windows servisi prunsrv'yi görür. Servis ile ilgili başlat, durdur gibi tüm komutlar prunsrv'ye ulaşır. prunsrv ise uygulamayı SimpleService sınıfı yardımı ile yönetir. SimpleService sınıfında servisi başlatmak yapılacak işlemleri windowsStart(String[] args) metodunda ve servisi durdurmak için gerekli işlemleri ise windowsStop(String[] args) metodunda kodluyoruz. Bu metod isimlerinin prunsrv için özel bir anlamı bulunmuyor. Bu nedenle prunsrv'ye tanıtmamız gerekecek. prunsrv'nin Java prosesini yaratırken hangi Java Sanal Makinasının (JSM) kullanacağını, Heap ve diğer JSM parametrelerinin neler olacağını, CLASSPATH tanımı, servis sınıfı ve servisi başlatma ve durdurma metodlarının adlarının ne olduğunu özel çevre değişkenlerinde tanımlamamız gerekiyor. Yukarıdaki uygulamamızı servis olarak ekleyecek komutları bir betik haline getirebiliriz:
set SERVICE_NAME=LotteryService
set PR_INSTALL=C:\opt\prunsrv.exe
 
REM Service log configuration
set PR_LOGPREFIX=%SERVICE_NAME%
set PR_LOGPATH=c:\tmp
set PR_STDOUTPUT=c:\tmp\stdout.txt
set PR_STDERROR=c:\tmp\stderr.txt
set PR_LOGLEVEL=Info
 
REM Path to java installation
set PR_JVM=c:\opt64\java\jdk1.8.0_60\jre\bin\server\jvm.dll
set PR_CLASSPATH=c:\opt\lottery-service.jar;c:\opt\commons-daemon-1.0.15.jar;c:\opt\slf4j-simple-1.7.6.jar;c:\opt\slf4j-api-1.7.6.jar;c:\opt\logback-core-1.1.7.jar;c:\opt\logback-classic-1.1.7.jar
 
REM Startup configuration
set PR_STARTUP=auto
set PR_STARTMODE=jvm
set PR_STARTCLASS=com.example.daemon.SimpleService
set PR_STARTMETHOD=windowsStart
REM Shutdown configuration
set PR_STOPMODE=jvm
set PR_STOPCLASS=com.example.daemon.SimpleService
set PR_STOPMETHOD=windowsStop
 
REM JVM configuration
set PR_JVMMS=256
set PR_JVMMX=1024
set PR_JVMSS=4000
set PR_JVMOPTIONS=-Duser.language=en;-Duser.region=us
REM Install service 
prunsrv.exe //IS//%SERVICE_NAME%
Servisi kaldırmak için ise aşağıdaki komutu çalıştırıyoruz:
prunsrv.exe //DS/LotteryService
Servisi başlatmak ve durdurmayı test etmek için aşağıdaki komuttan yararlanabilirsiniz:
c:\opt>prunsrv.exe //TS/LotteryService
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/opt/slf4j-simple-1.7.6.jar!/org/slf4j/impl
/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/opt/logback-classic-1.1.7.jar!/org/slf4j/i
mpl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.

SLF4J: Actual binding is of type [org.slf4j.impl.SimpleLoggerFactory]
[main] INFO com.example.daemon.SimpleService - windowsStart called
[main] INFO com.example.daemon.SimpleService - Starting the WS
[Thread-3] INFO com.example.daemon.SimpleService - windowsStop is called
[Thread-3] INFO com.example.daemon.SimpleService - Stopping the WS
[Thread-3] INFO com.example.daemon.SimpleService - Web service is stopped.
Windows servislerini services.msc komutu ile çalıştırdığımız pencere uygulamasından izleyebilir ve yönetebiliriz:
Windows servise eklediğimiz servisleri komut satırından da başlatıp durdurabiliriz:
c:\opt>net start LotteryService
The LotteryService service is starting.
The LotteryService service was started successfully.

c:\opt>net stop LotteryService
The LotteryService service is stopping.
The LotteryService service was stopped successfully.
Servisin durumunu ise aşağıda verildiği şekilde izleyebilirsiniz:
c:\opt>net start LotteryService
The LotteryService service is starting.
The LotteryService service was started successfully.

c:\opt>tasklist | find /I "prun"
prunsrv.exe                   7628 Services                   0     46,256 K

c:\opt>net start | find /I "lottery"
   LotteryService

Tuesday, April 19, 2016

Java Uygulamalarından Python Betiklerinin Çalıştırılması

Java uygulamalarından Python betiklerinin çalıştırılması için birden fazla yöntem bulunuyor. Bu yazıda bu yöntemler incelenecektir.



Jython Kullanımı

Jython projesi, Python dilinin Java platformundaki bir gerçeklemesidir. Jython'un güncel sürümü, Python dilinin 2.7 sürümünü destekliyor. Jython sayesinde Java platformunda Python dilinde yazılmış betikleri doğrudan çalıştırabilirsiniz. Bunun için ilk olarak projesinin sayfasından jython-standalone-2.7.0.jar dosyasını indirmelisiniz. Bundan sonra sample.py isimli Python betiğini Java uygulamamız içinden PythonInterpreter sınıfı aracılığı ile kolaylıkla çalıştırabiliriz:
package com.example.exercise;

import java.util.Properties;

import org.python.util.PythonInterpreter;

public class JythonExample {
 private static PythonInterpreter interpreter;

 public static void main(String[] args) throws Exception {
  Properties properties = System.getProperties();
  properties.setProperty("python.console.encoding", "UTF-8");
  PythonInterpreter.initialize(properties,properties, new String[0]);
  interpreter = new PythonInterpreter();
  interpreter.set("firstName", "Jack");
  interpreter.set("lastName", "Bauer");
  interpreter.execfile("bin/sample.py");
 }

}
sample.py:
print "Hello " + firstName + ", " + lastName +" !"
Java uygulamasından Python betiğine interpreter.set() metodu aracılığı parametre aktarabilir, interpreter.get() metodu aracılığı ile de çalışma sonrasında değişkenlerin değerlerine ulaşabiliriz. Bu yöntemde, en fazla zamanı PythonInterpreter sınıfından nesneyi yarattığımız satır alacaktır: interpreter = new PythonInterpreter();. Bir kez PythonInterpreter nesnesini yarattıktan sonra çalıştırmak hızlıdır. Bu yöntemde, Java uygulamasının çalıştırıldığı makinada Python kurulu olmasına gerek bulunmaz. Java uygulamalarının çalıştırılabildiği herhangi bir makinada Java uygulamamız ve Python betiği çalışacaktır. Jython kütüphanesine maven projesinden erişebilmek için pom.xml dosyasına aşağıdaki bağımlılığı tanımlamak yeterli olacaktır:
<dependency>
 <groupId>org.python</groupId>
 <artifactId>jython-standalone</artifactId>
 <version>2.7.0</version>
</dependency>


ProcessBuilder Kullanımı

İnceleyeceğimiz ikinci yöntem JDK içinde yer alan ProcessBuilder sınıfını kullanmaktır. Java uygulamasından çalıştıracağımız Python betiği (sample.py) aşağıda verilmiştir.
sample.py:
from sys import argv

script, firstName, lastName = argv

print "Hello " + firstName + ", " + lastName +" !"
Şimdi, bu betiği çalıştıracağımız Java uygulamasına bakalım:
package com.example.exercise;

import java.io.File;
import java.util.Map;

public class PythonProcessExample {

 public static void main(String[] args) throws Exception {
  ProcessBuilder pb = new ProcessBuilder("cmd", "/C", "bin\\sample.py",
    "Jack", "Bauer");
  pb.redirectError(new File("src", "err.txt"));
  pb.redirectOutput(new File("src", "out.txt"));
  Map<String, String> env = pb.environment();
  String path = "C:\\opt64\\python27;" + env.get("Path");
  env.put("Path", path);
  Process process = pb.start();
  process.waitFor();
 }

}
Burada ProcessBuilder sınıfının kurucusuna çalıştırmak isteğimiz Python betiği için komutu parametreleri ile birlikte veriyoruz:
cmd /C bin\sample.py Jack Bauer
Bu yöntemde Java uygulamasını çalıştırdığımız makinada Python ortamının kurulu olması ve komuta erişelebilmesi için ise PATH sistem değişkeninde python komutunun kurulu olduğu dizinin yer alması gerekir. Eğer PATH sistem değişkeninde yer almıyor ise pb.environment() çağrısı ile erişebildiğimiz sistem değişkenlerinden PATH'e gerekli ayarın yapılması gerekir:
Map<String, String> env = pb.environment();
String path = "C:\\opt64\\python27;" + env.get("Path");
env.put("Path", path);
Bu yöntemde betik içindeki değişkenlere atama yapmak için komut satırını kullandık:
from sys import argv
script, firstName, lastName = argv

Scripting API Kullanımı

İnceleyeceğimiz üçüncü yöntem Java SE 6 ile gelen Scripting API (JSR-223) kullanmak olacaktır. Scripting API sayesinde 20 civarında farklı dilde yazılmış uygulamayı Java SE platformu üzerinde çalıştırabiliyoruz. Ancak CLASSPATH'e önce kullanmak istediğimiz dil için Scripting API gerçeklemesini koymamız gerekir. JDK 6+ içinde Javascript gerçeklemesi hazır olarak gelir. Java 7'de gelen Javascript için yazılmış yeni gerçeklemenin kod adı Nashorn'dur. Java'dan Scripting API aracılığı ile çalıştırabileceğimiz dillerin listesine aşağıdaki basit kodla ulaşabiliriz:
ScriptEngineManager factory = new ScriptEngineManager();
 for (ScriptEngineFactory scriptEngineFactory: factory.getEngineFactories())
      System.out.println(scriptEngineFactory.getEngineName());
Şimdi Python betiğini Jython gerçeklemesini Scripting API üzerinden kullanarak çalıştıralım:
package com.example.exercise;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.Properties;

import javax.script.Bindings;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class ScriptingApiExample {

 public static void main(String[] args) throws Throwable {
  Properties properties = System.getProperties();
  properties.setProperty("python.console.encoding", "UTF-8");

  ScriptEngineManager factory = new ScriptEngineManager();
  for (ScriptEngineFactory scriptEngineFactory
                         : factory.getEngineFactories())
       System.out.println(scriptEngineFactory.getEngineName());
  ScriptEngine jytonEngine = factory.getEngineByExtension("py");
  jytonEngine.put("firstName", "Jack");
  jytonEngine.put("lastName", "Bauer");
  jytonEngine.eval(new FileReader(new File("bin", "sample.py")));
 }

}
Bu yöntemde, Java uygulamasının çalıştırıldığı makinada Python kurulu olmasına gerek bulunmaz. Java uygulamalarının çalıştırılabildiği herhangi bir makinada Java uygulamamız ve Python betiği çalışacaktır.