| package freemarker.debug.impl; |
| |
| import java.rmi.Remote; |
| import java.rmi.RemoteException; |
| import java.rmi.server.UnicastRemoteObject; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Set; |
| |
| import freemarker.cache.CacheStorage; |
| import freemarker.cache.SoftCacheStorage; |
| import freemarker.core.Configurable; |
| import freemarker.core.Environment; |
| import freemarker.debug.DebugModel; |
| import freemarker.debug.DebuggedEnvironment; |
| import freemarker.ext.util.IdentityHashMap; |
| import freemarker.template.Configuration; |
| import freemarker.template.SimpleCollection; |
| import freemarker.template.SimpleScalar; |
| import freemarker.template.Template; |
| import freemarker.template.TemplateCollectionModel; |
| import freemarker.template.TemplateHashModelEx; |
| import freemarker.template.TemplateModel; |
| import freemarker.template.TemplateModelException; |
| import freemarker.template.utility.UndeclaredThrowableException; |
| |
| /** |
| * @author Attila Szegedi |
| */ |
| class RmiDebuggedEnvironmentImpl |
| extends |
| RmiDebugModelImpl |
| implements |
| DebuggedEnvironment |
| { |
| private static final long serialVersionUID = 1L; |
| |
| private static final CacheStorage storage = new SoftCacheStorage(new IdentityHashMap()); |
| private static final Object idLock = new Object(); |
| private static long nextId = 1; |
| private static Set remotes = new HashSet(); |
| |
| |
| private boolean stopped = false; |
| private final long id; |
| |
| private RmiDebuggedEnvironmentImpl(Environment env) throws RemoteException |
| { |
| super(new DebugEnvironmentModel(env), DebugModel.TYPE_ENVIRONMENT); |
| synchronized(idLock) |
| { |
| id = nextId++; |
| } |
| } |
| |
| static synchronized Object getCachedWrapperFor(Object key) |
| throws |
| RemoteException |
| { |
| Object value = storage.get(key); |
| if(value == null) |
| { |
| if(key instanceof TemplateModel) |
| { |
| int extraTypes; |
| if(key instanceof DebugConfigurationModel) |
| { |
| extraTypes = DebugModel.TYPE_CONFIGURATION; |
| } |
| else if(key instanceof DebugTemplateModel) |
| { |
| extraTypes = DebugModel.TYPE_TEMPLATE; |
| } |
| else |
| { |
| extraTypes = 0; |
| } |
| value = new RmiDebugModelImpl((TemplateModel)key, extraTypes); |
| } |
| else if(key instanceof Environment) |
| { |
| value = new RmiDebuggedEnvironmentImpl((Environment)key); |
| } |
| else if(key instanceof Template) |
| { |
| value = new DebugTemplateModel((Template)key); |
| } |
| else if(key instanceof Configuration) |
| { |
| value = new DebugConfigurationModel((Configuration)key); |
| } |
| } |
| if(value != null) |
| { |
| storage.put(key, value); |
| } |
| if(value instanceof Remote) |
| { |
| remotes.add(value); |
| } |
| return value; |
| } |
| |
| public void resume() |
| { |
| synchronized(this) |
| { |
| notify(); |
| } |
| } |
| |
| public void stop() |
| { |
| stopped = true; |
| resume(); |
| } |
| |
| public long getId() |
| { |
| return id; |
| } |
| |
| boolean isStopped() |
| { |
| return stopped; |
| } |
| |
| private abstract static class DebugMapModel implements TemplateHashModelEx |
| { |
| public int size() |
| { |
| return keySet().size(); |
| } |
| |
| public TemplateCollectionModel keys() |
| { |
| return new SimpleCollection(keySet()); |
| } |
| |
| public TemplateCollectionModel values() throws TemplateModelException |
| { |
| Collection keys = keySet(); |
| List list = new ArrayList(keys.size()); |
| |
| for(Iterator it = keys.iterator(); it.hasNext();) |
| { |
| list.add(get((String)it.next())); |
| } |
| return new SimpleCollection(list); |
| } |
| |
| public boolean isEmpty() |
| { |
| return size() == 0; |
| } |
| |
| abstract Collection keySet(); |
| |
| static List composeList(Collection c1, Collection c2) |
| { |
| List list = new ArrayList(c1); |
| list.addAll(c2); |
| Collections.sort(list); |
| return list; |
| } |
| } |
| |
| private static class DebugConfigurableModel extends DebugMapModel |
| { |
| static final List KEYS = Arrays.asList(new String[] |
| { |
| Configurable.ARITHMETIC_ENGINE_KEY, |
| Configurable.BOOLEAN_FORMAT_KEY, |
| Configurable.CLASSIC_COMPATIBLE_KEY, |
| Configurable.LOCALE_KEY, |
| Configurable.NUMBER_FORMAT_KEY, |
| Configurable.OBJECT_WRAPPER_KEY, |
| Configurable.TEMPLATE_EXCEPTION_HANDLER_KEY |
| }); |
| |
| final Configurable configurable; |
| |
| DebugConfigurableModel(Configurable configurable) |
| { |
| this.configurable = configurable; |
| } |
| |
| Collection keySet() |
| { |
| return KEYS; |
| } |
| |
| public TemplateModel get(String key) throws TemplateModelException |
| { |
| String s = configurable.getSetting(key); |
| return s == null ? null : new SimpleScalar(s); |
| } |
| |
| } |
| |
| private static class DebugConfigurationModel extends DebugConfigurableModel |
| { |
| private static final List KEYS = composeList(DebugConfigurableModel.KEYS, Collections.singleton("sharedVariables")); |
| |
| private TemplateModel sharedVariables = new DebugMapModel() |
| { |
| Collection keySet() |
| { |
| return ((Configuration)configurable).getSharedVariableNames(); |
| } |
| |
| public TemplateModel get(String key) |
| { |
| return ((Configuration)configurable).getSharedVariable(key); |
| } |
| }; |
| |
| DebugConfigurationModel(Configuration config) |
| { |
| super(config); |
| } |
| |
| Collection keySet() |
| { |
| return KEYS; |
| } |
| |
| public TemplateModel get(String key) throws TemplateModelException |
| { |
| if("sharedVariables".equals(key)) |
| { |
| return sharedVariables; |
| } |
| else |
| { |
| return super.get(key); |
| } |
| } |
| } |
| |
| private static class DebugTemplateModel extends DebugConfigurableModel |
| { |
| private static final List KEYS = composeList(DebugConfigurableModel.KEYS, |
| Arrays.asList(new String[] { |
| "configuration", |
| "name", |
| })); |
| |
| private final SimpleScalar name; |
| |
| DebugTemplateModel(Template template) |
| { |
| super(template); |
| this.name = new SimpleScalar(template.getName()); |
| } |
| |
| Collection keySet() |
| { |
| return KEYS; |
| } |
| |
| public TemplateModel get(String key) throws TemplateModelException |
| { |
| if("configuration".equals(key)) |
| { |
| try |
| { |
| return (TemplateModel)getCachedWrapperFor(((Template)configurable).getConfiguration()); |
| } |
| catch (RemoteException e) |
| { |
| throw new TemplateModelException(e); |
| } |
| } |
| if("name".equals(key)) |
| { |
| return name; |
| } |
| return super.get(key); |
| } |
| } |
| |
| private static class DebugEnvironmentModel extends DebugConfigurableModel |
| { |
| private static final List KEYS = composeList(DebugConfigurableModel.KEYS, |
| Arrays.asList(new String[] { |
| "currentNamespace", |
| "dataModel", |
| "globalNamespace", |
| "knownVariables", |
| "mainNamespace", |
| "template", |
| })); |
| |
| private TemplateModel knownVariables = new DebugMapModel() |
| { |
| Collection keySet() |
| { |
| try |
| { |
| return ((Environment)configurable).getKnownVariableNames(); |
| } |
| catch (TemplateModelException e) |
| { |
| throw new UndeclaredThrowableException(e); |
| } |
| } |
| |
| public TemplateModel get(String key) throws TemplateModelException |
| { |
| return ((Environment)configurable).getVariable(key); |
| } |
| }; |
| |
| DebugEnvironmentModel(Environment env) |
| { |
| super(env); |
| } |
| |
| Collection keySet() |
| { |
| return KEYS; |
| } |
| |
| public TemplateModel get(String key) throws TemplateModelException |
| { |
| if("currentNamespace".equals(key)) |
| { |
| return ((Environment)configurable).getCurrentNamespace(); |
| } |
| if("dataModel".equals(key)) |
| { |
| return ((Environment)configurable).getDataModel(); |
| } |
| if("globalNamespace".equals(key)) |
| { |
| return ((Environment)configurable).getGlobalNamespace(); |
| } |
| if("knownVariables".equals(key)) |
| { |
| return knownVariables; |
| } |
| if("mainNamespace".equals(key)) |
| { |
| return ((Environment)configurable).getMainNamespace(); |
| } |
| if("template".equals(key)) |
| { |
| try |
| { |
| return (TemplateModel) getCachedWrapperFor(((Environment)configurable).getTemplate()); |
| } |
| catch (RemoteException e) |
| { |
| throw new TemplateModelException(e); |
| } |
| } |
| return super.get(key); |
| } |
| } |
| |
| public static void cleanup() { |
| for(Iterator i = remotes.iterator(); i.hasNext();) |
| { |
| Object remoteObject = i.next(); |
| try |
| { |
| UnicastRemoteObject.unexportObject((Remote) remoteObject, true); |
| } |
| catch (Exception e) |
| { |
| } |
| } |
| } |
| } |