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

Classes in this File | Line Coverage | Branch Coverage | Complexity
CountDirective |
3% | 3/80
0% | 0/50
| 9.5;9.5

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 |  |
     package org.webmacro.directive;
23 |  |
24 |  |
     import org.webmacro.Context;
25 |  |
     import org.webmacro.FastWriter;
26 |  |
     import org.webmacro.Macro;
27 |  |
     import org.webmacro.PropertyException;
28 |  |
     import org.webmacro.engine.Block;
29 |  |
     import org.webmacro.engine.BuildContext;
30 |  |
     import org.webmacro.engine.BuildException;
31 |  |
     import org.webmacro.engine.UndefinedMacro;
32 |  |
     import org.webmacro.engine.Variable;
33 |  |
34 |  |
     import java.io.IOException;
35 |  |
36 |  |
     /**
37 |  |
      * Syntax:
38 |  |
      * <pre>
39 |  |
      * #count $i from 1 to 100 [step 1]
40 |  |
      * </pre>
41 |  |
      *
42 |  |
      * @author Eric B. Ridge (ebr@tcdi.com)
43 |  |
      * @since 1.1b1
44 |  |
      */
45 | 0 |
     public class CountDirective extends Directive
46 |  |
     {
47 |  |
48 |  |
         private static final int COUNT_ITERATOR = 1;
49 |  |
         private static final int COUNT_FROM_K = 2;
50 |  |
         private static final int COUNT_START = 3;
51 |  |
         private static final int COUNT_TO_K = 4;
52 |  |
         private static final int COUNT_END = 5;
53 |  |
         private static final int COUNT_STEP_K = 6;
54 |  |
         private static final int COUNT_STEP = 7;
55 |  |
         private static final int COUNT_BODY = 8;
56 |  |
57 | 2 |
         private static final Directive.ArgDescriptor[] _args =
58 |  |
             new Directive.ArgDescriptor[]{
59 |  |
                 new Directive.LValueArg(COUNT_ITERATOR),
60 |  |
                 new Directive.KeywordArg(COUNT_FROM_K, "from"),
61 |  |
                 new Directive.RValueArg(COUNT_START),
62 |  |
                 new Directive.KeywordArg(COUNT_TO_K, "to"),
63 |  |
                 new Directive.RValueArg(COUNT_END),
64 |  |
                 new Directive.OptionalGroup(2),
65 |  |
                 new Directive.KeywordArg(COUNT_STEP_K, "step"),
66 |  |
                 new Directive.RValueArg(COUNT_STEP),
67 |  |
                 new Directive.BlockArg(COUNT_BODY),
68 |  |
            };
69 |  |
70 | 2 |
         private static final DirectiveDescriptor _desc =
71 |  |
             new DirectiveDescriptor("count", null, _args, null);
72 |  |
73 |  |
         public static DirectiveDescriptor getDescriptor ()
74 |  |
         {
75 | 6 |
             return _desc;
76 |  |
         }
77 |  |
78 |  |
         private Variable _iterator;
79 |  |
         private Macro _body;
80 |  |
         private Object _objStart;
81 |  |
         private Object _objEnd;
82 |  |
         private Object _objStep;
83 |  |
84 | 0 |
         private int _start, _end, _step = Integer.MAX_VALUE;
85 |  |
86 |  |
         public Object build (DirectiveBuilder builder, BuildContext bc)
87 |  |
             throws BuildException
88 |  |
         {
89 |  |
             try
90 |  |
             {
91 | 0 |
                 _iterator = (Variable) builder.getArg(COUNT_ITERATOR, bc);
92 |  |
             }
93 | 0 |
             catch (ClassCastException e)
94 |  |
             {
95 | 0 |
                 throw new Directive.NotVariableBuildException(_desc.name, e);
96 | 0 |
             }
97 | 0 |
             _objStart = builder.getArg(COUNT_START, bc);
98 | 0 |
             _objEnd = builder.getArg(COUNT_END, bc);
99 | 0 |
             _objStep = builder.getArg(COUNT_STEP, bc);
100 | 0 |
             _body = (Block) builder.getArg(COUNT_BODY, bc);
101 |  |
102 |  |
             // attempt to go ahead and force the start, end, and step values
103 |  |
             // into primitive ints
104 | 0 |
             if (_objStart != null)
105 |  |
             {
106 | 0 |
                 if (_objStart instanceof Number)
107 |  |
                 {
108 | 0 |
                     _start = ((Number) _objStart).intValue();
109 | 0 |
                     _objStart = null;
110 |  |
                 }
111 | 0 |
                 else if (_objStart instanceof String)
112 |  |
                 {
113 | 0 |
                     _start = Integer.parseInt((String) _objStart);
114 | 0 |
                     _objStart = null;
115 |  |
                 }
116 |  |
             }
117 | 0 |
             if (_objEnd != null)
118 |  |
             {
119 | 0 |
                 if (_objEnd instanceof Number)
120 |  |
                 {
121 | 0 |
                     _end = ((Number) _objEnd).intValue();
122 | 0 |
                     _objEnd = null;
123 |  |
                 }
124 | 0 |
                 else if (_objEnd instanceof String)
125 |  |
                 {
126 | 0 |
                     _end = Integer.parseInt((String) _objEnd);
127 | 0 |
                     _objEnd = null;
128 |  |
                 }
129 |  |
             }
130 | 0 |
             if (_objStep != null)
131 |  |
             {
132 | 0 |
                 if (_objStep instanceof Number)
133 |  |
                 {
134 | 0 |
                     _step = ((Number) _objStep).intValue();
135 | 0 |
                     _objStep = null;
136 |  |
                 }
137 | 0 |
                 else if (_objStep instanceof String)
138 |  |
                 {
139 | 0 |
                     _step = Integer.parseInt((String) _objStep);
140 | 0 |
                     _objStep = null;
141 |  |
                 }
142 |  |
             }
143 |  |
144 | 0 |
             return this;
145 |  |
         }
146 |  |
147 |  |
         public void write (FastWriter out, Context context)
148 |  |
             throws PropertyException, IOException
149 |  |
         {
150 | 0 |
             int start = _start, end = _end, step = _step;
151 | 0 |
             boolean error = false;
152 |  |
153 |  |
             // if necessary, do run-time evaluation of our
154 |  |
             // start, end, and step objects.
155 |  |
             // If object is null then it has been fully resolved during build.
156 |  |
             try {
157 | 0 |
                if (_objStart != null)
158 | 0 |
                   start = evalAsInt(context, _objStart);
159 | 0 |
                if (_objEnd != null)
160 | 0 |
                   end = evalAsInt(context, _objEnd);
161 | 0 |
                if (_objStep != null)
162 | 0 |
                   step = evalAsInt(context, _objStep);
163 |  |
             }
164 | 0 |
             catch (Exception e)
165 |  |
             {
166 | 0 |
                out.write(context.getEvaluationExceptionHandler()
167 |  |
                        .expand(_iterator, context, e));
168 | 0 |
                error = true;
169 | 0 |
             }
170 |  |
171 | 0 |
             if (!error)
172 |  |
             {
173 |  |
                // Check if no step explicitly assigned, if so auto-detect it
174 | 0 |
                if (step == Integer.MAX_VALUE)
175 |  |
                {
176 | 0 |
                    step = (start > end) ? -1 : +1;
177 |  |
                }
178 |  |
179 | 0 |
                if (step > 0)
180 |  |
                {
181 | 0 |
                    for ( ; start <= end; start += step)
182 |  |
                    {
183 | 0 |
                        _iterator.setValue(context, new Integer(start));
184 | 0 |
                        _body.write(out, context);
185 |  |
                    }
186 |  |
                }
187 | 0 |
                else if (step < 0)
188 |  |
                {
189 | 0 |
                    for ( ; start >= end; start += step)
190 |  |
                    {
191 | 0 |
                        _iterator.setValue(context, new Integer(start));
192 | 0 |
                        _body.write(out, context);
193 |  |
                    }
194 |  |
                }
195 |  |
                else
196 |  |
                {
197 | 0 |
                   PropertyException pe = new PropertyException.UndefinedVariableException();
198 | 0 |
                   pe.setMessage("#count: step cannot be 0.");
199 | 0 |
                   out.write(context.getEvaluationExceptionHandler()
200 |  |
                           .expand(_iterator, context, pe));
201 |  |
                }
202 |  |
             }
203 | 0 |
         }
204 |  |
205 |  |
         private int evalAsInt(Context context, Object o) throws PropertyException
206 |  |
         {
207 | 0 |
            if (o != null)
208 |  |
            {
209 | 0 |
               while (o instanceof Macro && !(o == UndefinedMacro.getInstance()))
210 |  |
               {
211 | 0 |
                  o = ((Macro)o).evaluate(context);
212 |  |
               }
213 | 0 |
               if (o == UndefinedMacro.getInstance()){
214 | 0 |
                  PropertyException pe = new PropertyException.UndefinedVariableException();
215 | 0 |
                  pe.setMessage("Undefined expression in #count directive.");
216 | 0 |
                  throw pe;
217 |  |
               }
218 |  |
            }
219 | 0 |
            if (o == null)
220 |  |
            {
221 | 0 |
               PropertyException pe = new PropertyException.UndefinedVariableException();
222 | 0 |
               pe.setMessage("Null expression in #count directive.");
223 | 0 |
               throw pe;
224 |  |
            }
225 | 0 |
            if (o instanceof Number)
226 | 0 |
                return ((Number) o).intValue();
227 |  |
            try {
228 | 0 |
               return Integer.parseInt(o.toString());
229 |  |
            }
230 | 0 |
            catch (NumberFormatException e)
231 |  |
            {
232 | 0 |
               PropertyException pe = new PropertyException.UndefinedVariableException();
233 | 0 |
               pe.setMessage("Invalid numeric expression in #count directive: [" + o + "]");
234 | 0 |
               throw pe;
235 |  |
            }
236 |  |
         }
237 |  |
     }