##### Coverage Report - org.webmacro.engine.Block

Classes in this File | Line Coverage | Branch Coverage | Complexity
Block |
81% | 120/147
62% | 18/29
| 2.5294117647058822;2.529
Block$BlockIterator |
0% | 0/19
0% | 0/6
| 2.5294117647058822;2.529

1 |  |
     /*
2 |  |
      * Copyright (C) 1998-2000 Semiotek Inc.  All Rights Reserved.
3 |  |
      *
4 |  |
      * Redistribution and use in source and binary forms, with or without
5 |  |
      * modification, are permitted under the terms of either of the following
6 |  |
      * Open Source licenses:
7 |  |
      *
8 |  |
      * The GNU General Public License, version 2, or any later version, as
9 |  |
      * published by the Free Software Foundation
10 |  |
      * (http://www.fsf.org/copyleft/gpl.html);
11 |  |
      *
12 |  |
      *  or
13 |  |
      *
14 |  |
      * The Semiotek Public License (http://webmacro.org/LICENSE.)
15 |  |
      *
16 |  |
      * This software is provided "as is", with NO WARRANTY, not even the
17 |  |
      * implied warranties of fitness to purpose, or merchantability. You
18 |  |
      * assume all risks and liabilities associated with its use.
19 |  |
      *
20 |  |
      * See www.webmacro.org for more information on the WebMacro project.
21 |  |
      */
22 |  |
23 |  |
24 |  |
     package org.webmacro.engine;
25 |  |
26 |  |
     import java.io.IOException;
27 |  |
     import java.util.List;
28 |  |
29 |  |
     import org.slf4j.Logger;
30 |  |
     import org.slf4j.LoggerFactory;
31 |  |
     import org.webmacro.Context;
32 |  |
     import org.webmacro.FastWriter;
33 |  |
     import org.webmacro.Macro;
34 |  |
     import org.webmacro.PropertyException;
35 |  |
     import org.webmacro.TemplateVisitor;
36 |  |
     import org.webmacro.Visitable;
37 |  |
     import org.webmacro.WebMacroRuntimeException;
38 |  |
     import org.webmacro.util.Encoder;
39 |  |
40 |  |
     /**
41 |  |
      * A Block is essentially a Macro[] that knows how to write itself
42 |  |
      * out as a String.
43 |  |
      */
44 |  |
     final public class Block implements Macro, Visitable
45 |  |
     {
46 |  |
47 | 2 |
         static Logger _log =  LoggerFactory.getLogger(Block.class);
48 |  |
49 |  |
         private final String[] _strings;
50 |  |
         private final Macro[] _macros;
51 |  |
         private final int[] _lineNos, _colNos;
52 |  |
53 |  |
         private final Encoder.Block _block;
54 |  |
         private final int _length;
55 |  |
         private final int _remainder;
56 |  |
         private String _name;
57 |  |
58 |  |
         /**
59 |  |
          * A Block must be constructed from a BlockBuilder. The format
60 |  |
          * of a block is:  String (Macro String)*
61 |  |
          * and the constructor expects to receive two arrays matching
62 |  |
          * this structure. The output of the block will be the first
63 |  |
          * string, followed by the first macro, followed by the second
64 |  |
          * string, followed by the second macro, etc., and terminated
65 |  |
          * by the final string.
66 |  |
          */
67 |  |
         protected Block (String name, String[] strings, Macro[] macros,
68 |  |
                          int lineNos[], int colNos[])
69 | 1484 |
         {
70 | 1484 |
             _name = name;
71 | 1484 |
             _strings = strings;
72 | 1484 |
             _macros = macros;
73 | 1484 |
             _lineNos = lineNos;
74 | 1484 |
             _colNos = colNos;
75 |  |
76 | 1484 |
             _length = _macros.length;
77 | 1484 |
             _remainder = 10 - _length % 10;
78 |  |
79 |  |
             // we'll use this to encode our strings for output to the user
80 | 1484 |
             _block = new Encoder.Block(_strings);
81 | 1484 |
         }
82 |  |
83 |  |
         /**
84 |  |
          * Interpret the directive and write it out, using the values in
85 |  |
          * the supplied context as appropriate.
86 |  |
          *
87 |  |
          * @exception PropertyException if required data was missing from context
88 |  |
          * @exception IOException if we could not successfully write to out
89 |  |
          */
90 |  |
         final public void write (final FastWriter out, final Context context)
91 |  |
                 throws PropertyException, IOException
92 |  |
         {
93 | 56066 |
             final byte[][] bcontent = out.getEncoder().encode(_block);
94 |  |
             byte[] b;
95 | 56066 |
             Context.TemplateEvaluationContext teC = context.getTemplateEvaluationContext();
96 | 56066 |
             String oldName = teC._templateName;
97 |  |
98 | 56066 |
             teC._templateName = _name;
99 |  |
             //
100 |  |
             // The _remainder is 10 minus the number of bytes left.
101 |  |
             // If we need to write out 3 bytes remainder will be 7,
102 |  |
             // so control starts at case 7 and falls through 8 and 9,
103 |  |
             // so 3 bytes are written.
104 |  |
             //
105 | 56066 |
             int i = 0;
106 | 56066 |
             switch (_remainder)
107 |  |
             {
108 |  |
                 case 1:
109 | 80 |
                     b = bcontent[i];
110 | 80 |
                     out.write(b, 0, b.length);
111 | 80 |
                     teC._lineNo = this.getLineNo(i);
112 | 80 |
                     teC._columnNo = this.getColNo(i);
113 | 80 |
                     _macros[i++].write(out, context);
114 |  |
                 case 2:
115 | 170 |
                     b = bcontent[i];
116 | 170 |
                     out.write(b, 0, b.length);
117 | 170 |
                     teC._lineNo = this.getLineNo(i);
118 | 170 |
                     teC._columnNo = this.getColNo(i);
119 | 170 |
                     _macros[i++].write(out, context);
120 |  |
                 case 3:
121 | 280 |
                     b = bcontent[i];
122 | 280 |
                     out.write(b, 0, b.length);
123 | 280 |
                     teC._lineNo = this.getLineNo(i);
124 | 280 |
                     teC._columnNo = this.getColNo(i);
125 | 280 |
                     _macros[i++].write(out, context);
126 |  |
                 case 4:
127 | 1716 |
                     b = bcontent[i];
128 | 1716 |
                     out.write(b, 0, b.length);
129 | 1716 |
                     teC._lineNo = this.getLineNo(i);
130 | 1716 |
                     teC._columnNo = this.getColNo(i);
131 | 1716 |
                     _macros[i++].write(out, context);
132 |  |
                 case 5:
133 | 4918 |
                     b = bcontent[i];
134 | 4918 |
                     out.write(b, 0, b.length);
135 | 4918 |
                     teC._lineNo = this.getLineNo(i);
136 | 4918 |
                     teC._columnNo = this.getColNo(i);
137 | 4918 |
                     _macros[i++].write(out, context);
138 |  |
                 case 6:
139 | 9646 |
                     b = bcontent[i];
140 | 9646 |
                     out.write(b, 0, b.length);
141 | 9646 |
                     teC._lineNo = this.getLineNo(i);
142 | 9646 |
                     teC._columnNo = this.getColNo(i);
143 | 9646 |
                     _macros[i++].write(out, context);
144 |  |
                 case 7:
145 | 12242 |
                     b = bcontent[i];
146 | 12242 |
                     out.write(b, 0, b.length);
147 | 12242 |
                     teC._lineNo = this.getLineNo(i);
148 | 12242 |
                     teC._columnNo = this.getColNo(i);
149 | 12242 |
                     _macros[i++].write(out, context);
150 |  |
                 case 8:
151 | 24694 |
                     b = bcontent[i];
152 | 24694 |
                     out.write(b, 0, b.length);
153 | 24694 |
                     teC._lineNo = this.getLineNo(i);
154 | 24694 |
                     teC._columnNo = this.getColNo(i);
155 | 24694 |
                     _macros[i++].write(out, context);
156 |  |
                 case 9:
157 | 55330 |
                     b = bcontent[i];
158 | 55330 |
                     out.write(b, 0, b.length);
159 | 55330 |
                     teC._lineNo = this.getLineNo(i);
160 | 55330 |
                     teC._columnNo = this.getColNo(i);
161 | 55330 |
                     _macros[i++].write(out, context);
162 |  |
                 case 10:
163 | 56042 |
                     break;
164 |  |
                 default :
165 | 0 |
                     throw new WebMacroRuntimeException(
166 |  |
                             "Bug: _remainder value not 0 to 10: " + _remainder);
167 |  |
168 |  |
             }
169 |  |
170 | 56632 |
             while (i < _length)
171 |  |
             {
172 | 596 |
                 b = bcontent[i];
173 | 596 |
                 out.write(b, 0, b.length);
174 | 596 |
                 teC._lineNo = this.getLineNo(i);
175 | 596 |
                 teC._columnNo = this.getColNo(i);
176 | 596 |
                 _macros[i++].write(out, context);
177 | 590 |
                 b = bcontent[i];
178 | 590 |
                 out.write(b, 0, b.length);
179 | 590 |
                 teC._lineNo = this.getLineNo(i);
180 | 590 |
                 teC._columnNo = this.getColNo(i);
181 | 590 |
                 _macros[i++].write(out, context);
182 | 590 |
                 b = bcontent[i];
183 | 590 |
                 out.write(b, 0, b.length);
184 | 590 |
                 teC._lineNo = this.getLineNo(i);
185 | 590 |
                 teC._columnNo = this.getColNo(i);
186 | 590 |
                 _macros[i++].write(out, context);
187 | 590 |
                 b = bcontent[i];
188 | 590 |
                 out.write(b, 0, b.length);
189 | 590 |
                 teC._lineNo = this.getLineNo(i);
190 | 590 |
                 teC._columnNo = this.getColNo(i);
191 | 590 |
                 _macros[i++].write(out, context);
192 | 590 |
                 b = bcontent[i];
193 | 590 |
                 out.write(b, 0, b.length);
194 | 590 |
                 teC._lineNo = this.getLineNo(i);
195 | 590 |
                 teC._columnNo = this.getColNo(i);
196 | 590 |
                 _macros[i++].write(out, context);
197 | 590 |
                 b = bcontent[i];
198 | 590 |
                 out.write(b, 0, b.length);
199 | 590 |
                 teC._lineNo = this.getLineNo(i);
200 | 590 |
                 teC._columnNo = this.getColNo(i);
201 | 590 |
                 _macros[i++].write(out, context);
202 | 590 |
                 b = bcontent[i];
203 | 590 |
                 out.write(b, 0, b.length);
204 | 590 |
                 teC._lineNo = this.getLineNo(i);
205 | 590 |
                 teC._columnNo = this.getColNo(i);
206 | 590 |
                 _macros[i++].write(out, context);
207 | 590 |
                 b = bcontent[i];
208 | 590 |
                 out.write(b, 0, b.length);
209 | 590 |
                 teC._lineNo = this.getLineNo(i);
210 | 590 |
                 teC._columnNo = this.getColNo(i);
211 | 590 |
                 _macros[i++].write(out, context);
212 | 590 |
                 b = bcontent[i];
213 | 590 |
                 out.write(b, 0, b.length);
214 | 590 |
                 teC._lineNo = this.getLineNo(i);
215 | 590 |
                 teC._columnNo = this.getColNo(i);
216 | 590 |
                 _macros[i++].write(out, context);
217 | 590 |
                 b = bcontent[i];
218 | 590 |
                 out.write(b, 0, b.length);
219 | 590 |
                 teC._lineNo = this.getLineNo(i);
220 | 590 |
                 teC._columnNo = this.getColNo(i);
221 | 590 |
                 _macros[i++].write(out, context);
222 |  |
             }
223 | 56036 |
             b = bcontent[_length];
224 | 56036 |
             out.write(b, 0, b.length);
225 | 56036 |
             teC._templateName = oldName;
226 | 56036 |
         }
227 |  |
228 |  |
         public String getTemplateName ()
229 |  |
         {
230 | 0 |
             return _name;
231 |  |
         }
232 |  |
233 |  |
         public void setTemplateName (String name)
234 |  |
         {
235 | 0 |
             _name = name;
236 | 0 |
         }
237 |  |
238 |  |
         public int getLineNo (int i)
239 |  |
         {
240 | 114982 |
             return (_lineNos != null && i >= 0 && _lineNos.length > i) ? _lineNos[i] : 0;
241 |  |
         }
242 |  |
243 |  |
         public int getColNo (int i)
244 |  |
         {
245 | 114982 |
             return (_colNos != null && i >= 0 && _colNos.length > i) ? _colNos[i] : 0;
246 |  |
         }
247 |  |
248 |  |
         private static class BlockIterator implements BlockBuilder.BlockIterator
249 |  |
         {
250 |  |
251 | 0 |
             private int i = 0;
252 | 0 |
             private boolean doneString = false, done = false;
253 |  |
             private String[] strings;
254 |  |
             private Macro[] macros;
255 |  |
             private Block block;
256 |  |
257 |  |
             public BlockIterator (String[] strings, Macro[] macros, Block b)
258 | 0 |
             {
259 | 0 |
                 this.strings = strings;
260 | 0 |
                 this.macros = macros;
261 | 0 |
                 this.block = b;
262 | 0 |
             }
263 |  |
264 |  |
             public boolean hasNext ()
265 |  |
             {
266 | 0 |
                 return !done;
267 |  |
             }
268 |  |
269 |  |
             public String getName ()
270 |  |
             {
271 | 0 |
                 return block.getTemplateName();
272 |  |
             }
273 |  |
274 |  |
             public int getLineNo ()
275 |  |
             {
276 | 0 |
                 return block.getLineNo(i - 1);
277 |  |
             }
278 |  |
279 |  |
             public int getColNo ()
280 |  |
             {
281 | 0 |
                 return block.getColNo(i - 1);
282 |  |
             }
283 |  |
284 |  |
             public void remove ()
285 |  |
             {
286 | 0 |
                 throw new UnsupportedOperationException();
287 |  |
             }
288 |  |
289 |  |
             public Object next ()
290 |  |
             {
291 | 0 |
                 if (doneString)
292 |  |
                 {
293 | 0 |
                     doneString = false;
294 | 0 |
                     return macros[i++];
295 |  |
                 }
296 |  |
                 else
297 |  |
                 {
298 | 0 |
                     if (i == strings.length - 1)
299 | 0 |
                         done = true;
300 | 0 |
                     doneString = true;
301 | 0 |
                     return strings[i];
302 |  |
                 }
303 |  |
             }
304 |  |
         }
305 |  |
306 |  |
         public BlockBuilder.BlockIterator getBlockIterator ()
307 |  |
         {
308 | 0 |
             return new BlockIterator(_strings, _macros, this);
309 |  |
         }
310 |  |
311 |  |
         final void appendTo (List l)
312 |  |
         {
313 | 0 |
             final int len = _macros.length;
314 | 0 |
             for (int i = 0; i < _macros.length; i++)
315 |  |
             {
316 | 0 |
                 l.add(_strings[i]);
317 | 0 |
                 l.add(_macros[i]);
318 |  |
             }
319 | 0 |
             l.add(_strings[len]);
320 | 0 |
         }
321 |  |
322 |  |
         final public void accept (TemplateVisitor v)
323 |  |
         {
324 | 0 |
             v.beginBlock();
325 | 0 |
             final int len = _macros.length;
326 | 0 |
             for (int i = 0; i < len; i++)
327 |  |
             {
328 | 0 |
                 v.visitString(_strings[i]);
329 | 0 |
                 v.visitMacro(_macros[i]);
330 |  |
             }
331 | 0 |
             v.visitString(_strings[len]);
332 | 0 |
             v.endBlock();
333 | 0 |
         }
334 |  |
335 |  |
         /**
336 |  |
          * @exception PropertyException if required data was missing from context
337 |  |
          */
338 |  |
         final public Object evaluate (Context context) throws PropertyException
339 |  |
         {
340 |  |
             try
341 |  |
             {
342 | 0 |
                 FastWriter fw = FastWriter.getInstance(context.getBroker());
343 | 0 |
                 write(fw, context);
344 | 0 |
                 String ret = fw.toString();
345 | 0 |
                 fw.close();
346 | 0 |
                 return ret;
347 |  |
             }
348 | 0 |
             catch (IOException e)
349 |  |
             {
350 | 0 |
                 _log.error("StringWriter threw an IOException!", e);
351 | 0 |
                 return null;
352 |  |
             }
353 |  |
         }
354 |  |
355 |  |
     }
356 |  |