You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by ja...@apache.org on 2015/07/28 10:56:55 UTC
deltaspike git commit: add ValueExpressionEvaluationInputStream to
jsf util (+ tests) from relative-resource-handler project as discussed with
gpetracek
Repository: deltaspike
Updated Branches:
refs/heads/master b11d8174b -> 6e42e6637
add ValueExpressionEvaluationInputStream to jsf util (+ tests) from relative-resource-handler project as discussed with gpetracek
Project: http://git-wip-us.apache.org/repos/asf/deltaspike/repo
Commit: http://git-wip-us.apache.org/repos/asf/deltaspike/commit/6e42e663
Tree: http://git-wip-us.apache.org/repos/asf/deltaspike/tree/6e42e663
Diff: http://git-wip-us.apache.org/repos/asf/deltaspike/diff/6e42e663
Branch: refs/heads/master
Commit: 6e42e66376aab2c39e7714418136440902966e8c
Parents: b11d817
Author: Jakob Korherr <ja...@gmail.com>
Authored: Tue Jul 28 10:55:08 2015 +0200
Committer: Jakob Korherr <ja...@gmail.com>
Committed: Tue Jul 28 10:55:08 2015 +0200
----------------------------------------------------------------------
deltaspike/modules/jsf/api/pom.xml | 15 +-
.../ValueExpressionEvaluationInputStream.java | 183 +++++++++++++++++++
...alueExpressionEvaluationInputStreamTest.java | 180 ++++++++++++++++++
3 files changed, 377 insertions(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/6e42e663/deltaspike/modules/jsf/api/pom.xml
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/api/pom.xml b/deltaspike/modules/jsf/api/pom.xml
index 6a11e4e..bfc087b 100644
--- a/deltaspike/modules/jsf/api/pom.xml
+++ b/deltaspike/modules/jsf/api/pom.xml
@@ -45,8 +45,21 @@
<groupId>org.apache.myfaces.core</groupId>
<artifactId>myfaces-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-el_2.2_spec</artifactId>
+ </dependency>
-
+ <dependency>
+ <groupId>org.apache.myfaces.test</groupId>
+ <artifactId>myfaces-test20</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-logging</groupId>
+ <artifactId>commons-logging</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/6e42e663/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/util/ValueExpressionEvaluationInputStream.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/util/ValueExpressionEvaluationInputStream.java b/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/util/ValueExpressionEvaluationInputStream.java
new file mode 100644
index 0000000..7e81aca
--- /dev/null
+++ b/deltaspike/modules/jsf/api/src/main/java/org/apache/deltaspike/jsf/util/ValueExpressionEvaluationInputStream.java
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.jsf.util;
+
+import javax.faces.context.FacesContext;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A filtered stream that evaluates value expressions in the original stream while reading from it.
+ */
+public class ValueExpressionEvaluationInputStream extends InputStream
+{
+
+ /**
+ * Logger for this class.
+ */
+ private static final Logger log = Logger.getLogger(ValueExpressionEvaluationInputStream.class.getName());
+
+ private FacesContext facesContext;
+ private PushbackInputStream wrapped;
+ private String currentValue;
+ private int currentValueIndex = -1;
+
+ public ValueExpressionEvaluationInputStream(FacesContext facesContext, InputStream inputStream)
+ {
+ this.facesContext = facesContext;
+ this.wrapped = new PushbackInputStream(inputStream, 512);
+ }
+
+ /**
+ * Reads a byte from the original stream and checks for value expression occurrences.
+ * A value expression has the following format: #{xxx}
+ * If a value expression is found, its occurrence in the stream will replaced with
+ * the evaluated value of the expression.
+ *
+ * @return
+ * @throws java.io.IOException
+ */
+ @Override
+ public int read() throws IOException
+ {
+ // check for a current value
+ if (currentValueIndex != -1)
+ {
+ if (currentValueIndex < currentValue.length())
+ {
+ return currentValue.charAt(currentValueIndex++);
+ }
+ else
+ {
+ // current value exhausted, reset index
+ currentValueIndex = -1;
+ }
+ }
+
+ // read byte and check for value expression begin
+ int c1 = wrapped.read();
+ if (c1 != '#')
+ {
+ return c1; // can't be a value expression, just return the character
+ }
+ else
+ {
+ // could be a value expression, next character must be '{'
+ int c2 = wrapped.read();
+ if (c2 != '{')
+ {
+ wrapped.unread(c2); // we did not find a value expression, unread byte that we read too much
+ return c1; // return original character
+ }
+ else
+ {
+ // read until '}', '\n' or eof occurs (end of value expression or data)
+ List<Integer> possibleValueExpression = new LinkedList<Integer>();
+ int c = wrapped.read();
+ boolean insideString = (c == '\''); // a '}' inside a string must not terminate the expression string
+ while (c != -1 && c != '\n' && (insideString || c != '}'))
+ {
+ possibleValueExpression.add(c);
+ c = wrapped.read();
+ if (c == '\'')
+ {
+ insideString = !insideString;
+ }
+ }
+
+ if (c != '}')
+ {
+ // we did not find a value expression, unread bytes that we read too much (in reverse order)
+ if (c != -1) // we can't unread eof
+ {
+ wrapped.unread(c);
+ }
+ ListIterator<Integer> it = possibleValueExpression.listIterator(possibleValueExpression.size());
+ while (it.hasPrevious())
+ {
+ wrapped.unread(it.previous());
+ }
+ wrapped.unread(c2);
+ return c1; // return original character
+ }
+ else
+ {
+ // we found a value expression #{xxx} (xxx is stored in possibleValueExpression)
+ // create the expression string
+ String expressionString = createExpressionString(possibleValueExpression);
+
+ // evaluate it
+ String expressionValue = facesContext.getApplication()
+ .evaluateExpressionGet(facesContext, expressionString, String.class);
+
+ if (expressionValue == null)
+ {
+ if (log.isLoggable(Level.WARNING))
+ {
+ log.warning("ValueExpression " + expressionString + " evaluated to null.");
+ }
+
+ expressionValue = "null"; // fallback value for null
+ }
+
+ // do NOT unread the evaluated value, but rather store it in an internal buffer,
+ // because otherwise we could recursively evaluate value expressions (a value expression
+ // that resolves to a string containing "#{...}" would be re-evaluated).
+ this.currentValue = expressionValue;
+
+ // return first character of currentValue, if exists (not an empty string)
+ if (currentValue.length() != 0)
+ {
+ this.currentValueIndex = 0;
+ return currentValue.charAt(currentValueIndex++);
+ }
+ else // currentValue is an empty string
+ {
+ // in this case we must recursively start a new read (incl. checks for a new value expression)
+ this.currentValueIndex = -1;
+ return read();
+ }
+ }
+ }
+ }
+ }
+
+ private String createExpressionString(List<Integer> expressionList)
+ {
+ char[] expressionChars = new char[expressionList.size() + 3]; // #{expressionList}
+ int i = 0;
+
+ expressionChars[i++] = '#';
+ expressionChars[i++] = '{';
+ for (Integer c : expressionList)
+ {
+ expressionChars[i++] = (char) c.intValue();
+ }
+ expressionChars[i] = '}';
+
+ return String.valueOf(expressionChars);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/6e42e663/deltaspike/modules/jsf/api/src/test/java/org/apache/deltaspike/jsf/util/ValueExpressionEvaluationInputStreamTest.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/jsf/api/src/test/java/org/apache/deltaspike/jsf/util/ValueExpressionEvaluationInputStreamTest.java b/deltaspike/modules/jsf/api/src/test/java/org/apache/deltaspike/jsf/util/ValueExpressionEvaluationInputStreamTest.java
new file mode 100644
index 0000000..d83d0f5
--- /dev/null
+++ b/deltaspike/modules/jsf/api/src/test/java/org/apache/deltaspike/jsf/util/ValueExpressionEvaluationInputStreamTest.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.jsf.util;
+
+import org.apache.myfaces.test.base.junit4.AbstractJsfTestCase;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.faces.context.FacesContext;
+import java.io.ByteArrayInputStream;
+
+/**
+ * Tests for {@link ValueExpressionEvaluationInputStream}.
+ */
+public class ValueExpressionEvaluationInputStreamTest extends AbstractJsfTestCase
+{
+
+ @Test
+ public void testStreamWithoutExpression_mustBeUnmodified() throws Exception
+ {
+ final String data = "aa\nbbbb\ncccc\ndddd\n\n";
+ byte[] dataArray = data.getBytes();
+
+ ValueExpressionEvaluationInputStream inputStream = new ValueExpressionEvaluationInputStream(
+ FacesContext.getCurrentInstance(), new ByteArrayInputStream(dataArray));
+
+ byte[] inputStreamDataArray = new byte[dataArray.length];
+ inputStream.read(inputStreamDataArray);
+
+ // checks
+ Assert.assertArrayEquals(dataArray, inputStreamDataArray); // data arrays must match
+ Assert.assertEquals(-1, inputStream.read()); // stream must be at eof
+ }
+
+ @Test
+ public void testStreamWithSimpleExpression_mustBeEvaluated() throws Exception
+ {
+ final String data = "aa\nbbbb\ncc#{requestScope.test}cc\ndddd\n\n";
+ final String evaluatedData = "aa\nbbbb\ncctest-valuecc\ndddd\n\n";
+ byte[] dataArray = data.getBytes();
+ byte[] evaluatedDataArray = evaluatedData.getBytes();
+
+ // put test value into scope, so that expression can evaluate to this value
+ FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("test", "test-value");
+
+ ValueExpressionEvaluationInputStream inputStream = new ValueExpressionEvaluationInputStream(
+ FacesContext.getCurrentInstance(), new ByteArrayInputStream(dataArray));
+
+ byte[] inputStreamDataArray = new byte[evaluatedDataArray.length];
+ inputStream.read(inputStreamDataArray);
+
+ // checks
+ Assert.assertArrayEquals(evaluatedDataArray, inputStreamDataArray); // evaluated data arrays must match
+ Assert.assertEquals(-1, inputStream.read()); // stream must be at eof
+ }
+
+ @Test
+ public void testStreamWithHalfExpressionAtEnd_mustBeUnmodified() throws Exception
+ {
+ final String data = "aa\nbbbb\ncccc\ndddd\n\n#{requestScope.test"; // } is missing at the end
+ byte[] dataArray = data.getBytes();
+
+ // put test value into scope, so that expression could evaluate to this value
+ FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("test", "test-value");
+
+ ValueExpressionEvaluationInputStream inputStream = new ValueExpressionEvaluationInputStream(
+ FacesContext.getCurrentInstance(), new ByteArrayInputStream(dataArray));
+
+ byte[] inputStreamDataArray = new byte[dataArray.length];
+ inputStream.read(inputStreamDataArray);
+
+ // checks
+ Assert.assertArrayEquals(dataArray, inputStreamDataArray); // data arrays must match
+ Assert.assertEquals(-1, inputStream.read()); // stream must be at eof
+ }
+
+ @Test
+ public void testStreamWithHalfExpressionAtLineEnd_mustBeUnmodified() throws Exception
+ {
+ final String data = "aa\nbb#{requestScope.test\n}bb\ncccc\ndddd\n\n"; // } is missing at the end
+ byte[] dataArray = data.getBytes();
+
+ // put test value into scope, so that expression could evaluate to this value
+ FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("test", "test-value");
+
+ ValueExpressionEvaluationInputStream inputStream = new ValueExpressionEvaluationInputStream(
+ FacesContext.getCurrentInstance(), new ByteArrayInputStream(dataArray));
+
+ byte[] inputStreamDataArray = new byte[dataArray.length];
+ inputStream.read(inputStreamDataArray);
+
+ // checks
+ Assert.assertArrayEquals(dataArray, inputStreamDataArray); // data arrays must match
+ Assert.assertEquals(-1, inputStream.read()); // stream must be at eof
+ }
+
+ @Test
+ public void testStreamWithExpressionEvaluatingToExpressionString_mustOnlyEvaluateFirstExpression() throws Exception
+ {
+ final String data = "aa\nbbbb\ncc#{requestScope.test}cc\ndddd\n\n";
+ final String evaluatedData = "aa\nbbbb\ncc#{requestScope.test2}cc\ndddd\n\n";
+ byte[] dataArray = data.getBytes();
+ byte[] evaluatedDataArray = evaluatedData.getBytes();
+
+ // put test value into scope, so that expression can evaluate to this value
+ FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("test", "#{requestScope.test2}");
+ FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("test2", "test-value");
+
+ ValueExpressionEvaluationInputStream inputStream = new ValueExpressionEvaluationInputStream(
+ FacesContext.getCurrentInstance(), new ByteArrayInputStream(dataArray));
+
+ byte[] inputStreamDataArray = new byte[evaluatedDataArray.length];
+ inputStream.read(inputStreamDataArray);
+
+ // checks
+ Assert.assertArrayEquals(evaluatedDataArray, inputStreamDataArray); // evaluated data arrays must match
+ Assert.assertEquals(-1, inputStream.read()); // stream must be at eof
+ }
+
+ @Test
+ public void testStreamThatOnlyConsistsOfExpression_mustEvaluateExpression() throws Exception
+ {
+ final String data = "#{requestScope.test}";
+ final String evaluatedData = "test-value";
+ byte[] dataArray = data.getBytes();
+ byte[] evaluatedDataArray = evaluatedData.getBytes();
+
+ // put test value into scope, so that expression can evaluate to this value
+ FacesContext.getCurrentInstance().getExternalContext().getRequestMap().put("test", "test-value");
+
+ ValueExpressionEvaluationInputStream inputStream = new ValueExpressionEvaluationInputStream(
+ FacesContext.getCurrentInstance(), new ByteArrayInputStream(dataArray));
+
+ byte[] inputStreamDataArray = new byte[evaluatedDataArray.length];
+ inputStream.read(inputStreamDataArray);
+
+ // checks
+ Assert.assertArrayEquals(evaluatedDataArray, inputStreamDataArray); // evaluated data arrays must match
+ Assert.assertEquals(-1, inputStream.read()); // stream must be at eof
+ }
+
+ @Test
+ public void testStreamWithNullExpression_mustEvaluateToEmptyString() throws Exception
+ {
+ final String data = "aa\nbbbb\ncc#{requestScope.test}cc\ndddd\n\n";
+ final String evaluatedData = "aa\nbbbb\ncccc\ndddd\n\n";
+ byte[] dataArray = data.getBytes();
+ byte[] evaluatedDataArray = evaluatedData.getBytes();
+
+ // make sure there is no value
+ FacesContext.getCurrentInstance().getExternalContext().getRequestMap().remove("test");
+
+ ValueExpressionEvaluationInputStream inputStream = new ValueExpressionEvaluationInputStream(
+ FacesContext.getCurrentInstance(), new ByteArrayInputStream(dataArray));
+
+ byte[] inputStreamDataArray = new byte[evaluatedDataArray.length];
+ inputStream.read(inputStreamDataArray);
+
+ // checks
+ Assert.assertArrayEquals(evaluatedDataArray, inputStreamDataArray); // evaluated data arrays must match
+ Assert.assertEquals(-1, inputStream.read()); // stream must be at eof
+ }
+
+}