KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mckoi > database > TriggerManager


1 /**
2  * com.mckoi.database.TriggerManager 02 Oct 2000
3  *
4  * Mckoi SQL Database ( http://www.mckoi.com/database )
5  * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * Version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License Version 2 for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * Version 2 along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  * Change Log:
21  *
22  *
23  */

24
25 package com.mckoi.database;
26
27 import java.util.*;
28 import com.mckoi.util.HashMapList;
29
30 /**
31  * An object that manages high level trigger events within a Database context.
32  * This manager is designed to manage the map between session and triggers
33  * being listened for. It is the responsibility of the language parsing
34  * layer to notify this manager of trigger events.
35  * <p>
36  * NOTE: It is intended that this object manages events from the highest layer,
37  * so it is possible that trigger events may not get to be notified if
38  * queries are not evaluated properly.
39  * <p>
40  * NOTE: This object serves a different purpose than DataTableListener.
41  * DataTableListener is guarenteed to pick up all low level access to the
42  * tables. This object is only intended as a helper for implementing a
43  * trigger event dispatcher by a higher level package (eg.
44  * com.mckoi.database.sql)
45  * <p>
46  * CONCURRENCY: This class is thread safe. It may safely be accessed by
47  * multiple threads. Any events that are fired are put on the
48  * DatabaseDispatcher thread.
49  *
50  * @author Tobias Downer
51  */

52
53 final class TriggerManager {
54
55   /**
56    * The parent TransactionSystem object.
57    */

58   private TransactionSystem system;
59
60   /**
61    * Maps from the user session (User) to the list of TriggerAction objects
62    * for this user.
63    */

64   private HashMapList listener_map;
65
66   /**
67    * Maps from the trigger source string to the list of TriggerAction
68    * objects that are listening for events from this source.
69    */

70   private HashMapList table_map;
71
72   /**
73    * Constructor.
74    */

75   TriggerManager(TransactionSystem system) {
76     this.system = system;
77     listener_map = new HashMapList();
78     table_map = new HashMapList();
79   }
80
81   /**
82    * Flushes the list of TriggerEvent objects and dispatches them to the
83    * users that are listening. This is called after the given connection
84    * has successfully committed and closed.
85    */

86   void flushTriggerEvents(final ArrayList event_list) {
87     for (int i = 0; i < event_list.size(); ++i) {
88       TriggerEvent evt = (TriggerEvent) event_list.get(i);
89       fireTrigger(evt);
90     }
91   }
92
93   /**
94    * Adds a listener for an event with the given 'id' for this user session.
95    * <p>
96    * For example,<br>
97    * addTriggerListener(user, "my_trigger",
98    * TriggerEvent.UPDATE, "Part", my_listener);
99    * <p>
100    * This listener is notified of all update events on the 'Part' table.
101    */

102   synchronized void addTriggerListener(DatabaseConnection database,
103                  String JavaDoc trigger_name, int event_id, String JavaDoc trigger_source,
104                                                  TriggerListener listener) {
105
106     // Has this trigger name already been defined for this user?
107
List list = listener_map.get(database);
108     for (int i = 0; i < list.size(); ++i) {
109       TriggerAction action = (TriggerAction) list.get(i);
110       if (action.getName().equals(trigger_name)) {
111         throw new Error JavaDoc("Duplicate trigger name '" + trigger_name + "'");
112       }
113     }
114
115     TriggerAction action = new TriggerAction(database, trigger_name, event_id,
116                                              trigger_source, listener);
117
118     listener_map.put(database, action);
119     table_map.put(trigger_source, action);
120   }
121
122   /**
123    * Removes a trigger for the given user session.
124    */

125   synchronized void removeTriggerListener(DatabaseConnection database,
126                                           String JavaDoc trigger_name) {
127     List list = listener_map.get(database);
128     for (int i = 0; i < list.size(); ++i) {
129       TriggerAction action = (TriggerAction) list.get(i);
130       if (action.getName().equals(trigger_name)) {
131         listener_map.remove(database, action);
132         table_map.remove(action.trigger_source, action);
133         return;
134       }
135     }
136     throw new Error JavaDoc("Trigger name '" + trigger_name + "' not found.");
137   }
138
139   /**
140    * Clears all the user triggers that have been defined.
141    */

142   synchronized void clearAllDatabaseConnectionTriggers(
143                                                DatabaseConnection database) {
144     List list = listener_map.clear(database);
145     for (int i = 0; i < list.size(); ++i) {
146       TriggerAction action = (TriggerAction) list.get(i);
147       table_map.remove(action.trigger_source, action);
148     }
149   }
150
151   /**
152    * Notifies all the listeners on a trigger_source (ie. a table) that a
153    * specific type of event has happened, as denoted by the type.
154    *
155    * @param trigger_source the source of the trigger.
156    * @param trigger_type either INSERT, DELETE or UPDATE
157    * @param fire_count the number of times the trigger was fired for this
158    * event.
159    */

160   private void fireTrigger(final TriggerEvent evt) {
161
162     final ArrayList trig_list;
163     // Get all the triggers for this trigger source,
164
// System.out.println(evt.getSource());
165
// System.out.println(table_map);
166
synchronized (this) {
167       List list = table_map.get(evt.getSource());
168       if (list.size() == 0) {
169         return;
170       }
171       trig_list = new ArrayList(list);
172     }
173
174     // Post an event that fires the triggers for each listener.
175
Runnable JavaDoc runner = new Runnable JavaDoc() {
176       public void run() {
177         for (int i = 0; i < trig_list.size(); ++i) {
178           TriggerAction action = (TriggerAction) trig_list.get(i);
179           if (evt.getType() == action.trigger_event) {
180             action.listener.fireTrigger(action.database, action.trigger_name,
181                                         evt);
182           }
183         }
184       }
185     };
186
187     // Post the event to go off approx 3ms from now.
188
system.postEvent(3, system.createEvent(runner));
189
190   }
191
192   // ---------- Inner classes ----------
193

194   /**
195    * Encapsulates the information of a trigger listener for a specific event
196    * for a user.
197    */

198   private static class TriggerAction {
199
200     private DatabaseConnection database;
201     private String JavaDoc trigger_name; // The name of the trigger.
202
private TriggerListener listener; // The trigger listener.
203
private String JavaDoc trigger_source; // The source of the trigger.
204
private int trigger_event; // Event we are to listen for.
205

206     /**
207      * Constructor.
208      */

209     TriggerAction(DatabaseConnection database, String JavaDoc name, int type,
210                   String JavaDoc trigger_source, TriggerListener listener) {
211       this.database = database;
212       this.trigger_name = name;
213       this.trigger_event = type;
214       this.listener = listener;
215       this.trigger_source = trigger_source;
216     }
217
218     /**
219      * Returns the name of the trigger.
220      */

221     public String JavaDoc getName() {
222       return trigger_name;
223     }
224
225   }
226
227 }
228
Popular Tags