Dans une application Eclipse RCP le composant Browser permet de mixer web et desktop. Les avantages de cette technique sont nombreux, notamment quand il s’agit de réutiliser un existant Web pour l’encapsuler dans une application desktop. L’interêt est de ne plus être dépendant d’un navigateur mais d’être son propre navigateur. Cependant pour que cela fonctonne il faut faire communiquer web et desktop. Lorsqu’il s’agit d’envoyer des données à l’application Web cela reste simple en modifiant l’URL (setURL()) ou en executant du Javascript (execute()). Mais lorsqu’il s’agit de récupérer des données depuis le web c’est plus fastidieux. Je vous propose ici 6 techniques :
1. via la barre de statut: c’est le code que l’on trouve sur les snippets SWT (Snippet160)
2. via la barre d’adresse: comme le propose Peter Nehrer
3. en requetant directement le DOM : depuis la 3.3 il est possible d’utiliser Mozilla et l’API XPCOM fournie la possibilité d’accèder au DOM de la page HTML. Ci-dessous un petit exemple reprenant le Snippet267 mais en requetant en XPath pour récupérer le titre d’un champ. Les possibilités sont multiples à l’image de l’utilisation qu’en fait ATF (faudrait que j’y consacre un article complet pour explorer toutes les possibilités qu’offre XPCOM).
static Browser browser;
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setLayout(new GridLayout(2, true));
shell.setText("Use Mozilla's Design Mode");
try {
browser = new Browser(shell, SWT.MOZILLA);
} catch (SWTError e) {
System.out.println("Could not instantiate Browser: " + e.getMessage());
return;
}
browser.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true, 2, 1));
Button searchButton = new Button(shell, SWT.PUSH);
searchButton.setText("Search");
searchButton.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
search();
}
});
browser.setUrl("http://www.google.com");
shell.setSize(400, 400);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch())
display.sleep();
}
display.dispose();
}
public static boolean search() {
nsIWebBrowser webBrowser = (nsIWebBrowser) browser.getWebBrowser();
if (webBrowser == null) {
System.out.println("Could not get the nsIWebBrowser from the Browser widget");
return false;
}
nsIDOMWindow window = webBrowser.getContentDOMWindow();
nsIDOMDocument document = window.getDocument();
nsIDOMXPathEvaluator xpath = (nsIDOMXPathEvaluator) document.queryInterface(nsIDOMXPathEvaluator.NS_IDOMXPATHEVALUATOR_IID);
nsIDOMXPathNSResolver res = xpath.createNSResolver(document);
nsISupports obj = xpath.evaluate("//input[@name='q']/@title",
document,
res,
nsIDOMXPathResult.STRING_TYPE,
null);
nsIDOMXPathResult result = (nsIDOMXPathResult) obj.queryInterface(nsIDOMXPathResult.NS_IDOMXPATHRESULT_IID);
System.out.println(result.getStringValue());
return true;
}
4. via un socket : en executant une XMLHTTPRequest via la méthode execute() qui fait appel à un socket ouvert pour l'occasion et permet de récupérer un contenu.
private String getDataFromBrowser() {
String javascript = "try {";
javascript += "xhr_object = new ActiveXObject(\"Microsoft.XMLHTTP\"); ";
javascript += "xhr_object.open(\"POST\", \"http://localhost:9091\", false);";
javascript += "xhr_object.setRequestHeader(\"Content-type\", \"application/x-www-form-urlencoded\");";
javascript += "xhr_param = generateXML();"; // appel d'une fonction retournant un contenu
javascript += "xhr_object.send(xhr_param);";
javascript += "} catch (ex) { alert(\"Failed to save document\"); }";
String xml = null;
XMLPicker e = new XMLPicker();
Thread t = new Thread(e);
t.start();
// Attend que le thread démarre.
try {
Thread.sleep(10);
} catch (InterruptedException eee) {
}
// Demande au browser un contenu.
boolean ok = browser.execute(javascript);
int wait = 0;
while (xml == null && wait < 10)
try {
Thread.sleep(10);
wait++;
xml = e.getXML();
} catch (InterruptedException eeee) {
}
System.out.println(xml);
return xml;
}
private class XMLPicker implements Runnable {
private String xml;
public String getXML() {
return xml;
}
public void run() {
ServerSocket server = null;
try {
server = new ServerSocket(9091);
server.setSoTimeout(5000);
System.out.println("Waiting for response");
Socket socket = server.accept();
// Traitement du flux, la classe HTTPServer est disponible pour ceux que ca intéresse
xml = HttpServer.getXMLString(socket, "UTF-8");
socket.close();
} catch (IOException ee) {
System.err.println(ee);
} finally {
if (server != null) {
try {
server.close();
} catch (Exception e) {
// Ignore.
}
}
}
}
}
5. en démarrant un serveur http dans la meme JVM que Eclipse RCP : tomcat peut être embarqué et demarré depuis une application Java, c'est aussi le cas de WebObjects (Application.primeApplication()). Les objets étant issus de la même JVM leur statut est partagée par les deux application mais attention toutefois aux classloaders.
6. via terracota : ce cluster de JVM permet de synchroniser les objets de 2 JVM et de répercuter en temps réel les états des objets.
