Coverage Report

##### Coverage Report - org.webmacro.directive.Directive

Classes in this File | Line Coverage | Branch Coverage | Complexity
Directive |
40% | 6/15
N/A | N/A
| 1.0606060606060606;1.061
Directive$ArgDescriptor |
100% | 10/10
N/A | N/A
| 1.0606060606060606;1.061
Directive$AssignmentArg |
100% | 2/2
N/A | N/A
| 1.0606060606060606;1.061
Directive$BlockArg |
100% | 2/2
N/A | N/A
| 1.0606060606060606;1.061
Directive$ConditionArg |
100% | 2/2
N/A | N/A
| 1.0606060606060606;1.061
Directive$ExactlyOneChoice |
0% | 0/4
N/A | N/A
| 1.0606060606060606;1.061
Directive$FormalArgListArg |
100% | 2/2
N/A | N/A
| 1.0606060606060606;1.061
Directive$KeywordArg |
100% | 3/3
N/A | N/A
| 1.0606060606060606;1.061
Directive$LValueArg |
100% | 2/2
N/A | N/A
| 1.0606060606060606;1.061
Directive$LiteralBlockArg |
100% | 2/2
N/A | N/A
| 1.0606060606060606;1.061
Directive$NameArg |
100% | 2/2
N/A | N/A
| 1.0606060606060606;1.061
Directive$OptionChoice |
100% | 5/5
N/A | N/A
| 1.0606060606060606;1.061
Directive$OptionalGroup |
100% | 4/4
N/A | N/A
| 1.0606060606060606;1.061
Directive$OptionalRepeatingSubdirective |
50% | 3/6
N/A | N/A
| 1.0606060606060606;1.061
Directive$OptionalSubdirective |
50% | 3/6
N/A | N/A
| 1.0606060606060606;1.061
Directive$QuotedStringArg |
100% | 2/2
N/A | N/A
| 1.0606060606060606;1.061
Directive$RValueArg |
100% | 2/2
N/A | N/A
| 1.0606060606060606;1.061
Directive$SingleOptionChoice |
100% | 3/3
N/A | N/A
| 1.0606060606060606;1.061
Directive$StringArg |
0% | 0/2
N/A | N/A
| 1.0606060606060606;1.061
Directive$Subdirective |
100% | 8/8
50% | 1/2
| 1.0606060606060606;1.061

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 |  |
     package org.webmacro.directive;
24 |  |
25 |  |
     import java.io.IOException;
26 |  |
27 |  |
     import org.slf4j.Logger;
28 |  |
     import org.slf4j.LoggerFactory;
29 |  |
     import org.webmacro.Context;
30 |  |
     import org.webmacro.FastWriter;
31 |  |
     import org.webmacro.Macro;
32 |  |
     import org.webmacro.PropertyException;
33 |  |
     import org.webmacro.TemplateVisitor;
34 |  |
     import org.webmacro.Visitable;
35 |  |
     import org.webmacro.engine.BuildContext;
36 |  |
     import org.webmacro.engine.BuildException;
37 |  |
38 |  |
     /**
39 |  |
      * Directive is an abstract class which directives can extend.
40 |  |
      * Nested within Directive (as static classes) are a host of classes used
41 |  |
      * for building directive argument lists.
42 |  |
      *
43 |  |
      * Directives are Macros, so they must implement the Macro interface.
44 |  |
      * For convenience, an implementation of evaluate() (written in terms of
45 |  |
      * write()) is provided in the base class.)
46 |  |
      *
47 |  |
      * Directives must implement the following static method:
48 |  |
      *   public DirectiveDescriptor getDescriptor();
49 |  |
      *
50 |  |
      * It is expected that all directives will build a copy of their descriptor
51 |  |
      * statically, using the various XxxArg() constructors, and return a reference
52 |  |
      * to that from getDescriptor().
53 |  |
      *
54 |  |
      * @author Brian Goetz
55 |  |
      */
56 |  |
57 | 1284 |
     public abstract class Directive implements Macro, Visitable
58 |  |
     {
59 |  |
60 | 2 |
         static Logger _log =  LoggerFactory.getLogger(Directive.class);
61 |  |
         public static final int ArgType_CONDITION = 1;
62 |  |
         public static final int ArgType_LVALUE = 2;
63 |  |
         public static final int ArgType_RVALUE = 3;
64 |  |
         public static final int ArgType_KEYWORD = 4;
65 |  |
         public static final int ArgType_ASSIGN = 5;
66 |  |
         public static final int ArgType_BLOCK = 6;
67 |  |
         public static final int ArgType_LITBLOCK = 7;
68 |  |
         public static final int ArgType_SUBDIRECTIVE = 8;
69 |  |
         public static final int ArgType_QUOTEDSTRING = 9;
70 |  |
         public static final int ArgType_STRING = 10;
71 |  |
         public static final int ArgType_NAME = 11;
72 |  |
         public static final int ArgType_ARGLIST = 12;
73 |  |
74 |  |
         public static final int ArgType_GROUP = 50;
75 |  |
         public static final int ArgType_CHOICE = 51;
76 |  |
77 |  |
         /**
78 |  |
          * Directives must implement a build() method.  The build method
79 |  |
          * should examine the directive arguments (available through the
80 |  |
          * DirectiveBuilder) and return a macro describing the built
81 |  |
          * directive.  In most cases, build() will just set up the
82 |  |
          * directive's private fields and return 'this', but in some
83 |  |
          * cases, no macro needs be returned (such as directives with only
84 |  |
          * side effects on the build context) or some other macro may be
85 |  |
          * returned (such as in the case of "#if (true) { }" -- no IfDirective
86 |  |
          * object need be returned, just return the block.)
87 |  |
          */
88 |  |
89 |  |
         public abstract Object build (DirectiveBuilder b,
90 |  |
                                       BuildContext bc)
91 |  |
                 throws BuildException;
92 |  |
93 |  |
         /* Convenience implementation of evaluate() which Directives can inherit */
94 |  |
         public Object evaluate (Context context)
95 |  |
                 throws PropertyException
96 |  |
         {
97 |  |
             try
98 |  |
             {
99 | 0 |
                 FastWriter fw = FastWriter.getInstance(context.getBroker());
100 | 0 |
                 write(fw, context);
101 | 0 |
                 return fw.toString();
102 |  |
             }
103 | 0 |
             catch (IOException e)
104 |  |
             {
105 | 0 |
                 _log.error(
106 |  |
                         "Directive.evaluate: IO exception on write to StringWriter", e);
107 | 0 |
                 return "";
108 |  |
             }
109 |  |
         }
110 |  |
111 |  |
         /**
112 |  |
          * Convenience method for directives to write HTML warnings into the output
113 |  |
          * stream.  Eventually this will be parameterizable so that HTML is not
114 |  |
          * assumed to be the only underlying language.
115 |  |
          */
116 |  |
117 |  |
         protected static String getWarningText (String warning, Context context)
118 |  |
                 throws IOException, PropertyException
119 |  |
         {
120 | 4 |
             return context.getEvaluationExceptionHandler()
121 |  |
                     .warningString("WARNING: " + warning +
122 |  |
                             " at " + context.getCurrentLocation());
123 |  |
         }
124 |  |
125 |  |
         /**
126 |  |
          * Convenience method for directives to write HTML warnings into the output
127 |  |
          * stream.  Eventually this will be parameterizable so that HTML is not
128 |  |
          * assumed to be the only underlying language.<p>
129 |  |
          *
130 |  |
          * This method also outputs the same warning message to a log named "directive"
131 |  |
          */
132 |  |
         protected static void writeWarning (String warning, Context context,
133 |  |
                 FastWriter writer) throws IOException, PropertyException
134 |  |
         {
135 | 4 |
             context.getLog("directive").warn(warning +
136 |  |
                     " at " + context.getCurrentLocation());
137 | 4 |
             writer.write(getWarningText(warning, context));
138 | 0 |
         }
139 |  |
140 |  |
         public void accept (TemplateVisitor v)
141 |  |
         {
142 | 0 |
             v.visitUnknownMacro(this.getClass().getName(), this);
143 | 0 |
         }
144 |  |
145 |  |
         /* Nested static classes */
146 |  |
147 |  |
148 |  |
         /**
149 |  |
          * ArgDescriptor is the base class for all the different types
150 |  |
          * of argument descriptors, like ConditionalArg, KeywordArg, RValueArg,
151 |  |
          * etc.
152 |  |
          * Most ArgDescriptor constructors take an argId parameter, which is
153 |  |
          * an integer which uniquely identifies the argument which will be passed
154 |  |
          * to DirectiveBuilder.getArg when retrieving the argument.
155 |  |
          */
156 |  |
157 |  |
         public static abstract class ArgDescriptor
158 |  |
         {
159 |  |
160 |  |
             public final int id;
161 |  |
             public final int type;
162 | 208 |
             public boolean optional = false;
163 | 208 |
             public int subordinateArgs = 0, nextArg = 0;
164 |  |
             public int[] children;
165 |  |
             public String keyword;
166 |  |
167 |  |
             protected ArgDescriptor (int id, int type)
168 | 208 |
             {
169 | 208 |
                 this.id = id;
170 | 208 |
                 this.type = type;
171 | 208 |
             }
172 |  |
173 |  |
             protected void setOptional (boolean optional)
174 |  |
             {
175 | 50 |
                 this.optional = optional;
176 | 50 |
             }
177 |  |
178 |  |
             protected void setSubordinateArgs (int subordinateArgs)
179 |  |
             {
180 | 46 |
                 this.subordinateArgs = subordinateArgs;
181 | 46 |
             }
182 |  |
         }
183 |  |
184 |  |
185 |  |
         /**
186 |  |
          * Condition argument type.  Accepts a WM expression which evaluates
187 |  |
          * to a boolean result, evaluated according to Expression.isTrue.
188 |  |
          */
189 |  |
         public static class ConditionArg extends ArgDescriptor
190 |  |
         {
191 |  |
192 |  |
             public ConditionArg (int id)
193 |  |
             {
194 | 4 |
                 super(id, ArgType_CONDITION);
195 | 4 |
             }
196 |  |
         }
197 |  |
198 |  |
         /**
199 |  |
          * Block argument type.  Accepts a WM Block.
200 |  |
          */
201 |  |
         public static class BlockArg extends ArgDescriptor
202 |  |
         {
203 |  |
204 |  |
             public BlockArg (int id)
205 |  |
             {
206 | 20 |
                 super(id, ArgType_BLOCK);
207 | 20 |
             }
208 |  |
         }
209 |  |
210 |  |
         /**
211 |  |
          * Literal block argument type.  Accepts a WM Block, but does not intepret
212 |  |
          * any directives or property references contained in the block.
213 |  |
          */
214 |  |
         public static class LiteralBlockArg extends ArgDescriptor
215 |  |
         {
216 |  |
217 |  |
             public LiteralBlockArg (int id)
218 |  |
             {
219 | 4 |
                 super(id, ArgType_LITBLOCK);
220 | 4 |
             }
221 |  |
         }
222 |  |
223 |  |
         /**
224 |  |
          * RValue argument type.  Accepts any WM expression.
225 |  |
          */
226 |  |
         public static class RValueArg extends ArgDescriptor
227 |  |
         {
228 |  |
229 |  |
             public RValueArg (int id)
230 |  |
             {
231 | 30 |
                 super(id, ArgType_RVALUE);
232 | 30 |
             }
233 |  |
         }
234 |  |
235 |  |
         /**
236 |  |
          * LValue argument type.  Accepts any WM property reference.
237 |  |
          */
238 |  |
         public static class LValueArg extends ArgDescriptor
239 |  |
         {
240 |  |
241 |  |
             public LValueArg (int id)
242 |  |
             {
243 | 24 |
                 super(id, ArgType_LVALUE);
244 | 24 |
             }
245 |  |
         }
246 |  |
247 |  |
         /**
248 |  |
          * Quoted string argument type.  Accepts a quoted string with embedded
249 |  |
          * property references (e.g., "hello $foo")
250 |  |
          */
251 |  |
         public static class QuotedStringArg extends ArgDescriptor
252 |  |
         {
253 |  |
254 |  |
             public QuotedStringArg (int id)
255 |  |
             {
256 | 8 |
                 super(id, ArgType_QUOTEDSTRING);
257 | 8 |
             }
258 |  |
         }
259 |  |
260 |  |
         /**
261 |  |
          * String argument type.  Accepts either a quoted string with embedded
262 |  |
          * property references (e.g., "hello $foo"), or a single property
263 |  |
          * reference ($something).
264 |  |
          */
265 |  |
         public static class StringArg extends ArgDescriptor
266 |  |
         {
267 |  |
268 |  |
             public StringArg (int id)
269 |  |
             {
270 | 0 |
                 super(id, ArgType_STRING);
271 | 0 |
             }
272 |  |
         }
273 |  |
274 |  |
         /**
275 |  |
          * Keyword argument type.  Accepts only the specified keyword.
276 |  |
          */
277 |  |
         public static class KeywordArg extends ArgDescriptor
278 |  |
         {
279 |  |
280 |  |
             public KeywordArg (int id, String keyword)
281 |  |
             {
282 | 50 |
                 super(id, ArgType_KEYWORD);
283 | 50 |
                 this.keyword = keyword;
284 | 50 |
             }
285 |  |
         }
286 |  |
287 |  |
         /**
288 |  |
          * Assignment.  In the standard parser, the parser looks for an =
289 |  |
          * operator, but other parsers can handle this as they see fit.
290 |  |
          */
291 |  |
         public static class AssignmentArg extends ArgDescriptor
292 |  |
         {
293 |  |
294 |  |
             public AssignmentArg ()
295 |  |
             {
296 | 14 |
                 super(0, ArgType_ASSIGN);
297 | 14 |
             }
298 |  |
         }
299 |  |
300 |  |
         /**
301 |  |
          * Implements an argument as a simple name.
302 |  |
          */
303 |  |
         public static class NameArg extends ArgDescriptor
304 |  |
         {
305 |  |
306 |  |
             public NameArg (int id)
307 |  |
             {
308 | 2 |
                 super(id, ArgType_NAME);
309 | 2 |
             }
310 |  |
         }
311 |  |
312 |  |
         /**
313 |  |
          * Argument list.  Accepts a ()-delimited list of simple variable names.
314 |  |
          */
315 |  |
         public static class FormalArgListArg extends ArgDescriptor
316 |  |
         {
317 |  |
318 |  |
             public FormalArgListArg (int id)
319 |  |
             {
320 | 2 |
                 super(id, ArgType_ARGLIST);
321 | 2 |
             }
322 |  |
         }
323 |  |
324 |  |
         /**
325 |  |
          * Optional group.  An optional group can begin with a Keyword argument.
326 |  |
          * If the keyword argument is not present in the input text, the entire
327 |  |
          * group is skipped.  Can contain other groups.  The argCount parameter
328 |  |
          * is the number of simple arguments or groups in this argument group.
329 |  |
          */
330 |  |
         public static class OptionalGroup extends ArgDescriptor
331 |  |
         {
332 |  |
333 |  |
             public OptionalGroup (int argCount)
334 |  |
             {
335 | 42 |
                 super(0, ArgType_GROUP);
336 | 42 |
                 setOptional(true);
337 | 42 |
                 setSubordinateArgs(argCount);
338 | 42 |
             }
339 |  |
         }
340 |  |
341 |  |
         /**
342 |  |
          * The OptionChoice indicates that several optional groups can be accepted
343 |  |
          * in any order.  The groupCount parameter is the number of OptionalGroup
344 |  |
          * arguments following.  Each group in the choice will be accepted zero
345 |  |
          * or one time, in any order.
346 |  |
          * For example, OptionChoice would allow a directive with the optional
347 |  |
          * groups (Keyword("from"), RValue()) and (Keyword("max"), RValue()) to
348 |  |
          * accept either "from n max m" or "from n" or "max m from n".
349 |  |
          */
350 |  |
         public static class OptionChoice extends ArgDescriptor
351 |  |
         {
352 |  |
353 | 4 |
             public boolean repeating = true;
354 |  |
355 |  |
             public OptionChoice (int groupCount)
356 |  |
             {
357 | 4 |
                 super(0, ArgType_CHOICE);
358 | 4 |
                 setOptional(true);
359 | 4 |
                 setSubordinateArgs(groupCount);
360 | 4 |
             }
361 |  |
         }
362 |  |
363 |  |
364 |  |
         /**
365 |  |
          * The SingleOptionChoice indicates that zero or one of several
366 |  |
          * optional groups can be accepted, but only once.  Otherwise works
367 |  |
          * exactly as OptionChoice.  */
368 |  |
         public static class SingleOptionChoice extends OptionChoice
369 |  |
         {
370 |  |
371 |  |
             public SingleOptionChoice (int groupCount)
372 |  |
             {
373 | 2 |
                 super(groupCount);
374 | 2 |
                 repeating = false;
375 | 2 |
             }
376 |  |
         }
377 |  |
378 |  |
379 |  |
         /**
380 |  |
          * The ExactlyOneChoice indicates that exactly one of several
381 |  |
          * optional groups can be accepted, only once.  Otherwise works
382 |  |
          * exactly as OptionChoice.  */
383 |  |
         public static class ExactlyOneChoice extends OptionChoice
384 |  |
         {
385 |  |
386 |  |
             public ExactlyOneChoice (int groupCount)
387 |  |
             {
388 | 0 |
                 super(groupCount);
389 | 0 |
                 setOptional(false);
390 | 0 |
                 repeating = false;
391 | 0 |
             }
392 |  |
         }
393 |  |
394 |  |
395 |  |
         /**
396 |  |
          * Subdirectives are like directives, except that they do not have their
397 |  |
          * own class.  The directive is responsible for fetching and processing
398 |  |
          * the subdirective's arguments.  Each Subdirective can have its own
399 |  |
          * argument list.
400 |  |
          */
401 |  |
         public static class Subdirective extends ArgDescriptor
402 |  |
         {
403 |  |
404 |  |
             public final static int BREAKING = 1;
405 |  |
406 |  |
             public final String name;
407 |  |
             public final ArgDescriptor[] args;
408 | 4 |
             public boolean repeating = false, isBreaking = false;
409 |  |
410 |  |
             public Subdirective (int id, String name,
411 |  |
                                  ArgDescriptor[] args)
412 |  |
             {
413 | 4 |
                 super(id, ArgType_SUBDIRECTIVE);
414 | 4 |
                 this.name = name;
415 | 4 |
                 this.args = args;
416 | 4 |
             }
417 |  |
418 |  |
             public Subdirective (int id, String name, ArgDescriptor[] args,
419 |  |
                                  int flags)
420 |  |
             {
421 | 4 |
                 this(id, name, args);
422 | 4 |
                 isBreaking = ((flags & BREAKING) != 0);
423 | 4 |
             }
424 |  |
         }
425 |  |
426 |  |
         /**
427 |  |
          * Optional subdirective.  This means that the subdirective can appear
428 |  |
          * zero or one time.
429 |  |
          */
430 |  |
         public static class OptionalSubdirective extends Subdirective
431 |  |
         {
432 |  |
433 |  |
             public OptionalSubdirective (int id, String name,
434 |  |
                                          ArgDescriptor[] args)
435 |  |
             {
436 | 0 |
                 super(id, name, args);
437 | 0 |
                 setOptional(true);
438 | 0 |
             }
439 |  |
440 |  |
             public OptionalSubdirective (int id, String name,
441 |  |
                                          ArgDescriptor[] args, int flags)
442 |  |
             {
443 | 4 |
                 super(id, name, args, flags);
444 | 4 |
                 setOptional(true);
445 | 4 |
             }
446 |  |
         }
447 |  |
448 |  |
         /**
449 |  |
          * Optional repeating subdirective.  This means that the
450 |  |
          * subdirective can appear zero or more times.
451 |  |
          */
452 |  |
         public static class OptionalRepeatingSubdirective
453 |  |
                 extends OptionalSubdirective
454 |  |
         {
455 |  |
456 |  |
             public OptionalRepeatingSubdirective (int id, String name,
457 |  |
                                                   ArgDescriptor[] args)
458 |  |
             {
459 | 0 |
                 super(id, name, args);
460 | 0 |
                 repeating = true;
461 | 0 |
             }
462 |  |
463 |  |
             public OptionalRepeatingSubdirective (int id, String name,
464 |  |
                                                   ArgDescriptor[] args, int flags)
465 |  |
             {
466 | 2 |
                 super(id, name, args, flags);
467 | 2 |
                 repeating = true;
468 | 2 |
             }
469 |  |
         }
470 |  |
471 |  |
472 |  |
         // Utility exception classes for use by directives
473 |  |
474 |  |
         /**
475 |  |
          * Utility exception used by directives to signal that an argument
476 |  |
          * that was supposed to be a Variable is not a variable.  Subclasses
477 |  |
          * BuildException.
478 |  |
          */
479 |  |
         public static class NotVariableBuildException extends BuildException
480 |  |
         {
481 |  |
482 |  |
             /**
483 |  |
                      *
484 |  |
                      */
485 |  |
                     private static final long serialVersionUID = 1L;
486 |  |
487 |  |
                     public NotVariableBuildException (String directive)
488 |  |
             {
489 |  |
                 super("#" + directive + ": Argument must be a variable");
490 |  |
             }
491 |  |
492 |  |
             public NotVariableBuildException (String directive, Exception e)
493 |  |
             {
494 |  |
                 super("#" + directive + ": Argument must be a variable", e);
495 |  |
             }
496 |  |
         }
497 |  |
498 |  |
         /**
499 |  |
          * Utility exception used by directives to signal that an argument
500 |  |
          * that was supposed to be a simple Variable (only one term) is not.
501 |  |
          * Subclasses BuildException.
502 |  |
          */
503 | 1284 |
         public static class NotSimpleVariableBuildException extends BuildException
504 |  |
         {
505 |  |
                     private static final long serialVersionUID = 1L;
506 |  |
507 |  |
                     public NotSimpleVariableBuildException (String directive)
508 |  |
             {
509 |  |
                 super("#" + directive + ": Argument must be a simple variable");
510 |  |
             }
511 |  |
512 |  |
             public NotSimpleVariableBuildException (String directive, Exception e)
513 |  |
             {
514 |  |
                 super("#" + directive + ": Argument must be a simple variable", e);
515 |  |
             }
516 |  |
         }
517 |  |
518 |  |
519 |  |
     }
520 |  |