Coverage Report - org.webmacro.directive.Directive
 
Classes in this File Line Coverage Branch Coverage Complexity
Directive
40%
6/15
N/A
1.061
Directive$ArgDescriptor
100%
10/10
N/A
1.061
Directive$AssignmentArg
100%
2/2
N/A
1.061
Directive$BlockArg
100%
2/2
N/A
1.061
Directive$ConditionArg
100%
2/2
N/A
1.061
Directive$ExactlyOneChoice
0%
0/4
N/A
1.061
Directive$FormalArgListArg
100%
2/2
N/A
1.061
Directive$KeywordArg
100%
3/3
N/A
1.061
Directive$LValueArg
100%
2/2
N/A
1.061
Directive$LiteralBlockArg
100%
2/2
N/A
1.061
Directive$NameArg
100%
2/2
N/A
1.061
Directive$OptionChoice
100%
5/5
N/A
1.061
Directive$OptionalGroup
100%
4/4
N/A
1.061
Directive$OptionalRepeatingSubdirective
50%
3/6
N/A
1.061
Directive$OptionalSubdirective
50%
3/6
N/A
1.061
Directive$QuotedStringArg
100%
2/2
N/A
1.061
Directive$RValueArg
100%
2/2
N/A
1.061
Directive$SingleOptionChoice
100%
3/3
N/A
1.061
Directive$StringArg
0%
0/2
N/A
1.061
Directive$Subdirective
100%
8/8
50%
1/2
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