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