Source Code Cross Referenced for DataManager.java in  » ERP-CRM-Financial » jmoney » net » sf » jmoney » model2 » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » ERP CRM Financial » jmoney » net.sf.jmoney.model2 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *
003:         *  JMoney - A Personal Finance Manager
004:         *  Copyright (c) 2004 Nigel Westbury <westbury@users.sourceforge.net>
005:         *
006:         *
007:         *  This program is free software; you can redistribute it and/or modify
008:         *  it under the terms of the GNU General Public License as published by
009:         *  the Free Software Foundation; either version 2 of the License, or
010:         *  (at your option) any later version.
011:         *
012:         *  This program is distributed in the hope that it will be useful,
013:         *  but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
015:         *  GNU General Public License for more details.
016:         *
017:         *  You should have received a copy of the GNU General Public License
018:         *  along with this program; if not, write to the Free Software
019:         *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
020:         *
021:         */
022:
023:        package net.sf.jmoney.model2;
024:
025:        import java.lang.ref.WeakReference;
026:        import java.util.Collection;
027:        import java.util.Vector;
028:
029:        import org.eclipse.core.runtime.IAdaptable;
030:        import org.eclipse.swt.events.DisposeEvent;
031:        import org.eclipse.swt.events.DisposeListener;
032:        import org.eclipse.swt.widgets.Control;
033:
034:        /**
035:         * An interface to an object that manages a view on the data.
036:         * This is a base interface that is extended by ISessionManager to
037:         * manage a view of data committed to a datastore and is also
038:         * extended by ITransactionManager to manage a view of uncommitted data.
039:         */
040:        public abstract class DataManager implements  IAdaptable {
041:
042:            private Vector<WeakReference<SessionChangeListener>> sessionChangeListenerRefs = new Vector<WeakReference<SessionChangeListener>>();
043:
044:            private Vector<SessionChangeListener> sessionChangeListeners = new Vector<SessionChangeListener>();
045:
046:            private Vector<SessionChangeFirerListener> sessionChangeFirerListeners = new Vector<SessionChangeFirerListener>();
047:
048:            private boolean sessionFiring = false;
049:
050:            //	private ReferenceQueue referenceQueue = new ReferenceQueue();
051:
052:            public void addChangeListener(SessionChangeListener listener) {
053:                sessionChangeListeners.add(listener);
054:            }
055:
056:            public void removeChangeListener(SessionChangeListener listener) {
057:                sessionChangeListeners.remove(listener);
058:            }
059:
060:            /**
061:             * Adds a change listener.
062:             * <P>
063:             * Adds the listener to the collection of listeners who will be notified
064:             * when a change is made to the version of the datastore as seen through
065:             * this data manager.  Notifications will be sent when either a
066:             * change is committed to this data view by a transaction manager
067:             * or an uncommitted change is made through this data manager.
068:             * <P>
069:             * When listening for changes to a datastore, there are two options.
070:             * If the listener is interested only in receiving committed changes
071:             * then the listener should listen to the Session object or the JMoneyPlugin
072:             * object.  However, if a listener wants to be notified of changes
073:             * made through a transaction manager, even though those changes are
074:             * not committed to the datastore, then the listener should add the
075:             * listener to the transaction manager using this method.
076:             * <P>
077:             * The listener will not recieve any notification at the time a transaction
078:             * is committed as the listener will already have been notified of the
079:             * changes.  Note that there is no support for rollbacks as the transaction
080:             * manager can be just dropped (and garbage collected) without ever having been
081:             * committed, so getting a notification for a change that is never committed is
082:             * not an issue.  Views should do a full refresh if they change the data manager
083:             * through which they are obtaining the data to be shown.
084:             * <P>
085:             * This method maintains only a weak reference to the listener.  Therefore
086:             * the caller MUST maintain a reference to the listener.  If the caller does
087:             * not maintain a reference to the listener then the listener will be garbage
088:             * collected and the caller may wonder why no events are being notified.
089:             */
090:            public void addChangeListenerWeakly(SessionChangeListener listener) {
091:                sessionChangeListenerRefs
092:                        .add(new WeakReference<SessionChangeListener>(listener));
093:            }
094:
095:            /**
096:             * Adds a change listener.
097:             * <P>
098:             * The listener is active only for as long as the given control exists.  When the
099:             * given control is disposed, the listener is removed and will receive no more
100:             * notifications.
101:             * <P>
102:             * This method is generally used when a listener is used to update contents in a
103:             * control.  Typically multiple controls are updated by a listener and the parent
104:             * composite control is passed to this method.
105:             * <P>
106:             * This method creates a strong reference to the listener.  There is thus no need
107:             * for the caller to maintain a reference to the listener.
108:             * 
109:             * @param listener
110:             * @param control
111:             */
112:            public void addChangeListener(final SessionChangeListener listener,
113:                    Control control) {
114:                sessionChangeListeners.add(listener);
115:
116:                // Remove the listener when the given control is disposed.
117:                control.addDisposeListener(new DisposeListener() {
118:                    public void widgetDisposed(DisposeEvent e) {
119:                        sessionChangeListeners.remove(listener);
120:                    }
121:                });
122:            }
123:
124:            public void addSessionChangeFirerListener(
125:                    SessionChangeFirerListener listener) {
126:                sessionChangeFirerListeners.add(listener);
127:            }
128:
129:            public void removeSessionChangeFirerListener(
130:                    SessionChangeFirerListener listener) {
131:                sessionChangeFirerListeners.remove(listener);
132:            }
133:
134:            /**
135:             * Send change notifications to all listeners who are listening for changes
136:             * to the version of the datastore as seen through this data manager.
137:             * <P>
138:             * In practice it is likely that the only listener will be the JMoneyPlugin
139:             * object. Views should all listen to the JMoneyPlugin class for changes to
140:             * the model. The JMoneyPlugin object will pass on events from this session
141:             * object.
142:             * <P>
143:             * Listeners may register directly with a session object. However if they do
144:             * so then they must re-register whenever the session object changes. If a
145:             * viewer wants to listen for changes to a session even if that session is
146:             * not the session currently shown in the workbench then it should register
147:             * with the session object, but if the viewer wants to be told about changes
148:             * to the current workbench window then it should register with the
149:             * JMoneyPlugin object.
150:             * 
151:             * This method is public because the layer above this data manager is
152:             * responsible for calling this method. Only the above layer (code outside
153:             * the data manager) knows, for example, when objectInserted should be
154:             * called.
155:             */
156:            public void fireEvent(ISessionChangeFirer firer) {
157:                sessionFiring = true;
158:
159:                /*
160:                 * Notify listeners who are listening to us using the
161:                 * SessionChangeFirerListener interface.
162:                 */
163:                if (!sessionChangeFirerListeners.isEmpty()) {
164:                    /*
165:                     * Take a copy of the listener list. By doing this we allow
166:                     * listeners to safely add or remove listeners.
167:                     */
168:                    SessionChangeFirerListener listenerArray[] = new SessionChangeFirerListener[sessionChangeFirerListeners
169:                            .size()];
170:                    sessionChangeFirerListeners.copyInto(listenerArray);
171:                    for (int i = 0; i < listenerArray.length; i++) {
172:                        listenerArray[i].sessionChanged(firer);
173:                    }
174:                }
175:
176:                /*
177:                 * Notify listeners who are listening to us using the
178:                 * SessionChangeListener interface.
179:                 */
180:
181:                /*
182:                 * Take a copy of the listener list. By doing this we allow
183:                 * listeners to safely add or remove listeners.
184:                 */
185:                Vector<SessionChangeListener> listenerArray = new Vector<SessionChangeListener>();
186:
187:                for (WeakReference<SessionChangeListener> listenerRef : sessionChangeListenerRefs) {
188:                    SessionChangeListener listener = listenerRef.get();
189:                    if (listener != null) {
190:                        listenerArray.add(listener);
191:                    }
192:                }
193:
194:                for (SessionChangeListener listener : sessionChangeListeners) {
195:                    listenerArray.add(listener);
196:                }
197:
198:                for (SessionChangeListener listener : listenerArray) {
199:                    firer.fire(listener);
200:                }
201:
202:                sessionFiring = false;
203:            }
204:
205:            /**
206:             * This method is used by plug-ins so that they know if
207:             * code is being called from within change notification.
208:             *
209:             * It is important for plug-ins to know this.  Plug-ins
210:             * MUST NOT change the session data while a listener is
211:             * being notified of a change to the datastore.
212:             * This can happen very indirectly.  For example, suppose
213:             * an account is deleted.  The navigation view's listener
214:             * is notified and so removes the account's node from the
215:             * navigation tree.  If an account properties panel is
216:             * open, the panel is destroyed.  Because the panel is
217:             * being destroyed, the control that had the focus is sent
218:             * a 'focus lost' notification.  The 'focus lost' notification
219:             * takes the edited data from the control and writes it to
220:             * the datastore.
221:             * <P>
222:             * Writing data to the datastore during session change notifications
223:             * can cause serious problems.  The data may conflict.  The
224:             * undo/redo operations are almost impossible to manage.
225:             * In the above scenario with the deleted account, an attempt
226:             * is made to update a property for an object that has been
227:             * deleted.  The problems are endless.
228:             * <P>
229:             * It would be good if the datastore simply ignored such changes.
230:             * This would provide more robust support for plug-ins, and plug-ins
231:             * would not have to test this flag.  However, for the time being,
232:             * plug-ins must test this flag and avoid making changes when this
233:             * flag is set.  Plug-ins only need to do this in focus lost events
234:             * as that is the only time I can think of where this problem may
235:             * occur.
236:             *  
237:             * @return true if the session is notifying listeners of
238:             * 			a change to the session data, otherwise false
239:             */
240:            // TODO: Revisit this, especially the last paragraph above.
241:            public boolean isSessionFiring() {
242:                return sessionFiring;
243:            }
244:
245:            /**
246:             * This method is called when a transaction is about to start.
247:             * <P>
248:             * If the datastore is kept in a transactional database then the code
249:             * needed to start a transaction should be put in the implementation
250:             * of this method.
251:             * <P>
252:             * The framework will always call this method, then make changes to
253:             * the datastore, then call <code>commitTransaction</code> within
254:             * a single function call.  The framework also ensures that no events
255:             * are fired between the call to <code>startTransaction</code> and
256:             * the call to <code>commitTransaction</code>.  The implementation of
257:             * this method thus has no need to support or guard against nested
258:             * transactions.
259:             * 
260:             * @see commitTransaction
261:             */
262:            public abstract void startTransaction();
263:
264:            /**
265:             * This method is called when a transaction is to be committed.
266:             * <P>
267:             * If the datastore is kept in a transactional database then the code
268:             * needed to commit the transaction should be put in the implementation
269:             * of this method.
270:             * 
271:             * @see startTransaction
272:             */
273:            public abstract void commitTransaction();
274:
275:            /** Returns the session object.  The session object must be
276:             * non-null.
277:             * 
278:             * @return the session object
279:             */
280:            public abstract Session getSession();
281:
282:            /**
283:             * @param account
284:             * @return
285:             */
286:            public abstract boolean hasEntries(Account account);
287:
288:            /**
289:             * @param account
290:             * @return
291:             */
292:            public abstract Collection<Entry> getEntries(Account account);
293:        }
294:
295:        /*
296:         //@author Santhosh Kumar T - santhosh@in.fiorano.com 
297:         public class WeakPropertyChangeListener implements PropertyChangeListener{ 
298:         WeakReference listenerRef; 
299:         Object src; 
300:        
301:         public WeakPropertyChangeListener(PropertyChangeListener listener, Object src){ 
302:         listenerRef = new WeakReference(listener); 
303:         this.src = src; 
304:         } 
305:        
306:         public void propertyChange(PropertyChangeEvent evt){ 
307:         PropertyChangeListener listener = (PropertyChangeListener)listenerRef.get(); 
308:         if(listener==null){ 
309:         removeListener(); 
310:         }else 
311:         listener.propertyChange(evt); 
312:         } 
313:        
314:         private void removeListener(){ 
315:         try{ 
316:         Method method = src.getClass().getMethod("removePropertyChangeListener" 
317:         , new Class[] {PropertyChangeListener.class}); 
318:         method.invoke(src, new Object[]{ this }); 
319:         } catch(Exception e){ 
320:         e.printStackTrace(); 
321:         } 
322:         } 
323:         }
324:
325:
326:         How to use this:
327:
328:         KeyboardFocusManager focusManager = 
329:         KeyboardFocusManager.getCurrentKeyboardFocusManager(); 
330:        
331:         // instead of registering direclty use weak listener 
332:         // focusManager.addPropertyChangeListener(focusOwnerListener); 
333:        
334:         focusManager.addPropertyChangeListener( 
335:         new WeakPropertyChangeListener(focusOwnerListener, focusManager));
336:
337:
338:         How does this work:
339:
340:         Instead of registering propertyChangeListener directly to keyboardFocusManager, we wrap it inside WeakPropertyChangeListener and register this weak listener to keyboardFocusManager. This weak listener acts a delegate.
341:         It receives the propertyChangeEvents from keyboardFocusManager and delegates it the wrapped listener.
342:
343:         The interesting part of this weak listener, it hold a weakReference to the original propertyChangeListener. so this delegate is eligible for garbage collection which it is no longer reachable via references. When it gets garbage
344:         collection, the weakReference will be pointing to null. On next propertyChangeEvent notification from keyboardFocusManager, it find that the weakReference is pointing to null, and unregisters itself from
345:         keyboardFocusManager. Thus the weak listener will also become eligible for garbage collection in next gc cycle.
346:
347:         This concept is not something new. If you have a habit of looking into swing sources, you will find that AbstractButton actually adds a weak listener to its action. The weak listener class used for this is :
348:         javax.swing.AbstractActionPropertyChangeListener; This class is package-private, so you don't find it in javadoc.
349:
350:         The full-fledged, generic implementation of weak listeners is available in Netbeans OpenAPI: WeakListeners.java . It is worth to have a look at it.
351:
352:         We create a subclass of ReferenceQueue, which will help us in performing such resource cleanup very easily:
353:
354:         //	 @author Santhosh Kumar T - santhosh@in.fiorano.com 
355:         public class ActiveReferenceQueue 
356:         extends ReferenceQueue implements Runnable{ 
357:         private static ActiveReferenceQueue singleton = null; 
358:        
359:         public static ActiveReferenceQueue getInstance(){ 
360:         if(singleton==null) 
361:         singleton = new ActiveReferenceQueue(); 
362:         return singleton; 
363:         } 
364:        
365:         private ActiveReferenceQueue(){ 
366:         Thread t = new Thread(this, "ActiveReferenceQueue"); 
367:         t.setDaemon(false); 
368:         t.start(); 
369:         } 
370:        
371:         public void run(){ 
372:         for(;;){ 
373:         try{ 
374:         Reference ref = super.remove(0); 
375:         if(ref instanceof Runnable){ 
376:         try{ 
377:         ((Runnable)ref).run(); 
378:         } catch(Exception e){ 
379:         e.printStackTrace(); 
380:         } 
381:         } 
382:         } catch(InterruptedException e){ 
383:         e.printStackTrace(); 
384:         } 
385:         } 
386:         } 
387:         } 
388:
389:
390:         ActiveReferenceQueue is a singleton class, and starts a thread when it is instantiated. This thread keeps polling for weakReferences that are eligible for garbage collection, and if those weakReferenes implement Runnable interface, it executes them.
391:
392:         To use this, we can create a subclass of WeakReference implementing Runnable interface, which does the cleanup it run() method.
393:
394:         Let us see how we will change the WeakPropertyChangeListener to use the above reference queue:
395:
396:         //	 @author Santhosh Kumar T - santhosh@in.fiorano.com 
397:         public class WeakPropertyChangeListener implements PropertyChangeListener{ 
398:         WeakReference listenerRef; 
399:         Object src; 
400:        
401:         public WeakPropertyChangeListener(PropertyChangeListener listener, Object src){ 
402:         listenerRef = new ListenerReference(listener, this); 
403:         this.src = src; 
404:         } 
405:        
406:         public void propertyChange(PropertyChangeEvent evt){ 
407:         PropertyChangeListener listener = (PropertyChangeListener)listenerRef.get(); 
408:         if(listener!=null) 
409:         listener.propertyChange(evt); 
410:         } 
411:        
412:         private void removeListener(){ 
413:         try{ 
414:         Method method = src.getClass().getMethod("removePropertyChangeListener" 
415:         , new Class[] {PropertyChangeListener.class}); 
416:         method.invoke(src, new Object[]{ this }); 
417:         } catch(Exception e){ 
418:         e.printStackTrace(); 
419:         } 
420:         } 
421:        
422:         static class ListenerReference extends WeakReference{ 
423:         WeakPropertyChangeListener listener; 
424:        
425:         public ListenerReference(Object ref, WeakPropertyChangeListener listener){ 
426:         super(ref, ActiveReferenceQueue.getInstance()); 
427:         this.listener = listener; 
428:         } 
429:        
430:         public void run(){ 
431:         listener.removeListener(); 
432:         listener = null; 
433:         } 
434:         } 
435:         }
436:         */
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.