Coverage Report - org.webmacro.engine.Block
 
Classes in this File Line Coverage Branch Coverage Complexity
Block
87%
128/147
62%
18/29
2.529
Block$BlockIterator
89%
17/19
100%
6/6
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  37
     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  4605
     {
 70  4605
         _name = name;
 71  4605
         _strings = strings;
 72  4605
         _macros = macros;
 73  4605
         _lineNos = lineNos;
 74  4605
         _colNos = colNos;
 75  
 
 76  4605
         _length = _macros.length;
 77  4605
         _remainder = 10 - _length % 10;
 78  
 
 79  
         // we'll use this to encode our strings for output to the user
 80  4605
         _block = new Encoder.Block(_strings);
 81  4605
     }
 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  6943
         final byte[][] bcontent = out.getEncoder().encode(_block);
 94  
         byte[] b;
 95  6943
         Context.TemplateEvaluationContext teC = context.getTemplateEvaluationContext();
 96  6943
         String oldName = teC._templateName;
 97  
 
 98  6943
         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  6943
         int i = 0;
 106  6943
         switch (_remainder)
 107  
         {
 108  
             case 1:
 109  106
                 b = bcontent[i];
 110  106
                 out.write(b, 0, b.length);
 111  106
                 teC._lineNo = this.getLineNo(i);
 112  106
                 teC._columnNo = this.getColNo(i);
 113  106
                 _macros[i++].write(out, context);
 114  
             case 2:
 115  110
                 b = bcontent[i];
 116  110
                 out.write(b, 0, b.length);
 117  110
                 teC._lineNo = this.getLineNo(i);
 118  110
                 teC._columnNo = this.getColNo(i);
 119  110
                 _macros[i++].write(out, context);
 120  
             case 3:
 121  110
                 b = bcontent[i];
 122  110
                 out.write(b, 0, b.length);
 123  110
                 teC._lineNo = this.getLineNo(i);
 124  110
                 teC._columnNo = this.getColNo(i);
 125  110
                 _macros[i++].write(out, context);
 126  
             case 4:
 127  113
                 b = bcontent[i];
 128  113
                 out.write(b, 0, b.length);
 129  113
                 teC._lineNo = this.getLineNo(i);
 130  113
                 teC._columnNo = this.getColNo(i);
 131  113
                 _macros[i++].write(out, context);
 132  
             case 5:
 133  142
                 b = bcontent[i];
 134  142
                 out.write(b, 0, b.length);
 135  142
                 teC._lineNo = this.getLineNo(i);
 136  142
                 teC._columnNo = this.getColNo(i);
 137  142
                 _macros[i++].write(out, context);
 138  
             case 6:
 139  331
                 b = bcontent[i];
 140  331
                 out.write(b, 0, b.length);
 141  331
                 teC._lineNo = this.getLineNo(i);
 142  331
                 teC._columnNo = this.getColNo(i);
 143  331
                 _macros[i++].write(out, context);
 144  
             case 7:
 145  665
                 b = bcontent[i];
 146  665
                 out.write(b, 0, b.length);
 147  665
                 teC._lineNo = this.getLineNo(i);
 148  665
                 teC._columnNo = this.getColNo(i);
 149  665
                 _macros[i++].write(out, context);
 150  
             case 8:
 151  1506
                 b = bcontent[i];
 152  1506
                 out.write(b, 0, b.length);
 153  1506
                 teC._lineNo = this.getLineNo(i);
 154  1506
                 teC._columnNo = this.getColNo(i);
 155  1506
                 _macros[i++].write(out, context);
 156  
             case 9:
 157  4182
                 b = bcontent[i];
 158  4182
                 out.write(b, 0, b.length);
 159  4182
                 teC._lineNo = this.getLineNo(i);
 160  4182
                 teC._columnNo = this.getColNo(i);
 161  4182
                 _macros[i++].write(out, context);
 162  
             case 10:
 163  6900
                 break;
 164  
             default :
 165  0
                 throw new WebMacroRuntimeException(
 166  
                         "Bug: _remainder value not 0 to 10: " + _remainder); 
 167  
                 
 168  
         }
 169  
 
 170  7081
         while (i < _length)
 171  
         {
 172  181
             b = bcontent[i];
 173  181
             out.write(b, 0, b.length);
 174  181
             teC._lineNo = this.getLineNo(i);
 175  181
             teC._columnNo = this.getColNo(i);
 176  181
             _macros[i++].write(out, context);
 177  181
             b = bcontent[i];
 178  181
             out.write(b, 0, b.length);
 179  181
             teC._lineNo = this.getLineNo(i);
 180  181
             teC._columnNo = this.getColNo(i);
 181  181
             _macros[i++].write(out, context);
 182  181
             b = bcontent[i];
 183  181
             out.write(b, 0, b.length);
 184  181
             teC._lineNo = this.getLineNo(i);
 185  181
             teC._columnNo = this.getColNo(i);
 186  181
             _macros[i++].write(out, context);
 187  181
             b = bcontent[i];
 188  181
             out.write(b, 0, b.length);
 189  181
             teC._lineNo = this.getLineNo(i);
 190  181
             teC._columnNo = this.getColNo(i);
 191  181
             _macros[i++].write(out, context);
 192  181
             b = bcontent[i];
 193  181
             out.write(b, 0, b.length);
 194  181
             teC._lineNo = this.getLineNo(i);
 195  181
             teC._columnNo = this.getColNo(i);
 196  181
             _macros[i++].write(out, context);
 197  181
             b = bcontent[i];
 198  181
             out.write(b, 0, b.length);
 199  181
             teC._lineNo = this.getLineNo(i);
 200  181
             teC._columnNo = this.getColNo(i);
 201  181
             _macros[i++].write(out, context);
 202  181
             b = bcontent[i];
 203  181
             out.write(b, 0, b.length);
 204  181
             teC._lineNo = this.getLineNo(i);
 205  181
             teC._columnNo = this.getColNo(i);
 206  181
             _macros[i++].write(out, context);
 207  181
             b = bcontent[i];
 208  181
             out.write(b, 0, b.length);
 209  181
             teC._lineNo = this.getLineNo(i);
 210  181
             teC._columnNo = this.getColNo(i);
 211  181
             _macros[i++].write(out, context);
 212  181
             b = bcontent[i];
 213  181
             out.write(b, 0, b.length);
 214  181
             teC._lineNo = this.getLineNo(i);
 215  181
             teC._columnNo = this.getColNo(i);
 216  181
             _macros[i++].write(out, context);
 217  181
             b = bcontent[i];
 218  181
             out.write(b, 0, b.length);
 219  181
             teC._lineNo = this.getLineNo(i);
 220  181
             teC._columnNo = this.getColNo(i);
 221  181
             _macros[i++].write(out, context);
 222  
         }
 223  6900
         b = bcontent[_length];
 224  6900
         out.write(b, 0, b.length);
 225  6900
         teC._templateName = oldName;
 226  6900
     }
 227  
 
 228  
     public String getTemplateName ()
 229  
     {
 230  0
         return _name;
 231  
     }
 232  
 
 233  
     public void setTemplateName (String name)
 234  
     {
 235  23
         _name = name;
 236  23
     }
 237  
 
 238  
     public int getLineNo (int i)
 239  
     {
 240  9158
         return (_lineNos != null && i >= 0 && _lineNos.length > i) ? _lineNos[i] : 0;
 241  
     }
 242  
 
 243  
     public int getColNo (int i)
 244  
     {
 245  9158
         return (_colNos != null && i >= 0 && _colNos.length > i) ? _colNos[i] : 0;
 246  
     }
 247  
 
 248  
     private static class BlockIterator implements BlockBuilder.BlockIterator
 249  
     {
 250  
 
 251  116
         private int i = 0;
 252  116
         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  116
         {
 259  116
             this.strings = strings;
 260  116
             this.macros = macros;
 261  116
             this.block = b;
 262  116
         }
 263  
 
 264  
         public boolean hasNext ()
 265  
         {
 266  680
             return !done;
 267  
         }
 268  
 
 269  
         public String getName ()
 270  
         {
 271  0
             return block.getTemplateName();
 272  
         }
 273  
 
 274  
         public int getLineNo ()
 275  
         {
 276  83
             return block.getLineNo(i - 1);
 277  
         }
 278  
 
 279  
         public int getColNo ()
 280  
         {
 281  83
             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  282
             if (doneString)
 292  
             {
 293  83
                 doneString = false;
 294  83
                 return macros[i++];
 295  
             }
 296  
             else
 297  
             {
 298  199
                 if (i == strings.length - 1)
 299  116
                     done = true;
 300  199
                 doneString = true;
 301  199
                 return strings[i];
 302  
             }
 303  
         }
 304  
     }
 305  
 
 306  
     public BlockBuilder.BlockIterator getBlockIterator ()
 307  
     {
 308  116
         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  93
             FastWriter fw = FastWriter.getInstance(context.getBroker());
 343  93
             write(fw, context);
 344  93
             String ret = fw.toString();
 345  93
             fw.close();
 346  93
             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