MYFACES-3477 refactored and applied some optimizations to non-state-saving related parts of MyFaces
diff --git a/impl/src/main/java/org/apache/myfaces/application/viewstate/StateUtils.java b/impl/src/main/java/org/apache/myfaces/application/viewstate/StateUtils.java
index 2703664..cd9d3ef 100644
--- a/impl/src/main/java/org/apache/myfaces/application/viewstate/StateUtils.java
+++ b/impl/src/main/java/org/apache/myfaces/application/viewstate/StateUtils.java
@@ -267,23 +267,22 @@
public static final byte[] getAsByteArray(Object object, ExternalContext ctx)
{
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-
// get the Factory that was instantiated @ startup
SerialFactory serialFactory = (SerialFactory) ctx.getApplicationMap().get(SERIAL_FACTORY);
-
Assert.notNull(serialFactory, "serialFactory");
try
{
- ObjectOutputStream writer = serialFactory.getObjectOutputStream(outputStream);
- writer.writeObject(object);
- byte[] bytes = outputStream.toByteArray();
- writer.close();
- outputStream.close();
- writer = null;
- outputStream = null;
- return bytes;
+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream())
+ {
+ try (ObjectOutputStream oos = serialFactory.getObjectOutputStream(baos))
+ {
+ oos.writeObject(object);
+ oos.flush();
+
+ return baos.toByteArray();
+ }
+ }
}
catch (IOException e)
{
@@ -342,18 +341,20 @@
public static final byte[] compress(byte[] bytes)
{
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
try
{
- GZIPOutputStream gzip = new GZIPOutputStream(baos);
- gzip.write(bytes, 0, bytes.length);
- gzip.finish();
- byte[] fewerBytes = baos.toByteArray();
- gzip.close();
- baos.close();
- gzip = null;
- baos = null;
- return fewerBytes;
+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream())
+ {
+ try (GZIPOutputStream gzip = new GZIPOutputStream(baos))
+ {
+ gzip.write(bytes, 0, bytes.length);
+ gzip.finish();
+ gzip.flush();
+
+ return baos.toByteArray();
+ }
+ }
}
catch (IOException e)
{
@@ -409,28 +410,26 @@
public static final byte[] decompress(byte[] bytes)
{
Assert.notNull(bytes, "bytes");
-
- ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- byte[] buffer = new byte[bytes.length];
- int length;
try
{
- GZIPInputStream gis = new GZIPInputStream(bais);
- while ((length = gis.read(buffer)) != -1)
+ try (ByteArrayOutputStream baos = new ByteArrayOutputStream())
{
- baos.write(buffer, 0, length);
- }
+ try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes))
+ {
+ try (GZIPInputStream gis = new GZIPInputStream(bais))
+ {
+ byte[] buffer = new byte[bytes.length];
+ int length;
+ while ((length = gis.read(buffer)) != -1)
+ {
+ baos.write(buffer, 0, length);
+ }
+ }
+ }
- byte[] moreBytes = baos.toByteArray();
- baos.close();
- bais.close();
- gis.close();
- baos = null;
- bais = null;
- gis = null;
- return moreBytes;
+ return baos.toByteArray();
+ }
}
catch (IOException e)
{
diff --git a/impl/src/main/java/org/apache/myfaces/component/validate/WholeBeanValidator.java b/impl/src/main/java/org/apache/myfaces/component/validate/WholeBeanValidator.java
index d55f115..2132a45 100644
--- a/impl/src/main/java/org/apache/myfaces/component/validate/WholeBeanValidator.java
+++ b/impl/src/main/java/org/apache/myfaces/component/validate/WholeBeanValidator.java
@@ -21,9 +21,8 @@
import org.apache.myfaces.el.ELContextDecorator;
import org.apache.myfaces.el.ValueReferenceResolver;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Constructor;
@@ -64,6 +63,7 @@
import org.apache.myfaces.util.MessageUtils;
import org.apache.myfaces.util.MyFacesObjectInputStream;
import org.apache.myfaces.util.ExternalSpecifications;
+import org.apache.myfaces.util.lang.FastByteArrayOutputStream;
/**
*
@@ -214,20 +214,19 @@
private Object copySerializableObject(Object base)
{
- Object copy = null;
try
{
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(baos);
- oos.writeObject(base);
- oos.flush();
- oos.close();
- baos.close();
- byte[] byteData = baos.toByteArray();
- ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
+ FastByteArrayOutputStream baos = new FastByteArrayOutputStream();
+ try (ObjectOutputStream oos = new ObjectOutputStream(baos))
+ {
+ oos.writeObject(base);
+ oos.flush();
+ }
+
+ ObjectInputStream ois = new MyFacesObjectInputStream(baos.getInputStream());
try
{
- copy = new MyFacesObjectInputStream(bais).readObject();
+ return ois.readObject();
}
catch (ClassNotFoundException e)
{
@@ -238,7 +237,8 @@
{
//e.printStackTrace();
}
- return copy;
+
+ return null;
}
private javax.validation.Validator createValidator(final ValidatorFactory validatorFactory,
diff --git a/impl/src/main/java/org/apache/myfaces/renderkit/html/util/HTMLEncoder.java b/impl/src/main/java/org/apache/myfaces/renderkit/html/util/HTMLEncoder.java
index 27154f1..36e49be 100644
--- a/impl/src/main/java/org/apache/myfaces/renderkit/html/util/HTMLEncoder.java
+++ b/impl/src/main/java/org/apache/myfaces/renderkit/html/util/HTMLEncoder.java
@@ -18,10 +18,10 @@
*/
package org.apache.myfaces.renderkit.html.util;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
+import org.apache.myfaces.util.lang.FastByteArrayOutputStream;
/**
* Converts Strings so that they can be used within HTML-Code.
@@ -688,28 +688,30 @@
private static String percentEncodeNonUsAsciiCharacter(char c, String characterEncoding)
{
- ByteArrayOutputStream baos = new ByteArrayOutputStream(10);
- StringBuilder builder = new StringBuilder();
+ FastByteArrayOutputStream baos = new FastByteArrayOutputStream(10);
try
{
- OutputStreamWriter writer = new OutputStreamWriter(baos,characterEncoding);
- writer.write(c);
- writer.flush();
+ try (OutputStreamWriter writer = new OutputStreamWriter(baos, characterEncoding))
+ {
+ writer.write(c);
+ writer.flush();
+ }
}
- catch(IOException e)
+ catch (IOException e)
{
- baos.reset();
return null;
}
-
- byte [] byteArray = baos.toByteArray();
- for (int i=0; i < byteArray.length; i++)
+
+ StringBuilder builder = new StringBuilder();
+
+ byte[] byteArray = baos.getByteArray();
+ for (int i = 0; i < baos.getSize(); i++)
{
builder.append('%');
builder.append(HEX_CHARSET.charAt( (( ((short) byteArray[i] & 0xFF ) >> 0x4) % 0x10)) );
builder.append(HEX_CHARSET.charAt( ((short) byteArray[i] & 0xFF ) % 0x10));
}
-
+
return builder.toString();
}
@@ -1100,22 +1102,23 @@
private static void percentEncodeNonUsAsciiCharacter(Writer currentWriter, char c, String characterEncoding)
throws IOException
{
- ByteArrayOutputStream baos = new ByteArrayOutputStream(10);
+ FastByteArrayOutputStream baos = new FastByteArrayOutputStream(10);
try
{
- OutputStreamWriter writer = new OutputStreamWriter(baos,characterEncoding);
- writer.write(c);
- writer.flush();
+ try (OutputStreamWriter writer = new OutputStreamWriter(baos,characterEncoding))
+ {
+ writer.write(c);
+ writer.flush();
+ }
}
- catch(IOException e)
+ catch (IOException e)
{
- baos.reset();
return;
}
-
- byte [] byteArray = baos.toByteArray();
- for (int i=0; i < byteArray.length; i++)
+
+ byte[] byteArray = baos.getByteArray();
+ for (int i = 0; i < baos.getSize(); i++)
{
currentWriter.write('%');
currentWriter.write(HEX_CHARSET.charAt( (( ((short) byteArray[i] & 0xFF ) >> 0x4) % 0x10)) );
diff --git a/impl/src/main/java/org/apache/myfaces/util/lang/FastByteArrayInputStream.java b/impl/src/main/java/org/apache/myfaces/util/lang/FastByteArrayInputStream.java
new file mode 100644
index 0000000..7e15dca
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/util/lang/FastByteArrayInputStream.java
@@ -0,0 +1,94 @@
+/*
+ * 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.myfaces.util.lang;
+
+import java.io.InputStream;
+
+/**
+ * ByteArrayInputStream implementation that does not synchronize methods.
+ */
+public class FastByteArrayInputStream extends InputStream
+{
+ /**
+ * Our byte buffer
+ */
+ protected byte[] buf = null;
+
+ /**
+ * Number of bytes that we can read from the buffer
+ */
+ protected int count = 0;
+
+ /**
+ * Number of bytes that have been read from the buffer
+ */
+ protected int pos = 0;
+
+ public FastByteArrayInputStream(byte[] buf, int count)
+ {
+ this.buf = buf;
+ this.count = count;
+ }
+
+ @Override
+ public final int available()
+ {
+ return count - pos;
+ }
+
+ @Override
+ public final int read()
+ {
+ return pos < count ? (buf[pos++] & 0xff) : -1;
+ }
+
+ @Override
+ public final int read(byte[] b, int off, int len)
+ {
+ if (pos >= count)
+ {
+ return -1;
+ }
+
+ if ((pos + len) > count)
+ {
+ len = count - pos;
+ }
+
+ System.arraycopy(buf, pos, b, off, len);
+ pos += len;
+ return len;
+ }
+
+ @Override
+ public final long skip(long n)
+ {
+ if ((pos + n) > count)
+ {
+ n = count - pos;
+ }
+ if (n < 0)
+ {
+ return 0;
+ }
+
+ pos += n;
+ return n;
+ }
+}
\ No newline at end of file
diff --git a/impl/src/main/java/org/apache/myfaces/util/lang/FastByteArrayOutputStream.java b/impl/src/main/java/org/apache/myfaces/util/lang/FastByteArrayOutputStream.java
new file mode 100644
index 0000000..12ba8a8
--- /dev/null
+++ b/impl/src/main/java/org/apache/myfaces/util/lang/FastByteArrayOutputStream.java
@@ -0,0 +1,110 @@
+/*
+ * 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.myfaces.util.lang;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * ByteArrayOutputStream implementation that doesn't synchronize methods
+ * and doesn't copy the data on toByteArray().
+ */
+public class FastByteArrayOutputStream extends OutputStream
+{
+ protected byte[] buf = null;
+ protected int size = 0;
+
+ public FastByteArrayOutputStream()
+ {
+ this(1024);
+ }
+
+ public FastByteArrayOutputStream(int size)
+ {
+ this.size = 0;
+ this.buf = new byte[size];
+ }
+
+ /**
+ * Ensures that we have a large enough buffer for the given size.
+ */
+ private void verifyBufferSize(int sz)
+ {
+ if (sz > buf.length)
+ {
+ byte[] old = buf;
+ buf = new byte[Math.max(sz, 2 * buf.length)];
+ System.arraycopy(old, 0, buf, 0, old.length);
+ old = null;
+ }
+ }
+
+ public int getSize()
+ {
+ return size;
+ }
+
+ /**
+ * Returns the byte array containing the written data. Note that this
+ * array will almost always be larger than the amount of data actually
+ * written.
+ */
+ public byte[] getByteArray()
+ {
+ return buf;
+ }
+
+ @Override
+ public final void write(byte b[])
+ {
+ verifyBufferSize(size + b.length);
+ System.arraycopy(b, 0, buf, size, b.length);
+ size += b.length;
+ }
+
+ @Override
+ public final void write(byte b[], int off, int len)
+ {
+ verifyBufferSize(size + len);
+ System.arraycopy(b, off, buf, size, len);
+ size += len;
+ }
+
+ @Override
+ public final void write(int b)
+ {
+ verifyBufferSize(size + 1);
+ buf[size++] = (byte) b;
+ }
+
+ public void reset()
+ {
+ size = 0;
+ }
+
+ /**
+ * Returns a ByteArrayInputStream for reading back the written data
+ */
+ public InputStream getInputStream()
+ {
+ return new FastByteArrayInputStream(buf, size);
+ }
+}
+
+
diff --git a/impl/src/main/java/org/apache/myfaces/view/ServletViewResponseWrapper.java b/impl/src/main/java/org/apache/myfaces/view/ServletViewResponseWrapper.java
index f501314..549df4c 100644
--- a/impl/src/main/java/org/apache/myfaces/view/ServletViewResponseWrapper.java
+++ b/impl/src/main/java/org/apache/myfaces/view/ServletViewResponseWrapper.java
@@ -105,7 +105,7 @@
}
catch (IllegalStateException e)
{
- getResponse().getOutputStream().write(_byteArrayWriter.toByteArray());
+ getResponse().getOutputStream().write(_byteArrayWriter.toByteArray());
}
_byteArrayWriter.reset();
_byteArrayWriter.flush();
@@ -180,23 +180,22 @@
static class WrappedServletOutputStream extends ServletOutputStream
{
- private WrappedByteArrayOutputStream _byteArrayOutputStream;
-
+ private WrappedByteArrayOutputStream baos;
public WrappedServletOutputStream()
{
- _byteArrayOutputStream = new WrappedByteArrayOutputStream(1024);
+ baos = new WrappedByteArrayOutputStream(1024);
}
@Override
public void write(int i) throws IOException
{
- _byteArrayOutputStream.write(i);
+ baos.write(i);
}
public byte[] toByteArray()
{
- return _byteArrayOutputStream.toByteArray();
+ return baos.toByteArray();
}
/**
@@ -209,14 +208,14 @@
*/
private void writeTo(Writer out, String encoding) throws IOException
{
- //Get the charset based on the encoding or return the default if
- //encoding == null
- Charset charset = (encoding == null) ?
- Charset.defaultCharset() : Charset.forName(encoding);
+ //Get the charset based on the encoding or return the default if encoding == null
+ Charset charset = encoding == null
+ ? Charset.defaultCharset()
+ : Charset.forName(encoding);
+
CharsetDecoder decoder = charset.newDecoder();
CharBuffer decodedBuffer = decoder.decode(
- ByteBuffer.wrap(_byteArrayOutputStream.getInnerArray(),
- 0,_byteArrayOutputStream.getInnerCount()));
+ ByteBuffer.wrap(baos.getInnerArray(), 0, baos.getInnerCount()));
if (decodedBuffer.hasArray())
{
out.write(decodedBuffer.array());
@@ -225,7 +224,7 @@
public void reset()
{
- _byteArrayOutputStream.reset();
+ baos.reset();
}
@Override
@@ -248,7 +247,6 @@
*/
static class WrappedByteArrayOutputStream extends ByteArrayOutputStream
{
-
public WrappedByteArrayOutputStream()
{
super();