1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.maven.doxia.module.markdown;
20
21 import java.io.IOException;
22 import java.io.Writer;
23 import java.util.Collections;
24 import java.util.LinkedList;
25 import java.util.Queue;
26
27 public class BufferingStackWriter extends Writer {
28
29 /**
30 * A buffer stack that holds the output when the current context requires buffering.
31 * The content of this buffer is supposed to be already escaped.
32 */
33 private final Queue<StringBuilder> bufferStack;
34
35 private final Writer out;
36
37 public BufferingStackWriter(Writer out) {
38 this.out = out;
39 this.bufferStack = Collections.asLifoQueue(new LinkedList<>());
40 }
41
42 @Override
43 public void write(char[] cbuf, int off, int len) throws IOException {
44 if (bufferStack.isEmpty()) {
45 out.write(cbuf, off, len);
46 } else {
47 bufferStack.element().append(cbuf, off, len);
48 }
49 }
50
51 /**
52 * Adds another buffer to the stack. The content of the current buffer is not affected, but the new content will
53 * be written to the new buffer until it is polled.
54 */
55 public void addBuffer() {
56 StringBuilder sb = new StringBuilder();
57 bufferStack.add(sb);
58 }
59
60 /**
61 * Retrieves the content of the current buffer without removing it from the stack.
62 * Also writing to the StringBuffer returned by this method will affect the content of the current buffer.
63 */
64 public StringBuilder getCurrentBuffer() {
65 return bufferStack.element();
66 }
67
68 /**
69 * Retrieves the content of the current buffer without removing it from the stack.
70 * In contrast to {@link #getCurrentBuffer()} the current buffer is cleared.
71 */
72 public String getAndClearCurrentBuffer() {
73 String buffer = bufferStack.remove().toString();
74 addBuffer();
75 return buffer;
76 }
77
78 /**
79 * Remove the current buffer from the stack. The content of the current buffer is discarded. The previous buffer in the stack becomes the current buffer.
80 */
81 public void removeBuffer() {
82 bufferStack.remove();
83 }
84
85 @Override
86 public void flush() throws IOException {
87 // do nothing when there are buffers in the stack
88 if (bufferStack.isEmpty()) {
89 out.flush();
90 }
91 }
92
93 @Override
94 public void close() throws IOException {
95 if (!bufferStack.isEmpty()) {
96 throw new IllegalStateException(
97 "Cannot close BufferingStackWriter while there are still buffers in the stack.");
98 }
99 out.close();
100 }
101 }