1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.esigate.extension.parallelesi;
16
17 import java.io.IOException;
18 import java.io.Writer;
19 import java.util.Map;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Executor;
22 import java.util.concurrent.Future;
23 import java.util.concurrent.TimeUnit;
24 import java.util.concurrent.TimeoutException;
25 import java.util.regex.Pattern;
26
27 import org.apache.http.HttpStatus;
28 import org.esigate.HttpErrorPage;
29 import org.esigate.Renderer;
30 import org.esigate.impl.DriverRequest;
31 import org.esigate.parser.future.FutureAppendable;
32 import org.esigate.parser.future.FutureAppendableAdapter;
33 import org.esigate.parser.future.FutureParser;
34 import org.esigate.parser.future.StringBuilderFutureAppendable;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52 public class EsiRenderer implements Renderer, FutureAppendable {
53
54 private static final Logger LOG = LoggerFactory.getLogger(EsiRenderer.class);
55
56
57
58 public static final String DATA_EXECUTOR = "executor";
59
60 private static final Pattern PATTERN = Pattern
61 .compile("(<esi:\\w+((\\s+\\w+(\\s*=\\s*(?:\".*?\"|'.*?'|[^'\">\\s]+))?)+\\s*|\\s*)/?>)|(</esi:[^>]*>)");
62 private static final Pattern PATTERN_COMMENTS = Pattern.compile("(<!--esi)|(-->)");
63
64 private final FutureParser parser = new FutureParser(PATTERN, IncludeElement.TYPE, CommentElement.TYPE,
65 RemoveElement.TYPE, VarsElement.TYPE, ChooseElement.TYPE, WhenElement.TYPE, OtherwiseElement.TYPE,
66 TryElement.TYPE, AttemptElement.TYPE, ExceptElement.TYPE, InlineElement.TYPE, ReplaceElement.TYPE,
67 FragmentElement.TYPE);
68
69 private final FutureParser parserComments = new FutureParser(PATTERN_COMMENTS, Comment.TYPE);
70
71 private Map<String, CharSequence> fragmentsToReplace;
72
73 private final String page;
74
75 private final String name;
76
77 private boolean write = true;
78
79 private boolean found = false;
80
81 private FutureAppendableAdapter futureOut;
82
83 private Executor executor;
84
85 public String getName() {
86 return name;
87 }
88
89 public void setWrite(boolean write) {
90 this.write = write;
91 }
92
93
94
95
96
97
98
99 public EsiRenderer(Executor executor) {
100 this.page = null;
101 this.name = null;
102 this.executor = executor;
103 }
104
105
106
107
108
109
110
111
112
113
114
115 public EsiRenderer(String page, String name, Executor executor) {
116 this.page = page;
117 this.name = name;
118 this.write = false;
119 this.executor = executor;
120 }
121
122 public Map<String, CharSequence> getFragmentsToReplace() {
123 return fragmentsToReplace;
124 }
125
126 public void setFragmentsToReplace(Map<String, CharSequence> fragmentsToReplace) {
127 this.fragmentsToReplace = fragmentsToReplace;
128 }
129
130 @Override
131 public void render(DriverRequest originalRequest, String content, Writer out) throws IOException, HttpErrorPage {
132 if (name != null) {
133 LOG.debug("Rendering fragment {} in page {}", name, page);
134 }
135 this.futureOut = new FutureAppendableAdapter(out);
136 if (content == null) {
137 return;
138 }
139
140 try {
141
142 StringBuilderFutureAppendable contentWithoutComments = new StringBuilderFutureAppendable();
143 parserComments.setHttpRequest(originalRequest);
144 parserComments.setData(DATA_EXECUTOR, this.executor);
145 parserComments.parse(content, contentWithoutComments);
146 CharSequence contentWithoutCommentsResult;
147
148 contentWithoutCommentsResult = contentWithoutComments.get();
149
150
151 parser.setHttpRequest(originalRequest);
152 parser.setData(DATA_EXECUTOR, this.executor);
153 parser.parse(contentWithoutCommentsResult, this);
154
155 if (name != null && !this.found) {
156 throw new HttpErrorPage(HttpStatus.SC_BAD_GATEWAY, "Fragment " + name + " not found", "Fragment "
157 + name + " not found");
158 }
159
160 this.futureOut.performAppends();
161
162 } catch (ExecutionException e) {
163 throw new IOException(e);
164 }
165 }
166
167 @Override
168 public FutureAppendable enqueueAppend(Future<CharSequence> csq) {
169 if (this.write) {
170 this.futureOut.enqueueAppend(csq);
171 }
172 return this;
173 }
174
175 public boolean isWrite() {
176 return this.write;
177 }
178
179 public void setFound(boolean found) {
180 this.found = found;
181
182 }
183
184 @Override
185 public FutureAppendable performAppends() throws IOException, HttpErrorPage {
186 return this.futureOut.performAppends();
187 }
188
189 @Override
190 public boolean hasPending() {
191 return this.futureOut.hasPending();
192 }
193
194 @Override
195 public FutureAppendable performAppends(int timeout, TimeUnit unit) throws IOException, HttpErrorPage,
196 TimeoutException {
197 return this.futureOut.performAppends(timeout, unit);
198 }
199
200 }