When you call any "async" method in GWT, you can think of it as starting in 
another Thread. This is the plain Java equivalent to your XmlParserUtil class:

public class XmlParserUtil {
        String url;
        Document doc;
        public RequestBuilder requestBuilder;
        String xmlStr;

        public XmlParserUtil(String xmlFileName) {
                this.url = xmlFileName;
        }

        public Document getDocument() {
                Thread runner = new Thread(new Runnable() {
                        public void run() {

// I'm changing indent here for readability
try {
        // This little bit in the RequestBuilder
        URL javaUrl = new URL(XmlParserUtil.this);
        InputStream in = javaUrl.openStream();
        Reader isr = new InputStreamRead(in);
        StringBuilder builder = new StringBuilder();
        char[] buffer = new char[1024];
        int bufferSize = 0;

        // read in the String data from the URL
        while((size = isr.read(buffer)) != -1) {
                builder.append(buffer, 0, size);
        }

        isr.close();
        in.close();
        
        xmlStr = builder.toString();
        
        // this is a GWT call
        doc = XmlParser.parse(xmlStr);
} catch(IOException ioe) {
        // this would be your onFailure method
        GWT.log(ex.getMessage(), ex);
}


                        }
                });
                
                runner.start();

                // do you see the problem here?
                return doc;
        }
}


So the solution to this problem is: any method that at any level calls an async 
method cannot return anything from that async call! Thus we pass in a Callback 
object of some sort. Then, once the data has been fetched, you can invoke the 
Callback with the data you retrieved.

For a really simple way of fetching data into properties, take a look at my 
blog 
here:

http://lemnik.wordpress.com/2008/07/22/easy-property-binding-and-aync-callbacks-in-gwt/

and here (for an example of the usage):

http://lemnik.wordpress.com/2008/11/11/using-propertychangelisteners-to-ease-gwt-async-calls/

Again, these deal with RPC, but the principal is the same for a RequestBuilder.

gregor wrote:
> Hi Mives29,
> 
> Jason's solution is correct. If you have TreeX implement his Callback
> interface, then XmlParserUtil  will call TreeX.callback() when it has
> retrieved and parsed the XML document, so you move the tree building
> code (getTreeitem()) to start from TreeX.callback(String XML). This
> will solve you immediate problem, but the design cost is that
> XmlParserUtil can _only_  pass XML back to client widgets via that
> route. That is not necessarily a good design decision in the GWT
> asynchronous world.
> 
> Because remote calls have so much effect on the user experience
> (network latency, deserialization etc) it is a good idea to keep as
> much flexibility as possible in how you sequence remote calls and
> widget construction. If you abandoned your idea of a reusable all in
> one XML fetcher/parser utility, you would have other ways to build
> this tree, e.g.
> 
> 1) Make the XML fetch call and parse the XML in onModuleLoad() up
> front before you build the Tree and supply the imgUri's to the Tree's
> constructor
> 2) Make the fetch call from the Tree's constructor, and in
> onResponseReceived(..) parse the returned XML then build the
> Treeitems.
> 
> Since you would normally want to make the user experience as smooth
> and uninterrupted as possible, it is good to maximize flexibility as
> to where and when you make remote calls. That means you can move them
> around to make improvements - it all depends on your particular
> application and your users. For example, many people pre-fetch all
> necessary data to build their top most layer of widgets and display an
> "Application Loading..." type message whilst this is going on. This
> might be good for a complex business application where users will
> typically start it up in the morning and read their mail whilst its
> loading. But in GMail Google don't do that: they pre-fetch the inbox
> list, but they build the little contacts widget on the left separately
> as you watch.
> 
> The point is it's not always immediately obvious what the "best" way
> to sequence remote calls and widget construction is at first - I think
> being able to try out different approaches is an important design goal
> in GWT apps, maybe more so than making something like XmlParserUtil
> reusable. The user's convenience is more important than yours.
> 
> regards
> gregor
> 
> 
> 
> On Nov 11, 6:56 am, mives29 <[EMAIL PROTECTED]> wrote:
>> Hi! I've just re-read your reply, but I cant understand how the
>> interface would affect the program, and how would I use that new
>> getDocument() method of the XmlUtilParser class. Could you provide
>> another example (a working one, if possible)?
>>
>> This whole AsyncCallback/asynchronous stuff of GWT is driving me nuts.
>> I've created the same parser using a service, and Java's own DOM
>> parser, and it works already, however I really want to develop this
>> app of mine full GWT-style. Hope you could help me again, thanks.
>>
>> On Nov 10, 5:58 pm, Jason Morris <[EMAIL PROTECTED]> wrote:
>>
>>> Heya,
>>> Your basic problem here is that you can't have your XmlParserUtil return a
>>> Document object. The doc field will only be filled in when the async
>>> RequestBuilder request returns and the parser is finished with the XML 
>>> string.
>>> By that time, your method has already returned.
>>> The only way to solve this is to create something like a:
>>> public interface Callback<V> {
>>>         void callback(V value);
>>> }
>>> and have the XmlParserUtil look something more like this:
>>> public class XmlParserUtil {
>>>         String url;
>>>         Document doc;
>>>         public RequestBuilder requestBuilder;
>>>         String xmlStr;
>>>         public XmlParserUtil(String xmlFileName) {
>>>                 this.url = xmlFileName;
>>>         }
>>>         public void getDocument(Callback<Document> callback) {
>>>                 if(doc != null) {
>>>                         callback.callback(doc);
>>>                         return;
>>>                 }
>>>                 try {
>>>                         requestBuilder = new 
>>> RequestBuilder(RequestBuilder.GET,url);
>>>                         requestBuilder.sendRequest(null,new 
>>> RequestCallback()
>>>                         {public void onResponseReceived(Request arg0, 
>>> Response arg1) {
>>>                                 xmlStr = arg1.getText();
>>>                                 callback.callback(doc = 
>>> XMLParser.parse(xmlStr));
>>>                         }
>>>                         public void onError(Request request, Throwable 
>>> exception) {
>>>                         }});
>>>                 }
>>>                 catch (RequestException ex) {
>>>                         GWT.log(ex.getMessage(), ex);
>>>             }
>>>         }
>>> }
>>> For more information about async problems, it's related to RPC, but 
>>> applicable
>>> to the RequestBuilder as well:
>>> http://lemnik.wordpress.com/2008/07/04/gwt-rpc-is-called-aynchronous-...
>>> mives29 wrote:
>>>> okay, let me be clear on this, again, my code. (now posting full
>>>> reworked source code)
>>>> // A composite w/c contains a tree.
>>>> public class TreeX extends Composite {
>>>>    Document doc;
>>>>    Tree t = new Tree();
>>>>    int imgUris;
>>>>    XmlParserUtil xmlParser;
>>>>    public TreePol() {
>>>>            TreeItem tItem = getTreeItem();
>>>>            t.addItem(tItem);
>>>>            initWidget(t);
>>>>    }
>>>>    private TreeItem getTreeItem() {
>>>>            doc = getDoc();
>>>>            imgUris = doc.getElementsByTagName("Image").getLength();
>>>>            TreeItem root = null;
>>>>            root = new TreeItem("Image Names");
>>>>            for (int i=0;i<imgUris;i++) {
>>>>                    String tmpImgUri =
>>>> doc.getElementsByTagName("Image").item(i).getChildNodes().item(1).toString();
>>>>                    root.addItem(tmpImgUri);
>>>>            }
>>>>            return root;
>>>>    }
>>>>    public Document getDoc() {
>>>>            xmlParser = new XmlParserUtil("image_uris.xml");
>>>>              while (doc==null) {
>>>>                      doc = xmlParser.getDocument();
>>>>              }
>>>>            return doc;
>>>>    }
>>>> }
>>>> //A class that i want to use as a utility class for parsing xml
>>>> documents. intended to be reusable
>>>> public class XmlParserUtil {
>>>>    String url;
>>>>    Document doc;
>>>>    public RequestBuilder requestBuilder;
>>>>    String xmlStr;
>>>>    public XmlParserUtil(String xmlFileName) {
>>>>            this.url = xmlFileName;
>>>>    }
>>>>    public Document getDocument() {
>>>>            try {
>>>>                    requestBuilder = new 
>>>> RequestBuilder(RequestBuilder.GET,url);
>>>>                    requestBuilder.sendRequest(null,new RequestCallback()
>>>>                    {public void onResponseReceived(Request arg0, Response 
>>>> arg1) {
>>>>                            xmlStr = arg1.getText();
>>>>                            doc = XMLParser.parse(xmlStr);
>>>>                    }
>>>>                    public void onError(Request request, Throwable 
>>>> exception) {
>>>>                    }});
>>>>            }
>>>>            catch (RequestException ex) {
>>>>                    GWT.log(ex.getMessage(), ex);
>>>>        }
>>>>            return doc;
>>>>    }
>>>> }
>>>> //my entrypoint's onModuleLoad(), which adds the various custom
>>>> widgets i made to a tab panel
>>>> public void onModuleLoad() {
>>>>      RichTextAreaX1 rtaPol = new RichTextAreaX1();
>>>>      PictureViewer imgBrowser = new PictureViewer();
>>>>      TreeX tree = new TreeX();
>>>>      TabPanel tp = new TabPanel();
>>>>      tp.add(tree, "1");
>>>>      tp.add(rtaPol, "2");
>>>>      tp.add(imgBrowser, "3");
>>>>      tp.selectTab(0);
>>>>      tp.setWidth("100%");
>>>>      RootPanel.get("leftpanel").add(tp);
>>>>   }
>>>> as you can see, I intend the XmlParserUtil class to be reusable. If I
>>>> place there various logic, then it would be out of scope for that
>>>> classs, because I intend to use XmlParserUtil just to parse an XML
>>>> file, and bring me back a parsed Document object. now how would I do
>>>> that if XmlParserUtil, which contains the requestbuilder and callback,
>>>> would be used by another class (which is a composite).
>>>> im new to this async thing, more so the  requestbuilder stuff. thank
>>>> you for replying, i hope you could answer my question.
>>>> On Nov 10, 3:44 pm, "alex.d" <[EMAIL PROTECTED]> wrote:
>>>>> You have to accept the asynchronous nature of RPC-Requests in GWT and
>>>>> stop trying to build smth. synchronous around them. This code:
>>>>> -----------------------------------
>>>>> doc = getDoc(); //(where doc is a Document object)
>>>>> String subject =
>>>>> doc.getElementsByTagName("Image").item(0).getChildNodes().item(1).toString();
>>>>> String subject2 =
>>>>> doc.getElementsByTagName("Image").item(1).getFirstChild().getNodeValue();
>>>>> -----------------------------------
>>>>> should not be executed in the onload-routine but in the
>>>>> onResponseReceived()-method (or in any other procedure that you call
>>>>> out of it).
>>>>> On 10 Nov., 07:12, mives29 <[EMAIL PROTECTED]> wrote:
>>>>>> hi all. ive re-done my code just a while ago(been a busy week) and my
>>>>>> code kinda bothers me.  here's the code re-done:
>>>>>> Entrypoint onModuleLoad() method:
>>>>>> doc = getDoc(); //(where doc is a Document object)
>>>>>> String subject =
>>>>>> doc.getElementsByTagName("Image").item(0).getChildNodes().item(1).toString();
>>>>>> String subject2 =
>>>>>> doc.getElementsByTagName("Image").item(1).getFirstChild().getNodeValue();
>>>>>> Entrypoiny getDoc() method:
>>>>>> public Document getDoc() {
>>>>>>           XmlParserUtil xmlParser = new XmlParserUtil("image_uris.xml");
>>>>>>           int i = 0;
>>>>>>           while (doc==null) {
>>>>>>                   doc = xmlParser.getDocument();
>>>>>>           }
>>>>>>         return doc;
>>>>>>   }
>>>>>> here's the service implementation:
>>>>>> public class XmlParserUtil {
>>>>>>         String url;
>>>>>>         Document doc;
>>>>>>         RequestBuilder requestBuilder;
>>>>>>         public String xmlStr;
>>>>>>         public XmlParserUtil(String xmlFileName) {
>>>>>>                 this.url = xmlFileName;
>>>>>>         }
>>>>>>         public Document getDocument() {
>>>>>>                 RequestCallback xmlRcb = new RequestCallback()
>>>>>>                 {public void onResponseReceived(Request arg0, Response 
>>>>>> arg1) {
>>>>>>                         xmlStr = arg1.getText();
>>>>>>                         doc = XMLParser.parse(xmlStr);
>>>>>>                 }
>>>>>>                 public void onError(Request request, Throwable 
>>>>>> exception) {
>>>>>>                         // TODO Auto-generated method stub
>>>>>>                 }};
>>>>>>                 try {
>>>>>>                         requestBuilder = new 
>>>>>> RequestBuilder(RequestBuilder.GET,url);
>>>>>>                         requestBuilder.sendRequest(null,xmlRcb);
>>>>>>                 }
>>>>>>                 catch (RequestException ex) {
>>>>>>                         GWT.log(ex.getMessage(), ex);
>>>>>>             }
>>>>>>                 return doc;
>>>>>>         }
>>>>>> }
>>>>>> my problem is on the Entrypoint logic. you see the getDoc() method
>>>>>> there?
>>>>>> it has this:
>>>>>>           while (doc==null) {
>>>>>>                   doc = xmlParser.getDocument();
>>>>>>           }
>>>>>> which just loops around until the service implementation has already
>>>>>> populated the parsed document.
>>>>>> what bothers me with this code is that it
>> ...
>>
>> read more ยป
> > 
> 

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Google Web Toolkit" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/Google-Web-Toolkit?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to