views:

28

answers:

1

I have a class MyModel with a property datalogEnabled (and other ones, but let's start there) that I would like to be able to implement properly for use with UI/view binding.

public class MyModel  { 
    static final String KEY_DATALOG_ENABLED = "datalogEnabled";
    final private PropertyChangeSupport pcs = new PropertyChangeSupport(this); 
    final private Object syncLock = new Object();   
    final private Datalogger datalogger = new Datalogger();

    public void addPropertyChangeListener(PropertyChangeListener pcl)
    {
        this.pcs.addPropertyChangeListener(pcl);
    }
    public void removePropertyChangeListener(PropertyChangeListener pcl)
    {
        this.pcs.removePropertyChangeListener(pcl);
    }    
    public boolean isDatalogEnabled() 
    {
        synchronized (this.syncLock) 
        {
            return this.datalogEnabled; 
        }
    }
    public void setDatalogEnabled(final boolean enable) {
        boolean old;
        synchronized (this.syncLock) {
            old = this.datalogEnabled;
            this.datalogEnabled=enable;             
        }
            /* begin snippet X: this is wrong for threading reasons */
        this.pcs.firePropertyChange(KEY_DATALOG_ENABLED, old, enable);      
            setDatalogEnabledNow(enable);
            /* end snippet X */
    }   
    setDatalogEnabledNow(boolean b)
    {
        this.datalogger.setEnable(b);
    }
    /* other methods */
}

public class Datalogger() { 
    public void setEnable(boolean enable) { ... }
}

Except for snippet X, this seems right, but I'm not sure. What's getting me is that the various ways of accessing/setting/listening to the property may happen on different threads, and what I need to do is to act upon the datalogEnabled property somewhere (do some file I/O) within my Datalogger class, on another thread besides the Swing UI thread, because I don't want the UI thread to be unresponsive.

How can I properly rewrite snippet X?

In my overall program, I have an instance of ExecutorService. I could add an Executor (superclass of ExecutorService) as a constructor parameter in the MyModel class, and do this for snippet X:

this.pcs.firePropertyChange(KEY_DATALOG_ENABLED, old, enable);      
this.executor.execute(new Runnable() {
     @Override public void run() { setDatalogEnabledNow(enable); }
});

Should I put the firePropertyChange call into the deferred Runnable task as well? (is firePropertyChange supposed to be called immediately or after a property change really takes effect)

Or should the Datalogger class have an Executor as well so it can coordinate various tasks?

I'm confused on this one....

+1  A: 

The listeners of a model can be uis components, or domains components. If a listener is a ui component, it must run on the edt, and not if the listener is domain.

The event come from a ui component, or from a domain component. If the event come from a ui component, the fire method is on the edt, and it is not if the event come from a domain.

So it's a little complicated... My opinion is than each listener should work for itself : a ui listener goes on the edt if it is not, and a domain goes not if it is. So the fire method stays on it's original thread.

2 cts.

Istao
so do you mean that `MyModel` should just be a blank state model, and my Datalogger should be a listener to that as well?
Jason S
Yes. In my opinion Datalogger should listen property "datalogEnabled" in MyModel, and all the thread micmac should be in a propertyChange method in Datalogger.
Istao