Archive for April, 2009

All your base are belong to us

Friday, April 24th, 2009

Oracle ha comprato la Sun per $7.4 miliardi. In attesa che l’accordo venga approvato pensiamoci un attimo. La Oracle ora possiede Oracle DBMS, MySQL e Berkley DB.
E proprio ora di dire Tutte le vostre basi ci appartengono!
Meno male che uso postgresql ­čÖé

Google App Engine introduce Java

Friday, April 10th, 2009

E’ un dato di fatto che spesso, la piattaforma di sviluppo che scegliamo ├Ę collegata con i servizi di hosting che esistono. Le preferenze personali semplicemente passano in secondo piano. LAMP ├Ę un successo mondiale sopratutto perche esistono migliaia siti di hosting pronti e a basso costo. .Net ├Ę un “fallimento” lato server perche i server non sono gratis e aperti. Java ha i server gratis e aperti, ma presenta i problemi. Se un host provider mette a disposizione un application/servlet container, come dare un servizio che scala e contemporaneamente proibire ai sviluppatori di fare idiozie che potrebbero mettere in ginocchio il sistema o lasciarlo meno sicuro, alla fine avete a disposizione tutte le API del JDK. Aggiungiamo anche il fatto che i requisiti neccessari sono pi├╣ esigenti in termini di RAM e CPU messi a confronto con LAMP. Un problema non da poco che gli ingegneri della Google hanno deciso di affrontare e offrire una soluzione tutta loro.
Google App Engine, che fin’ora offriva Python come piattaforma di sviluppo, ora offre anche Java. Per il momento, ├Ę in fase di “prova” e limitato ai primi 10’000 sviluppatori che faranno la richiesta (10 siti a testa).
Chi sar├á il fortunato, vedr├á che la Java VM ├Ę stata modificata, le modifiche principali sono

  1. Non poter scrivere sul file system (ma potete leggere)
  2. Non si possono aprire delle Socket, ma si possono utilizzare le API di google per eseguire richieste HTTP e HTTPS
  3. Non si possono creare dei Thread, le richieste devono essere “servite” in tempo limitato (30sec)
  4. Altro, qui ci sar├á da divertire sicuramente man mano che scopriamo tutte le limitazioni e modi per evitarle ­čÖé

Esiste una lista dettagliata delle classi del JDK disponibili per lo sviluppo e la guida per il sviluppatore e l’SDK, e sono messe a disposizione anche delle API proprietarie per la persistenza dei dati (api JDO e JPA tramite la libreria DataNucleus), autenticazione utenti, mail, memcache, modifiche immagine, task schedulati e fetch di URL. E’ stato publiccato anche il plugin per Eclipse con l’SDK e GWT incluso.
In breve, prevedo che avremo tantissime applicazioni che d’ora in poi proveranno a fare vita e miracoli per stare dentro questi limiti. Gi├á ci sono post in giro per vedere se il i vari framework possono girare su App Engine e si sta gi├á lavorando per fare le modifiche neccessari (es. struts 2, osgi).
Il hosting ├Ę gratis con il limite di stare al di sotto i 500MB di storage e 5 milioni di pagine servite al mese, per andare oltre bisogna attivare il billing.
Una piccola rivoluzione ├Ę iniziata (di nuovo) grazie a Google e ora, andiamo avanti per creare il prossimo milione di siti ­čÖé

GWT SuggestBoxReloaded

Monday, April 6th, 2009

This article will present how to implement a GWT 1.6 (RC2) SuggestBox with backing hidden fields, RPC calls and not query the server on every character event.
While integrating GWT on work, I needed to implement a SuggestBox with a backend RPC service but I had some requirements that the default SuggestBox didn’t fulfill. Namely, I needed that the suggestion sets hidden fields (ex. displaying a human readable name for the user and setting a hidden id field). The solution presented in GWT SuggestBox backed by DTO Model and the Using the GWT SuggestBox with RPC were very helpful in creating this example project. I advise you to read/implement them before reading further in order to understand the issues.
The first article hit the sweet point on how to pass hidden values using the DTO pattern, you can either wrap your hidden fields (Hidden.wrap) or as in this example we’ll instantiate them using GWT and add them to the panel. The next issues were following, 1. You need to be able to clear the value either by a button or by deleting the text in the TextBox, 2. The Lombardi solution presented an issue as it sent out every query string, 3. Enable some sort of reusability of the generated javascript client.
First of all I created three basic Suggestion classes, IdEnabledSuggestion, TextEnabledSuggestion and SimpleSuggestion. These three probably cover 90% of the cases (actually, the TextEnabledSuggestion can replace IdEnabledSuggestion just as well), otherwise you can add a DTO with the data you need, just remember that you must put the DTO class in the /client package, in my first trials I had it outside which led to problems.

 
public class IdEnabledSuggestion implements IsSerializable, Suggestion {

private String displayString, replacementString;
private Long id;

public IdEnabledSuggestion(){

}

public IdEnabledSuggestion(String displayString, String replacementString, Long id){
this.displayString = displayString;
this.replacementString = replacementString;
this.id = id;
}

public String getDisplayString() {
return displayString;
}

public String getReplacementString() {
return replacementString;
}

public Long getId() {
return id;
}
}

Then you extend the RemoteService interface and also the Async version. In order to achieve reusability, I’ve added an enum that acts as a switch, that way I can group all suggestion methods under the same servlet. A even more flexible solution would be to add a text parameter to the javascript client that would switch the endpoint ending on separate url’s, probably using ServiceDefTarget.setServiceEntryPoint(String), but as I don’t really like declaring a servlet for each endpoint I would recommend that solution with some kind of rest/mvc framework, I would love to see someone extending this example with struts2 and spring mvc endpoints ­čÖé

 
@RemoteServiceRelativePath("oracle")
public interface OracleService extends RemoteService {

public SuggestOracle.Response getSuggestions(SuggestOracle.Request search, Oracles oracle);

public static class Util {
public static OracleServiceAsync getInstance() {
OracleServiceAsync instance = (OracleServiceAsync) GWT.create(OracleService.class);
return instance;
}
}
}

In order to solve the second issue, and avoid sending queries on every key event, I have extracted a SuggestOracle.Request and SuggestOracle.Callback on a instance level. When a user inserts a query, I temporarily set the variables and schedule the timer, this way, even if new events come, they overwrite the instance variables effectively caching them for later so when the time passes the service gets invoked once and only once with the last query.
It’s a simple trick that produces the expected actions and I hope I’m not missing some threading, timer or leakage issue?
I’ve added also setters so that you can set your delay and minimum number of characters needed to send the query.
I then wrap the Hidden, the SuggestBox and a widget that implements HasClickHandlers in a object that adds the various handlers to manage form state and you are good to go. ­čÖé

 
public class HiddenSuggestBox {

private SuggestBox suggestBox;
private Hidden hidden;
private HasClickHandlers clearWidget;

public HiddenSuggestBox(SuggestBox suggestBox, Hidden hidden, HasClickHandlers clearWidget) {
super();
this.suggestBox = suggestBox;
this.hidden = hidden;
this.clearWidget = clearWidget;
this.suggestBox.addSelectionHandler(new MySelectionHandler());
this.suggestBox.getTextBox().addValueChangeHandler(new ClearTextBox());
this.clearWidget.addClickHandler(new ClearValueHandler());
}

private class MySelectionHandler implements SelectionHandler<suggestion> {
public void onSelection(SelectionEvent<suggestion> event) {
if(event.getSelectedItem() instanceof TextEnabledSuggestion){
TextEnabledSuggestion suggestion = (TextEnabledSuggestion)event.getSelectedItem();
hidden.setValue(suggestion.getText());
} else if(event.getSelectedItem() instanceof IdEnabledSuggestion){
IdEnabledSuggestion suggestion = (IdEnabledSuggestion)event.getSelectedItem();
hidden.setValue(suggestion.getId()+"");
} else {
hidden.setValue(event.getSelectedItem().getReplacementString());
}

}
}

private class ClearTextBox implements ValueChangeHandler<string> {
public void onValueChange(ValueChangeEvent<string> event) {
if(event.getValue().trim().equals("")){
suggestBox.getTextBox().setValue("");
hidden.setValue("");
}
}
}
private class ClearValueHandler implements ClickHandler {
public void onClick(ClickEvent event) {
hidden.setValue("");
suggestBox.setValue("");
}
}
}

eclipse project archive
You might need to set JVM in launcher and ant script.