OGNL-training
(30 minutes)
Xiang yingbing
2011-05-15
All Rights Reserved © Alcatel-Lucent 2007, #####
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
2
All Rights Reserved © Alcatel-Lucent 2007
1. Express Language (EL)在
J2EE(MVC)中的应用
(a)model
3
All Rights Reserved © Alcatel-Lucent 2007
(b)controller
4
All Rights Reserved © Alcatel-Lucent 2007
(c)view
5
All Rights Reserved © Alcatel-Lucent 2007
说明:
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
6
All Rights Reserved © Alcatel-Lucent 2007
7
All Rights Reserved © Alcatel-Lucent 2007
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
8
All Rights Reserved © Alcatel-Lucent 2007
文档
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)
•
•
•
•
•
•
•
•
•
9
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
All Rights Reserved © Alcatel-Lucent 2007
2.1 History
OGNL最开始作为MVC架构中UI组件和Controllers之间的一种关联方法,利用属性名
字进行关联。随着对更复杂关联的需求的日益增加,Drew Davidson创建了一个他称为
KVCL的东西,用于Key-Value Coding Language,这是Luke Blanshard鼓动的。
Luke然后用ANTLR重新实现了该语言,取了个新名字,这次由Drew鼓动的,这就是
现在这种状态。后来Luke又用 JavaCC重新实现了该语言。所有代码的进一步维护都
由Drew完成 (Luke进行spiritual指导)。
10
All Rights Reserved © Alcatel-Lucent 2007
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包含下面几部分:
11
All Rights Reserved © Alcatel-Lucent 2007
举例: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.
12
All Rights Reserved © Alcatel-Lucent 2007
2.3 Expressions
EL表达式遵守的格式(语法)
下面先列举一些简单的例子,以及一些重要的例子。
完整内容请参见Language Guide (PDF)的第四章
简单的例子:
array.length: 获取数组的长度
array[0]: 读取数组的第一个元素
array.length = array["length"] = array["len" + "gth"]
session.attribute[“foo”] :从map中获取某key对应的值
13
All Rights Reserved © Alcatel-Lucent 2007
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())
14
All Rights Reserved © Alcatel-Lucent 2007
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
15
All Rights Reserved © Alcatel-Lucent 2007
其余内容,自己研究。
16
All Rights Reserved © Alcatel-Lucent 2007
17
All Rights Reserved © Alcatel-Lucent 2007
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以解析这些语言。
18
All Rights Reserved © Alcatel-Lucent 2007
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
19
All Rights Reserved © Alcatel-Lucent 2007
用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。
20
All Rights Reserved © Alcatel-Lucent 2007
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"
21
All Rights Reserved © Alcatel-Lucent 2007
(b)mobject-beans.xml
用SmiDefaultParser.parse解析mib文件,得到的结果: bean id="mib"
22
All Rights Reserved © Alcatel-Lucent 2007
23
All Rights Reserved © Alcatel-Lucent 2007
4. OGNL examples
先把ognl-2.6.9-sources\ognl导入eclipse,然后运行ognl-2.6.9sources\ognl\src\test\java\org\ognl\test中的test cases。
先看看改造的:
24
All Rights Reserved © Alcatel-Lucent 2007
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" } },
//…
};
25
All Rights Reserved © Alcatel-Lucent 2007
接上…
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();
}
}
}
}
}
26
All Rights Reserved © Alcatel-Lucent 2007
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));
27
All Rights Reserved © Alcatel-Lucent 2007
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) },
...28
};
// BigDecimal-valued arithmetic expressions
{ "-1b", new BigDecimal(-1) },
{ "+1b", new BigDecimal(1) },
{ "--1b", new BigDecimal(1) },
...
...
{ "#y + \"1\"", "11" },
{ "\"1\" + #y", "11" }
All Rights Reserved © Alcatel-Lucent 2007
这里
(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的时候,这些例子非常有用。
29
All Rights Reserved © Alcatel-Lucent 2007
The END
30
All Rights Reserved © Alcatel-Lucent 2007