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 name | Folder role |
---|---|
core | This 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-impl | Tree 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-api | Interfaces for thread factories and pools and performing background tasks. |
thread-impl | Implementation 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.