Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added chained buffers.

  • Loading branch information...
commit e50fec8396f093203e3de0372a064139e30e93cc 1 parent 292cc28
@jroper jroper authored
Showing with 484 additions and 95 deletions.
  1. +4 −0 .gitignore
  2. +85 −0 src/java/com/opensymphony/module/sitemesh/DefaultSitemeshBuffer.java
  3. +2 −14 src/java/com/opensymphony/module/sitemesh/PageParser.java
  4. +58 −0 src/java/com/opensymphony/module/sitemesh/SitemeshBuffer.java
  5. +38 −0 src/java/com/opensymphony/module/sitemesh/SitemeshBufferFragment.java
  6. +32 −0 src/java/com/opensymphony/module/sitemesh/SitemeshBufferWriter.java
  7. +28 −0 src/java/com/opensymphony/module/sitemesh/SitemeshWriter.java
  8. +9 −24 src/java/com/opensymphony/module/sitemesh/filter/Buffer.java
  9. +2 −0  src/java/com/opensymphony/module/sitemesh/filter/BufferedContent.java
  10. +2 −1  src/java/com/opensymphony/module/sitemesh/filter/PageResponseWrapper.java
  11. +25 −1 src/java/com/opensymphony/module/sitemesh/filter/RoutablePrintWriter.java
  12. +29 −0 src/java/com/opensymphony/module/sitemesh/filter/SitemeshPrintWriter.java
  13. +19 −2 src/java/com/opensymphony/module/sitemesh/multipass/MultipassReplacementPageParser.java
  14. +15 −5 src/java/com/opensymphony/module/sitemesh/parser/FastPageParser.java
  15. +19 −4 src/java/com/opensymphony/module/sitemesh/parser/HTMLPageParser.java
  16. +6 −6 src/java/com/opensymphony/module/sitemesh/parser/SuperFastHtmlPage.java
  17. +13 −6 src/java/com/opensymphony/module/sitemesh/parser/SuperFastPage.java
  18. +12 −12 src/java/com/opensymphony/module/sitemesh/parser/SuperFastSimplePageParser.java
  19. +8 −5 src/java/com/opensymphony/module/sitemesh/taglib/page/ApplyDecoratorTag.java
  20. +2 −1  src/java/com/opensymphony/sitemesh/ContentProcessor.java
  21. +3 −6 src/java/com/opensymphony/sitemesh/compatability/PageParser2ContentProcessor.java
  22. +2 −1  src/java/com/opensymphony/sitemesh/webapp/ContentBufferingResponse.java
  23. +61 −0 src/test/com/opensymphony/module/sitemesh/chaining/ChainingBufferTest.java
  24. +2 −1  src/test/com/opensymphony/module/sitemesh/multipass/DivExtractingPageParserTest.java
  25. +3 −2 src/test/com/opensymphony/module/sitemesh/parser/HTMLPageParserTest.java
  26. +5 −4 src/test/com/opensymphony/module/sitemesh/parser/ParserPerformanceComparison.java
View
4 .gitignore
@@ -1,2 +1,6 @@
build
+out
+*.iml
+*.ipr
+*.iws
dist
View
85 src/java/com/opensymphony/module/sitemesh/DefaultSitemeshBuffer.java
@@ -0,0 +1,85 @@
+package com.opensymphony.module.sitemesh;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * The default implementation of sitemesh buffer
+ */
+public class DefaultSitemeshBuffer implements SitemeshBuffer {
+
+ private final char[] buffer;
+ private final int length;
+ private final List<SitemeshBufferFragment> chainedBuffers;
+
+ public DefaultSitemeshBuffer(char[] buffer) {
+ this(buffer, buffer.length);
+ }
+
+ public DefaultSitemeshBuffer(char[] buffer, int length) {
+ this(buffer, length, Collections.<SitemeshBufferFragment>emptyList());
+ }
+
+ public DefaultSitemeshBuffer(char[] buffer, int length, List<SitemeshBufferFragment> chainedBuffers) {
+ this.buffer = buffer;
+ this.length = length;
+ this.chainedBuffers = new ArrayList<SitemeshBufferFragment>(chainedBuffers);
+ Collections.sort(chainedBuffers);
+ }
+
+ public void writeTo(Writer writer, int start, int length) throws IOException {
+ int pos = start;
+ for (SitemeshBufferFragment fragment : chainedBuffers) {
+ if (fragment.getPosition() < pos) {
+ continue;
+ }
+ if (fragment.getPosition() >= start + length) {
+ break;
+ }
+ // Write the buffer up to the fragment
+ writer.write(buffer, pos, fragment.getPosition() - pos);
+ // Write the fragment
+ fragment.getBuffer().writeTo(writer, fragment.getStart(), fragment.getLength());
+ // increment pos
+ pos = fragment.getPosition();
+ }
+ // Write out the remaining buffer
+ if (pos < start + length) {
+ writer.write(buffer, pos, (start + length) - pos);
+ }
+ }
+
+ public int getTotalLength() {
+ return getTotalLength(0, length);
+ }
+
+ public int getTotalLength(int start, int length) {
+ int total = length;
+
+ for (SitemeshBufferFragment fragment : chainedBuffers) {
+ if (fragment.getPosition() < start) {
+ continue;
+ }
+ if (fragment.getPosition() > start + length) {
+ break;
+ }
+ total += fragment.getBuffer().getTotalLength(fragment.getStart(), fragment.getLength());
+ }
+ return total;
+ }
+
+ public int getBufferLength() {
+ return length;
+ }
+
+ public char[] getCharArray() {
+ return buffer;
+ }
+
+ public boolean hasFragments() {
+ return !chainedBuffers.isEmpty();
+ }
+}
View
16 src/java/com/opensymphony/module/sitemesh/PageParser.java
@@ -25,24 +25,12 @@
* @version $Revision: 1.2 $
*/
public interface PageParser {
-
- /**
- * This builds a Page.
- *
- * @param data The data for the page. Note, this array may be larger than the length of the content.
- * @param length The length of the page.
- * @return The parsed page
- * @throws IOException if an error occurs
- * @since 2.5
- */
- Page parse(char[] data, int length) throws IOException;
-
/**
* This builds a Page.
*
- * @param data The data for the page.
+ * @param buffer The buffer for the page.
* @return The parsed page
* @throws IOException if an error occurs
*/
- Page parse(char[] data) throws IOException;
+ Page parse(SitemeshBuffer buffer) throws IOException;
}
View
58 src/java/com/opensymphony/module/sitemesh/SitemeshBuffer.java
@@ -0,0 +1,58 @@
+package com.opensymphony.module.sitemesh;
+
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * A potentially chained sitemesh buffer
+ */
+public interface SitemeshBuffer {
+
+ /**
+ * Get the char array for this buffer. This array may be longer than the length of the content, you must use
+ * getBufferLength() in combination with this method.
+ *
+ * @return The char array for this buffer
+ */
+ char[] getCharArray();
+
+ /**
+ * Get the length of the buffered content.
+ *
+ * @return The length of the buffered content.
+ */
+ int getBufferLength();
+
+ /**
+ * Get the total length of the buffered content, including the length of any chained buffers.
+ *
+ * @return The total length.
+ */
+ int getTotalLength();
+
+ /**
+ * Get the total length of the buffered content, including chained buffers from start to length
+ *
+ * @param start Where to start counting the length from
+ * @param length Where to finish
+ * @return THe total length in the given range
+ */
+ int getTotalLength(int start, int length);
+
+ /**
+ * Write this buffer, and any chained sub buffers in the given range, out to the given writer
+ *
+ * @param start The position to start writing from
+ * @param length The length to write
+ * @param writer The writer to write to
+ * @throws IOException If an error occurred
+ */
+ void writeTo(Writer writer, int start, int length) throws IOException;
+
+ /**
+ * Whether the buffer has fragments or not
+ *
+ * @return True if it has fragments
+ */
+ boolean hasFragments();
+}
View
38 src/java/com/opensymphony/module/sitemesh/SitemeshBufferFragment.java
@@ -0,0 +1,38 @@
+package com.opensymphony.module.sitemesh;
+
+/**
+ * A fragment of a sitemesh buffer
+ */
+public class SitemeshBufferFragment implements Comparable<SitemeshBufferFragment> {
+ private final SitemeshBuffer buffer;
+ private final int position;
+ private final int start;
+ private final int length;
+
+ public SitemeshBufferFragment(SitemeshBuffer buffer, int start, int length, int position) {
+ this.buffer = buffer;
+ this.start = start;
+ this.length = length;
+ this.position = position;
+ }
+
+ public SitemeshBuffer getBuffer() {
+ return buffer;
+ }
+
+ public int getStart() {
+ return start;
+ }
+
+ public int getLength() {
+ return length;
+ }
+
+ public int getPosition() {
+ return position;
+ }
+
+ public int compareTo(SitemeshBufferFragment o) {
+ return o.position - position;
+ }
+}
View
32 src/java/com/opensymphony/module/sitemesh/SitemeshBufferWriter.java
@@ -0,0 +1,32 @@
+package com.opensymphony.module.sitemesh;
+
+import com.opensymphony.module.sitemesh.util.CharArrayWriter;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A char array writer that caches other sitemesh buffers written to it, so that it doesn't have to continually copy
+ * them from buffer to buffer.
+ */
+public class SitemeshBufferWriter extends CharArrayWriter implements SitemeshWriter {
+
+ private final List<SitemeshBufferFragment> fragments = new ArrayList<SitemeshBufferFragment>();
+
+ public SitemeshBufferWriter() {
+ }
+
+ public SitemeshBufferWriter(int initialSize) {
+ super(initialSize);
+ }
+
+ public boolean writeSitemeshBuffer(SitemeshBuffer sitemeshBuffer, int start, int length) throws IOException {
+ fragments.add(new SitemeshBufferFragment(sitemeshBuffer, start, length, count));
+ return false;
+ }
+
+ public SitemeshBuffer getSitemeshBuffer() {
+ return new DefaultSitemeshBuffer(buf, count, fragments);
+ }
+}
View
28 src/java/com/opensymphony/module/sitemesh/SitemeshWriter.java
@@ -0,0 +1,28 @@
+package com.opensymphony.module.sitemesh;
+
+import java.io.IOException;
+
+/**
+ * A sitemesh buffer writer. Provides the ability to defer the writing of a page body until it is finally written to the
+ * stream, so it isn't copied from buffer to buffer
+ */
+public interface SitemeshWriter {
+ /**
+ * Write a sitemesh buffer to the writer. This may not be written immediately, it may be stored and written later,
+ * when this buffer is written out to a writer.
+ *
+ * @param sitemeshBuffer The buffer to write
+ * @param start The place in the buffer to write from
+ * @param length The length of the buffer to write
+ * @return True if the buffer was written immediately, or false if it will be written later
+ * @throws IOException If an IOException occurred
+ */
+ boolean writeSitemeshBuffer(SitemeshBuffer sitemeshBuffer, int start, int length) throws IOException;
+
+ /**
+ * Get the underlying buffer for the writer
+ *
+ * @return The underlying buffer
+ */
+ public SitemeshBuffer getSitemeshBuffer();
+}
View
33 src/java/com/opensymphony/module/sitemesh/filter/Buffer.java
@@ -3,12 +3,10 @@
* distribution in the LICENSE.txt file. */
package com.opensymphony.module.sitemesh.filter;
-import com.opensymphony.module.sitemesh.Page;
-import com.opensymphony.module.sitemesh.PageParser;
+import com.opensymphony.module.sitemesh.*;
import com.opensymphony.module.sitemesh.util.FastByteArrayOutputStream;
import javax.servlet.ServletOutputStream;
-import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.PrintWriter;
@@ -25,7 +23,7 @@
private final String encoding;
private final static TextEncoder TEXT_ENCODER = new TextEncoder();
- private AccessibleCharArrayWriter bufferedWriter;
+ private SitemeshBufferWriter bufferedWriter;
private FastByteArrayOutputStream bufferedStream;
private PrintWriter exposedWriter;
private ServletOutputStream exposedStream;
@@ -35,19 +33,18 @@ public Buffer(PageParser pageParser, String encoding) {
this.encoding = encoding;
}
- public BufferedContent getContents() throws IOException {
+ public SitemeshBuffer getContents() throws IOException {
if (bufferedWriter != null) {
- return new BufferedContent(bufferedWriter.getCharArray(), bufferedWriter.size());
+ return bufferedWriter.getSitemeshBuffer();
} else if (bufferedStream != null) {
- return new BufferedContent(TEXT_ENCODER.encode(bufferedStream.toByteArray(), encoding));
+ return new DefaultSitemeshBuffer(TEXT_ENCODER.encode(bufferedStream.toByteArray(), encoding));
} else {
- return new BufferedContent(new char[0]);
+ return new DefaultSitemeshBuffer(new char[0]);
}
}
public Page parse() throws IOException {
- BufferedContent content = getContents();
- return pageParser.parse(content.getBuffer(), content.getLength());
+ return pageParser.parse(getContents());
}
public PrintWriter getWriter() {
@@ -55,8 +52,8 @@ public PrintWriter getWriter() {
if (bufferedStream != null) {
throw new IllegalStateException("response.getWriter() called after response.getOutputStream()");
}
- bufferedWriter = new AccessibleCharArrayWriter(128);
- exposedWriter = new PrintWriter(bufferedWriter);
+ bufferedWriter = new SitemeshBufferWriter(128);
+ exposedWriter = new SitemeshPrintWriter(bufferedWriter);
}
return exposedWriter;
}
@@ -79,16 +76,4 @@ public void write(int b) {
public boolean isUsingStream() {
return bufferedStream != null;
}
-
- private static class AccessibleCharArrayWriter extends CharArrayWriter {
-
- private AccessibleCharArrayWriter(int initialSize) {
- super(initialSize);
- }
-
- public char[] getCharArray()
- {
- return buf;
- }
- }
}
View
2  src/java/com/opensymphony/module/sitemesh/filter/BufferedContent.java
@@ -1,5 +1,7 @@
package com.opensymphony.module.sitemesh.filter;
+import java.util.TreeMap;
+
public class BufferedContent {
private final char[] buffer;
private final int length;
View
3  src/java/com/opensymphony/module/sitemesh/filter/PageResponseWrapper.java
@@ -5,6 +5,7 @@
import com.opensymphony.module.sitemesh.Page;
import com.opensymphony.module.sitemesh.PageParserSelector;
+import com.opensymphony.module.sitemesh.SitemeshBuffer;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
@@ -185,7 +186,7 @@ public boolean isUsingStream() {
return buffer != null && buffer.isUsingStream();
}
- public BufferedContent getContents() throws IOException {
+ public SitemeshBuffer getContents() throws IOException {
if (aborted || !parseablePage) {
return null;
} else {
View
26 src/java/com/opensymphony/module/sitemesh/filter/RoutablePrintWriter.java
@@ -7,6 +7,10 @@
import java.io.IOException;
import java.io.Writer;
+import com.opensymphony.module.sitemesh.Page;
+import com.opensymphony.module.sitemesh.SitemeshBuffer;
+import com.opensymphony.module.sitemesh.SitemeshWriter;
+
/**
* Provides a PrintWriter that routes through to another PrintWriter, however the destination
* can be changed at any point. The destination can be passed in using a factory, so it will not be created
@@ -15,7 +19,7 @@
* @author Joe Walnes
* @version $Revision: 1.1 $
*/
-public class RoutablePrintWriter extends PrintWriter {
+public class RoutablePrintWriter extends PrintWriter implements SitemeshWriter {
private PrintWriter destination;
private DestinationFactory factory;
@@ -179,4 +183,24 @@ public void close() throws IOException {
}
+ public boolean writeSitemeshBuffer(SitemeshBuffer sitemeshBuffer, int start, int length) throws IOException
+ {
+ PrintWriter destination = getDestination();
+ if (destination instanceof SitemeshWriter) {
+ return ((SitemeshWriter) destination).writeSitemeshBuffer(sitemeshBuffer, start, length);
+ } else {
+ sitemeshBuffer.writeTo(destination, start, length);
+ return true;
+ }
+ }
+
+ public SitemeshBuffer getSitemeshBuffer()
+ {
+ PrintWriter destination = getDestination();
+ if (destination instanceof SitemeshWriter) {
+ return ((SitemeshWriter) destination).getSitemeshBuffer();
+ } else {
+ throw new IllegalStateException("Print writer is not a sitemesh buffer");
+ }
+ }
}
View
29 src/java/com/opensymphony/module/sitemesh/filter/SitemeshPrintWriter.java
@@ -0,0 +1,29 @@
+package com.opensymphony.module.sitemesh.filter;
+
+import com.opensymphony.module.sitemesh.SitemeshBufferWriter;
+import com.opensymphony.module.sitemesh.SitemeshBuffer;
+import com.opensymphony.module.sitemesh.SitemeshWriter;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * A sitemesh print writer
+ */
+public class SitemeshPrintWriter extends PrintWriter implements SitemeshWriter {
+
+ private final SitemeshWriter sitemeshWriter;
+
+ public SitemeshPrintWriter(SitemeshBufferWriter sitemeshWriter) {
+ super(sitemeshWriter);
+ this.sitemeshWriter = sitemeshWriter;
+ }
+
+ public boolean writeSitemeshBuffer(SitemeshBuffer sitemeshBuffer, int start, int length) throws IOException {
+ return sitemeshWriter.writeSitemeshBuffer(sitemeshBuffer, start, length);
+ }
+
+ public SitemeshBuffer getSitemeshBuffer() {
+ return sitemeshWriter.getSitemeshBuffer();
+ }
+}
View
21 src/java/com/opensymphony/module/sitemesh/multipass/MultipassReplacementPageParser.java
@@ -2,6 +2,7 @@
import com.opensymphony.module.sitemesh.PageParser;
import com.opensymphony.module.sitemesh.Page;
+import com.opensymphony.module.sitemesh.SitemeshBuffer;
import com.opensymphony.module.sitemesh.html.util.CharArray;
import com.opensymphony.module.sitemesh.html.HTMLProcessor;
import com.opensymphony.module.sitemesh.html.BasicRule;
@@ -19,7 +20,23 @@ public MultipassReplacementPageParser(Page page, HttpServletResponse response) {
this.response = response;
}
- public Page parse(char[] data, int length) throws IOException
+ public Page parse(SitemeshBuffer buffer) throws IOException {
+ char[] data;
+ int length;
+ if (buffer.hasFragments()) {
+ // Write the buffer into a char array
+ com.opensymphony.module.sitemesh.util.CharArrayWriter writer = new com.opensymphony.module.sitemesh.util.CharArrayWriter(buffer.getTotalLength());
+ buffer.writeTo(writer, 0, buffer.getBufferLength());
+ data = writer.toCharArray();
+ length = data.length;
+ } else {
+ data = buffer.getCharArray();
+ length = buffer.getBufferLength();
+ }
+ return parse(data, length);
+ }
+
+ private Page parse(char[] data, int length) throws IOException
{
if (data.length > length) {
// todo fix this parser so that it doesn't need to compact the array
@@ -30,7 +47,7 @@ public Page parse(char[] data, int length) throws IOException
return parse(data);
}
- public Page parse(char[] data) throws IOException {
+ private Page parse(char[] data) throws IOException {
final CharArray result = new CharArray(4096);
HTMLProcessor processor = new HTMLProcessor(data, result);
processor.addRule(new BasicRule("sitemesh:multipass") {
View
20 src/java/com/opensymphony/module/sitemesh/parser/FastPageParser.java
@@ -11,8 +11,10 @@
import com.opensymphony.module.sitemesh.Page;
import com.opensymphony.module.sitemesh.PageParser;
+import com.opensymphony.module.sitemesh.SitemeshBuffer;
import com.opensymphony.module.sitemesh.html.util.CharArray;
import com.opensymphony.module.sitemesh.util.CharArrayReader;
+import com.opensymphony.module.sitemesh.util.CharArrayWriter;
import java.io.IOException;
import java.io.Reader;
@@ -83,13 +85,21 @@
private static final int SLASH_BODY_HASH = 46434897; // "/body".hashCode();
private static final int CONTENT_HASH = 951530617; // "content".hashCode();
- public Page parse(char[] data) throws IOException
+ public Page parse(SitemeshBuffer buffer) throws IOException
{
- return parse(data, data.length);
- }
+ char[] data;
+ int length;
+ if (buffer.hasFragments()) {
+ // Write the buffer into a char array
+ CharArrayWriter writer = new CharArrayWriter(buffer.getTotalLength());
+ buffer.writeTo(writer, 0, buffer.getBufferLength());
+ data = writer.toCharArray();
+ length = data.length;
+ } else {
+ data = buffer.getCharArray();
+ length = buffer.getBufferLength();
+ }
- public Page parse(char[] data, int length) throws IOException
- {
FastPage page = internalParse(new CharArrayReader(data, 0, length));
page.setVerbatimPage(data, length);
return page;
View
23 src/java/com/opensymphony/module/sitemesh/parser/HTMLPageParser.java
@@ -2,10 +2,10 @@
import com.opensymphony.module.sitemesh.Page;
import com.opensymphony.module.sitemesh.PageParser;
+import com.opensymphony.module.sitemesh.SitemeshBuffer;
import com.opensymphony.module.sitemesh.html.HTMLProcessor;
import com.opensymphony.module.sitemesh.html.State;
import com.opensymphony.module.sitemesh.html.StateTransitionRule;
-import com.opensymphony.module.sitemesh.html.tokenizer.TagTokenizer;
import com.opensymphony.module.sitemesh.html.util.CharArray;
import com.opensymphony.module.sitemesh.html.rules.BodyTagRule;
import com.opensymphony.module.sitemesh.html.rules.ContentBlockExtractingRule;
@@ -18,7 +18,6 @@
import com.opensymphony.module.sitemesh.html.rules.TitleExtractingRule;
import com.opensymphony.module.sitemesh.html.rules.PageBuilder;
-import java.io.CharArrayWriter;
import java.io.IOException;
/**
@@ -34,7 +33,23 @@
*/
public class HTMLPageParser implements PageParser {
- public Page parse(char[] data, int length) throws IOException
+ public Page parse(SitemeshBuffer buffer) throws IOException {
+ char[] data;
+ int length;
+ if (buffer.hasFragments()) {
+ // Write the buffer into a char array
+ com.opensymphony.module.sitemesh.util.CharArrayWriter writer = new com.opensymphony.module.sitemesh.util.CharArrayWriter(buffer.getTotalLength());
+ buffer.writeTo(writer, 0, buffer.getBufferLength());
+ data = writer.toCharArray();
+ length = data.length;
+ } else {
+ data = buffer.getCharArray();
+ length = buffer.getBufferLength();
+ }
+ return parse(data, length);
+ }
+
+ private Page parse(char[] data, int length) throws IOException
{
if (data.length > length) {
// todo fix this parser so that it doesn't need to compact the array
@@ -45,7 +60,7 @@ public Page parse(char[] data, int length) throws IOException
return parse(data);
}
- public Page parse(char[] data) throws IOException {
+ private Page parse(char[] data) throws IOException {
CharArray head = new CharArray(64);
CharArray body = new CharArray(4096);
TokenizedHTMLPage page = new TokenizedHTMLPage(data, body, head);
View
12 src/java/com/opensymphony/module/sitemesh/parser/SuperFastHtmlPage.java
@@ -1,6 +1,7 @@
package com.opensymphony.module.sitemesh.parser;
import com.opensymphony.module.sitemesh.HTMLPage;
+import com.opensymphony.module.sitemesh.SitemeshBuffer;
import java.io.IOException;
import java.io.Writer;
@@ -10,15 +11,14 @@
{
private final char[] head;
- public SuperFastHtmlPage(char[] pageData, int pageLength, int bodyStart, int bodyLength, Map<String, String> bodyProperties)
+ public SuperFastHtmlPage(SitemeshBuffer sitemeshBuffer, int bodyStart, int bodyLength, Map<String, String> bodyProperties)
{
- this(pageData, pageLength, bodyStart, bodyLength, bodyProperties, null, null, null, null);
+ this(sitemeshBuffer, bodyStart, bodyLength, bodyProperties, null, null, null, null);
}
/**
*
- * @param pageData The data for the page
- * @param pageLength The length of the page
+ * @param sitemeshBuffer The buffer for the page
* @param bodyStart The start of the body
* @param bodyLength The length of the body
* @param bodyProperties The properties of the body
@@ -27,10 +27,10 @@ public SuperFastHtmlPage(char[] pageData, int pageLength, int bodyStart, int bod
* @param metaAttributes The meta attributes found in the head section
* @param pageProperties The page properties extracted from the head section
*/
- public SuperFastHtmlPage(char[] pageData, int pageLength, int bodyStart, int bodyLength, Map<String, String> bodyProperties,
+ public SuperFastHtmlPage(SitemeshBuffer sitemeshBuffer, int bodyStart, int bodyLength, Map<String, String> bodyProperties,
char[] head, String title, Map<String, String> metaAttributes, Map<String, String> pageProperties)
{
- super(pageData, pageLength, bodyStart, bodyLength);
+ super(sitemeshBuffer, bodyStart, bodyLength);
this.head = head;
if (title == null)
{
View
19 src/java/com/opensymphony/module/sitemesh/parser/SuperFastPage.java
@@ -5,23 +5,26 @@
import java.io.OutputStreamWriter;
import java.io.Writer;
+import com.opensymphony.module.sitemesh.SitemeshBuffer;
+import com.opensymphony.module.sitemesh.SitemeshWriter;
+
public class SuperFastPage extends AbstractPage {
+ private final SitemeshBuffer sitemeshBuffer;
private final int bodyStart;
private final int bodyLength;
- private final int pageLength;
- public SuperFastPage(char[] pageData, int pageLength, int bodyStart, int bodyLength) {
- this.pageLength = pageLength;
+ public SuperFastPage(SitemeshBuffer sitemeshBuffer, int bodyStart, int bodyLength) {
+ this.sitemeshBuffer = sitemeshBuffer;
this.bodyStart = bodyStart;
this.bodyLength = bodyLength;
- this.pageData = pageData;
+ this.pageData = sitemeshBuffer.getCharArray();
}
@Override
public void writePage(Writer out) throws IOException {
- out.write(pageData, 0, pageLength);
+ sitemeshBuffer.writeTo(out, 0, sitemeshBuffer.getBufferLength());
}
@Override
@@ -42,7 +45,11 @@ public int getContentLength() {
@Override
public void writeBody(Writer out) throws IOException {
- out.write(pageData, bodyStart, bodyLength);
+ if (out instanceof SitemeshWriter) {
+ ((SitemeshWriter) out).writeSitemeshBuffer(sitemeshBuffer, bodyStart, bodyLength);
+ } else {
+ sitemeshBuffer.writeTo(out, bodyStart, bodyLength);
+ }
}
protected static class CountingOutputStream extends OutputStream {
View
24 src/java/com/opensymphony/module/sitemesh/parser/SuperFastSimplePageParser.java
@@ -7,6 +7,7 @@
import com.opensymphony.module.sitemesh.Page;
import com.opensymphony.module.sitemesh.PageParser;
+import com.opensymphony.module.sitemesh.SitemeshBuffer;
/**
* Super fast page parser. It uses a single buffer, and never copies anything, apart from the title, meta attributes
@@ -19,13 +20,10 @@
*/
public class SuperFastSimplePageParser implements PageParser
{
- public Page parse(final char[] data) throws IOException
- {
- return parse(data, data.length);
- }
-
- public Page parse(final char[] data, final int length) throws IOException
+ public Page parse(SitemeshBuffer buffer) throws IOException
{
+ char[] data = buffer.getCharArray();
+ int length = buffer.getBufferLength();
int position = 0;
while (position < data.length)
{
@@ -39,21 +37,23 @@ public Page parse(final char[] data, final int length) throws IOException
if (compareLowerCase(data, length, position, "html"))
{
// It's an HTML page, handle HTML pages
- return parseHtmlPage(data, length, position);
+ return parseHtmlPage(buffer, position);
}
else
{
// The whole thing is the body.
- return new SuperFastHtmlPage(data, length, 0, length, null);
+ return new SuperFastHtmlPage(buffer, 0, length, null);
}
}
}
// If we're here, we mustn't have found a tag
- return new SuperFastHtmlPage(data, length, 0, length, null);
+ return new SuperFastHtmlPage(buffer, 0, length, null);
}
- private Page parseHtmlPage(final char[] data, final int length, int position)
+ private Page parseHtmlPage(SitemeshBuffer buffer, int position)
{
+ char[] data = buffer.getCharArray();
+ int length = buffer.getBufferLength();
int bodyStart = -1;
int bodyLength = -1;
int headStart = -1;
@@ -163,11 +163,11 @@ else if (compareLowerCase(data, headEnd, i + 1, "content"))
}
}
- return new SuperFastHtmlPage(data, length, bodyStart, bodyLength, bodyProperties, head.toCharArray(), title, metaAttributes, pageProperties);
+ return new SuperFastHtmlPage(buffer, bodyStart, bodyLength, bodyProperties, head.toCharArray(), title, metaAttributes, pageProperties);
}
else
{
- return new SuperFastHtmlPage(data, length, bodyStart, bodyLength, bodyProperties);
+ return new SuperFastHtmlPage(buffer, bodyStart, bodyLength, bodyProperties);
}
}
View
13 src/java/com/opensymphony/module/sitemesh/taglib/page/ApplyDecoratorTag.java
@@ -151,9 +151,12 @@ public int doEndTag() throws JspException {
if (page == null) {
// inline content
if (bodyContent != null) {
- pageObj = parser.parse(bodyContent.getString().toCharArray());
+ // Would be nice if we could do our own buffering...
+ SitemeshBufferWriter sitemeshWriter = new SitemeshBufferWriter();
+ bodyContent.writeOut(sitemeshWriter);
+ pageObj = parser.parse(sitemeshWriter.getSitemeshBuffer());
} else {
- pageObj = parser.parse(new char[]{});
+ pageObj = parser.parse(new DefaultSitemeshBuffer(new char[] {}));
}
}
else if (page.startsWith("http://") || page.startsWith("https://")) {
@@ -164,15 +167,15 @@ else if (page.startsWith("http://") || page.startsWith("https://")) {
BufferedReader in = new BufferedReader(
new InputStreamReader(urlConn.getInputStream()));
- StringBuffer sbuf = new StringBuffer();
+ SitemeshBufferWriter sitemeshWriter = new SitemeshBufferWriter();
char[] buf = new char[1000];
for (; ;) {
int moved = in.read(buf);
if (moved < 0) break;
- sbuf.append(buf, 0, moved);
+ sitemeshWriter.write(buf, 0, moved);
}
in.close();
- pageObj = parser.parse(sbuf.toString().toCharArray());
+ pageObj = parser.parse(sitemeshWriter.getSitemeshBuffer());
}
catch (MalformedURLException e) {
throw new JspException(e);
View
3  src/java/com/opensymphony/sitemesh/ContentProcessor.java
@@ -1,5 +1,6 @@
package com.opensymphony.sitemesh;
+import com.opensymphony.module.sitemesh.SitemeshBuffer;
import com.opensymphony.module.sitemesh.filter.BufferedContent;
import java.io.IOException;
@@ -13,5 +14,5 @@
boolean handles(SiteMeshContext context);
boolean handles(String contentType);
- Content build(BufferedContent content, SiteMeshContext context) throws IOException;
+ Content build(SitemeshBuffer buffer, SiteMeshContext context) throws IOException;
}
View
9 src/java/com/opensymphony/sitemesh/compatability/PageParser2ContentProcessor.java
@@ -1,9 +1,6 @@
package com.opensymphony.sitemesh.compatability;
-import com.opensymphony.module.sitemesh.Factory;
-import com.opensymphony.module.sitemesh.HTMLPage;
-import com.opensymphony.module.sitemesh.Page;
-import com.opensymphony.module.sitemesh.PageParser;
+import com.opensymphony.module.sitemesh.*;
import com.opensymphony.module.sitemesh.filter.BufferedContent;
import com.opensymphony.module.sitemesh.filter.HttpContentType;
import com.opensymphony.sitemesh.Content;
@@ -46,10 +43,10 @@ public boolean handles(String contentType) {
return factory.shouldParsePage(contentType);
}
- public Content build(BufferedContent content, SiteMeshContext context) throws IOException {
+ public Content build(SitemeshBuffer buffer, SiteMeshContext context) throws IOException {
HttpContentType httpContentType = new HttpContentType(context.getContentType());
PageParser pageParser = factory.getPageParser(httpContentType.getType());
- Page page = pageParser.parse(content.getBuffer(), content.getLength());
+ Page page = pageParser.parse(buffer);
return new HTMLPage2Content((HTMLPage) page);
}
}
View
3  src/java/com/opensymphony/sitemesh/webapp/ContentBufferingResponse.java
@@ -1,5 +1,6 @@
package com.opensymphony.sitemesh.webapp;
+import com.opensymphony.module.sitemesh.SitemeshBuffer;
import com.opensymphony.module.sitemesh.filter.BufferedContent;
import com.opensymphony.module.sitemesh.filter.PageResponseWrapper;
import com.opensymphony.module.sitemesh.PageParserSelector;
@@ -50,7 +51,7 @@ public boolean isUsingStream() {
}
public Content getContent() throws IOException {
- BufferedContent content = pageResponseWrapper.getContents();
+ SitemeshBuffer content = pageResponseWrapper.getContents();
if (content != null) {
return contentProcessor.build(content, webAppContext);
} else {
View
61 src/test/com/opensymphony/module/sitemesh/chaining/ChainingBufferTest.java
@@ -0,0 +1,61 @@
+package com.opensymphony.module.sitemesh.chaining;
+
+import java.io.CharArrayWriter;
+import java.util.Arrays;
+
+import com.opensymphony.module.sitemesh.DefaultSitemeshBuffer;
+import com.opensymphony.module.sitemesh.SitemeshBuffer;
+import com.opensymphony.module.sitemesh.SitemeshBufferFragment;
+
+import junit.framework.TestCase;
+
+/**
+ */
+public class ChainingBufferTest extends TestCase
+{
+ public void testSimpleChain() throws Exception
+ {
+ SitemeshBuffer buffer = newSitemeshBuffer("aaaa", newBufferFragment("bb", 2));
+ assertEquals("aabbaa", getContent(buffer));
+ }
+
+ public void testBefore() throws Exception
+ {
+ SitemeshBuffer buffer = newSitemeshBuffer("aaaa", newBufferFragment("bb", 2));
+ assertEquals("a", getContent(buffer, 0, 1));
+ assertEquals("aa", getContent(buffer, 0, 2));
+ }
+
+ public void testAfter() throws Exception
+ {
+ SitemeshBuffer buffer = newSitemeshBuffer("aaaa", newBufferFragment("bb", 2));
+ assertEquals("bbaa", getContent(buffer, 2, 2));
+ assertEquals("a", getContent(buffer, 3, 1));
+ }
+
+ public void
+
+ private String getContent(SitemeshBuffer buffer) throws Exception
+ {
+ CharArrayWriter writer = new CharArrayWriter();
+ buffer.writeTo(writer, 0, buffer.getBufferLength());
+ return writer.toString();
+ }
+
+ private String getContent(SitemeshBuffer buffer, int start, int length) throws Exception
+ {
+ CharArrayWriter writer = new CharArrayWriter();
+ buffer.writeTo(writer, start, length);
+ return writer.toString();
+ }
+
+ private SitemeshBuffer newSitemeshBuffer(String content, SitemeshBufferFragment... fragments)
+ {
+ return new DefaultSitemeshBuffer(content.toCharArray(), content.length(), Arrays.asList(fragments));
+ }
+
+ private SitemeshBufferFragment newBufferFragment(String content, int position)
+ {
+ return new SitemeshBufferFragment(newSitemeshBuffer(content), 0, content.length(), position);
+ }
+}
View
3  src/test/com/opensymphony/module/sitemesh/multipass/DivExtractingPageParserTest.java
@@ -1,5 +1,6 @@
package com.opensymphony.module.sitemesh.multipass;
+import com.opensymphony.module.sitemesh.DefaultSitemeshBuffer;
import com.opensymphony.module.sitemesh.Page;
import com.opensymphony.module.sitemesh.PageParser;
import com.opensymphony.module.sitemesh.multipass.DivExtractingPageParser;
@@ -25,7 +26,7 @@ public void testReplacesTopLevelDivsWithPlaceHolders() throws IOException {
"</html>";
PageParser parser = new DivExtractingPageParser();
- Page page = parser.parse(input.toCharArray());
+ Page page = parser.parse(new DefaultSitemeshBuffer(input.toCharArray()));
String expectedBody = "" +
" <sitemesh:multipass id=\"div.one\"/>\n" +
View
5 src/test/com/opensymphony/module/sitemesh/parser/HTMLPageParserTest.java
@@ -1,5 +1,6 @@
package com.opensymphony.module.sitemesh.parser;
+import com.opensymphony.module.sitemesh.DefaultSitemeshBuffer;
import com.opensymphony.module.sitemesh.HTMLPage;
import com.opensymphony.module.sitemesh.Page;
import com.opensymphony.module.sitemesh.PageParser;
@@ -84,7 +85,7 @@ protected void setUp() throws Exception {
this.blocks = readBlocks(new FileReader(file));
// create PageParser and parse input block into HTMLPage object.
String input = (String) blocks.get("INPUT");
- this.page = parser.parse(input.toCharArray());
+ this.page = parser.parse(new DefaultSitemeshBuffer(input.toCharArray()));
}
public void testTitle() throws Exception {
@@ -146,7 +147,7 @@ public void testContentSanity() throws Exception {
final char[] chars = input.toCharArray();
final char[] bigChars = new char[chars.length * 2 + 10]; // make it bigger
System.arraycopy(chars, 0, bigChars, 0, chars.length);
- Page bigPage = parser.parse(bigChars, chars.length);
+ Page bigPage = parser.parse(new DefaultSitemeshBuffer(bigChars, chars.length));
assertEquals(bigPage.getPage(), page.getPage());
assertEquals(bigPage.getContentLength(), page.getContentLength());
View
9 src/test/com/opensymphony/module/sitemesh/parser/ParserPerformanceComparison.java
@@ -1,5 +1,6 @@
package com.opensymphony.module.sitemesh.parser;
+import com.opensymphony.module.sitemesh.DefaultSitemeshBuffer;
import com.opensymphony.module.sitemesh.Page;
import com.opensymphony.module.sitemesh.PageParser;
@@ -18,7 +19,7 @@
{
private static final String HTML_FILE = "sitemesh-performance-test.html";
- private static final String HTML_URL = "http://jira.atlassian.com/browse/JRA-1330";
+ private static final String HTML_URL = "https://jira.atlassian.com/browse/JRA-1330";
private static final int PARSE_COUNT = 1000;
public static void main(String... args) throws Exception
@@ -82,9 +83,9 @@ public static void main(String... args) throws Exception
System.gc();
double normalTime = runPerformanceTest("Normal #3", page, normal, PARSE_COUNT);
System.gc();
- double fastTime = runPerformanceTest("Fast #2", page, fast, PARSE_COUNT);
+ double fastTime = runPerformanceTest("Fast #3", page, fast, PARSE_COUNT);
System.gc();
- double superfastTime = runPerformanceTest("Super Fast #2", page, superfast, PARSE_COUNT);
+ double superfastTime = runPerformanceTest("Super Fast #3", page, superfast, PARSE_COUNT);
System.out.println("\nPerformance comparison %\n========================");
System.out.println(String.format("%-10s%12s%12s%12s", "", "Normal", "Fast", "Super Fast"));
@@ -99,7 +100,7 @@ public static long runPerformanceTest(String name, char[] data, PageParser parse
long start = System.currentTimeMillis();
for (int i = 0; i < times; i++)
{
- Page page = parser.parse(data);
+ Page page = parser.parse(new DefaultSitemeshBuffer(data));
page.writeBody(writer);
}
long finish = System.currentTimeMillis();
Please sign in to comment.
Something went wrong with that request. Please try again.