When reading up on the play2 documentation I found this:
Because of the way Play 2.0 works, action code must be as fast as possible (i.e. non blocking). So what should we return as result if we are not yet able to compute it? The response should be a promise of a result!
Wow! This of course made me interested in playakka and akka. I'm currently building an autocomplete application that is integrating with elasticsearch, so this would be a perfect fit!
Controller:
public class AutoComplete extends Controller {
@BodyParser.Of(value = BodyParser.Json.class)
public static Result complete(final String term) {
F.Promise<List<String>> list = Akka.future(new Callable<List<String>>() {
public List<String> call() throws Exception {
List<String> list = IndexService.find(term);
return list;
}
});
return async(list.map(new F.Function<List<String>, Result>() {
@Override
public Result apply(List<String> list) throws Throwable {
return ok(Json.toJson(list));
}
}));
}
Service:
public static List<String> find(final String term) {
IndexQuery < SearchWord > query = SearchWord.find.query();
query.setQuery("{\n" +
" \"bool\": {\n" +
" \"should\": [\n" +
" {\n" +
" \"text\": {\n" +
" \"search_word.ngrams\": {\n" +
" \"operator\": \"and\",\n" +
" \"query\": \""+term+"\"\n" +
" }\n" +
" }\n" +
" },\n" +
" {\n" +
" \"text\": {\n" +
" \"search_word.full\": {\n" +
" \"boost\": 1,\n" +
" \"query\": \""+term+"\"\n" +
" }\n" +
" }\n" +
" }\n" +
" ]\n" +
" }\n" +
"}");
IndexResults<SearchWord> indexResults = SearchWord.find.search(query);
List<String> list = new ArrayList<String>();
for(SearchWord word : indexResults.getResults()){
list.add(word.getWord());
}
return list;
}
}
SearchWord:
@IndexType(name = "search_word")
public class SearchWord extends Index {
// Find method static for request
public static Index.Finder<SearchWord> find = new Index.Finder<SearchWord>(SearchWord.class);
public enum WordType {
NAME,
STRONG_SEARCH_WORD,
WEAK_SEARCH_WORD,
BANNED
}
private String word;
private WordType wordType;
public SearchWord() {
}
public SearchWord(IndexWord indexWord) {
super.id = ""+indexWord.getId();
this.word = StringUtils.lowerCase(indexWord.getWord());
this.wordType = WordType.valueOf(indexWord.getType());
}
public String getId() {
return super.id;
}
public void setId(String id) {
super.id = id;
}
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
public WordType getWordType() {
return wordType;
}
public void setWordType(WordType wordType) {
this.wordType = wordType;
}
@Override
public Map toIndex() {
HashMap map = new HashMap();
map.put("id", super.id);
map.put("word", word);
map.put("word_type", wordType.toString());
return map;
}
@Override
public Indexable fromIndex(Map map) {
if (map == null) {
return this;
}
this.word = (String) map.get("word");
this.wordType = WordType.valueOf((String)map.get("word_type"));
return this;
}
}
The code works very well but I must say that I'm not that sure that I have implemented this correctly. I'm really struggling to understand the documentation. So my questions are basically:
=====
return async(
Akka.asPromise(ask(myActor,"hello", 1000)).map(
new Function<Object,Result>() {
public Result apply(Object response) {
return ok(response.toString());
}
}
)
);
AFAIK, your code is totally ok.
I may be wrong, but I think that the second option is strictly equivalent to the first one, since the Akka.future()
method is a wrapper around the Akka.promise()
method.
From the Akka class source code of Play 2.0.4:
/**
* Executes a block of code asynchronously in the application Akka Actor system.
*/
public static <T> Promise<T> future(java.util.concurrent.Callable<T> callable) {
return asPromise(akka.dispatch.Futures.future(callable, system().dispatcher()));
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With