Xerces2-J
  1. Xerces2-J
  2. XERCESJ-1429

[GSoC]: Asynchronous LSParser and parseWithContext

    Details

    • Type: New Feature New Feature
    • Status: In Progress
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 2.9.1
    • Fix Version/s: None
    • Labels:

      Description

      The goal of this project is to complete the implementation of the DOM Level 3 LSParser. Though Xerces has a functional LSParser, there are a couple parts of the spec which still need to be implemented. This includes an asynchronous [1] version which returns from the parse method immediately and builds the DOM tree on another thread as well as parseWithContext [2] which allows a document fragment to be parsed and attached to an existing DOM.

      Possible Mentors: Michael Glavassevich

      [1] http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407/load-save.html#LS-LSParser
      [2] http://www.w3.org/TR/2004/REC-DOM-Level-3-LS-20040407/load-save.html#LS-LSParser-parseWithContext

      1. AsynchronousDOMParserImplPatch.txt
        12 kB
        Thiwanka Somasiri
      2. ListenerCountPatch.txt
        1 kB
        Thiwanka Somasiri
      3. LoadEventImplPatch.txt
        2 kB
        Thiwanka Somasiri
      4. ProgressEventImplPatch.txt
        2 kB
        Thiwanka Somasiri
      5. AsynchronousDOMParserImplPatch.txt
        13 kB
        Thiwanka Somasiri
      6. DOMParserImpl.parseWithContext.txt
        2 kB
        Thiwanka Somasiri
      7. CustomEntityResolver.java
        3 kB
        Thiwanka Somasiri
      8. DOMParserImpl.parseWithContext.txt
        1 kB
        Thiwanka Somasiri
      9. parseWithContext.txt
        4 kB
        Thiwanka Somasiri
      10. CustomEntityResolver.java
        5 kB
        Thiwanka Somasiri
      11. DOMParserImpl_PATCH.java
        12 kB
        Thiwanka Somasiri
      12. CustomEntityResourceResolver.java
        1 kB
        Thiwanka Somasiri
      13. CoreDOMImplementationImpl_PATCH.java
        2 kB
        Thiwanka Somasiri

        Activity

        Thiwanka Somasiri made changes -
        Attachment CoreDOMImplementationImpl_PATCH.java [ 12491067 ]
        Hide
        Thiwanka Somasiri added a comment -

        Added patch for CoreDOMImplementationImpl.java

        Show
        Thiwanka Somasiri added a comment - Added patch for CoreDOMImplementationImpl.java
        Thiwanka Somasiri made changes -
        Attachment DOMParserImpl_PATCH.java [ 12490871 ]
        Attachment CustomEntityResourceResolver.java [ 12490872 ]
        Hide
        Thiwanka Somasiri added a comment -

        Contains the functionality for parseWithContext() and the CustomEntityResourceResolver which resolves the XML fragment.

        Show
        Thiwanka Somasiri added a comment - Contains the functionality for parseWithContext() and the CustomEntityResourceResolver which resolves the XML fragment.
        Thiwanka Somasiri made changes -
        Attachment parseWithContext.txt [ 12490598 ]
        Attachment CustomEntityResolver.java [ 12490599 ]
        Hide
        Thiwanka Somasiri added a comment -

        parseWithOntext.txt contains only the code for parseWithContsxt - In progress

        Show
        Thiwanka Somasiri added a comment - parseWithOntext.txt contains only the code for parseWithContsxt - In progress
        Hide
        Thiwanka Somasiri added a comment -

        Hi Michael,

        I have attached the latest modifications to the parseWithContext() method and wanted to check it with you whether the approach is correct.

        Thanks.

        Show
        Thiwanka Somasiri added a comment - Hi Michael, I have attached the latest modifications to the parseWithContext() method and wanted to check it with you whether the approach is correct. Thanks.
        Thiwanka Somasiri made changes -
        Attachment DOMParserImpl.parseWithContext.txt [ 12490042 ]
        Thiwanka Somasiri made changes -
        Attachment CustomEntityResolver.java [ 12490041 ]
        Hide
        Thiwanka Somasiri added a comment - - edited

        CustomEntityResolver which restructures the user's XML fragment and returns the fragment Document

        Show
        Thiwanka Somasiri added a comment - - edited CustomEntityResolver which restructures the user's XML fragment and returns the fragment Document
        Hide
        Thiwanka Somasiri added a comment -

        Hi Michael and devs,

        I have attached the approach I have taken to parseWithContext() and I am continuing the merging nodes part.

        Thanks

        Show
        Thiwanka Somasiri added a comment - Hi Michael and devs, I have attached the approach I have taken to parseWithContext() and I am continuing the merging nodes part. Thanks
        Thiwanka Somasiri made changes -
        Attachment DOMParserImpl.parseWithContext.txt [ 12489513 ]
        Hide
        Thiwanka Somasiri added a comment -

        DOMParserImpl's parseWithContext() in progress

        Show
        Thiwanka Somasiri added a comment - DOMParserImpl's parseWithContext() in progress
        Thiwanka Somasiri made changes -
        Attachment AsynchronousDOMParserImplPatch.txt [ 12486220 ]
        Hide
        Thiwanka Somasiri added a comment -

        Updated the dispatchEvent() method functionality

        Show
        Thiwanka Somasiri added a comment - Updated the dispatchEvent() method functionality
        Hide
        Thiwanka Somasiri added a comment -

        Hi Michael and devs,

        I updated the dispatchEvent() as you mentioned in the previous post. But still unclear about one point in the w3c spec [1]. In the spec it says that the dispatchEvent() should return FALSE if any of the listeners which handled the event called preventDefault(). But in the implementation in org.apache.xerces.dom.events.EventImpl.java class the preventDefault() is as follows :

        public void preventDefault()

        { preventDefault = true; }

        where the preventDefault value is set to TRUE which we return in the dispatchEvent() method as event.preventDefault. According to the implementation, if any of the listeners called the preventDefault() method dispatchEvent() should return TRUE. So I think there is a conflict.

        [1]. http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget

        Thanks.

        Show
        Thiwanka Somasiri added a comment - Hi Michael and devs, I updated the dispatchEvent() as you mentioned in the previous post. But still unclear about one point in the w3c spec [1] . In the spec it says that the dispatchEvent() should return FALSE if any of the listeners which handled the event called preventDefault(). But in the implementation in org.apache.xerces.dom.events.EventImpl.java class the preventDefault() is as follows : public void preventDefault() { preventDefault = true; } where the preventDefault value is set to TRUE which we return in the dispatchEvent() method as event.preventDefault. According to the implementation, if any of the listeners called the preventDefault() method dispatchEvent() should return TRUE. So I think there is a conflict. [1] . http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget Thanks.
        Hide
        Michael Glavassevich added a comment -

        Hi Thiwanka,

        I've had a look at your implementation of dispatchEvent(). Before returning from the method I think you should also be calling the registered EventListeners.

        Thanks.

        Show
        Michael Glavassevich added a comment - Hi Thiwanka, I've had a look at your implementation of dispatchEvent(). Before returning from the method I think you should also be calling the registered EventListeners. Thanks.
        Hide
        Thiwanka Somasiri added a comment -

        Hi Michael,

        I have attached the files and need to mention the latest changes I made recently. Since there is only one EventTarget (thus there are no Ancestor EventTargets) in this case I ignored the "useCapture" in addActionListener() and removeActionListener(). In dispatchEvent(Event evt) we have to get the Event's type and check whether there are any EventListeners listening on the particular Event. So I implemented a class called ListenerCount.java which is similar to LCount.java(used in DocumentImpl) to keep track of the counts on the EventListeners registered on the EventTarget.

        I added initLoadEvent() and initProgressEvent() to LoadEventImpl.java and ProgressEventImpl.java classes respectively. After instantiating objects from these classes I call the initXXXEvent("XXX", false, false) passing "false" values on canBubbleArg and cancelableArg parameters.

        Can you review the dispatchEvent() and other changes I have done and tell me how should I improve on them.

        Thanks.

        Show
        Thiwanka Somasiri added a comment - Hi Michael, I have attached the files and need to mention the latest changes I made recently. Since there is only one EventTarget (thus there are no Ancestor EventTargets) in this case I ignored the "useCapture" in addActionListener() and removeActionListener(). In dispatchEvent(Event evt) we have to get the Event's type and check whether there are any EventListeners listening on the particular Event. So I implemented a class called ListenerCount.java which is similar to LCount.java(used in DocumentImpl) to keep track of the counts on the EventListeners registered on the EventTarget. I added initLoadEvent() and initProgressEvent() to LoadEventImpl.java and ProgressEventImpl.java classes respectively. After instantiating objects from these classes I call the initXXXEvent("XXX", false, false) passing "false" values on canBubbleArg and cancelableArg parameters. Can you review the dispatchEvent() and other changes I have done and tell me how should I improve on them. Thanks.
        Thiwanka Somasiri made changes -
        Status Open [ 1 ] In Progress [ 3 ]
        Thiwanka Somasiri made changes -
        Attachment AsynchronousDOMParserImplPatch.txt [ 12485970 ]
        Attachment ListenerCountPatch.txt [ 12485971 ]
        Attachment LoadEventImplPatch.txt [ 12485972 ]
        Attachment ProgressEventImplPatch.txt [ 12485973 ]
        Hide
        Michael Glavassevich added a comment -

        Hi Thiwanka,

        I assume you're referring to this code which checks the character offset and produces progress events if the XMLLocator has advanced at least 2K:

        public void startElement (QName element, XMLAttributes attributes, Augmentations augs) throws XNIException {
        if(locator.getCharacterOffset() == 0)

        { reportProgressEvents(); nextCharOffset += 2048; }else if(locator.getCharacterOffset() > nextCharOffset) { reportProgressEvents(); nextCharOffset += 2048; }

        //Call the AbstractDOMParser.startElement()
        super.startElement(element, attributes, augs);
        }

        That looks fine to me.

        Just mentioned this to Ishara... In future it would be easier to review changes if you created a patch (e.g. diff -u) which shows the differences between the previous version. Generally also better to add source files as an attachment to the JIRA issue rather than including it directly as a comment. This makes it easier to review and apply to the codebase.

        Thanks.

        Show
        Michael Glavassevich added a comment - Hi Thiwanka, I assume you're referring to this code which checks the character offset and produces progress events if the XMLLocator has advanced at least 2K: public void startElement (QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { if(locator.getCharacterOffset() == 0) { reportProgressEvents(); nextCharOffset += 2048; }else if(locator.getCharacterOffset() > nextCharOffset) { reportProgressEvents(); nextCharOffset += 2048; } //Call the AbstractDOMParser.startElement() super.startElement(element, attributes, augs); } That looks fine to me. Just mentioned this to Ishara... In future it would be easier to review changes if you created a patch (e.g. diff -u) which shows the differences between the previous version. Generally also better to add source files as an attachment to the JIRA issue rather than including it directly as a comment. This makes it easier to review and apply to the codebase. Thanks.
        Hide
        Thiwanka Somasiri added a comment -

        Hi Michael,
        I have done some modifications to AsynchronousDOMParserImpl. Modifications were done mostly on progress events scenario. Can you give your feed back on the modifications?

        public class AsynchronousDOMParserImpl extends DOMParserImpl implements EventTarget{

        private Hashtable eventListeners;
        //private DOMParserImpl parser;
        private volatile boolean fBusy = false;//TODO make this volatile to avoid other threads using the async parser when busy
        private XMLLocator locator;
        private int nextCharOffset = 0;
        private Vector progressEventListeners;
        private LSInput input;
        private boolean callByParsingThread = false;

        //Call the super class constructors - there are four constructors in the DOMParserImpl class

        public AsynchronousDOMParserImpl(String configuration, String schemaType)

        { super(configuration, schemaType); //parser = new DOMParserImpl(configuration, schemaType); }

        public AsynchronousDOMParserImpl(XMLParserConfiguration config)

        { super(config); //parser = new DOMParserImpl(config); }

        public AsynchronousDOMParserImpl(SymbolTable symbolTable)

        { super(symbolTable); //parser = new DOMParserImpl(symbolTable); }

        public AsynchronousDOMParserImpl(SymbolTable symbolTable, XMLGrammarPool grammarPool)

        { super(symbolTable, grammarPool); //parser = new DOMParserImpl(symbolTable, grammarPool); }

        public void addEventListener(String type, EventListener listener, boolean useCapture){

        if (type == null || type.length() == 0 || listener == null)
        return;

        //Remove the previous entry for the same EventListener
        removeEventListener(type, listener, useCapture);

        Vector listeners = getEventListeners(type);
        if(listeners == null)

        { listeners = new Vector(); setEventListeners(type, listeners); }

        listeners .addElement(new ListenerHolder(listener, useCapture));

        //TODO Initiate capture and bubbling stuff

        }

        private Vector getEventListeners(String type){
        if (eventListeners == null)

        { return null; }

        return (Vector) eventListeners.get(type);
        }

        private void setEventListeners(String type, Vector listeners){
        if (eventListeners == null)

        { eventListeners = new Hashtable(); }


        if(listeners == null)

        { eventListeners.remove(type); }

        else

        { eventListeners.put(type, listeners); }


        }

        public void removeEventListener(String type, EventListener listener, boolean useCapture){
        if (type == null || type.length() == 0 || listener == null)
        return;

        //If the vector is null for a particular type it will return
        Vector listeners = getEventListeners(type);
        if (listeners == null)
        return;

        //If the vector is not null, compare the listener and useCapture and remove the listener
        for(int i = 0; i < listeners.size(); i++){
        ListenerHolder lh = (ListenerHolder) listeners.get;
        if(lh.useCapture == useCapture && lh.el == listener){
        listeners.removeElementAt;
        //TODO assign null value in to hashtable when the vector is empty
        if(listeners.size()==0)

        { setEventListeners(type, null); }

        //TODO Initiate capture and bubbling stuff

        break;
        }
        }
        }

        public boolean dispatchEvent(Event evt)

        { return false;//TODO change the return value }

        public void startDocument (XMLLocator locator, String encoding,NamespaceContext namespaceContext, Augmentations augs) throws XNIException

        { this.locator = locator; super.startDocument(locator, encoding, namespaceContext, augs); }

        public void startElement (QName element, XMLAttributes attributes, Augmentations augs) throws XNIException {
        if(locator.getCharacterOffset() == 0)

        { reportProgressEvents(); nextCharOffset += 2048; }else if(locator.getCharacterOffset() > nextCharOffset) { reportProgressEvents(); nextCharOffset += 2048; }

        //Call the AbstractDOMParser.startElement()
        super.startElement(element, attributes, augs);
        }

        public void reportProgressEvents(){
        //Invoke the progress event listeners
        if(eventListeners != null){
        Hashtable eventListenersClone = (Hashtable) eventListeners.clone();
        if(progressEventListeners == null)

        { progressEventListeners = (Vector)eventListenersClone.get("progress"); }

        else{
        Iterator iterator = progressEventListeners.iterator();
        while(iterator.hasNext())

        { EventListener el = (EventListener) iterator.next(); ProgressEventImpl pei = new ProgressEventImpl(input, nextCharOffset, 0); el.handleEvent(pei); }

        }
        }
        }

        /*private Document parseLSInput(LSInput is)

        { return super.parse(is); }

        */

        public Document parse(LSInput is){
        //final Object lock = new Object();
        if(!fBusy)

        { setBusyFlag(); }

        else if(callByParsingThread)

        { super.parse(is);//What will happen if the user tries to call the parse() again? }

        else

        { //Check what is the domain for the first argument String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null); throw new DOMException(DOMException.INVALID_STATE_ERR, msg); }

        input = is;
        final LSInput ls = is;

        //Parsing thread
        Runnable parsingThread = new Runnable() {

        @Override
        public void run() {
        try{

        //Document documentParsed = parser.parse(ls);
        //Document documentParsed = asyncParser.parseLSInput(ls);
        callByParsingThread = true;
        Document documentParsed = parse(ls);

        //TODO Invoke the listeners who were waiting for the load events
        if(eventListeners != null){
        Hashtable eventListenersClone = (Hashtable) eventListeners.clone();
        //Extract the listeners who were waiting for the load event and call the handleEvent() - after parsing occurs
        Vector loadEventListeners = (Vector)eventListenersClone.get("load");
        if(loadEventListeners != null){
        Iterator iterator = loadEventListeners.iterator();

        while(iterator.hasNext())

        { EventListener el = (EventListener) iterator.next(); //Just for testing LoadEventImpl lei = new LoadEventImpl(documentParsed, ls); el.handleEvent(lei); }

        }
        }
        }finally

        { resetBusyFlag(); }


        }
        };

        Thread target = new Thread(parsingThread);
        target.start();

        return null;
        }

        public void setBusyFlag(){
        if(fBusy)

        { fBusy = true; }

        else

        { //Check what is the domain for the first argument String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null); throw new DOMException(DOMException.INVALID_STATE_ERR, msg); }


        }

        public void resetBusyFlag ()

        { fBusy = false; }

        public boolean getBusy ()

        { return fBusy; }

        /**

        • return true always as it is asynchronous
        • */
          public boolean getAsync () { return true; }

        //This struct holds the EventListner associated with the string types
        class ListenerHolder{

        EventListener el;
        boolean useCapture;

        ListenerHolder(EventListener el, boolean useCapture)

        { this.el = el; this.useCapture = useCapture; }

        }
        }

        Thanks.

        Show
        Thiwanka Somasiri added a comment - Hi Michael, I have done some modifications to AsynchronousDOMParserImpl. Modifications were done mostly on progress events scenario. Can you give your feed back on the modifications? public class AsynchronousDOMParserImpl extends DOMParserImpl implements EventTarget{ private Hashtable eventListeners; //private DOMParserImpl parser; private volatile boolean fBusy = false;//TODO make this volatile to avoid other threads using the async parser when busy private XMLLocator locator; private int nextCharOffset = 0; private Vector progressEventListeners; private LSInput input; private boolean callByParsingThread = false; //Call the super class constructors - there are four constructors in the DOMParserImpl class public AsynchronousDOMParserImpl(String configuration, String schemaType) { super(configuration, schemaType); //parser = new DOMParserImpl(configuration, schemaType); } public AsynchronousDOMParserImpl(XMLParserConfiguration config) { super(config); //parser = new DOMParserImpl(config); } public AsynchronousDOMParserImpl(SymbolTable symbolTable) { super(symbolTable); //parser = new DOMParserImpl(symbolTable); } public AsynchronousDOMParserImpl(SymbolTable symbolTable, XMLGrammarPool grammarPool) { super(symbolTable, grammarPool); //parser = new DOMParserImpl(symbolTable, grammarPool); } public void addEventListener(String type, EventListener listener, boolean useCapture){ if (type == null || type.length() == 0 || listener == null) return; //Remove the previous entry for the same EventListener removeEventListener(type, listener, useCapture); Vector listeners = getEventListeners(type); if(listeners == null) { listeners = new Vector(); setEventListeners(type, listeners); } listeners .addElement(new ListenerHolder(listener, useCapture)); //TODO Initiate capture and bubbling stuff } private Vector getEventListeners(String type){ if (eventListeners == null) { return null; } return (Vector) eventListeners.get(type); } private void setEventListeners(String type, Vector listeners){ if (eventListeners == null) { eventListeners = new Hashtable(); } if(listeners == null) { eventListeners.remove(type); } else { eventListeners.put(type, listeners); } } public void removeEventListener(String type, EventListener listener, boolean useCapture){ if (type == null || type.length() == 0 || listener == null) return; //If the vector is null for a particular type it will return Vector listeners = getEventListeners(type); if (listeners == null) return; //If the vector is not null, compare the listener and useCapture and remove the listener for(int i = 0; i < listeners.size(); i++){ ListenerHolder lh = (ListenerHolder) listeners.get ; if(lh.useCapture == useCapture && lh.el == listener){ listeners.removeElementAt ; //TODO assign null value in to hashtable when the vector is empty if(listeners.size()==0) { setEventListeners(type, null); } //TODO Initiate capture and bubbling stuff break; } } } public boolean dispatchEvent(Event evt) { return false;//TODO change the return value } public void startDocument (XMLLocator locator, String encoding,NamespaceContext namespaceContext, Augmentations augs) throws XNIException { this.locator = locator; super.startDocument(locator, encoding, namespaceContext, augs); } public void startElement (QName element, XMLAttributes attributes, Augmentations augs) throws XNIException { if(locator.getCharacterOffset() == 0) { reportProgressEvents(); nextCharOffset += 2048; }else if(locator.getCharacterOffset() > nextCharOffset) { reportProgressEvents(); nextCharOffset += 2048; } //Call the AbstractDOMParser.startElement() super.startElement(element, attributes, augs); } public void reportProgressEvents(){ //Invoke the progress event listeners if(eventListeners != null){ Hashtable eventListenersClone = (Hashtable) eventListeners.clone(); if(progressEventListeners == null) { progressEventListeners = (Vector)eventListenersClone.get("progress"); } else{ Iterator iterator = progressEventListeners.iterator(); while(iterator.hasNext()) { EventListener el = (EventListener) iterator.next(); ProgressEventImpl pei = new ProgressEventImpl(input, nextCharOffset, 0); el.handleEvent(pei); } } } } /*private Document parseLSInput(LSInput is) { return super.parse(is); } */ public Document parse(LSInput is){ //final Object lock = new Object(); if(!fBusy) { setBusyFlag(); } else if(callByParsingThread) { super.parse(is);//What will happen if the user tries to call the parse() again? } else { //Check what is the domain for the first argument String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null); throw new DOMException(DOMException.INVALID_STATE_ERR, msg); } input = is; final LSInput ls = is; //Parsing thread Runnable parsingThread = new Runnable() { @Override public void run() { try{ //Document documentParsed = parser.parse(ls); //Document documentParsed = asyncParser.parseLSInput(ls); callByParsingThread = true; Document documentParsed = parse(ls); //TODO Invoke the listeners who were waiting for the load events if(eventListeners != null){ Hashtable eventListenersClone = (Hashtable) eventListeners.clone(); //Extract the listeners who were waiting for the load event and call the handleEvent() - after parsing occurs Vector loadEventListeners = (Vector)eventListenersClone.get("load"); if(loadEventListeners != null){ Iterator iterator = loadEventListeners.iterator(); while(iterator.hasNext()) { EventListener el = (EventListener) iterator.next(); //Just for testing LoadEventImpl lei = new LoadEventImpl(documentParsed, ls); el.handleEvent(lei); } } } }finally { resetBusyFlag(); } } }; Thread target = new Thread(parsingThread); target.start(); return null; } public void setBusyFlag(){ if(fBusy) { fBusy = true; } else { //Check what is the domain for the first argument String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null); throw new DOMException(DOMException.INVALID_STATE_ERR, msg); } } public void resetBusyFlag () { fBusy = false; } public boolean getBusy () { return fBusy; } /** return true always as it is asynchronous */ public boolean getAsync () { return true; } //This struct holds the EventListner associated with the string types class ListenerHolder{ EventListener el; boolean useCapture; ListenerHolder(EventListener el, boolean useCapture) { this.el = el; this.useCapture = useCapture; } } } Thanks.
        Hide
        Thiwanka Somasiri added a comment -

        Hi Michael,

        As I figured out we cannot call the progress event listeners from the parsing thread itself (ie the runnable which parses the document) because we are calling the DOMParser.parse() in that and it cannot be paused from our end. So I thought of creating a new thread which listens to the progress. For example,

        while(locator.getCharacterOffset()%500 == 0)

        { //locating approach may change ie. using load() in XML scanner //code goes here to pause the parsing thread,invoke the progress event listeners and resume the parsing thread }

        But the issue is how the parsing thread can be paused and resumed(it may have to be paused multiple times because the progress events might be invoked multiple times). This idea is somewhat deviated with the IRC chat we had and would like to know your opinion on this.

        Thanks.

        Show
        Thiwanka Somasiri added a comment - Hi Michael, As I figured out we cannot call the progress event listeners from the parsing thread itself (ie the runnable which parses the document) because we are calling the DOMParser.parse() in that and it cannot be paused from our end. So I thought of creating a new thread which listens to the progress. For example, while(locator.getCharacterOffset()%500 == 0) { //locating approach may change ie. using load() in XML scanner //code goes here to pause the parsing thread,invoke the progress event listeners and resume the parsing thread } But the issue is how the parsing thread can be paused and resumed(it may have to be paused multiple times because the progress events might be invoked multiple times). This idea is somewhat deviated with the IRC chat we had and would like to know your opinion on this. Thanks.
        Hide
        Thiwanka Somasiri added a comment -

        Hi Michael and devs,

        While the DOMParser is parsing the document we cannot interfere that process and trigger the progressEvent(because it is not in the Asynchronous Parser context at runtime). So I suggest to create an ExecutorService from executor framework and create two runnables in that. Then one can continue parsing while the other checks the character offset through the XMLLocator. Hope your ideas on that or any other suggestions regarding this.

        In the AbstractDOMParser it has a 'private fLocator' which contains that org.apache.xerces.xni.XMLLocator and there is not an accessor method to that field. So it cannot be accessed in the AsynchronousDOMParserImpl to get the character offset. Or is there any other way to load that to AsynchronousDOMParserImpl?

        Thanks.

        Show
        Thiwanka Somasiri added a comment - Hi Michael and devs, While the DOMParser is parsing the document we cannot interfere that process and trigger the progressEvent(because it is not in the Asynchronous Parser context at runtime). So I suggest to create an ExecutorService from executor framework and create two runnables in that. Then one can continue parsing while the other checks the character offset through the XMLLocator. Hope your ideas on that or any other suggestions regarding this. In the AbstractDOMParser it has a 'private fLocator' which contains that org.apache.xerces.xni.XMLLocator and there is not an accessor method to that field. So it cannot be accessed in the AsynchronousDOMParserImpl to get the character offset. Or is there any other way to load that to AsynchronousDOMParserImpl? Thanks.
        Michael Glavassevich made changes -
        Assignee Thiwanka Somasiri [ asthiwanka ]
        Hide
        Michael Glavassevich added a comment - - edited

        Some notes from a chat I had with Thiwanka on IRC today:

        • The addEventListener() and removeEventListener() methods on the LSParser should recognize "load" (for LSLoadEvents) and "progress" (for LSProgressEvents) as the event types.
        • The frequency that LSProgressEvents are reported is indeed implementation dependent.
        • Computing the totalSize attribute may be challenging. The DOM Level 3 specification allows 0 to be returned from getTotalSize(). I would suggest that we return 0 for now.
        • The current position stored in the LSProgressEvent (returned from getPosition()) can be obtained from the org.apache.xerces.xni.XMLLocator. In particular see XMLLocator.getCharacterOffset() which returns the current character offset in the document.
        • May want to start a thread on the j-users to get a sense of how frequent users would want LSProgressEvents to be reported and whether they would want an option to control the frequency.
        Show
        Michael Glavassevich added a comment - - edited Some notes from a chat I had with Thiwanka on IRC today: The addEventListener() and removeEventListener() methods on the LSParser should recognize "load" (for LSLoadEvents) and "progress" (for LSProgressEvents) as the event types. The frequency that LSProgressEvents are reported is indeed implementation dependent. Computing the totalSize attribute may be challenging. The DOM Level 3 specification allows 0 to be returned from getTotalSize(). I would suggest that we return 0 for now. The current position stored in the LSProgressEvent (returned from getPosition()) can be obtained from the org.apache.xerces.xni.XMLLocator. In particular see XMLLocator.getCharacterOffset() which returns the current character offset in the document. May want to start a thread on the j-users to get a sense of how frequent users would want LSProgressEvents to be reported and whether they would want an option to control the frequency.
        Hide
        Thiwanka Somasiri added a comment -

        Hi Michael and Devs,

        I have posted the AsynchronousParser's latest version here.

        I have few things to clarify:

        LoadEvent listeners should be triggered as the parser.parse() is executed and that can be done by extracting the listeners from the Hashtable by using the relevant type(LS_LOAD_EVENT). But progress event should be triggered in the middle of the parsing process. W3C specification has left it implementation-dependent. I want to know ideas of you regarding this scenario.

        public class AsynchronousDOMParserImpl extends DOMParserImpl implements EventTarget{

        private Hashtable eventListeners;
        private DOMParserImpl parser;
        private volatile boolean fBusy = false;//TODO make this volatile to avoid other threads using the async parser when busy

        //Call the super class constructors - there are four constructors in the DOMParserImpl class

        public AsynchronousDOMParserImpl(String configuration, String schemaType)

        { super(configuration, schemaType); parser = new DOMParserImpl(configuration, schemaType); }

        public AsynchronousDOMParserImpl(XMLParserConfiguration config)

        { super(config); parser = new DOMParserImpl(config); }

        public AsynchronousDOMParserImpl(SymbolTable symbolTable)

        { super(symbolTable); parser = new DOMParserImpl(symbolTable); }

        public AsynchronousDOMParserImpl(SymbolTable symbolTable, XMLGrammarPool grammarPool)

        { super(symbolTable, grammarPool); parser = new DOMParserImpl(symbolTable, grammarPool); }

        public void addEventListener(String type, EventListener listener, boolean useCapture){

        if (type == null || type.length() == 0 || listener == null)
        return;

        //Remove the previous entry for the same EventListener
        removeEventListener(type, listener, useCapture);

        Vector listeners = getEventListeners(type);
        if(listeners == null)

        { listeners = new Vector(); setEventListeners(type, listeners); }

        listeners .addElement(new ListenerHolder(listener, useCapture));

        //TODO Initiate capture and bubbling stuff

        }

        private Vector getEventListeners(String type){
        if (eventListeners == null)

        { return null; }

        return (Vector) eventListeners.get(type);
        }

        private void setEventListeners(String type, Vector listeners){
        if (eventListeners == null)

        { eventListeners = new Hashtable(); }


        if(listeners == null)

        { eventListeners.remove(type); }

        else

        { eventListeners.put(type, listeners); }


        }

        public void removeEventListener(String type, EventListener listener, boolean useCapture){
        if (type == null || type.length() == 0 || listener == null)
        return;

        //If the vector is null for a particular type it will return
        Vector listeners = getEventListeners(type);
        if (listeners == null)
        return;

        //If the vector is not null, compare the listener and useCapture and remove the listener
        for(int i = 0; i < listeners.size(); i++){
        ListenerHolder lh = (ListenerHolder) listeners.get;
        if(lh.useCapture == useCapture && lh.el == listener){
        listeners.removeElementAt;
        //TODO assign null value in to hashtable when the vector is empty
        if(listeners.size()==0)

        { setEventListeners(type, null); }

        //TODO Initiate capture and bubbling stuff

        break;
        }
        }
        }

        public boolean dispatchEvent(Event evt)

        { return false;//TODO change the return value }

        public Document parse(LSInput is){
        final LSInput ls = is;
        setBusyFlag();

        /* if(eventListeners != null)

        { final Hashtable eventListenersClone = (Hashtable) eventListeners.clone(); }


        */

        Runnable target = new Runnable() {

        @Override
        public void run() {
        try{
        Document documentParsed = parser.parse(ls);
        //TODO Invoke the listeners who were waiting for the events
        if(eventListeners != null){
        Hashtable eventListenersClone = (Hashtable) eventListeners.clone();
        //Extract the listeners who were waiting for the load event and call the handleEvent() - after parsing occurs
        Vector loadEventListeners = (Vector)eventListenersClone.get("LS_LOAD_EVENT"); //Change the String 'type'
        if(loadEventListeners != null){
        Iterator iterator = loadEventListeners.iterator();

        while(iterator.hasNext())

        { EventListener el = (EventListener) iterator.next(); //Just for testing LoadEventImpl lei = new LoadEventImpl(documentParsed, ls); el.handleEvent(lei); }

        }
        }
        }finally

        { resetBusyFlag(); }


        }
        };

        Thread t = new Thread(target);
        t.start();

        return null;
        }

        public void setBusyFlag(){
        if(fBusy == false)

        { fBusy = true; }

        else

        { //Check what is the domain for the first argument String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null); throw new DOMException(DOMException.INVALID_STATE_ERR, msg); }


        }

        public void resetBusyFlag ()

        { fBusy = false; }

        public boolean getBusy ()

        { return fBusy; }

        /**

        • return true always as it is asynchronous
        • */
          public boolean getAsync () { return true; }

        //This struct holds the EventListner associated with the string types
        class ListenerHolder{

        EventListener el;
        boolean useCapture;

        ListenerHolder(EventListener el, boolean useCapture)

        { this.el = el; this.useCapture = useCapture; }

        }
        }

        Show
        Thiwanka Somasiri added a comment - Hi Michael and Devs, I have posted the AsynchronousParser's latest version here. I have few things to clarify: LoadEvent listeners should be triggered as the parser.parse() is executed and that can be done by extracting the listeners from the Hashtable by using the relevant type(LS_LOAD_EVENT). But progress event should be triggered in the middle of the parsing process. W3C specification has left it implementation-dependent. I want to know ideas of you regarding this scenario. public class AsynchronousDOMParserImpl extends DOMParserImpl implements EventTarget{ private Hashtable eventListeners; private DOMParserImpl parser; private volatile boolean fBusy = false;//TODO make this volatile to avoid other threads using the async parser when busy //Call the super class constructors - there are four constructors in the DOMParserImpl class public AsynchronousDOMParserImpl(String configuration, String schemaType) { super(configuration, schemaType); parser = new DOMParserImpl(configuration, schemaType); } public AsynchronousDOMParserImpl(XMLParserConfiguration config) { super(config); parser = new DOMParserImpl(config); } public AsynchronousDOMParserImpl(SymbolTable symbolTable) { super(symbolTable); parser = new DOMParserImpl(symbolTable); } public AsynchronousDOMParserImpl(SymbolTable symbolTable, XMLGrammarPool grammarPool) { super(symbolTable, grammarPool); parser = new DOMParserImpl(symbolTable, grammarPool); } public void addEventListener(String type, EventListener listener, boolean useCapture){ if (type == null || type.length() == 0 || listener == null) return; //Remove the previous entry for the same EventListener removeEventListener(type, listener, useCapture); Vector listeners = getEventListeners(type); if(listeners == null) { listeners = new Vector(); setEventListeners(type, listeners); } listeners .addElement(new ListenerHolder(listener, useCapture)); //TODO Initiate capture and bubbling stuff } private Vector getEventListeners(String type){ if (eventListeners == null) { return null; } return (Vector) eventListeners.get(type); } private void setEventListeners(String type, Vector listeners){ if (eventListeners == null) { eventListeners = new Hashtable(); } if(listeners == null) { eventListeners.remove(type); } else { eventListeners.put(type, listeners); } } public void removeEventListener(String type, EventListener listener, boolean useCapture){ if (type == null || type.length() == 0 || listener == null) return; //If the vector is null for a particular type it will return Vector listeners = getEventListeners(type); if (listeners == null) return; //If the vector is not null, compare the listener and useCapture and remove the listener for(int i = 0; i < listeners.size(); i++){ ListenerHolder lh = (ListenerHolder) listeners.get ; if(lh.useCapture == useCapture && lh.el == listener){ listeners.removeElementAt ; //TODO assign null value in to hashtable when the vector is empty if(listeners.size()==0) { setEventListeners(type, null); } //TODO Initiate capture and bubbling stuff break; } } } public boolean dispatchEvent(Event evt) { return false;//TODO change the return value } public Document parse(LSInput is){ final LSInput ls = is; setBusyFlag(); /* if(eventListeners != null) { final Hashtable eventListenersClone = (Hashtable) eventListeners.clone(); } */ Runnable target = new Runnable() { @Override public void run() { try{ Document documentParsed = parser.parse(ls); //TODO Invoke the listeners who were waiting for the events if(eventListeners != null){ Hashtable eventListenersClone = (Hashtable) eventListeners.clone(); //Extract the listeners who were waiting for the load event and call the handleEvent() - after parsing occurs Vector loadEventListeners = (Vector)eventListenersClone.get("LS_LOAD_EVENT"); //Change the String 'type' if(loadEventListeners != null){ Iterator iterator = loadEventListeners.iterator(); while(iterator.hasNext()) { EventListener el = (EventListener) iterator.next(); //Just for testing LoadEventImpl lei = new LoadEventImpl(documentParsed, ls); el.handleEvent(lei); } } } }finally { resetBusyFlag(); } } }; Thread t = new Thread(target); t.start(); return null; } public void setBusyFlag(){ if(fBusy == false) { fBusy = true; } else { //Check what is the domain for the first argument String msg = DOMMessageFormatter.formatMessage(DOMMessageFormatter.DOM_DOMAIN, "INVALID_STATE_ERR", null); throw new DOMException(DOMException.INVALID_STATE_ERR, msg); } } public void resetBusyFlag () { fBusy = false; } public boolean getBusy () { return fBusy; } /** return true always as it is asynchronous */ public boolean getAsync () { return true; } //This struct holds the EventListner associated with the string types class ListenerHolder{ EventListener el; boolean useCapture; ListenerHolder(EventListener el, boolean useCapture) { this.el = el; this.useCapture = useCapture; } } }
        Hide
        Thiwanka Somasiri added a comment -

        Hi Michael,

        I have modified the class to add and remove listeners & made the changes you have asked. I used a similar way to add and remove listeners as it is in DocumentImpl class implementation. The modified class is as follows.

        Note: When a user tries to use the AsyncLSParser, he can check whether the parser is busy using the getBusy() method. But, if the user tries to access the parse() method without checking the busy flag, it should not be allowed. So I suggest to throw an exception when trying to set the busy flag(when invoking setBusyFlag() in parse() method) in to "true" where it is already set to "true". Hope your opinion on this.

        public class AsynchronousDOMParserImpl extends DOMParserImpl implements EventTarget{

        //Create the HashSet to hold the event listeners that the users are subscribed to
        private Hashtable eventListeners;
        private DOMParserImpl parser;
        private volatile boolean fBusy = false;//TODO make this volatile to avoid other threads using the async parser when busy
        //private LSInput ls;

        //Call the super class constructors - there are four constructors in the DOMParserImpl class

        public AsynchronousDOMParserImpl(String configuration, String schemaType)

        { super(configuration, schemaType); //Check whether these super() should be removed or not parser = new DOMParserImpl(configuration, schemaType); }

        public AsynchronousDOMParserImpl(XMLParserConfiguration config)

        { super(config); parser = new DOMParserImpl(config); }

        public AsynchronousDOMParserImpl(SymbolTable symbolTable)

        { super(symbolTable); parser = new DOMParserImpl(symbolTable); }

        public AsynchronousDOMParserImpl(SymbolTable symbolTable, XMLGrammarPool grammarPool)

        { super(symbolTable, grammarPool); parser = new DOMParserImpl(symbolTable, grammarPool); }

        public void addEventListener(String type, EventListener listener, boolean useCapture){
        if (type == null || type.length() == 0 || listener == null)
        return;

        //Remove the previous entry for the same EventListener
        //removeEventListener(type, listener, useCapture);

        Vector listeners = getEventListeners(type);

        if(listeners == null)

        { listeners = new Vector(); setEventListeners(type, listeners); }

        listeners .addElement(new ListenerHolder(listener, useCapture));
        }

        private Vector getEventListeners(String type){
        if (eventListeners == null)

        { return null; }

        return (Vector) eventListeners.get(type);
        }

        private void setEventListeners(String type, Vector listeners){
        if (eventListeners == null)

        { eventListeners = new Hashtable(); }


        eventListeners.put(type, listeners);
        }

        public void removeEventListener(String type, EventListener listener, boolean useCapture){
        if (type == null || type.length() == 0 || listener == null)
        return;

        //If the vector is null for a particular type it will return
        Vector listeners = getEventListeners(type);
        if (listeners == null)
        return;

        //If the vector is not null, compare the listener and useCapture and remove the listener
        for(int i = 0; i < listeners.size(); i++){
        ListenerHolder lh = (ListenerHolder) listeners.get;
        if(lh.useCapture == useCapture && lh.el == listener)

        { listeners.removeElementAt(i); //TODO assign null value in to hashtable when the vector is empty break; }

        }

        }

        public boolean dispatchEvent(Event evt)

        { return false;//TODO change the return value }

        public Document parse(LSInput is){
        final LSInput ls = is;
        setBusyFlag();

        //____________________________________
        Runnable target = new Runnable() {

        @Override
        public void run() {
        try

        { parser.parse(ls); }

        catch(LSException e)

        { e.printStackTrace(); }

        finally

        { resetBusyFlag(); }


        }
        };
        //____________________________________

        //AsynchronousDOMParserImpl.AsyncInnerParser target = new AsynchronousDOMParserImpl.AsyncInnerParser();
        Thread t = new Thread(target);
        t.start();
        return null;

        }

        public void setBusyFlag()

        { fBusy = true; }

        public void resetBusyFlag()

        { fBusy = false; }

        public boolean getBusy ()

        { return fBusy; }

        /*class AsyncInnerParser implements Runnable{
        public void run(){
        try

        { parser.parse(ls); }

        catch(LSException e)

        { e.printStackTrace(); }

        finally

        { resetBusyFlag(); }

        }
        }*/

        //This structure holds the EventListner associated with it
        class ListenerHolder{

        EventListener el;
        boolean useCapture;

        ListenerHolder(EventListener el, boolean useCapture)

        { this.el = el; this.useCapture = useCapture; }

        }
        }

        Show
        Thiwanka Somasiri added a comment - Hi Michael, I have modified the class to add and remove listeners & made the changes you have asked. I used a similar way to add and remove listeners as it is in DocumentImpl class implementation. The modified class is as follows. Note: When a user tries to use the AsyncLSParser, he can check whether the parser is busy using the getBusy() method. But, if the user tries to access the parse() method without checking the busy flag, it should not be allowed. So I suggest to throw an exception when trying to set the busy flag(when invoking setBusyFlag() in parse() method) in to "true" where it is already set to "true". Hope your opinion on this. public class AsynchronousDOMParserImpl extends DOMParserImpl implements EventTarget{ //Create the HashSet to hold the event listeners that the users are subscribed to private Hashtable eventListeners; private DOMParserImpl parser; private volatile boolean fBusy = false;//TODO make this volatile to avoid other threads using the async parser when busy //private LSInput ls; //Call the super class constructors - there are four constructors in the DOMParserImpl class public AsynchronousDOMParserImpl(String configuration, String schemaType) { super(configuration, schemaType); //Check whether these super() should be removed or not parser = new DOMParserImpl(configuration, schemaType); } public AsynchronousDOMParserImpl(XMLParserConfiguration config) { super(config); parser = new DOMParserImpl(config); } public AsynchronousDOMParserImpl(SymbolTable symbolTable) { super(symbolTable); parser = new DOMParserImpl(symbolTable); } public AsynchronousDOMParserImpl(SymbolTable symbolTable, XMLGrammarPool grammarPool) { super(symbolTable, grammarPool); parser = new DOMParserImpl(symbolTable, grammarPool); } public void addEventListener(String type, EventListener listener, boolean useCapture){ if (type == null || type.length() == 0 || listener == null) return; //Remove the previous entry for the same EventListener //removeEventListener(type, listener, useCapture); Vector listeners = getEventListeners(type); if(listeners == null) { listeners = new Vector(); setEventListeners(type, listeners); } listeners .addElement(new ListenerHolder(listener, useCapture)); } private Vector getEventListeners(String type){ if (eventListeners == null) { return null; } return (Vector) eventListeners.get(type); } private void setEventListeners(String type, Vector listeners){ if (eventListeners == null) { eventListeners = new Hashtable(); } eventListeners.put(type, listeners); } public void removeEventListener(String type, EventListener listener, boolean useCapture){ if (type == null || type.length() == 0 || listener == null) return; //If the vector is null for a particular type it will return Vector listeners = getEventListeners(type); if (listeners == null) return; //If the vector is not null, compare the listener and useCapture and remove the listener for(int i = 0; i < listeners.size(); i++){ ListenerHolder lh = (ListenerHolder) listeners.get ; if(lh.useCapture == useCapture && lh.el == listener) { listeners.removeElementAt(i); //TODO assign null value in to hashtable when the vector is empty break; } } } public boolean dispatchEvent(Event evt) { return false;//TODO change the return value } public Document parse(LSInput is){ final LSInput ls = is; setBusyFlag(); //____________________________________ Runnable target = new Runnable() { @Override public void run() { try { parser.parse(ls); } catch(LSException e) { e.printStackTrace(); } finally { resetBusyFlag(); } } }; //____________________________________ //AsynchronousDOMParserImpl.AsyncInnerParser target = new AsynchronousDOMParserImpl.AsyncInnerParser(); Thread t = new Thread(target); t.start(); return null; } public void setBusyFlag() { fBusy = true; } public void resetBusyFlag() { fBusy = false; } public boolean getBusy () { return fBusy; } /*class AsyncInnerParser implements Runnable{ public void run(){ try { parser.parse(ls); } catch(LSException e) { e.printStackTrace(); } finally { resetBusyFlag(); } } }*/ //This structure holds the EventListner associated with it class ListenerHolder{ EventListener el; boolean useCapture; ListenerHolder(EventListener el, boolean useCapture) { this.el = el; this.useCapture = useCapture; } } }
        Hide
        Michael Glavassevich added a comment -

        Hi Thiwanka,

        I know this is a work in progress and that you've probabaly added more and possibly changed it quite a bit since you posted this code. I do have some comments which I hope are of help to you.

        I would suggest making the 'fBusy' field volatile to allow its value to be consistent across threads. Also, you can avoid storing the LSInput as a field if you make the Runnable an anonymous class within the parse() method. It looks like you may have already been thinking about doing that as I see this line "//final LSInput input = is;" commented out in the method. Your Runnable would also need to call super.parse() otherwise the call sequence will end up in an infinite recursion and very quickly a stack overflow.

        Hope that helps.

        Thanks.

        Show
        Michael Glavassevich added a comment - Hi Thiwanka, I know this is a work in progress and that you've probabaly added more and possibly changed it quite a bit since you posted this code. I do have some comments which I hope are of help to you. I would suggest making the 'fBusy' field volatile to allow its value to be consistent across threads. Also, you can avoid storing the LSInput as a field if you make the Runnable an anonymous class within the parse() method. It looks like you may have already been thinking about doing that as I see this line "//final LSInput input = is;" commented out in the method. Your Runnable would also need to call super.parse() otherwise the call sequence will end up in an infinite recursion and very quickly a stack overflow. Hope that helps. Thanks.
        Hide
        Thiwanka Somasiri added a comment -

        This is a rough sketch for the AsynchronousDOMParserImpl class:

        package org.apache.xerces.parsers;

        import org.apache.xerces.util.SymbolTable;
        import org.apache.xerces.xni.grammars.XMLGrammarPool;
        import org.apache.xerces.xni.parser.XMLParserConfiguration;
        import org.w3c.dom.events.Event;
        import org.w3c.dom.events.EventListener;
        import org.w3c.dom.Document;
        import org.w3c.dom.events.*;
        import org.w3c.dom.ls.LSInput;
        import java.util.HashSet;
        /**

        • @version $Id: $
          */
          public class AsynchronousDOMParserImpl extends DOMParserImpl implements EventTarget{

        //Create the HashSet to hold the event listeners that the users are subscribed to
        private HashSet listenerSet = new HashSet(); // To be added a new data structure to hold the event type
        private DOMParserImpl parser;
        private boolean fBusy = false;
        private LSInput ls;

        //Call the super class constructors - there are four constructors in the DOMParserImpl class

        public AsynchronousDOMParserImpl(String configuration, String schemaType)

        { super(configuration, schemaType); //Check whether these super() should be removed or not parser = new DOMParserImpl(configuration, schemaType); }

        public AsynchronousDOMParserImpl(XMLParserConfiguration config)

        { super(config); parser = new DOMParserImpl(config); }

        public AsynchronousDOMParserImpl(SymbolTable symbolTable)

        { super(symbolTable); parser = new DOMParserImpl(symbolTable); }

        public AsynchronousDOMParserImpl(SymbolTable symbolTable, XMLGrammarPool grammarPool)

        { super(symbolTable, grammarPool); parser = new DOMParserImpl(symbolTable, grammarPool); }

        public void addEventListener(String type, EventListener listener, boolean useCapture){

        }

        public void removeEventListener(String type, EventListener listener, boolean useCapture){

        }

        public boolean dispatchEvent(Event evt)

        { return false;//TODO change the return value }

        public Document parse(LSInput is){
        try

        { //final LSInput input = is; ls = is; //Set the busy flag true before creating the thread - use a setBusyFlag() setBusyFlag(); //Instantiate an object from the inner class and start the thread AsynchronousDOMParserImpl.TestInner target = new AsynchronousDOMParserImpl.TestInner(); Thread t = new Thread(target); t.start(); }

        catch(Exception e)

        { //TODO apply the proper exception e.printStackTrace(); }

        finally

        { resetBusyFlag(); }

        return null;
        }

        public void setBusyFlag()

        { fBusy = true; }

        public void resetBusyFlag()

        { fBusy = false; }

        public boolean getBusy ()

        { return fBusy; }

        class TestInner implements Runnable{
        public void run(){
        try

        { parser.parse(ls); }

        catch(Exception e)

        { //TODO apply the proper exception e.printStackTrace(); }

        finally

        { resetBusyFlag(); }

        }
        }
        }

        Show
        Thiwanka Somasiri added a comment - This is a rough sketch for the AsynchronousDOMParserImpl class: package org.apache.xerces.parsers; import org.apache.xerces.util.SymbolTable; import org.apache.xerces.xni.grammars.XMLGrammarPool; import org.apache.xerces.xni.parser.XMLParserConfiguration; import org.w3c.dom.events.Event; import org.w3c.dom.events.EventListener; import org.w3c.dom.Document; import org.w3c.dom.events.*; import org.w3c.dom.ls.LSInput; import java.util.HashSet; /** @version $Id: $ */ public class AsynchronousDOMParserImpl extends DOMParserImpl implements EventTarget{ //Create the HashSet to hold the event listeners that the users are subscribed to private HashSet listenerSet = new HashSet(); // To be added a new data structure to hold the event type private DOMParserImpl parser; private boolean fBusy = false; private LSInput ls; //Call the super class constructors - there are four constructors in the DOMParserImpl class public AsynchronousDOMParserImpl(String configuration, String schemaType) { super(configuration, schemaType); //Check whether these super() should be removed or not parser = new DOMParserImpl(configuration, schemaType); } public AsynchronousDOMParserImpl(XMLParserConfiguration config) { super(config); parser = new DOMParserImpl(config); } public AsynchronousDOMParserImpl(SymbolTable symbolTable) { super(symbolTable); parser = new DOMParserImpl(symbolTable); } public AsynchronousDOMParserImpl(SymbolTable symbolTable, XMLGrammarPool grammarPool) { super(symbolTable, grammarPool); parser = new DOMParserImpl(symbolTable, grammarPool); } public void addEventListener(String type, EventListener listener, boolean useCapture){ } public void removeEventListener(String type, EventListener listener, boolean useCapture){ } public boolean dispatchEvent(Event evt) { return false;//TODO change the return value } public Document parse(LSInput is){ try { //final LSInput input = is; ls = is; //Set the busy flag true before creating the thread - use a setBusyFlag() setBusyFlag(); //Instantiate an object from the inner class and start the thread AsynchronousDOMParserImpl.TestInner target = new AsynchronousDOMParserImpl.TestInner(); Thread t = new Thread(target); t.start(); } catch(Exception e) { //TODO apply the proper exception e.printStackTrace(); } finally { resetBusyFlag(); } return null; } public void setBusyFlag() { fBusy = true; } public void resetBusyFlag() { fBusy = false; } public boolean getBusy () { return fBusy; } class TestInner implements Runnable{ public void run(){ try { parser.parse(ls); } catch(Exception e) { //TODO apply the proper exception e.printStackTrace(); } finally { resetBusyFlag(); } } } }
        Hide
        Thiwanka Somasiri added a comment -

        it's ok. Thanks for correcting me.

        Show
        Thiwanka Somasiri added a comment - it's ok. Thanks for correcting me.
        Hide
        Michael Glavassevich added a comment -

        Hi Thiwanka,

        I hope you don't mind, but I just moved the Wiki page you added to http://wiki.apache.org/xerces/ThiwankaSomasiri/gsoc_2011_XERCESJ-1429_proposal.

        http://wiki.apache.org/xerces/Proposal was a bit too generic.

        Thanks.

        Show
        Michael Glavassevich added a comment - Hi Thiwanka, I hope you don't mind, but I just moved the Wiki page you added to http://wiki.apache.org/xerces/ThiwankaSomasiri/gsoc_2011_XERCESJ-1429_proposal . http://wiki.apache.org/xerces/Proposal was a bit too generic. Thanks.
        Hide
        Thiwanka Somasiri added a comment - - edited

        I have created the WIKI page for my proposal.

        http://wiki.apache.org/xerces/Proposal

        Thanks.

        Show
        Thiwanka Somasiri added a comment - - edited I have created the WIKI page for my proposal. http://wiki.apache.org/xerces/Proposal Thanks.
        Hide
        Michael Glavassevich added a comment -

        See recent discussion [1] on the Xerces-J development mailing list.

        [1] http://markmail.org/thread/x4adifemzae5comi

        Show
        Michael Glavassevich added a comment - See recent discussion [1] on the Xerces-J development mailing list. [1] http://markmail.org/thread/x4adifemzae5comi
        Michael Glavassevich made changes -
        Labels gsoc gsoc2011
        Mark Thomas made changes -
        Workflow Default workflow, editable Closed status [ 12575578 ] jira [ 12598181 ]
        Mark Thomas made changes -
        Field Original Value New Value
        Workflow jira [ 12501984 ] Default workflow, editable Closed status [ 12575578 ]
        Michael Glavassevich created issue -

          People

          • Assignee:
            Thiwanka Somasiri
            Reporter:
            Michael Glavassevich
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:

              Development