1 package freemarker.debug.impl; 2 3 import java.rmi.RemoteException; 4 import java.util.ArrayList; 5 import java.util.Arrays; 6 import java.util.Collection; 7 import java.util.Collections; 8 import java.util.Iterator; 9 import java.util.List; 10 11 import freemarker.cache.CacheStorage; 12 import freemarker.cache.SoftCacheStorage; 13 import freemarker.core.Configurable; 14 import freemarker.core.Environment; 15 import freemarker.debug.DebugModel; 16 import freemarker.debug.DebuggedEnvironment; 17 import freemarker.ext.util.IdentityHashMap; 18 import freemarker.template.Configuration; 19 import freemarker.template.SimpleCollection; 20 import freemarker.template.SimpleScalar; 21 import freemarker.template.Template; 22 import freemarker.template.TemplateCollectionModel; 23 import freemarker.template.TemplateHashModelEx; 24 import freemarker.template.TemplateModel; 25 import freemarker.template.TemplateModelException; 26 import freemarker.template.utility.UndeclaredThrowableException; 27 28 /** 29 * @author Attila Szegedi 30 * @version $Id: RmiDebuggedEnvironmentImpl.java,v 1.3.2.2 2006/11/27 07:55:17 szegedia Exp $ 31 */ 32 class RmiDebuggedEnvironmentImpl 33 extends 34 RmiDebugModelImpl 35 implements 36 DebuggedEnvironment 37 { 38 private static final long serialVersionUID = 1L; 39 40 private static final CacheStorage storage = new SoftCacheStorage(new IdentityHashMap()); 41 private static final Object idLock = new Object(); 42 private static long nextId = 1; 43 44 private boolean stopped = false; 45 private final long id; 46 47 private RmiDebuggedEnvironmentImpl(Environment env) throws RemoteException 48 { 49 super(new DebugEnvironmentModel(env), DebugModel.TYPE_ENVIRONMENT); 50 synchronized(idLock) 51 { 52 id = nextId++; 53 } 54 } 55 56 static synchronized Object getCachedWrapperFor(Object key) 57 throws 58 RemoteException 59 { 60 Object value = storage.get(key); 61 if(value == null) 62 { 63 if(key instanceof TemplateModel) 64 { 65 int extraTypes; 66 if(key instanceof DebugConfigurationModel) 67 { 68 extraTypes = DebugModel.TYPE_CONFIGURATION; 69 } 70 else if(key instanceof DebugTemplateModel) 71 { 72 extraTypes = DebugModel.TYPE_TEMPLATE; 73 } 74 else 75 { 76 extraTypes = 0; 77 } 78 value = new RmiDebugModelImpl((TemplateModel)key, extraTypes); 79 } 80 else if(key instanceof Environment) 81 { 82 value = new RmiDebuggedEnvironmentImpl((Environment)key); 83 } 84 else if(key instanceof Template) 85 { 86 value = new DebugTemplateModel((Template)key); 87 } 88 else if(key instanceof Configuration) 89 { 90 value = new DebugConfigurationModel((Configuration)key); 91 } 92 } 93 return value; 94 } 95 96 public void resume() 97 { 98 synchronized(this) 99 { 100 notify(); 101 } 102 } 103 104 public void stop() 105 { 106 stopped = true; 107 resume(); 108 } 109 110 public long getId() 111 { 112 return id; 113 } 114 115 boolean isStopped() 116 { 117 return stopped; 118 } 119 120 private abstract static class DebugMapModel implements TemplateHashModelEx 121 { 122 public int size() 123 { 124 return keySet().size(); 125 } 126 127 public TemplateCollectionModel keys() 128 { 129 return new SimpleCollection(keySet()); 130 } 131 132 public TemplateCollectionModel values() throws TemplateModelException 133 { 134 Collection keys = keySet(); 135 List list = new ArrayList(keys.size()); 136 137 for(Iterator it = keys.iterator(); it.hasNext();) 138 { 139 list.add(get((String)it.next())); 140 } 141 return new SimpleCollection(list); 142 } 143 144 public boolean isEmpty() 145 { 146 return size() == 0; 147 } 148 149 abstract Collection keySet(); 150 151 static List composeList(Collection c1, Collection c2) 152 { 153 List list = new ArrayList(c1); 154 list.addAll(c2); 155 Collections.sort(list); 156 return list; 157 } 158 } 159 160 private static class DebugConfigurableModel extends DebugMapModel 161 { 162 static final List KEYS = Arrays.asList(new String[] 163 { 164 Configurable.ARITHMETIC_ENGINE_KEY, 165 Configurable.BOOLEAN_FORMAT_KEY, 166 Configurable.CLASSIC_COMPATIBLE_KEY, 167 Configurable.LOCALE_KEY, 168 Configurable.NUMBER_FORMAT_KEY, 169 Configurable.OBJECT_WRAPPER_KEY, 170 Configurable.TEMPLATE_EXCEPTION_HANDLER_KEY 171 }); 172 173 final Configurable configurable; 174 175 DebugConfigurableModel(Configurable configurable) 176 { 177 this.configurable = configurable; 178 } 179 180 Collection keySet() 181 { 182 return KEYS; 183 } 184 185 public TemplateModel get(String key) throws TemplateModelException 186 { 187 String s = configurable.getSetting(key); 188 return s == null ? null : new SimpleScalar(s); 189 } 190 191 } 192 193 private static class DebugConfigurationModel extends DebugConfigurableModel 194 { 195 private static final List KEYS = composeList(DebugConfigurableModel.KEYS, Collections.singleton("sharedVariables")); 196 197 private TemplateModel sharedVariables = new DebugMapModel() 198 { 199 Collection keySet() 200 { 201 return ((Configuration)configurable).getSharedVariableNames(); 202 } 203 204 public TemplateModel get(String key) 205 { 206 return ((Configuration)configurable).getSharedVariable(key); 207 } 208 }; 209 210 DebugConfigurationModel(Configuration config) 211 { 212 super(config); 213 } 214 215 Collection keySet() 216 { 217 return KEYS; 218 } 219 220 public TemplateModel get(String key) throws TemplateModelException 221 { 222 if("sharedVariables".equals(key)) 223 { 224 return sharedVariables; 225 } 226 else 227 { 228 return super.get(key); 229 } 230 } 231 } 232 233 private static class DebugTemplateModel extends DebugConfigurableModel 234 { 235 private static final List KEYS = composeList(DebugConfigurableModel.KEYS, 236 Arrays.asList(new String[] { 237 "configuration", 238 "name", 239 })); 240 241 private final SimpleScalar name; 242 243 DebugTemplateModel(Template template) 244 { 245 super(template); 246 this.name = new SimpleScalar(template.getName()); 247 } 248 249 Collection keySet() 250 { 251 return KEYS; 252 } 253 254 public TemplateModel get(String key) throws TemplateModelException 255 { 256 if("configuration".equals(key)) 257 { 258 try 259 { 260 return (TemplateModel)getCachedWrapperFor(((Template)configurable).getConfiguration()); 261 } 262 catch (RemoteException e) 263 { 264 throw new TemplateModelException(e); 265 } 266 } 267 if("name".equals(key)) 268 { 269 return name; 270 } 271 return super.get(key); 272 } 273 } 274 275 private static class DebugEnvironmentModel extends DebugConfigurableModel 276 { 277 private static final List KEYS = composeList(DebugConfigurableModel.KEYS, 278 Arrays.asList(new String[] { 279 "currentNamespace", 280 "dataModel", 281 "globalNamespace", 282 "knownVariables", 283 "mainNamespace", 284 "template", 285 })); 286 287 private TemplateModel knownVariables = new DebugMapModel() 288 { 289 Collection keySet() 290 { 291 try 292 { 293 return ((Environment)configurable).getKnownVariableNames(); 294 } 295 catch (TemplateModelException e) 296 { 297 throw new UndeclaredThrowableException(e); 298 } 299 } 300 301 public TemplateModel get(String key) throws TemplateModelException 302 { 303 return ((Environment)configurable).getVariable(key); 304 } 305 }; 306 307 DebugEnvironmentModel(Environment env) 308 { 309 super(env); 310 } 311 312 Collection keySet() 313 { 314 return KEYS; 315 } 316 317 public TemplateModel get(String key) throws TemplateModelException 318 { 319 if("currentNamespace".equals(key)) 320 { 321 return ((Environment)configurable).getCurrentNamespace(); 322 } 323 if("dataModel".equals(key)) 324 { 325 return ((Environment)configurable).getDataModel(); 326 } 327 if("globalNamespace".equals(key)) 328 { 329 return ((Environment)configurable).getGlobalNamespace(); 330 } 331 if("knownVariables".equals(key)) 332 { 333 return knownVariables; 334 } 335 if("mainNamespace".equals(key)) 336 { 337 return ((Environment)configurable).getMainNamespace(); 338 } 339 if("template".equals(key)) 340 { 341 try 342 { 343 return (TemplateModel) getCachedWrapperFor(((Environment)configurable).getTemplate()); 344 } 345 catch (RemoteException e) 346 { 347 throw new TemplateModelException(e); 348 } 349 } 350 return super.get(key); 351 } 352 } 353 }