Author: tchemit Date: 2008-04-19 18:39:07 +0000 (Sat, 19 Apr 2008) New Revision: 598 Modified: trunk/lutinui/src/main/java/org/codelutin/ui/DialogUIDef.java trunk/lutinui/src/main/java/org/codelutin/ui/DialogUIHandler.java trunk/lutinui/src/main/java/org/codelutin/ui/DialogUIModel.java trunk/lutinui/src/main/java/org/codelutin/ui/UIFactory.java trunk/lutinui/src/main/java/org/codelutin/ui/UIProvider.java Log: mise en place provider sur ui parametrable par nom d'application refactoring UIFactory: le ServiceLoader n'est pas conserv?\195?\169 Modified: trunk/lutinui/src/main/java/org/codelutin/ui/DialogUIDef.java =================================================================== --- trunk/lutinui/src/main/java/org/codelutin/ui/DialogUIDef.java 2008-04-19 18:31:55 UTC (rev 597) +++ trunk/lutinui/src/main/java/org/codelutin/ui/DialogUIDef.java 2008-04-19 18:39:07 UTC (rev 598) @@ -14,13 +14,32 @@ */ package org.codelutin.ui; -/** @author chemit */ -public class DialogUIDef<M extends DialogUIModel, U extends DialogUI<?>, H extends DialogUIHandler<M, U>> { +/** + * Definition of an ui, with his model, handler and ui class definitions. + * <p/> + * The class contains also a shared instace of concrete ui. + * + * @author chemit + */ +public class DialogUIDef<M extends DialogUIModel, U extends DialogUI<H>, H extends DialogUIHandler<M, U>> implements java.io.Serializable { - private final Class<U> uiClass; + /** model class */ private final Class<M> modelClass; + + /** handler class */ private final Class<H> handlerClass; + /** abstract ui class */ + private final Class<U> uiClass; + + /** concrete lookup ui class */ + private Class<? extends U> uiImplClass; + + /** shared instance of ui */ + protected U uiInstance; + + private static final long serialVersionUID = 1L; + public DialogUIDef(Class<H> handlerClass, Class<U> uiClass, Class<M> modelClass) { this.handlerClass = handlerClass; this.uiClass = uiClass; @@ -39,10 +58,18 @@ return modelClass; } + public Class<? extends U> getUiImplClass() { + return uiImplClass; + } + + @SuppressWarnings({"unchecked"}) + public void setUiImplClass(Class<?> uiImplClass) { + this.uiImplClass = (Class<? extends U>) uiImplClass; + } + @Override public boolean equals(Object o) { return this == o || o instanceof DialogUIDef && uiClass.equals(((DialogUIDef) o).uiClass); - } @Override @@ -52,6 +79,35 @@ @Override public String toString() { - return super.toString() + "<model:" + modelClass + ", ui:" + uiClass + ", handler:" + handlerClass + '>'; + StringBuilder sb = new StringBuilder(super.toString()).append('<'); + sb.append(printClass("handler", handlerClass, true)); + sb.append(printClass("model", modelClass, true)); + sb.append(printClass("ui", uiClass, true)); + sb.append(printClass("uiImpl", uiImplClass, false)); + return sb.toString(); } + + protected U getUiInstance() { + if (uiInstance == null) { + if (uiImplClass == null) { + throw new IllegalStateException("no concrete ui impl found in " + this); + } + synchronized (this) { + try { + uiInstance = uiImplClass.newInstance(); + } catch (Exception e) { + throw new IllegalStateException("could not instanciate ui " + this); + } + } + } + return uiInstance; + } + + protected void setUiInstance(U uiInstance) { + this.uiInstance = uiInstance; + } + + protected String printClass(String s, Class<?> aClass, boolean notLast) { + return s + ':' + (aClass == null ? null : aClass.getSimpleName()) + (notLast ? ", " : ">"); + } } Modified: trunk/lutinui/src/main/java/org/codelutin/ui/DialogUIHandler.java =================================================================== --- trunk/lutinui/src/main/java/org/codelutin/ui/DialogUIHandler.java 2008-04-19 18:31:55 UTC (rev 597) +++ trunk/lutinui/src/main/java/org/codelutin/ui/DialogUIHandler.java 2008-04-19 18:39:07 UTC (rev 598) @@ -17,6 +17,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import java.awt.event.WindowListener; import java.beans.PropertyChangeListener; /** @@ -55,6 +56,15 @@ } public void dispose() { - model.removePropertyChangeListener(this); + model.dispose(); + for (WindowListener windowListener : getUi().getWindowListeners()) { + getUi().removeWindowListener(windowListener); + } } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + dispose(); + } } \ No newline at end of file Modified: trunk/lutinui/src/main/java/org/codelutin/ui/DialogUIModel.java =================================================================== --- trunk/lutinui/src/main/java/org/codelutin/ui/DialogUIModel.java 2008-04-19 18:31:55 UTC (rev 597) +++ trunk/lutinui/src/main/java/org/codelutin/ui/DialogUIModel.java 2008-04-19 18:39:07 UTC (rev 598) @@ -82,4 +82,16 @@ } changeSupport.firePropertyChange(propertyName, oldValue, newValue); } + + public void dispose() { + for (PropertyChangeListener listener : changeSupport.getPropertyChangeListeners()) { + changeSupport.removePropertyChangeListener(listener); + } + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + dispose(); + } } \ No newline at end of file Modified: trunk/lutinui/src/main/java/org/codelutin/ui/UIFactory.java =================================================================== --- trunk/lutinui/src/main/java/org/codelutin/ui/UIFactory.java 2008-04-19 18:31:55 UTC (rev 597) +++ trunk/lutinui/src/main/java/org/codelutin/ui/UIFactory.java 2008-04-19 18:39:07 UTC (rev 598) @@ -16,18 +16,16 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.codelutin.util.ListenerSet; import org.codelutin.util.StringUtil; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.lang.reflect.InvocationTargetException; -import java.util.HashMap; -import java.util.Map; +import javax.swing.event.EventListenerList; +import java.lang.reflect.Constructor; +import java.util.ArrayList; +import java.util.List; import java.util.ServiceLoader; /** - * Factory if VCS UI, using a cache. + * Factory for UI, using a cache and aprovider to find ui implementations. * * @author chemit */ @@ -35,95 +33,132 @@ static protected final Log log = LogFactory.getLog(UIFactory.class); - protected static UIFactory instance; + private final String applicationName; - protected Map<DialogUIDef, DialogUI> cache; + private final DialogUIDef[] defs; - protected ServiceLoader<UIProvider> loader; + private final EventListenerList listeners; - protected String applicationName; - - protected ListenerSet<FactoryWindowListener> listeners; - - public static void initFactory(String applicationName, FactoryWindowListener... listeners) { - UIFactory factory = getInstance(); - synchronized (factory) { - factory.applicationName = applicationName; - for (FactoryWindowListener listener : listeners) { - listener.setFactory(factory); - factory.addFactoryWindowListener(listener); + public UIFactory(String applicationName, DialogUIDef[] defs, FactoryWindowListener... listeners) { + this.applicationName = applicationName; + this.listeners = new EventListenerList(); + for (FactoryWindowListener listener : listeners) { + listener.setFactory(this); + addFactoryWindowListener(listener); + } + this.defs = defs; + long t0 = System.nanoTime(); + if (log.isDebugEnabled()) { + log.debug("start at " + new java.util.Date()); + } + try { + init(); + } catch (Exception e) { + log.error(e); + throw new RuntimeException(e); + } finally { + if (log.isDebugEnabled()) { + log.info("end in " + StringUtil.convertTime(t0, System.nanoTime())); } } } public void addFactoryWindowListener(FactoryWindowListener l) { - listeners.add(l); + listeners.add(FactoryWindowListener.class, l); + if (log.isDebugEnabled()) { + log.debug("after added (" + listeners.getListenerCount() + ") : " + l); + } } public void removeFactoryWindowListener(FactoryWindowListener l) { - listeners.remove(l); + listeners.remove(FactoryWindowListener.class, l); + for (DialogUIDef def : getDefs()) { + if (def.uiInstance != null) { + def.uiInstance.removeWindowListener(l); + } + } + if (log.isDebugEnabled()) { + log.debug(" after removed (" + listeners.getListenerCount() + ") : " + l); + } + if (listeners.getListenerCount(FactoryWindowListener.class) == 0) { + // close for real factory + close(); + } } public void close() { - if (cache != null) { - cache.clear(); - cache = null; + log.info(this + " at " + new java.util.Date()); + for (DialogUIDef<?, ?, ?> def : defs) { + DialogUI<?> ui = def.uiInstance; + if (ui != null) { + ui.getHandler().dispose(); + def.uiInstance = null; + } } - if (loader != null) { - loader.reload(); - loader = null; + if (listeners.getListenerCount(FactoryWindowListener.class) > 0) { + log.warn("some listeners where not properly removed, force deletion..."); + for (FactoryWindowListener listener : listeners.getListeners(FactoryWindowListener.class)) { + removeFactoryWindowListener(listener); + } } - while (listeners.size() > 0) { - removeFactoryWindowListener(listeners.iterator().next()); - } } - protected static UIFactory getInstance() { - if (instance == null) { - instance = new UIFactory(); + protected void init() { + + UIProvider[] providers = detectProviders(); + + for (DialogUIDef<?, ?, ?> def : defs) { + initDef(providers, def); + if (def.getUiImplClass() == null) { + throw new IllegalStateException("could not find implementation for ui def " + def); + } } - return instance; } - @Override - protected void finalize() throws Throwable { - super.finalize(); - close(); - } - - protected synchronized Map<DialogUIDef, DialogUI> getCache() { - if (cache == null) { - cache = new HashMap<DialogUIDef, DialogUI>(); + protected void initDef(UIProvider[] providers, DialogUIDef<?, ?, ?> def) { + for (UIProvider provider : providers) { + Class<?> uiImplClass = provider.findUIImplementation(def); + if (uiImplClass != null) { + if (log.isDebugEnabled()) { + log.debug("init done for " + def); + } + // ui implementation was found + break; + } } - return cache; } - protected synchronized ServiceLoader<UIProvider> getProviders() { - checkInit(); - if (loader == null) { - long t0 = System.nanoTime(); - - loader = ServiceLoader.load(UIProvider.class); - int nb = 0; - for (UIProvider provider : loader) { - log.info(provider.getName() + " [" + provider + ']'); - nb++; + protected UIProvider[] detectProviders() { + long t0 = System.nanoTime(); + List<UIProvider> providers = new ArrayList<UIProvider>(); + for (UIProvider provider : ServiceLoader.load(UIProvider.class)) { + if (applicationName.equals(provider.getApplicationName())) { + if (log.isDebugEnabled()) { + log.debug("provider detected [" + provider + ']'); + } + providers.add(provider); } - log.info("found " + nb + " ui provider(s) in " + StringUtil.convertTime(t0, System.nanoTime())); } - return loader; + log.info("found " + providers.size() + " ui provider(s) in " + StringUtil.convertTime(t0, System.nanoTime()) + " : " + providers); + return providers.toArray(new UIProvider[providers.size()]); } - protected DialogUI newUI(DialogUIDef uiType) { + protected DialogUIDef[] getDefs() { + return defs; + } - DialogUI result = getInstance().getCache().get(uiType); + @Override + protected void finalize() throws Throwable { + super.finalize(); + close(); + } + + protected <M extends DialogUIModel, U extends DialogUI<H>, H extends DialogUIHandler<M, U>> U getUI(DialogUIDef<M, U, H> uiType, Object... params) { + U result = uiType.uiInstance; if (result == null) { try { - getCache().put(uiType, result = newUI0(uiType)); - for (FactoryWindowListener listener : listeners) { - result.addWindowListener(listener); - } + result = newUI(uiType, params); } catch (Exception e) { throw new IllegalStateException("could not instanciate ui handler " + uiType + " for reason : " + e.getMessage()); } @@ -131,88 +166,37 @@ return result; } - protected DialogUI newUI0(DialogUIDef uiType, Object... params) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { - for (UIProvider provider : getProviders()) { - DialogUI ui = provider.newUI(uiType); - if (ui != null) { - Class<?>[] prototype = getHandlerPrototype(ui.getClass(), params); - Object[] parameters = getHandlerParameters(ui, params); - uiType.getHandlerClass().getConstructor(prototype).newInstance(ui, parameters); - ui.getHandler().init(); - return ui; + protected <M extends DialogUIModel, U extends DialogUI<H>, H extends DialogUIHandler<M, U>> U newUI(DialogUIDef<M, U, H> uiType, Object... params) throws IllegalStateException { + U ui = uiType.getUiInstance(); + if (ui != null) { + Object[] parameters = getHandlerParameters(ui, params); + try { + Constructor<?> hConstructor = uiType.getHandlerClass().getConstructors()[0]; + hConstructor.newInstance(parameters); + } catch (Exception e) { + throw new IllegalStateException("could not init ui " + uiType + " for reason :" + e.getMessage(), e); } + ui.getHandler().init(); + registerUI(ui); + return ui; } throw new IllegalStateException("could not find ui " + uiType); } - protected UIFactory() { - listeners = new ListenerSet<FactoryWindowListener>(); - } - - protected Class<?>[] getHandlerPrototype(Class<? extends DialogUI> aClass, Object[] params) { - Class<?>[] classes = new Class<?>[1 + params.length]; - classes[0] = aClass.getSuperclass(); - for (int i = 0; i < params.length; i++) { - classes[i + 1] = params[i].getClass(); + protected <U extends DialogUI> void registerUI(U ui) { + for (FactoryWindowListener listener : listeners.getListeners(FactoryWindowListener.class)) { + if (log.isDebugEnabled()) { + log.debug("----- addFactoryWindowListener " + listener + " to " + ui); + } + ui.addWindowListener(listener); } - return classes; } protected Object[] getHandlerParameters(DialogUI ui, Object[] params) { - Object[] classes = new Object[1 + params.length]; - classes[0] = ui; - System.arraycopy(params, 0, classes, 1, params.length); - return classes; + Object[] result = new Object[1 + params.length]; + result[0] = ui; + System.arraycopy(params, 0, result, 1, params.length); + return result; } - private void checkInit() throws IllegalStateException { - if (applicationName == null) { - throw new IllegalStateException("factory " + this + " was not init "); - } - } - - public static abstract class FactoryWindowListener extends WindowAdapter { - - protected abstract void allWindowsClosed(); - - private UIFactory factory; - - private boolean wasClosed; - - public UIFactory getFactory() { - return factory; - } - - public void setFactory(UIFactory factory) { - this.factory = factory; - } - - @Override - public void windowClosed(WindowEvent e) { - if (log.isDebugEnabled()) { - log.debug(e.getSource()); - } - if (e.getWindow().isVisible()) { - // only deal with real closed and none visible windows... - return; - } - for (DialogUI vcsui : factory.getCache().values()) { - if (vcsui.isVisible()) { - // at least one ui visible, do not kill connexions - return; - } - } - if (wasClosed) { - // make sure to process once - return; - } - synchronized (this) { - try { - allWindowsClosed(); - } finally { - wasClosed = true; - } - } - } - } } \ No newline at end of file Modified: trunk/lutinui/src/main/java/org/codelutin/ui/UIProvider.java =================================================================== --- trunk/lutinui/src/main/java/org/codelutin/ui/UIProvider.java 2008-04-19 18:31:55 UTC (rev 597) +++ trunk/lutinui/src/main/java/org/codelutin/ui/UIProvider.java 2008-04-19 18:39:07 UTC (rev 598) @@ -21,20 +21,19 @@ protected String applicationName; /** the name of ui implementation used by this provider */ - protected String name; + protected String providerName; /** array of ui implementations */ protected Class<?>[] implementations; - protected UIProvider(String applicationName, String name, Class<?>... implementations) { + protected UIProvider(String applicationName, String providerName, Class<?>... implementations) { this.applicationName = applicationName; - this.name = name; + this.providerName = providerName; this.implementations = implementations; } - /** @return the identifier of the ui provider (eg jaxx, swing, ...) */ - public String getName() { - return name; + public String getProviderName() { + return providerName; } public String getApplicationName() { @@ -45,24 +44,43 @@ return implementations; } - public <U extends DialogUI<?>, D extends DialogUIDef<?, U, ?>> U newUI(D def) throws InstantiationException, IllegalAccessException { - Class<U> uiImpl = finImpl(def.getUiClass()); - return uiImpl != null ? uiImpl.newInstance() : null; + public Class<?> findUIImplementation(DialogUIDef<?, ?, ?> def) { + Class<? extends DialogUI<?>> uiClass = def.getUiClass(); + for (Class<?> klass : implementations) { + if (uiClass.isAssignableFrom(klass)) { + def.setUiImplClass(klass); + return klass; + } + } + return null; } @Override public String toString() { - return super.toString() + " application:" + applicationName + ", provider:" + name + ", uis:" + (java.util.Arrays.toString(implementations)); + StringBuilder sb = new StringBuilder(super.toString()).append('<'); + sb.append(printClass("application", applicationName, true)); + sb.append(printClass("provider", providerName, true)); + sb.append(printClass("uis", implementations.length, false)); + return sb.toString(); } - @SuppressWarnings({"unchecked"}) - private <X extends DialogUI> Class<X> finImpl(Class<X> uiType) { - for (Class<?> klass : implementations) { - if (uiType.isAssignableFrom(klass)) { - return (Class<X>) klass; - } - } - return null; + protected String printClass(String s, Object aClass, boolean notLast) { + return s + ':' + (aClass == null ? null : aClass) + (notLast ? ", " : ">"); } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof UIProvider)) return false; + + UIProvider that = (UIProvider) o; + return applicationName.equals(that.applicationName) && providerName.equals(that.providerName); + + } + + @Override + public int hashCode() { + return (31 * applicationName.hashCode()) + providerName.hashCode(); + } + } \ No newline at end of file