Berichten met label toolkit
Using GWT to create an OSGi-aware web application
Geplaatst door Angelo van der Sijpt in Uncategorized op 9 juli 2009
Update 2010-02-20 Both Pax Runner 1.3.0 and GWT 2.0 have caused quite some changes to this post. I have tried to stay up to date as well as I could (the zipped project now uses GWT 2.0), but you might find some inconsistencies when following the tutorial.
Google Web Toolkit is cool, and so is OSGi. However, when building a web UI for Apache ACE, I found out that creating a web application that can use OSGi services is not that easy. By the end of this tutorial, you will have created a GWT project that delivers a usable jar. If you’re impatient, skip to the end for the downloadable Eclipse project.
Step 1: Create a GWT project
Create a regular GWT project using the regular webAppCreator; this will give you a project that includes an Ant buildfile, we will need that later on.
angelos:workspace angelos$ ./gwt-mac-1.6.4/webAppCreator -out GwtDemo net.luminis.gwt.gwtdemo Created directory GwtDemo/src Created directory GwtDemo/war Created directory GwtDemo/war/WEB-INF Created directory GwtDemo/war/WEB-INF/lib Created directory GwtDemo/src/net/luminis/gwt Created directory GwtDemo/src/net/luminis/gwt/client Created directory GwtDemo/src/net/luminis/gwt/server Created file GwtDemo/src/net/luminis/gwt/gwtdemo.gwt.xml Created file GwtDemo/war/gwtdemo.html Created file GwtDemo/war/gwtdemo.css Created file GwtDemo/war/WEB-INF/web.xml Created file GwtDemo/src/net/luminis/gwt/client/gwtdemo.java Created file GwtDemo/src/net/luminis/gwt/client/GreetingService.java Created file GwtDemo/src/net/luminis/gwt/client/GreetingServiceAsync.java Created file GwtDemo/src/net/luminis/gwt/server/GreetingServiceImpl.java Created file GwtDemo/build.xml Created file GwtDemo/README.txt Created file GwtDemo/.project Created file GwtDemo/.classpath Created file GwtDemo/gwtdemo.launch Created file GwtDemo/war/WEB-INF/lib/gwt-servlet.jar
If you want to, you can import this project directly into your Eclipse. If you check the mark “use Google Web Toolkit” in the project properties, you can use all the same goodies that creating the project in Eclipse would have given you. Remember to replace the buildpath entries for gwt-user.jar and gwt-dev-*.jar by a Library import for GWT.
Step 2: Include the necessary OSGi references
Create an ‘ext’ directory, and add org.osgi.core.jar to that. In Eclipse, add this jar to your build path.
Step 3: Use OSGi services from your web applicaiton
We will first add a simple Activator on the server side.
package net.luminis.gwt.server; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; public class Activator implements BundleActivator { private static BundleContext m_context; public static BundleContext getContext() { return m_context; } public void start(BundleContext context) throws Exception { m_context = context; } public void stop(BundleContext context) throws Exception { } }
Then, we up the GreetingServiceImpl to actually use this BundleContext (note that we use it directly here, but you could use it to get other services, create a ServiceTracker, etc.)
public String greetServer(String input) { String serverInfo = getServletContext().getServerInfo(); String userAgent = getThreadLocalRequest().getHeader("User-Agent"); return "Hello, " + input + "! I am running " + serverInfo + ". It looks like you are using:" + userAgent + "The framework we run from has " + Activator.getContext().getBundles().length + " bundles in it."; }
Step 4: Add OSGi dependencies for the compiler
Add our OSGi dependencies to the classpath, so the compiler can find all of it.
<!-- Add any additional non-server libs (such as JUnit) -->Right, let’s give it a try!
angelos:GwtDemo angelos$ ant war Buildfile: build.xml ...some output removed... war: [zip] Building zip: /Users/angelos/workspace/workspace/GwtDemo/gwtdemo.war BUILD SUCCESSFUL Total time: 36 seconds
You will find a war in your project directory now. There still is one ingredient we need. We need to make this into a proper bundle. We can use bnd to help us with that.
Step 5: use bnd to create a proper war
Download bnd, and put into a lib directory, and add it to your buildfile.
We create a new target that transforms our war into a jar.
<target name="jar">
<copy file="gwtdemo.war" tofile="gwtdemo.jar"/>
<echo file="gwtdemo.bnd">Import-Package: junit.framework;resolution:=optional, com.google.gwt.*;resolution:=optional, org.w3c.*;resolution:=optional, sun.misc;resolution:=optional, javax.imageio;resolution:=optional, javax.servlet.*;resolution:=optional, *
Bundle-Name: GWT Demo
Bundle-ClassPath: WEB-INF/classes, WEB-INF/lib/gwt-servlet.jar
Bundle-SymbolicName: net.luminis.gwt.gwtdemo
Webapp-Context: gwtdemo
Bundle-Activator: net.luminis.gwt.server.Activator
</echo>
<bndwrap jars="gwtdemo.jar" output="gwtdemo.jar"/>
<jar file="gwtdemo.jar" update="true">
<manifest>
<attribute name="Bundle-ClassPath" value="WEB-INF/classes, WEB-INF/lib/gwt-servlet.jar, ."/>
</manifest>
</jar>
<delete file="gwtdemo.bnd"/>
</target>What’s happening here?
- we copy our war to the same file, but with a jar extension,
- we create a file for bnd to use, stating that we
- want optional imports for junit and the gwt benchmarks, and non-optional imports for everything else (that what the * is for),
- have some classes that we want bnd to scan for finding dependencies,
- want to use a given Webapp-Context (this is a Pax war extender specific entry),
- let bnd do its magic,
- update our manifest: we put the . back on the classpath. This is important for the web application to find all resources, but if we would tell bnd to do it like this, it would treat . as the root of the classpath.
- Finally, we delete that temporary bnd file.
What does that give us?
angelos:GwtDemo angelos$ ant jar Buildfile: build.xml ...some output removed... jar: [copy] Copying 1 file to /Users/angelos/workspace/workspace/GwtDemo [bndwrap] gwtdemo 41 910305 [bndwrap] Warnings [bndwrap] Superfluous export-package instructions: [WEB-INF.classes.net, gwtdemo.gwt.standard.images, WEB-INF, gwtdemo, WEB-INF.classes.net.luminis.gwt, gwtdemo.gwt.standard, WEB-INF.classes.net.luminis, WEB-INF.lib, WEB-INF.classes, gwtdemo.gwt.standard.images.ie6, WEB-INF.classes.net.luminis.gwt.client, WEB-INF.classes.net.luminis.gwt.server, gwtdemo.gwt] [jar] Updating jar: /Users/angelos/workspace/workspace/GwtDemo/gwtdemo.jar [delete] Deleting: /Users/angelos/workspace/workspace/GwtDemo/gwtdemo.bnd BUILD SUCCESSFUL Total time: 23 seconds
That’s it! You can now deploy this jar into a framework that uses the pax web tools. Right, let’s give that a try.
Download pax-runner, and unzip that somewhere. Copy in your new jar, an try the following command
angelos:pax-runner angelos$ sh bin/pax-run.sh --profiles=war,compendium gwtdemo.jar
Now visit http://localhost:8080/gwtdemo:

Summary
So, what did we need?
- A fairly regular GWT project, create with an Ant file,
- some code that tries to use OSGi services,
- some bnd magic to make the war into a jar,
- Pax tools to get it all running quickly.
If you don’t want to use pax runner, you can need to deploy pax-web-extender-war(jar, snapshot 23 June) and an http server, preferably pax-web-service(jar), into your framework.
You can download the gwtdemo Eclipse project to play around with it. I have not provided the GWT runtime in this download; you should edit line 4 of the build.xml to point to your installation of GWT.
LWUIT – een lichtgewicht ui toolkit voor Java ME
Geplaatst door admin in Uncategorized op 17 april 2009
Introductie
Ooit al eens een Java ME applicatie ontwikkeld voor een specifiek type mobiele telefoon? Wanneer het aankomt op het ontwikkelen van een gelikte interface loop je er al snel tegen aan dat de MIDP implementatie van de telefoon van invloed is op hoe de widgets van de applicatie getoond worden. Nadeel daarvan is dat de UI er op een ander type mobiel nogal anders uit kan zien. Om die reden was men voorheen nog wel eens geneigd om wat dieper in de code te duiken en de wat specifiekere (geliktere) widgets op de (javax.microedition.lcdui.)Canvas uit te werken. Deze Canvas ondersteunt sinds MIDP-2.0 een fullscreen modus: het is mogelijk om de complete applicatie direct op Canvas te ontwikkelen. Hiervan maakt LWUIT gebruik.
Mogelijk, maar wel bijzonder tijds-intensief, tenzij je gebruik maakt van het werk van anderen die al wat voorwerk hebben verricht op dit gebied. Een mooi voorbeeld hiervan is “LWUIT”, een door Sun ontwikkelde open-source UI toolkit. In tegenstelling tot het ontwerpen van UI’s met standaard Java ME is het met LWUIT mogelijk om op een Swing-achtige manier user interfaces te maken: layout managers, maar ook de pluggable look & feel, het MVC concept en “lightweight componenten” (componenten maken geen gebruik van de native UI controls, maar verzorgen zelf hun rendering en event handling) zijn terug te vinden.
Setup simpele MIDlet
Een MIDlet maken waarin met LWUIT een paar knoppen wordt getoond is simpel voor elkaar te krijgen via de volgende stappen:
Binnen NetBeans is het handig om de LWUIT jar toe te voegen als library via ‘Tools’, ‘Libraries en dan de ‘New Library…’ knop. Geef naam, type = ‘Class Libraries’, dan: ‘OK’ en ‘Add JAR/Folder…’: en selecteer het bestand “LWUIT.jar” dat te vinden is in de ‘lib’ dir van de LWUIT installatie (unzippen van de zip file). Het ‘LWUIT_stripped.jar’ bestand is de LWUIT library zonder code die gebruik maakt van JSR 184 (M3G: Mobile 3D Graphics), JSR 75 (PIM: Personal Information Management, FC: File Connection) of JSR 226 (SVG: Scalable 2D Vector Graphics).
Start vervolgens een nieuw project, kies als categorie ‘Java ME’ en als project ‘Mobile Application’ en druk op ‘Next’. Het is niet nodig om NetBeans een default MIDlet aan te laten maken; het vinkje bij ‘Create Hello MIDlet’ mag weg. Druk weer op ‘Next’. Selecteer de WTK die je hebt geïnstalleerd als ‘Emulator Platform’. LWUIT vereist minimaal MIDP-2.0 bovenop CLDC-1.1, dus i.p.v. MIDP-2.1 die default geselecteerd is zou je MIDP-2.0 kunnen kiezen, maar dit hoeft niet. Druk op ‘Finish’. Maak nu een nieuwe MIDlet aan met de naam ‘MyMIDlet’ en kopieer de volgende code er naartoe:
import com.sun.lwuit.*;
import com.sun.lwuit.events.ActionEvent;
import com.sun.lwuit.layouts.BoxLayout;
import javax.microedition.midlet.MIDlet;
public class MyMIDlet extends MIDlet {
Form form1;
public void startApp() {
Display.init(this);
form1 = new Form("LWUIT Demo Form");
form1.addCommand(new Command("Quit") {
public void actionPerformed(ActionEvent ae) {
destroyApp(true);
notifyDestroyed();
}
});
form1.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
Button l = new Button("Left");
l.setAlignment(Label.LEFT);
Button r = new Button("Right");
r.setAlignment(Label.RIGHT);
Button m = new Button("Middle");
m.setAlignment(Label.CENTER);
form1.addComponent(l);
form1.addComponent(r);
form1.addComponent(m);
form1.show();
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
}
Omdat het project de LWUIT jar nog niet kent zal je een aantal foutmeldingen zien: via de project properties kan je onder de ‘Build’ categorie ‘Libraries & Resources’ kiezen. Voeg de LWUIT library die je eerder hebt aangemaakt toe. Omdat er slechts 1 MIDlet in het project zit zal deze MIDlet automatisch gestart worden wanneer je het project right-clickt en dan ‘Run’ selecteert. Het resultaat hiervan is een simpele LWUIT applicatie met een paar knopjes!
MVC
Een aardige illustratie van het MVC concept bij LWUIT is de List. Voeg het volgende stuk code in voor de ‘form1.show()’ uit het vorige voorbeeld.
String[] bands = new String[]{
"AC/DShe",
"Public Enema",
"Beverly Beerbellies",
"Shirley Temple Pilots",
"Wynona Riders"};
List list = new List(bands);
form1.addComponent(list);
.
Resultaat
Zelf de implementatie van ListModel en ListCellRenderer verzorgen heeft als extra voordeel dat je de reeds bestaande data types direct kan gebruiken en er geen sprake hoeft te zijn van “state copying”: er is geen voorbepaald data type wat in de List past.
Ook goed om te weten is dat de List z’n Model alleen maar vraagt naar de data-elementen die op het scherm zichtbaar zijn. Dit (performance) aspect wordt belangrijker naarmate de hoeveelheid data groeit of bijv. vanaf een remote locatie moet worden binnengehaald.
Conclusie
Via de bovenstaande stappen is het relatief makkelijk om snel een simpele LWUIT applicatie te maken. Met name voor de ontwikkelaars die hun app op meerdere typen mobiele telefoons willen draaien zal het een aangename verrassing zijn om te zien dat deze voorbeeld-applicatie op alle mobieltjes (die MIDP-2.0/CLDC-1.1 supporten) in uiterlijk en gedrag hetzelfde zal zijn. In een volgende blog zal ik wat verder ingaan op “fancier features” zoals Transitions en Theming; het oog wil immers ook wat!
