Author: danielf Date: Sun Jan 2 13:15:36 2005 New Revision: 123901 URL: http://svn.apache.org/viewcvs?view=rev&rev=123901 Log: Pluggable expressions. This far only jexl and only part of the intended functionallity is supported. Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/Expression.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionCompiler.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionContext.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionException.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionFactory.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/jexl/ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/jexl/JexlCompiler.java cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/jexl/JexlExpression.java cocoon/trunk/src/blocks/template/test/org/apache/cocoon/components/ cocoon/trunk/src/blocks/template/test/org/apache/cocoon/components/expression/ cocoon/trunk/src/blocks/template/test/org/apache/cocoon/components/expression/ExpressionTestCase.java cocoon/trunk/src/blocks/template/test/org/apache/cocoon/components/expression/ExpressionTestCase.xtest cocoon/trunk/src/blocks/template/test/org/apache/cocoon/components/expression/jexl/ cocoon/trunk/src/blocks/template/test/org/apache/cocoon/components/expression/jexl/JexlTestCase.java
Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/Expression.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/Expression.java?view=auto&rev=123901 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/Expression.java Sun Jan 2 13:15:36 2005 @@ -0,0 +1,30 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.components.expression; + +import java.util.Iterator; + +public interface Expression { + public Object evaluate(ExpressionContext context) throws ExpressionException; + + public Iterator iterate(ExpressionContext context) throws ExpressionException; + + public void assign(ExpressionContext context, Object value) throws ExpressionException; + + public String getExpression(); + + public String getLanguage(); +} Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionCompiler.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionCompiler.java?view=auto&rev=123901 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionCompiler.java Sun Jan 2 13:15:36 2005 @@ -0,0 +1,23 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.components.expression; + +public interface ExpressionCompiler { + public String ROLE = ExpressionCompiler.class.getName(); + + public Expression compile(String language, String expression) + throws ExpressionException; +} Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionContext.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionContext.java?view=auto&rev=123901 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionContext.java Sun Jan 2 13:15:36 2005 @@ -0,0 +1,69 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.components.expression; + +import java.util.HashMap; +import java.util.Map; + +public class ExpressionContext extends HashMap { + private ExpressionContext closure; + private Object contextBean = null; + + public ExpressionContext() { + this(null); + } + + public ExpressionContext(ExpressionContext closure) { + this.closure = closure; + } + + public Object getContextBean() { + if (contextBean != null) + return contextBean; + else if (closure != null) + return closure.getContextBean(); + else + return null; + } + + public void setContextBean(Object contextBean) { + this.contextBean = contextBean; + } + + public Map getVars() { + return this; + } + + public void setVars(Map map) { + clear(); + putAll(map); + } + + public boolean containsKey(Object key) { + return this.get(key) != null; + } + + public Object get(Object key) { + if (key.equals("this")) { + return this; + } + Object result = super.get(key); + if (result == null && closure != null) { + result = closure.get(key); + } + return result; + } +} Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionException.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionException.java?view=auto&rev=123901 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionException.java Sun Jan 2 13:15:36 2005 @@ -0,0 +1,58 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.components.expression; + +import java.io.IOException; + +import org.apache.avalon.framework.CascadingThrowable; + +public class ExpressionException + extends IOException implements CascadingThrowable +{ + /** + * The Throwable that caused this exception to be thrown. + */ + private final Throwable throwable; + + /** + * Construct a new <code>ExpressionException</code> instance. + * + * @param message the detail message for this exception. + */ + public ExpressionException(final String message) { + this(message, null); + } + + /** + * Construct a new <code>ExpressionException</code> instance. + * + * @param message the detail message for this exception. + * @param throwable the root cause of the exception. + */ + public ExpressionException(final String message, final Throwable throwable) { + super(message); + this.throwable = throwable; + } + + /** + * Retrieve the cause of the exception. + * + * @return the cause. + */ + public final Throwable getCause() { + return this.throwable; + } +} Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionFactory.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionFactory.java?view=auto&rev=123901 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/ExpressionFactory.java Sun Jan 2 13:15:36 2005 @@ -0,0 +1,68 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.components.expression; + +import org.apache.avalon.framework.CascadingRuntimeException; +import org.apache.avalon.framework.activity.Disposable; +import org.apache.avalon.framework.logger.AbstractLogEnabled; +import org.apache.avalon.framework.service.ServiceException; +import org.apache.avalon.framework.service.ServiceManager; +import org.apache.avalon.framework.service.ServiceSelector; +import org.apache.avalon.framework.service.Serviceable; +import org.apache.avalon.framework.thread.ThreadSafe; + +public class ExpressionFactory + extends AbstractLogEnabled + implements Disposable, Serviceable, ThreadSafe { + public static String ROLE = ExpressionFactory.class.getName(); + + /** The component manager */ + protected ServiceManager manager; + + /** The Expression compiler selector */ + protected ServiceSelector compilerSelector; + + public void service(final ServiceManager manager) + throws ServiceException { + this.manager = manager; + + this.compilerSelector = + (ServiceSelector)this.manager.lookup(ExpressionCompiler.ROLE + "Selector"); + } + + public void dispose() { + if(null != this.manager) { + this.manager.release(this.compilerSelector); + this.compilerSelector = null; + } + } + + public Expression getExpression(String language, String expression) + throws ExpressionException { + + Expression expressionImpl = null; + ExpressionCompiler compiler = null; + try { + compiler = (ExpressionCompiler)this.compilerSelector.select(language); + expressionImpl = compiler.compile(language, expression); + } catch(final ServiceException ce) { + throw new ExpressionException("Can't find a compiler for " + language); + } finally { + this.compilerSelector.release(compiler); + } + return expressionImpl; + } +} Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/jexl/JexlCompiler.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/jexl/JexlCompiler.java?view=auto&rev=123901 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/jexl/JexlCompiler.java Sun Jan 2 13:15:36 2005 @@ -0,0 +1,28 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.components.expression.jexl; + +import org.apache.avalon.framework.thread.ThreadSafe; +import org.apache.cocoon.components.expression.Expression; +import org.apache.cocoon.components.expression.ExpressionCompiler; +import org.apache.cocoon.components.expression.ExpressionException; + +public class JexlCompiler implements ExpressionCompiler, ThreadSafe { + public Expression compile(String language, String expression) + throws ExpressionException{ + return new JexlExpression(language, expression); + } +} Added: cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/jexl/JexlExpression.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/jexl/JexlExpression.java?view=auto&rev=123901 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/java/org/apache/cocoon/components/expression/jexl/JexlExpression.java Sun Jan 2 13:15:36 2005 @@ -0,0 +1,84 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.components.expression.jexl; + +import java.util.Iterator; +import java.util.Map; + +import org.apache.commons.jexl.JexlContext; +import org.apache.cocoon.components.expression.Expression; +import org.apache.cocoon.components.expression.ExpressionCompiler; +import org.apache.cocoon.components.expression.ExpressionContext; +import org.apache.cocoon.components.expression.ExpressionException; + +public class JexlExpression implements Expression { + + private final String language; + private final org.apache.commons.jexl.Expression compiledExpression; + + public JexlExpression(String language, String expression) + throws ExpressionException { + this.language = language; + try { + this.compiledExpression = + org.apache.commons.jexl.ExpressionFactory.createExpression(expression); + } catch (Exception e) { + throw new ExpressionException("Couldn't create expression " + expression, e); + } + } + + public Object evaluate(ExpressionContext context) + throws ExpressionException{ + try { + return this.compiledExpression.evaluate(new ContextAdapter(context)); + } catch (Exception e) { + throw new ExpressionException("Couldn't evaluate expression " + + getExpression(), e); + } + } + + public Iterator iterate(ExpressionContext context) + throws ExpressionException { + return null; + } + + public void assign(ExpressionContext context, Object value) + throws ExpressionException { + } + + public String getExpression() { + return this.compiledExpression.getExpression(); + } + + public String getLanguage() { + return this.language; + } + + static class ContextAdapter implements JexlContext { + private final ExpressionContext context; + public ContextAdapter(ExpressionContext context) { + this.context = context; + } + + public Map getVars() { + return this.context.getVars(); + } + + public void setVars(Map map) { + this.context.setVars(map); + } + } +} Added: cocoon/trunk/src/blocks/template/test/org/apache/cocoon/components/expression/ExpressionTestCase.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/test/org/apache/cocoon/components/expression/ExpressionTestCase.java?view=auto&rev=123901 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/test/org/apache/cocoon/components/expression/ExpressionTestCase.java Sun Jan 2 13:15:36 2005 @@ -0,0 +1,57 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.components.expression; + +import org.apache.avalon.framework.service.ServiceException; +import org.apache.cocoon.CocoonTestCase; + +public class ExpressionTestCase extends CocoonTestCase { + + public void testContext() { + ExpressionContext parentContext = new ExpressionContext(); + parentContext.put("var1", "foo"); + parentContext.put("var2", "bar"); + + ExpressionContext context = new ExpressionContext(parentContext); + context.put("var1", "zonk"); + + assertEquals("foo", parentContext.get("var1")); + assertEquals("bar", parentContext.get("var2")); + assertEquals("zonk", context.get("var1")); + assertEquals("bar", context.get("var2")); + } + + public void testContextBean() { + ExpressionContext parentContext = new ExpressionContext(); + parentContext.setContextBean("foo"); + + ExpressionContext context = new ExpressionContext(parentContext); + context.setContextBean("bar"); + + assertEquals("foo", parentContext.getContextBean()); + assertEquals("bar", context.getContextBean()); + } + + public void testFactory() throws ExpressionException, ServiceException { + ExpressionFactory factory = (ExpressionFactory)this.lookup(ExpressionFactory.ROLE); + assertNotNull("Test lookup of expression factory", factory); + + Expression expression = factory.getExpression("jexl", "1+2"); + assertNotNull("Test expression compilation", expression); + + assertEquals(new Long(3), expression.evaluate(new ExpressionContext())); + } +} Added: cocoon/trunk/src/blocks/template/test/org/apache/cocoon/components/expression/ExpressionTestCase.xtest Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/test/org/apache/cocoon/components/expression/ExpressionTestCase.xtest?view=auto&rev=123901 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/test/org/apache/cocoon/components/expression/ExpressionTestCase.xtest Sun Jan 2 13:15:36 2005 @@ -0,0 +1,34 @@ +<?xml version="1.0"?> +<!-- + Copyright 1999-2004 The Apache Software Foundation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<testcase> + <roles> + <role name="org.apache.cocoon.components.expression.ExpressionCompilerSelector" + shorthand="expression-compilers" + default-class="org.apache.cocoon.core.container.DefaultServiceSelector"/> + <role name="org.apache.cocoon.components.expression.ExpressionFactory" + shorthand="expression-factory" + default-class="org.apache.cocoon.components.expression.ExpressionFactory"/> + </roles> + + <components> + <expression-compilers> + <component-instance class="org.apache.cocoon.components.expression.jexl.JexlCompiler" name="jexl"/> + </expression-compilers> + </components> + +</testcase> Added: cocoon/trunk/src/blocks/template/test/org/apache/cocoon/components/expression/jexl/JexlTestCase.java Url: http://svn.apache.org/viewcvs/cocoon/trunk/src/blocks/template/test/org/apache/cocoon/components/expression/jexl/JexlTestCase.java?view=auto&rev=123901 ============================================================================== --- (empty file) +++ cocoon/trunk/src/blocks/template/test/org/apache/cocoon/components/expression/jexl/JexlTestCase.java Sun Jan 2 13:15:36 2005 @@ -0,0 +1,40 @@ +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.cocoon.components.expression.jexl; + +import junit.framework.TestCase; +import org.apache.cocoon.components.expression.Expression; +import org.apache.cocoon.components.expression.ExpressionCompiler; +import org.apache.cocoon.components.expression.ExpressionContext; +import org.apache.cocoon.components.expression.ExpressionException; + +public class JexlTestCase extends TestCase { + + public void testExpression() throws ExpressionException { + ExpressionCompiler compiler = new JexlCompiler(); + Expression expression = compiler.compile("jexl", "1+2"); + assertEquals(new Long(3), expression.evaluate(new ExpressionContext())); + } + + public void testContextExpression() throws ExpressionException { + ExpressionCompiler compiler = new JexlCompiler(); + ExpressionContext context = new ExpressionContext(); + context.put("a", new Long(1)); + context.put("b", new Long(2)); + Expression expression = compiler.compile("jexl", "a+b"); + assertEquals(new Long(3), expression.evaluate(context)); + } +}