2021SC@SDUSC [application and practice of software engineering] Cocoon code analysis

2021SC@SDUSC

This should be my last blog on software engineering application and practice. The main analysis content this time is the content in the sitemap impl folder, including three folders: processing, selection and util. In addition to the previous content, I will also summarize the code I analyzed before.

MockProcessInfoProvider.java

Simulation Implementation of ProcessInfoProvider interface. This class contains a series of get and set operations, which are related to ObjectModel, Request, Response and ServletContext respectively. Then there are three internal classes - stubbrequest

  • StubRequest
    • This is a stub implementation of HttpServletRequest. The HttpServletRequest interface is implemented.
  • StubResponse
    • This is a stub implementation of HttpServletResponse. The httpservletresponseset interface is implemented.
  • StubSession
    • The HttpSession interface is implemented.

ProcessInfoProviderImpl.java

The default implementation of the process information provider.

There are two ways to focus:

1.getCurrentObjectModel():

After obtaining the current object model, you can get the Request, Response and other contents based on this method.

protected Map getCurrentObjectModel() {
    final Environment env = EnvironmentHelper.getCurrentEnvironment();
    if ( env == null ) {
        throw new IllegalStateException("Unable to locate current environment.");
    }
    return env.getObjectModel();
}

2.setServletContext():

Set dependency to servlet context

public void setServletContext(ServletContext context) {
    this.servletContext = context;
}

AbstractRegexpSelector.java

The abstract class AbstractRegexpSelector defines a simple selector that operates on a configured regular expression pattern.

The configuration of AbstractRegexpSelector is very simple: first, you must configure the mode for selection:

 <map:components>
   ...
   <map:selectors default="...">
     <map:selector name="..." src="org.apache.cocoon.selection....">
       <pattern name="empty">^$</pattern>
       <pattern name="number">^[0-9]+$</pattern>
       <pattern name="string">^.+$</pattern>
     </map:selector>
  </map:selectors>
 </map:components>

Each configured pattern can then be referenced in the pipeline section of the site map:

 <map:pipelines>
   ...
   <map:match ...>
     ...
     <map:select type="browser">
       <map:when test="empty">...</map:when>
       <map:when test="number">...</map:when>
       <map:when test="string">...</map:when>
       <map:otherwise>...</map:otherwise>
     </map:select>
     ...
   </map:match>
   ...
 </map:pipelines>

In this class, there is an attribute called pattern, which is used for the mapping of regular expression programs. The constructor of this class is used to create a new instance of AbstractRegexpSelector.

There are three important methods in this class:

1.select():

Select the pipe segment based on the previously configured mode

public boolean select(String patternName, Object selectorContext) {
    //Check what the context selection returns
    if (selectorContext == null) return(false);
    //Check that we have actually configured a pattern
    REProgram pattern = (REProgram) this.patterns.get(patternName);
    if (pattern == null) {
        if (this.getLogger().isWarnEnabled()) {
            this.getLogger().warn("The specified pattern name \"" + patternName + "\" was not configured in this instance");
        }
        return(false);
    }
    //pattern matching
    return(new RE(pattern).match(selectorContext.toString()));
}

2.configure():

Configure this instance to resolve all regular expression patterns

public void configure(Configuration configuration)
throws ConfigurationException {
    Configuration patterns[] = configuration.getChildren("pattern");
    for (int x = 0; x < patterns.length; x++) {
        String name = patterns[x].getAttribute("name");
        String pattern = patterns[x].getValue();
        this.patterns.put(name, this.compile(pattern));
    }
}

3.compile():

Compiling mode in REProgram

protected REProgram compile(String pattern)
throws ConfigurationException {
    if (pattern == null) {
        throw new ConfigurationException("Null pattern");
    }
    if (pattern.length() == 0) {
        pattern = "^$";
        if (this.getLogger().isWarnEnabled()) {
            this.getLogger().warn("The empty pattern string was rewritten to "+ "'^$' to match for empty strings.  If you "+ "intended to match all strings, please " + "change your pattern to '.*'");
        }
    }
    try {
        RECompiler compiler = new RECompiler();
        REProgram program = compiler.compile(pattern);
        return program;
    } catch (RESyntaxException rse) {
        getLogger().debug("Failed to compile the pattern '" + pattern + "'", rse);
        throw new ConfigurationException(rse.getMessage(), rse);
    }
}

AbstractSwitchSelector.java

Abstract SwitchSelector class.

There is one method that needs attention:

select():

The selector performs a pattern test on some objects in the Map model and uses the returned Boolean value to signal success

public boolean select(String expr, Map objectModel, Parameters params) {
    return select(expr, getSelectorContext(objectModel, params));
}

NamedPatternsSelector.java

An abstract class that is used to select a selector for a value when it matches certain patterns associated with a selection expression.

Known implementations of this abstract class include browserselector, and hostselector comes from the cocoon sitemap components Maven module.

There are two possible ways to focus:

1.checkPatterns():

Check whether value is a substring of one of the patterns associated with expression

protected boolean checkPatterns(String expression, String value) {
    if (value == null) {
        getLogger().debug("No value given -- failing.");
        return false;
    }
    //Gets the mode of the expression
    String[] patterns = (String[])this.strings.get(expression);
    if (patterns == null) {
        getLogger().warn("No configuration for expression '" + expression + "' -- failing.");
        return false;
    }
    for (int i = 0; i < patterns.length; i++) {
        if (value.indexOf(patterns[i]) != -1) {
            getLogger().debug(expression + " selected value " + value);
            return true;
        }
    }
    //Mismatch
    return false;
}

2.configure():

Sets the association from the expression to the schema list

protected void configure(Configuration conf, String confName, String nameAttr, String valueAttr)
  throws ConfigurationException {
    Configuration confs[] = conf.getChildren(confName);
    Map configMap = new HashMap();
	//Create a list of strings for each name
    for (int i = 0; i < confs.length; i++) {
        String name = confs[i].getAttribute(nameAttr);
        String value = confs[i].getAttribute(valueAttr);
		//Gets a list of values for the name
        List nameList = (List)configMap.get(name);
        if (nameList == null) {
            nameList = new ArrayList();
            configMap.put(name, nameList);
        }
		//Add current value
        nameList.add(value);
    }
	//Convert lists to arrays for faster lookup
    Iterator entries = configMap.entrySet().iterator();
    while(entries.hasNext()) {
        Map.Entry entry = (Map.Entry)entries.next();
        List nameList = (List)entry.getValue();
        entry.setValue(nameList.toArray(new String[nameList.size()]));
    }
    this.strings = configMap;
}

DOMFactory.java

Create JXPath AbstractFactory for DOM elements

There are two methods to analyze:

1.createObject():

If the factory cannot create the requested object, false is returned.

public boolean createObject(JXPathContext context,Pointer pointer,Object parent,String name,int index) 
{
	//JXPath automatically creates attributes if the element already exists, but does not call this method if the element does not exit
    addDOMElement((Node) parent, index, name);
    return true;
}

2.addDOMElement():

Add DOM element

private void addDOMElement(Node parent, int index, String tag) {
    int pos = tag.indexOf(':');
    String prefix = null;
    if (pos != -1) {
        prefix = tag.substring(0, pos);
    }
    String uri = null;
    Node child = parent.getFirstChild();
    int count = 0;
    while (child != null) {
        if (child.getNodeName().equals(tag)) {
            count++;
        }
        child = child.getNextSibling();
    }
    Document doc = parent.getOwnerDocument();  
    if (doc != null) {
        uri = getNamespaceURI((Element)parent, prefix);
    } else {
        if (parent instanceof Document) {
            doc = (Document)parent;
            if (prefix != null) {
                throw new RuntimeException("Cannot map non-null prefix " + "when creating a document element");    
            }
        } else { 
            //Should not occur (must be a DocumentType object)
            throw new RuntimeException("Node of class " + parent.getClass().getName() + " has null owner document " + "but is not a Document"); 
        }
    }
	//Continue inserting new elements until the index value is 1
    while (count <= index) {
        Node newElement = doc.createElementNS(uri, tag);
        parent.appendChild(newElement);
        count++;
    }
}

summary

In all blogs, the code I analyzed involves four large folders: core, sitemap impl, thread API and thread impl.

Folder nameFolder role
coreThis module is some kind of wrapper that puts all dependencies together to make it easier to use Cocoon as a web application framework. At present, the complete documentation of all core modules can be found in the Cocoon kernel.
sitemap-implTree handler implementation of site map with dependencies. The Spring package supports Avalon. Abstract base classes and support classes to make it easier to write site map components.
thread-apiInterfaces for thread factories and pools and performing background tasks.
thread-implImplementation of thread pool and factory components. Implementation of components that perform background tasks.

Over the past semester, I have benefited a lot from these 16 code analysis articles. I began to understand the cocoon project from the overall framework, and then gradually went deep into each attribute and method. I learned a lot of knowledge, including the four major features of object-oriented, polymorphism, inheritance, encapsulation, abstraction, DOM, SAX and so on.

Keywords: Java

Added by manichean on Sat, 25 Dec 2021 19:18:38 +0200