2021SC@SDUSC [software engineering application and practice] Cocoon project 9- analysis core folder

Keywords: Java

2021SC@SDUSC

IncludeTransformer.java (Part 2)

In this blog, I will continue to analyze the two internal classes class IncludeElement and class IncludeXMLPipe in IncludeTransformer.java.

class IncludeElement

1. Properties:

//Parameter control includes recursive processing.
private boolean recursive;
//Parameter control parallelism (in multiple threads) includes processing.
private boolean parallel;
//Parameter control parallelism (in multiple threads) includes processing recursion.
private boolean recursiveParallel;
//Source URI.
private String base;
//The source URI to include declared in the src attribute of the include element.
protected String source;
//Flag indicating whether the source content must be parsed as XML or contained as text.
protected boolean parse;
//mime type prompt.
protected String mimeType;
//Flag indicating whether to split the root element.
protected boolean stripRoot;
//The buffer collects fallback content.
protected SaxBuffer fallback;
//The Map provided to the parameters of the containing source.
protected Map parameters;
//The name of the currently captured parameter.
protected String parameter;
//Current parameter value (as StringBuffer).
protected StringBuffer value;

2. Method:

Constructor:

  • Create an include element.
  • The parameters passed in are: String base, Boolean parallel, Boolean recursive, Boolean recursive parallel

Member function:

  • public void process(SaxBuffer buffer)
    • The processing element enters the buffer.
    • This cannot be shared because it must be cleaned up if the call fallback.
    • Directly call process0(buffer, buffer);
  • public void process(ContentHandler contentHandler, LexicalHandler lexicalHandler)
    • Overloads the previous member function.
    • Load the URI into the provided handler to handle fallback.
    • If there is a fallback, call process(buffer);, Otherwise, call process0(contentHandler, lexicalHandler);
  • private void process0(ContentHandler contentHandler, LexicalHandler lexicalHandler)
    • Load the URI into the provided handler.
    • Set the environment for this thread.
      • Determine the parameters of resolver.resolveURI() by judging whether the base is empty.
      • If the validity is not empty, synchronization is performed.
      • If parse and recursive exist, call toSAX() function directly; If only parse exists, create a IncludeXMLConsumer object, set setIgnoreRootElement, and finally call toSAX () function. Otherwise, the source is directly converted to utf-8 characters.
      • Finally, there are some exception handling, including IOException, ProcessingException, etc.

class IncludeXMLPipe

1. Properties:

to configure:

//Indicates whether this is a root pipe (owned by the transformer) or a nested pipe.
private final boolean root;
//Parameter control includes recursive processing.
private boolean recursive;
//Parameter control parallelism (in multiple threads) includes processing.
private boolean parallel;
//Parameter control parallelism (in multiple threads) includes processing recursion.
private boolean recursiveParallel;

Current status:

//XMLConsumers stack.
private final Stack consumers = new Stack();
//The current depth of nested elements in the include namespace.
private int depth;
//The Base URI used to resolve the containing source.
private String base;
//The source declared in the include element to be included.
private IncludeElement element;
//If parallel processing is enabled, this Boolean tells us whether buffering has started.
private boolean buffering;
//IncludeBuffer used to buffer events when parallel processing is turned on.
//This object is also used as a lock for thread counters.
private SaxBuffer buffer;
//Contains thread / task counters if executed in parallel.
private int threads;

2. Method:

Constructor:

public IncludeXMLPipe() {
    root = true;
}

public IncludeXMLPipe(ContentHandler contentHandler, LexicalHandler lexicalHandler,boolean recursive, boolean parallel, boolean recursiveParallel) {
    root = false;
    setContentHandler(contentHandler);
    setLexicalHandler(lexicalHandler);
    this.recursive = recursive;
    this.parallel = parallel;
    this.recursiveParallel = recursiveParallel;
}

Create a new IncludeXMLPipe instance.

Member function:

  • public void recycle()
    • Finish processing.
  • private void push(XMLConsumer consumer)
    • Push the current user onto the stack and replace it with a new user.
  • private void pop()
    • Remove the user from the stack and replace the current user.
  • public void setDocumentLocator(Locator locator)
    • Set the document locator.
    • The basic URI of the document can be resolved.
  • public void startDocument()
    • Receive notification of the start of an XML document.
  • public void endDocument()
    • Receive notification of the end of the XML document.
    • This is the end of the line -- Handling buffered events.
  • public void startElement(String uri, String localName, String qName, Attributes atts)
    • Receive notification of the start of the element.
    • Check the namespace declaration.
      • If equal, the current depth of nested elements in the include namespace is reduced by 1.
      • if (INCLUDE_ELEMENT.equals(localName) && depth == 0)
        • Inclusion doesn't happen here, but when we close this tab.
        • Check before including (we don't want nested things) and remember the source code we're trying to include.
        • The default is "xml", the default is "text / xml" /, and the default is false.
        • Ignore nested content and end.
      • if (FALLBACK_ELEMENT.equals(localName) && depth == 1)
        • If this is a fallback parameter, its contents are captured.
        • Check that we are in the correct context, buffer fallback, complete.
      • if (PARAMETER_ELEMENT.equals(localName) && depth == 1)
        • If this is a parameter, make sure we are ready.
        • Check that we are in the correct context.
        • Get and process parameter names, done.
      • if (depth < 2)
        • Wrong element.
  • public void endElement(String uri, String localName, String qName)
    • Receive notification of the end of the element.
    • Check the namespace declaration.
      • If equal, the current depth of nested elements in the include namespace is reduced by 1.
      • if (INCLUDE_ELEMENT.equals(localName) && depth == 0)
      • When we close the include element, inclusion will occur here.
        • End ignore nested content.
        • Gets the source code found when opening the element and include.
        • Parallel processing checks, and then ends.
      • if (FALLBACK_ELEMENT.equals(localName) && depth == 1)
        • End buffering fallback content, the element is complete.
      • if (PARAMETER_ELEMENT.equals(localName) && depth == 1)
        • The parameter name and value are stored. The parameter name and value are URL encoded, so strange characters such as "&" or "=" (with special meaning) can be passed perfectly.
    • If it is not our namespace, please continue to pass the event.
  • public void characters(char[] data, int offset, int length)
    • Receive character notifications.
    • If we have a parameter value to add, let's add this block.
  • Thread management:
    • int incrementThreads()
      • The active thread increments the counter.
    • void decrementThreads()
      • The active thread decrements the counter.
    • private void waitForThreads()
      • Wait until there are no active threads.
      • If the number of threads is greater than 0, it will be recorded in the log and wait.

3. Other instructions:

An inner class in an inner class:

Load the buffer containing the source in a separate thread. Streaming the loaded buffer is possible only when the source is fully loaded. If the load is not completed, the toSAX method will block.

private class IncludeBuffer extends SaxBuffer implements Runnable {
    private IncludeElement element;
    private int thread;
    private boolean finished;
    private SAXException e;
    //Constructor
    public IncludeBuffer(IncludeElement element) {
        this.element = element;
        RunnableManager runnable = null;
        try {
            runnable = (RunnableManager) IncludeTransformer.this.manager.lookup(RunnableManager.ROLE);
            runnable.execute(IncludeTransformer.this.threadPool, this);
        } catch (final ServiceException e) {
            //In case we can't generate a thread
            throw new CascadingRuntimeException(e.getMessage(), e);
        } finally {
            IncludeTransformer.this.manager.release(runnable);
        }
        //Increment active thread counter
        this.thread = incrementThreads();
    }
    //Load the contents of the source into this buffer.
    public void run() {
        try {
            if (getLogger().isDebugEnabled()) {
                getLogger().debug("Thread #" + thread + " loading <" + element.source + ">");
            }
            //Set the environment for this thread
            RequestContextHolder.setRequestAttributes(attributes);
            EnvironmentHelper.enterProcessor(processor, environment);
            try {
                element.process(this);

            } catch (SAXException e) {
                this.e = e;

            } finally {
                EnvironmentHelper.leaveProcessor();
                RequestContextHolder.resetRequestAttributes();
            }
        } catch (ProcessingException e) {
            //Unable to set environment for thread
            this.e = new SAXException(e);
        } finally {
            synchronized (this) {
                this.finished = true;
                notify();
            }
            //Ensure that the active thread counter is decremented
            decrementThreads();
        }
        if (getLogger().isDebugEnabled()) {
            if (this.e == null) {
                getLogger().debug("Thread #" + thread + " loaded <" + element.source + ">");
            } else {
                getLogger().debug("Thread #" + thread + " failed to load <" + element.source + ">", this.e);
            }
        }
    }
    //The buffer stream content when it is fully loaded. If the load is not completed, this method will block.
    public void toSAX(ContentHandler contentHandler)
    throws SAXException {
        synchronized (this) {
            if (!this.finished) {
                try {
                    wait();
                } catch (InterruptedException e) { /* ignored */ }
                // Don't continue waiting if interrupted.
            }
        }
        if (this.e != null) {
            throw this.e;
        }
        super.toSAX(contentHandler);
    }
}

4. Keyword synchronized

synchronized is a keyword in Java. It is supported by Java natively. It is the most basic synchronization lock.
It modifies the following objects:

1. Modify a code block. The modified code block is called synchronization statement block. Its scope of action is the code enclosed in braces {}, and the object of action is the object calling the code block.
2. Modify a method. The modified method is called synchronous method. Its scope of action is the whole method, and the object of action is the object calling the method.
3. Modify a static method. Its scope of action is the whole static method, and the object of action is all objects of this class.
4. Modify a class. Its scope of action is the part enclosed in parentheses after synchronized. The main object of action is all objects of this class.

Posted by sharmeen on Sat, 06 Nov 2021 01:09:01 -0700