A következő címkéjű bejegyzések mutatása: JavaScript. Összes bejegyzés megjelenítése
A következő címkéjű bejegyzések mutatása: JavaScript. Összes bejegyzés megjelenítése

2014. január 16., csütörtök

Ping-conf Day 1

Volt szerencsém a napomat a Ping-conferencián tölteni. A 2 napos rendezvény fő témája a Play Framework, mely a legelterjedtebb, hanem az egyetlen Scala nyelvre épülő webes keretrendszer. A rendezvény bár nem volt olcsó, mégis elég nagy tömeget mozgatott meg, hogy őszinte legyek sokkal kevesebb magyar résztvevőre számítottam. A konferencia, mely minden igényt kielégítő módon volt megszervezve, népszerűsége láttán elgondolkoztam, hogy a JUMon is több Scalás előadással készülhetnénk, mert az itt látottak alapján komoly érdeklődés van a Scála iránt Magyarországon.


Az első előadást Sadek Drobi tartotta, és a funkcionális programozás alapjairól beszélt, betekintést nyújtva példákon keresztül a composability szépségeibe. Röviden: minden funkciónak kötelezően van visszatérési értéke, és ezekkel a funkciókkal könnyedén lehet hívási láncokat alkotni. Az előadás végén elhangzott egy kérdés, miszerint mennyivel jobb megoldás ez, mint a Java 8-cal érkező Lambda kifejezések? A válasz tömör volt és egyszerű, mivel a Java hemzseg a void metódusoktól, igazán sosem lesz benne az az erő, amit a Scala nyújtani képes.


A második prezentációt Matt Hamer tartotta, és témának a többszörös JVM architektúrákat választotta. Számomra ez volt az egyik legérdekesebb előadás. Matt elmesélte, hogy az alkalmazás, amit fejlesztenek több részre van felosztva, egy prezentációs rétegre, ahol Play biztosítja a kiszolgálást, és n+1 business rétegre -szintén Play-, ami értelem szerűen backendként funkcionál a prezentációs rétegnek, és egyéb klienseknek. A szeparáció elsődleges okainak a következőket nevezte meg:
  • Könnyebb Load balancing
  • Izoláció a rétegek között
  • Különböző gyakorisággal történik a deployment
Miután ismertette az architektúrát, Matt részletesen kifejtette, a két réteg közötti kommunikációs lehetőségeket. Először számba vette a JSON küldözgetést, de ez két JVM között nem a legideálisabb választás, ezért áttért Java közelibb megoldásokra.
  • java.io.Serialize, mint az köztudott érzékeny a verziózásra, egyáltalán nem rugalmas
  • Protocol Buffer, sokkal jobb választás, de a konfigurációs állományokat állandóan karba kell tartani
  • Akka custom serialization, ez a megoldás bizonyult a legjobbnak, orvosolja a kompatibilitási problémákat, nem kell konfigurációs állományokat napra készen tartani, és nem utolsó sorban a Playben van beépített Akka

Egy rövid szünetet követően a harmadik téma következett "Build reactive apps on the JVM" címmel. Christopher Hunt saját fejlesztésű keretrendszerüket mutatta be. Megmondom őszintén nem tudtam teljesen elképzelni a felépítését, de nagy vonalakban egy Play frameworkre épülő, Rhino enginet használó JavaScript, igen jól olvastad JavaScript webframeworkről volt szó. A rendszerhez már most is elérhető néhány plugin (CoffeeScript, JS Hint, Less, Require.js, Jasmine). Ez jutott eszembe.

A következő, szám szerint a negyedik prezentáció Yann Simon nevéhez fűződik, témája pedig a Cake Patter In Scala gyakorlati bemutatása volt. A példa alkalmazás 3 részre volt tagolva, 1 frontend, és 2 backend modulból állt. Az első verzióban a frontend modulba be voltak égetve a backend modul szervizei, és a hívások. A megoldással a legnagyobb probléma, hogy a teszt-piramis (unit, component, integration) valójában nem is piramis alakú, hiszen kis számú unit teszten kívül lényegében mindent az integration teszt szintjén kell vizsgálni. A probléma felismerését követően elkezdte átalakítani az egyes rétegeket, amíg el nem jutott arra a szintre, hogy mindent a Scala Component based Dependency Injectionnel oldott meg. Én valahol a folyamat közepén vesztettem el a fonalat, mikor elszaporodtak a trait x extends y with z, meg class a extends b self: c kifejezések. Mindentől függetlenül 2 fontos dolgot leszűrtem:
  • Ez a megoldás annyival jobb más DI megoldásoknál (Spring, Guice), hogy már fordítási időben kiderül ha valami nem stimmel, és nem csak futás időben jönnek elő a problémák
  • Nem érdemes kimaxolni ezt a megoldást, mert az egyszerű példa esetén is 20 trait "osztályra" volt szükség, inkább az elégséges szinten érdemes megállni

Az ebéd szünetet követően Julien Tournay és Pascal Voitot tartott egy érdekes és egyben vicces szösszenetet "Typesafing your blobs" címmel. Hogy pontosan elénk tárhassák a problémát egészen az ősrobbanásig mentek vissza, majd az utazás a dinoszauruszok korán át egészen napjainkig tartott. Történelmi kalandozásuk során megálltak egy pillanatra a modern korba, amikor az emberek kísérletet tettek egy egységes protokoll kidolgozására, hogy a különböző informatikai rendszerek tudjanak egymással kommunikálni, és megszületett a SOAP. Folytatásként arról beszéltek, hogy a technológia fejlődésével egyre inkább ki vannak téve a webes szolgáltatások egymásnak és pontosan ezért egyre fontosabb, hogy a külső forrásokból érkező adatokat rugalmasan tudjuk kezelni és ellenőrizni. Példának hozták fel, hogy 2 éve a WebSoket még csak Sky-fi volt, ma pedig már szolgáltatások épülnek rá, utalva ezzel, hogy milyen rohamosan fejlődik a világ. A fent említett dolgok vezették rá a srácokat, hogy egy teljesen új, a régivel kompatibilis, de a mai kor elvárásainak megfelelő (vagy inkább jövőbe mutató) validációs API-t fejlesztettek a Playhez. Természetesen teljesen funkcionális szemléletben készült a kód, kihasználja a Scala macrokban rejlő lehetőségeket, és a case classoknak valamint az implicit deklarációnak köszönhetően marshallerek, és konfigurációk nélkül képes egy JSON stinget Scala osztállyá alakítani. Az API másik erőssége, hogy POST-olt adatok ellenőrzésére is alkalmas kvázi módosítás nélkül. A fejlesztés még nagyban folyik, nem production ready a cucc, de akit érdekel itt megtalálja a projektet.

Az utolsó előtti előadást Matthias Nehlsen tartotta, és reaktív alkalmazás-fejlesztésről beszélt Play, Scala.js, és ReactJs segítségével. Engem főleg a ReactJs fogott meg, régóta keresek valami hasonló megoldást, de az AngularJs, Ember.js, KnockOut.js eddig nem nagyon jött be. A ReactJs-nek nagyon rövid a tanulási görbéje, és a teljesítménye is kiemelkedő, köszönhető annak, hogy a valós DOM fa mellett van belül egy virtuális DOM, és a DOM manipuláció után csak a diff-et szinkronizálja a valós fával. Érdekes volt látni, hogy milyen egyszerűen kötötte össze a nézeteket renderelő ReactJst a Scalaból generált JavaScript kódot, és a Scala.js-t a Play-el Mathias, lényegében minden Scalában volt megírva, volt pár action binding JavaScriptben, és némi HTML-nek látszó ReactJs template.

Utoljára maradt Nicolas Martignole esettanulmánya, melyben két általa fejlesztett projekt sikertörténetét tárta a nagyérdemű elé. Webes rétegnek Play2-t választotta, adattárolásra és cachelésre pedig Redist. Láthatóan ő boldog volt a megoldással :).

Ennyi történt az első napon, igyekszem holnap is megjelenni/jegyzetelni. Folytatás...

2010. február 25., csütörtök

JavaScript EE, JSON válaszol

Előző bejegyzésben bemutattam miként lehet Java környezetünket rávenni JavaScript futtatására. Folytatásban egy servlet-en keresztül rávesszük a web-konténert, hogy JSON válaszokat adjon a kérésekre.
Legelső lépésként egy hagyományos servletet kell létrehoznunk, majd a doGet metódusában megvalósítani a JavaScript futtatását.
Java kód:
Compilable scriptEngine = (Compilable) new ScriptEngineManager().getEngineByName("JavaScript");

ScriptContext scriptContext = new SimpleScriptContext();
scriptContext.setWriter(response.getWriter());
scriptContext.setAttribute("config", getServletConfig(), ScriptContext.ENGINE_SCOPE);
scriptContext.setAttribute("response", response, ScriptContext.ENGINE_SCOPE);
scriptContext.setReader(new InputStreamReader(JSONServlet.class.getResourceAsStream("json.js")));

try {
 CompiledScript script = scriptEngine.compile(scriptContext.getReader());
 script.eval(scriptContext);
} catch (ScriptException e) {}
Látható különbség, hogy ScriptEngine helyett Compilable osztályt használunk. A Compilable interfészt megvalósító értelmező annyival nyújt több szolgáltatást, hogy a lefordított JavaScripteket újra fel lehet használni újrafordítás nélkül, így segítségével gyorsító-tárazni lehet a scipteket csökkentve a szerver terhelését. Következő lépésként, mivel most nem a JavaScript visszatérési értékére van szükségünk (és azt sem szeretnénk, hogy az alapértelmezett kimenetre írjon), hanem azt szeretnénk, hogy a JavaScript közvetlenül a servlet kimenetre írjon, példányosítanunk kell egy ScriptContext objektumot, és referenciát adnunk a ServletResponse-ra. Természetesen van lehetőségünk Java objektumok átadására a JavaScriptnek, de ebben az esetben a ScriptContext osztálynak közvetlenül adhatjuk át a paramétereket a setAttribute metódus meghívásával. Ezután nincs más dolgunk, mint megadni a JavaScript fájlunkat, és futtatni a scriptet.
JavaScript kód:
response.setHeader("Cache-Control", "no-cache");
response.setContentType("application/json");

var json = {
response: {
  status: response.getStatus(),
  content_type: String(response.getContentType())
},
config: {
  servlet: String(config.getServletName())
}
};

println(json.toSource());
A scriptben jól látható miként használjuk a Java objektumokat, és végül miként írjunk a kimenetre.
A böngészőben az alábbi válasz jelenik meg:
({response:{status:200, content_type:"text/plain;charset=ISO-8859-1"}, config:{servlet:"JSONServlet"}})
Folyt köv...

2010. február 19., péntek

JavaScript EE, első felvonás

Bár a téma nem új-keletű, én most jutottam el oda, hogy legalább kipróbálás szinten foglalkozzam vele. Java SE 6-os verziója óta megtalálható benne a Mozilla Rhinó-ja, amely egy JavaScript értelmező, és segítségével a JVM-en lehetséges JavaScript kódok futtatása Java kódból. Nincs más dolgunk, mint importálni a javax.script csomagot, és a ScriptEngineManager segítségével példányosítani egy ScriptEngine értelmezőt.
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
Java kód:
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.StringBuilder;
import javax.script.*;

public class SimpleJavaScriptTest {
public static void main(String[] args) throws Exception {
//Get reference to the engine
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
//Bind some Java object to the script
Bindings vars = new SimpleBindings();
vars.put("testString", "This is a test string.");
StringBuilder stringBuilder = new StringBuilder();
vars.put("testStringBuilder", stringBuilder);
//Read the JavaScript code
Reader scriptReader = new InputStreamReader(SimpleJavaScriptTest.class.getResourceAsStream("test.js"));
try {
//Run the JavaScript
engine.eval(scriptReader, vars);

System.out.println(stringBuilder.toString());
System.out.println(vars.get("testFile").getClass());
System.out.println(vars.get("jsObject").getClass());
} finally {
scriptReader.close();
}
}
}
JavaScript kód:
function printType(obj) {
if (obj.getClass) println("Java object: " + obj.getClass().name);
else println("JS object: " + obj.toSource());
}
printType(testString);

printType(testStringBuilder);
testStringBuilder.append("This content added by JavaScript.");

var testFile = new java.io.File("/");
printType(testFile);

var jsObject = {x: 1, y: { u: 2, v: 3 }};
printType(jsObject);
A példát futtatva az alábbi eredményt kapjuk:
JS object: (new String("This is a test string."))
Java object: java.lang.StringBuilderJava object: java.io.File JS object: ({x:1, y:{u:2, v:3}})
This content added by JavaScript.
class java.io.File
class sun.org.mozilla.javascript.internal.NativeObject
Mint az jól lát-szódik szinte teljes az átjárás a két kód között, bemenő paramétert megfelelő JavaScript típusra cast-olja az értelmező, ennek sikertelensége esetén Java objektumként viselkedik, annak minden funkciójával. Továbbmenve JavaScript kódunkban is van lehetőség Java objektumok létrehozására, melyeket a script futása után elkérhetünk az értelmezőtől. Amennyiben olyan változót kapunk a scriptből, amit Java oldalon nem lehet megfeleltetni egyik osztálynak sem, akkor azzal egy dolgot tehetünk, paraméterként egy másik JavaScriptnek átadhatjuk.
Ezen a ponton merülhet fel a kérdés, hogy valójában ez mire is való? A válasz erre a kérdésre eléggé összetett, és nem is célom maradéktalanul körbejárni. Egyrészt ezzel a módszerrel tudjuk ötvözni a két nyelv tulajdonságait, tehát a Java robusztusságát a JavaScript egyszerűségével összepárosítva kiszélesedik a programozói paletta. Megjegyzem erre a célra nem csak JavaScriptet használhatunk, akár Groovie, vagy Scala kódot is integrálhatunk Java programunkba, ráadásul utóbbiak Java bytecode-ra fordulnak, ami mélyebb integrációra ad lehetőséget. Másrészt kliens oldali scriptjeinket is futtathatjuk server oldalon, ami azt jelenti, hogy nem kell két helyen, két környezetben implementálnunk az azonos működést, hanem szerver oldalon használhatjuk a kliens oldali program-kódokat. Hagyományosan egy űrlap elküldése esetén a böngészőben történik egy előellenőrzés, hogy az adatok formailag megfelelnek-e a követelménynek, ezzel csökkentve a hálózati forgalmat. Formailag helyes adatok elküldésre kerülnek, ahol szerver oldalon újra ellenőrizni kell őket, mind formailag, mind már adat-logikailag is. Mivel szerver környezetben nem a JavaScript az elterjedt programozási nyelv, a formai ellenőrzést sajnos ott is implementálni kell. Ehelyett a kliens oldali JavaScript-ünket nyugodtan felhasználhatjuk, időt, energiát, költséget, és nem utolsó sorban hiba-lehetőséget megspórolva.
Java kód:
engine.eval(scriptReader);
if (engine instanceof Invocable) {
Invocable invEngine = (Invocable) engine;
Object result = invEngine.invokeFunction("testStringLength", "valid string", 2);
System.out.println("Result: " + result + "(" + result.getClass().getName() + ")");
result = invEngine.invokeFunction("testStringLength", "invalid string", 20);
System.out.println("Result: " + result + "(" + result.getClass().getName() + ")");
} else System.out.println("NOT Invocable");
JavaScript kód:
function testStringLength(input, lenght) {
return input.length >= lenght ? true : false;
}
Eredmény:
Result: true(java.lang.Boolean)
Result: false(java.lang.Boolean)
Bár a példa nem tükrözi a technológia hasznosságát (így még talán bonyolultabb is), viszont bemutatja, hogyan tudunk JavaScript függvényeket meghívni, és azok visszatérési értékét felhasználni Java kódunkban. Folyt köv...
Aki szeretne a témáról bővebben is olvasni, az itt talál információt.