How to make SuggestBox reliably RPC-call to DB server in the GWTP (Gwt platform) framework?

advertisements

I spent many hours to search this info "How to make SuggestBox to reliably RPC-call to Server DB in GWTP (Gwt platform) Framework" but couldn't find any answer about it.

In fact, there were some answers but they were for people who do not use GWTP. For example, i found a website (http://jagadesh4java.blogspot.com.au/2009/03/hi-every-one-this-is-my-first-blog.html) that guide to code SuggestBox & RPC & it suggests these classes:

    -Client Side:
    + interface SuggestService extends RemoteService
    + interface SuggestServiceAsync
    + class Suggestions implements IsSerializable, Suggestion
    + class SuggestionOracle extends SuggestOracle

    -Server Side:
    + class SuggestServiceImpl extends RemoteServiceServlet implements
    SuggestService

I tried to follow up that website but i got error:

    [WARN] failed [email protected]:8888
    java.net.BindException: Address already in use: bind..........

The above guide clearly was not for people who use GWTP.

My task is I have a dictionary that contains 200k of English words & I want to have a suggest box that when user types any char or word it will look up into DB & suggest accordingly. Ex, when user types "c" it will suggest "cat, car, cut, etc", when typing "car" it will suggest "car service", "carbon", etc.

So I come up with my own solution, even it works but I am feeling I am not doing right thing. My solution is quite simple that I just bring the data from DB down & add them into MultiWordSuggestOracle. Whenever it found a list of word in DB, it won't clear the old data but just keep adding the new list into MultiWordSuggestOracle. However, my program will not constantly call to DB everytime user types a char, but it will call to DB only if the wordInTheMultiWordSuggestOracleList.indexOf(suggestBox.getText(),0)>0. However, there is no way to loop each string in the MultiWordSuggestOracle, so I used List<String> accumulatedSuggestedWordsList=new ArrayList<String>() to store data. Pls see ex:

    private final MultiWordSuggestOracle mySuggestions = new MultiWordSuggestOracle();
    private List<String> accumulatedSuggestedWordsList=new ArrayList<String>();

    private void updateSuggestions(List<String> suggestedWordsList) {
        // call some service to load the suggestions
        for(int i=0;i<suggestedWordsList.size(); i++){
            mySuggestions.add(suggestedWordsList.get(i));
            accumulatedSuggestedWordsList.add(suggestedWordsList.get(i));
        }
    }

    @Override
    protected void onBind() {
        super.onBind();

        final SuggestBox suggestBox = new SuggestBox(mySuggestions);

        getView().getShowingTriplePanel().add(suggestBox);

        suggestBox.addKeyDownHandler(new KeyDownHandler(){

            @Override
            public void onKeyDown(KeyDownEvent event) {
                // TODO Auto-generated method stub
                String word=suggestBox.getText();
                int index=-1;
                for(int i=0; i<accumulatedSuggestedWordsList.size();i++){
                    String w=accumulatedSuggestedWordsList.get(i);
                    index=w.indexOf(word,0);
                    if(index>0)
                        break;
                }
                if(index==0 || index==-1){
                    GetWordFromDictionary action=new      tWordFromDictionary(suggestBox.getText());
                    action.setActionType("getSuggestedWords");
                    dispatchAsync.execute(action, getWordFromDictionaryCallback);
                }

            }

        });
    }
    private AsyncCallback<GetWordFromDictionaryResult> getWordFromDictionaryCallback=new AsyncCallback<GetWordFromDictionaryResult>(){

        @Override
        public void onFailure(Throwable caught) {
            // TODO Auto-generated method stub

        }

        @Override
        public void onSuccess(GetWordFromDictionaryResult result) {
            // TODO Auto-generated method stub
            List<String> suggestedWordsFromDictionaryList=result.getSuggestedWordsFromDictionaryList();
            updateSuggestions(suggestedWordsFromDictionaryList);

        }

    };

The Result: it works but the suggest only show up if i type the "Backspace" button. For ex, when i type the word "car" then no suggested list popup, it only popup "car service, car sale, etc" when i hit the backspace button.

So, can u evaluate my solution? I am feeling i am not doing right. If i am not doing right thing, can u provide a SuggestBox PRC for GWTPframework?

Very Important Note:

How to build a Reliable SuggestBox PRC that prevents the a denial of service attack on our own servers?

What if there are too many calls generated by many people rapidly typing in a suggest box?

Actually I just found an error: SQL Exception: Data source rejected establishment of connection, message from server: "Too many connections" --> so there must be something wrong with my solution

I knew why i got "Too many connections" error. For example, when i type "ambassador" into the suggest box, & i saw my server call the Db 9 times continuously. -1st call, it will search any word like 'a%' -2nd call, it will search any word like 'am%' -3nd call, it will search any word like 'amb%'

The first problem is that it create too many calls at 1 time, second it is not effective cos the first time call like 'a%' may already contains word that will be called at 2nd time like 'am%', so it duplicate the data. Question is how to code to avoid this ineffectiveness.

Someone suggests to use RPCSuggestOracle.java (https://code.google.com/p/google-web-toolkit-incubator/source/browse/trunk/src/com/google/gwt/widgetideas/client/RPCSuggestOracle.java?spec=svn1310&r=1310)

If you can provide an example of using RPCSuggestOracle.java, that will be great. I hope your answer will help a lot of other people.


There were an old inspiring blog post, from the Lombardi Development, that I remember addresses almost all questions you are looking for. It took me a while to find that out but, fortunately, it has simply been moved! And the sources are available. Have a look.

Although being old, things in that post still applies. In particular:

  • use a single connection to avoid explosion of requests, and left free the other ones for other tasks (i.e. avoid to use all the 2-to-8 max parallel browser http connections);
  • reuse data from a previous requests (i.e., if your request is a substring of the previous one, you may already have the suggestions, hence just filter them client-side).

Other things that come to my mind are:

  • use a Timer to simulate a little delay in case of fast writers, so you call the server only after a bit (probably an over optimization, but still an idea);
  • allow to fetch suggestions only on a minimum input length (say, min 3 characters). If you have a lot of possible suggestions, the data returned might be expensive even to parse, specially if - for the search - you decide to adopt a contains instead of startswith strategy;
  • in case you still have tons of suggestions, you could try to implement a lazy load SuggestionDisplay that simply show you the first, say, 50 suggestions and then, on scroll, all the others in an incremental way using the same input string.

Can't say anything from the GWTP part, I've never used it. But AFAICS seems just like GWT-RPC + dispatch mechanism (command pattern) like the old gwt-dispatch. Should't be hard to use instead of vanilla GWT-RPC.

Also have a look at the other 2 previous articles linked in the one above. Might contain some other useful tips.