300 likes | 521 Views
OGNL-training (30 minutes). Xiang yingbing 2011-05-15. Content List. 1. Express Language (EL) 在 J2EE(MVC) 中的应用 2. OGNL 2.1 History 2.2 Syntax 2.3 Expressions 3. OGNL 与 ANTLR /JavaCC ( Java Compiler Compiler ) 3.1 OGNL 源代码是怎么生成出来的 3.2 AMS 和 ANTLR/JSMIPARSER 4. OGNL examples
E N D
OGNL-training(30 minutes) Xiang yingbing2011-05-15
Content List 1. Express Language (EL)在J2EE(MVC)中的应用 2. OGNL 2.1 History 2.2 Syntax 2.3 Expressions 3. OGNL与ANTLR /JavaCC(Java Compiler Compiler ) 3.1 OGNL源代码是怎么生成出来的 3.2 AMS和ANTLR/JSMIPARSER 4. OGNL examples 4.1 ArrayCreationTest 4.2 ognl\src\test\java\org\ognl\test 4.3 ArithmeticAndLogicalOperatorsTest.java
说明: • view中,#{menuMBean.getMenu(topicQueryMBean.mid).getName()} 就是个EL表达式。 • Controller中,@ManagedBean(name=“menuMBean”)中“menuMBean”是个简单的EL表达式。 OGNL最开始作为MVC架构中UI组件和Controllers之间的一种关联方法,利用属性名字进行关联。 • JSF/JSP页面如何显示给用户(web browser) • Web browser发送request(list.xhtml)到web container • Web container 读取list.xhtml文件,把所有的#{…}用适当的内容替换掉。 这个替换的过程就是对EL表达式的解析过程。 • 替换完毕后, Web container 把得到的html页面发送回web browser。 • 不同的web container/WEB FRAMEWORK采用不同的EL实现。 • Struts采用OGNL。 • JSF: sun EL(jsf-impl.jar\com\sun\faces\el ) • JBossEL: http://anonsvn.jboss.org/repos/jboss-el
2. OGNL • OGNL是Object-Graph Navigation Language的意思;它是一个表达式语言,用于获取Java对象的属性,或者为之设置属性。使用相同的表达式来读取属性或者设置属性。 • 主页OGNL 旧的主页: http://www.ognl.org/ [现在已经不可访问]OGNL 新的主页: http://www.opensymphony.com/ognl/OGNL由OpenSymphony开发,该公司其它产品 • WebWork • Quartz • OSCache • OSWorkflow • SiteMesh • Compass • OGNL • Tonic • XWork • OSUser • PropertySet • Clickstream • OSCore
文档Language Guide (PDF) • 下载cvs sourcecode: http://svn.opensymphony.com/svn/ognl/官方maven下载:http://maven.opensymphony.com/opensymphony/jars/ognl-2.6.10-javadoc.jar 15-Feb-2007 10:53 321K ognl-2.6.10-sources.jar 15-Feb-2007 10:53 198K ognl-2.6.10.jar 15-Feb-2007 10:53 164K ognl-2.6.11-javadoc.jar 18-Feb-2007 07:47 321K ognl-2.6.11-sources.jar 18-Feb-2007 07:47 198K ognl-2.6.11.jar 18-Feb-2007 07:47 164K • 应用(http://en.wikipedia.org/wiki/OGNL) • WebWork and its successor Struts2 • Tapestry • Spring Web Flow • Apache Click • NReco (.NET integration framework for lightweight MDD) • op4j (op4j-ognl extension) - Java fluent interface implementation. • MyBatis - SQL mapper framework • The Thymeleaf Template Engine - A Java XML/XHTML/HTML5 template engine • Unitils - Modular Testing framework for Java
2.1 History OGNL最开始作为MVC架构中UI组件和Controllers之间的一种关联方法,利用属性名字进行关联。随着对更复杂关联的需求的日益增加,Drew Davidson创建了一个他称为KVCL的东西,用于Key-Value Coding Language,这是Luke Blanshard鼓动的。Luke然后用ANTLR重新实现了该语言,取了个新名字,这次由Drew鼓动的,这就是现在这种状态。后来Luke又用 JavaCC重新实现了该语言。所有代码的进一步维护都由Drew完成 (Luke进行spiritual指导)。
2.2 Syntax • 简单的OGNL表达式非常简单。该语言带有各种features,变得非常丰富,但是,通常情况下,你不需要关心该语言的复杂部分:the simple cases have remained that way。比如说,要访问一个对象的name属性,OGNL表达式就是name。要得到通过headline属性返回的对象的text属性,OGNL表达式 就是headline.text。 • OGNL表达式的基本单元是导航链(navigation chain),通常就叫做链“chain”。最简单的chains包含下面几部分:
举例:name.toCharArray()[0].numericValue.toString() • This expression follows these steps to evaluate: • extracts the name property of the initial, or root, object (which the user provides to OGNL through the OGNL context) • calls the toCharArray() method on the resulting String • extracts the first character (the one at index 0) from the resulting array • gets the numericValue property from that character (the character is represented as a Character object, and the Character class has a method called getNumericValue()). • calls toString() on the resulting Integer object. The final result of this expression is the String returned by the last toString() call.
2.3 Expressions • EL表达式遵守的格式(语法) 下面先列举一些简单的例子,以及一些重要的例子。 完整内容请参见Language Guide (PDF)的第四章 • 简单的例子: array.length: 获取数组的长度 array[0]: 读取数组的第一个元素 array.length = array["length"] = array["len" + "gth"] session.attribute[“foo”] :从map中获取某key对应的值
2.3.1 Variable References: #this • OGNL在表达式的每个点号(.)那里存储该点号(.)之前的EL表达式的值,该值通过#this来获取。比如:listeners.size().(#this > 100? 2*#this : 20+#this) 第二个点(.)那里,存储的值为"listeners.size()",接着,在括号(...)内部,用#this来指向这个值,也就是"listeners.size()"。整个表达式的结果:如果listeners.size()大于100,那么为2*(listeners.size());否则,整个EL表达式的值为20+(listeners.size())
2.3.2 Chained Subexpressions • 如果OGNL表达式中,某个点号(.)后面跟了个括号表达式(...),比如:headline.parent.(ensureLoaded(), name)那么,这个点号(.)之前的所有表达式(这里为headline.parent)的值被传入括号表达式内,作为该括号表达式的root object。上例(ensureLoaded(), name)等价于:(a) rootObj1=headline.parent(b) 调用rootObj1.ensureLoaded()方法 【方法调用,可以用来做一些动作!比如赋值,检测,日志...】(c) 然后把rootObj1.name作为整个表达式的值。还可以按照这种模式,做很长的链接:obj1.obj2.(methodOfObj2(), propertyOfObj2).p1.p2.obj3.(methodOfObj3(), propertyOfObj3)另外一个例子:obj1.(obj2).(obj3).(obj4).(obj5) 等价于:obj1.obj2.obj3.obj4.obj5
3. OGNL与ANTLR/JavaCC(Java Compiler Compiler ) • 前面History中,我们提到: Luke然后用ANTLR重新实现了该语言,取了个新名字,这次由Drew鼓动的,这就是现在这种状态。后来Luke又用 JavaCC重新实现了该语言。 • JavaCC/ANTLR Java Compiler Compiler [tm] (JavaCC [tm]) is the most popular parser generator for use with Java [tm] applications. A parser generator is a tool that reads a grammar specification and converts it to a Java program that can recognize matches to the grammar. In addition to the parser generator itself, JavaCC provides other standard capabilities related to parser generation such as tree building (via a tool called JJTree included with JavaCC), actions, debugging, etc. JavaCC是一种grammar parser generator:语法解析器的生成器。也就是用于生成语法解析器。 ANTLR也是类似的工具 很多语言,比如Java,HTML,C/C++,OGNL,MIB,都遵循一定的格式。那么,就可以用ANTLR/JAVACC为这些语言生成parser以解析这些语言。
3.1 OGNL源代码是怎么生成出来的 • ognl-2.6.9-sources\ognl\src\java\ognl • ArrayElementsAccessor.java • ArrayPropertyAccessor.java • ASTAdd.java • … • ognl.jjt • ognl.jj • ognl-2.6.9-sources\ognl\build.xml
用JAVACC生成OGNL的Compiler(OGNL源代码)过程: • <java classname=“org.javacc.jjtree.Main”…> 根据ognl.jjt文件生成一些java文件和ognl.jj文件 • <java classname=“org.javacc.parser.Main” …>根据ognl.jj再生成一些java文件。 • 生成的Java文件可以用来读取并解析符合OGNL语言规范的EL表达式。也就是说,这些JAVA文件组成OGNL compiler。比如a+b,OGNL解析它的时候,就能理解该表达式的意思是a加上b。 • 如果想要计算EL表达式的值,或者根据EL表达式为java对象设置值,那么需要手工加入(OGNL开发人员已经完成)一些代码,一边OGNL解析完EL表达式的时候,接着执行get/set。
3.2 AMS和ANTLR/JSMIPARSER 【扩展内容,快速提示】 • AMS使用了jsmiparser解析MIB,而jsmiparser采用了antlr语法解析器生成器。通OGNL一样, jsmiparser也可以用JAVACC实现。 • JSMIPARSER读取MIB文件 9.0.10\basic.fttbmdu.1.2\axs-fttbmdu-mobject-plugin (a) \src\main\resources\META-INF\mobject-mibs.xml 下面这个bean指示哪些mib文件名字(路径)被读入bean id="mibFileNames"
(b)mobject-beans.xml 用SmiDefaultParser.parse解析mib文件,得到的结果: bean id="mib"
4.OGNL examples • 先把ognl-2.6.9-sources\ognl导入eclipse,然后运行ognl-2.6.9-sources\ognl\src\test\java\org\ognl\test中的test cases。 • 先看看改造的:
4.1 ArrayCreationTest import ognl.ExpressionSyntaxException; … public class ArrayCreationTest { private static Root ROOT = new Root(); private static Object[][] TESTS = { // Array creation { ROOT, "new String[] { \"one\", \"two\" }", new String[] { "one", "two" } }, { ROOT, "new String[] { 1, 2 }", new String[] { "1", "2" } }, //… };
接上… public static void main(String[] args) throws Exception { String expressionString = ""; Object root; for(int i=0;i<TESTS.length;i++){ try{ root = TESTS[i][0]; expressionString = (String)TESTS[i][1]; SimpleNode expression = (SimpleNode)Ognl.parseExpression(expressionString); OgnlContext context = new OgnlContext(); //OgnlContext context = (OgnlContext)Ognl.createDefaultContext(null); Object expressionvalue = Ognl.getValue(expression, context, root);//表达式值 Object expectedvalue = TESTS[i][2];//期望值 System.out.println(expressionString+" test-->" + OgnlTestCase.isEqual(expressionvalue, expectedvalue)); }catch(Exception e){ if(e.getClass() == ExpressionSyntaxException.class){ System.out.println(expressionString+" test-->This is the expected Exception"); }else{ e.printStackTrace(); } } } } }
4.2 ognl\src\test\java\org\ognl\test • 所有测试classes的定义结构相同,都扩展org.ognl.test.OgnlTestCase最终都是验证:表达式是否和某个期望值相同。运行过程:(a)//Root root= new Root();Root root= null;//(b) OgnlContext context = (OgnlContext)Ognl.createDefaultContext(null);(c)SimpleNode expression = (SimpleNode)Ognl.parseExpression(expressionString);(d)assertTrue(isEqual(Ognl.getValue(expression , context, root), expectedResult));
4.3 ArithmeticAndLogicalOperatorsTest.java public class ArithmeticAndLogicalOperatorsTest extends OgnlTestCase { private static Object[][] TESTS = { // Double-valued arithmetic expressions { "-1d", new Double(-1) }, { "+1d", new Double(1) }, { "--1f", new Float(1) }, { "2*2.0", new Double(4) }, { "5/2.", new Double(2.5) }, { "5+2D", new Double(7) }, { "5f-2F", new Float(3) }, { "5.+2*3", new Double(11) }, { "(5.+2)*3", new Double(21) }, // BigDecimal-valued arithmetic expressions { "-1b", new BigDecimal(-1) }, { "+1b", new BigDecimal(1) }, { "--1b", new BigDecimal(1) }, ... ... { "#y + \"1\"", "11" }, { "\"1\" + #y", "11" } }; ...
这里(a) root为空,(b) context为context = (OgnlContext)Ognl.createDefaultContext(null); context.put("x", "1"); context.put("y", new BigDecimal(1));(c)表达式TESTS [i][0]的值,总是等于期望值TESTS [i][1] 可以到源代码中看其它例子,设计web container/ams server的时候,这些例子非常有用。