Coverage Report - org.webslinger.bsf.Compiler
 
Classes in this File Line Coverage Branch Coverage Complexity
Compiler
64%
32/50
50%
2/4
0
Compiler$1
100%
2/2
N/A
0
Compiler$2
50%
4/8
N/A
0
Compiler$CompilerContext
100%
8/8
N/A
0
Compiler$NameEncoder
90%
18/20
100%
6/6
0
 
 1  
 package org.webslinger.bsf;
 2  
 
 3  
 import java.io.IOException;
 4  
 import java.util.HashMap;
 5  
 import java.util.Iterator;
 6  
 import java.util.Map;
 7  
 import java.util.StringTokenizer;
 8  
 
 9  
 import org.apache.bsf.BSFDeclaredBean;
 10  
 import org.apache.bsf.BSFException;
 11  
 import org.apache.bsf.BSFManager;
 12  
 
 13  
 import org.webslinger.lang.ConcurrentCache;
 14  
 import org.webslinger.util.GeneratedResult;
 15  
 import org.webslinger.util.TTLCachedObject;
 16  
 
 17  
 public abstract class Compiler<V, C> {
 18  
     public class CompilerContext {
 19  281
         public final StringBuilder code = new StringBuilder();
 20  
         public Key<C> key;
 21  
         public String text;
 22  
         public long lastModifiedTime;
 23  
         public BSFDeclaredBean[] beans;
 24  
 
 25  281
         public CompilerContext(Key<C> key) throws BSFException {
 26  281
             this.key = key;
 27  281
             Map<String, BSFDeclaredBean> beans = getBeans();
 28  281
             lastModifiedTime = key.getLastModifiedTime(engine);
 29  281
             this.beans = beans.values().toArray(new BSFDeclaredBean[beans.size()]);
 30  281
             text = filter(this, key.getText(getEngine()));
 31  281
         }
 32  
     }
 33  
 
 34  4
     public static class NameEncoder {
 35  
         public void encodeChar(StringBuilder target, char c, boolean isStart) {
 36  6164
             if (c != '_' && (isStart ? Character.isJavaIdentifierStart(c) : Character.isJavaIdentifierPart(c))) {
 37  5849
                 target.append(c);
 38  
             } else {
 39  315
                 target.append('_').append((int) c).append('$');
 40  
             }
 41  6164
         }
 42  
 
 43  
         public void encodeName(StringBuilder target, String part) {
 44  703
             char[] chars = part.toCharArray();
 45  703
             encodeChar(target, chars[0], true);
 46  6234
             for (int i = 1; i < chars.length; i++) {
 47  5531
                 encodeChar(target, chars[i], false);
 48  
             }
 49  703
         }
 50  
 
 51  
         public void makePackageClassName(StringBuilder packageName, StringBuilder className, String path) {
 52  260
             if (path == null) {
 53  0
                 className.append("ANONYMOUS");
 54  0
                 return;
 55  
             }
 56  520
             while (path.startsWith("/")) path = path.substring(1);
 57  260
             String[] parts = path.split("/");
 58  700
             for (int i = 0; i < parts.length - 1; i++) {
 59  440
                 if (i != 0) packageName.append('.');
 60  440
                 encodeName(packageName, parts[i]);
 61  
             }
 62  260
             encodeName(className, parts[parts.length - 1]);
 63  260
         }
 64  
     }
 65  
 
 66  1
     public static final NameEncoder STANDARD_NAME_ENCODER = new NameEncoder();
 67  
 
 68  
     protected final LanguageEngine engine;
 69  67
     protected final ConcurrentCache<Key<C>, TTLCachedObject<V>> cache = new ConcurrentCache<Key<C>, TTLCachedObject<V>>(getClass(), "cache", null, ConcurrentCache.SOFT) {
 70  
         protected TTLCachedObject<V> createValue(Key<C> frozen) {
 71  277
             return createTTLCachedObject(frozen);
 72  
         }
 73  
     };
 74  
     protected final NameEncoder nameEncoder;
 75  
 
 76  
     protected Compiler(LanguageEngine engine) {
 77  64
         this(engine, STANDARD_NAME_ENCODER);
 78  64
     }
 79  
 
 80  67
     protected Compiler(LanguageEngine engine, NameEncoder nameEncoder) {
 81  67
         this.engine = engine;
 82  67
         this.nameEncoder = nameEncoder;
 83  67
     }
 84  
 
 85  
     protected String filter(CompilerContext context, String text) throws BSFException {
 86  18
         return text;
 87  
     }
 88  
 
 89  
     public LanguageEngine getEngine() {
 90  1493
         return engine;
 91  
     }
 92  
 
 93  
     public void initialize(BSFManager bsfManager) throws BSFException {
 94  42
     }
 95  
 
 96  
     protected Map<String, BSFDeclaredBean> getBeans() {
 97  91
         return getEngine().getBeans();
 98  
     }
 99  
 
 100  
     public void clear() {
 101  1034
         cache.clear();
 102  1034
     }
 103  
 
 104  
     protected TTLCachedObject<V> createTTLCachedObject(final Key<C> key) {
 105  277
         return new TTLCachedObject<V>() {
 106  
             protected long getTTL() {
 107  562
                 return getEngine().getTTL();
 108  
             }
 109  
 
 110  
             protected long getTimestamp(V old) throws IOException {
 111  
                 try {
 112  561
                     return key.getLastModifiedTime(engine);
 113  0
                 } catch (BSFException e) {
 114  0
                     throw (IOException) new IOException(e.getMessage()).initCause(e);
 115  
                 }
 116  
             }
 117  
 
 118  
             protected GeneratedResult<V> generate(V old) throws IOException {
 119  
                 try {
 120  281
                     return regen(key);
 121  0
                 } catch (BSFException e) {
 122  0
                     throw (IOException) new IOException(e.getMessage()).initCause(e);
 123  
                 }
 124  
             }
 125  
         };
 126  
     }
 127  
 
 128  
     public V getObject(Key<C> key) throws BSFException {
 129  
         try {
 130  1466
             return cache.get(key).getObject();
 131  0
         } catch (IOException e) {
 132  0
             Throwable t = e.getCause();
 133  0
             if (t instanceof BSFException) throw (BSFException) t;
 134  0
             if (t != null) throw (BSFException) new BSFException(BSFException.REASON_IO_ERROR, t.getMessage()).initCause(t);
 135  0
             throw (RuntimeException) new RuntimeException(e.getMessage()).initCause(e);
 136  0
         } catch (RuntimeException e) {
 137  0
             throw e;
 138  0
         } catch (Exception e) {
 139  0
             throw (InternalError) new InternalError("SNO: " + e.getMessage()).initCause(e);
 140  
         }
 141  
     }
 142  
 
 143  
     public GeneratedResult<V> regen(Key<C> key) throws BSFException {
 144  
         try {
 145  281
             CompilerContext context = newContext(key);
 146  281
             return new GeneratedResult<V>(context.lastModifiedTime, init(context, compile(context)));
 147  0
         } catch (RuntimeException e) {
 148  0
             throw e;
 149  0
         } catch (Error e) {
 150  0
             throw e;
 151  0
         } catch (BSFException e) {
 152  0
             throw e;
 153  0
         } catch (Throwable t) {
 154  0
             throw (RuntimeException) new RuntimeException(t.getMessage() + '<' + getClass().getName() + '>', t);
 155  
         }
 156  
     }
 157  
 
 158  
     protected C compile(CompilerContext context) throws Throwable {
 159  278
         return context.key.compile(this, context);
 160  
     }
 161  
 
 162  
     protected abstract V init(CompilerContext context, C compiledResult) throws Throwable;
 163  
 
 164  
     public Object wrapForArgs(int i, Object object, Class type) {
 165  5400
         return wrap(object, type);
 166  
     }
 167  
 
 168  
     public Object wrap(Object object, Class type) {
 169  5373
         return object;
 170  
     }
 171  
 
 172  
     public Object unwrap(Object object) {
 173  1455
         return object;
 174  
     }
 175  
 
 176  
     public Object[] newWrapArray(int length) {
 177  0
         return new Object[length];
 178  
     }
 179  
 
 180  
     public Object[] newWrapArray(Object[] array) {
 181  1465
         return array;
 182  
     }
 183  
 
 184  
     protected void appendText(StringBuilder code, String prefix, String text) {
 185  9
         StringTokenizer st = new StringTokenizer(text, "\n", true);
 186  63
         while (st.hasMoreTokens()) {
 187  54
             String part = st.nextToken();
 188  54
             if (part.equals("\n")) {
 189  27
                 code.append('\n');
 190  
             } else {
 191  27
                 code.append(prefix).append(part);
 192  
             }
 193  54
         }
 194  9
     }
 195  
 
 196  
     protected String absolutePath(Key<?> key) throws BSFException, IOException {
 197  190
         return getEngine().getVFSDelegate().absolutePath(key.getId());
 198  
     }
 199  
 
 200  
     public abstract void declareBean(BSFDeclaredBean bean) throws BSFException;
 201  
     public abstract void undeclareBean(BSFDeclaredBean bean) throws BSFException;
 202  
     protected abstract CompilerContext newContext(Key<C> key) throws BSFException;
 203  
     public abstract C compileKey(ApplyKey<C> key, CompilerContext context) throws BSFException;
 204  
     public abstract C compileKey(EvalKey<C> key, CompilerContext context) throws BSFException;
 205  
     public abstract C compileKey(ExecKey<C> key, CompilerContext context) throws BSFException;
 206  
 }