KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > event > EventBridge


1 /* ====================================================================
2  *
3  * The ObjectStyle Group Software License, version 1.1
4  * ObjectStyle Group - http://objectstyle.org/
5  *
6  * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
7  * of the software. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if any,
22  * must include the following acknowlegement:
23  * "This product includes software developed by independent contributors
24  * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
29  * or promote products derived from this software without prior written
30  * permission. For written permission, email
31  * "andrus at objectstyle dot org".
32  *
33  * 5. Products derived from this software may not be called "ObjectStyle"
34  * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
35  * names without prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals and hosted on ObjectStyle Group web site. For more
53  * information on the ObjectStyle Group, please see
54  * <http://objectstyle.org/>.
55  */

56
57 package org.objectstyle.cayenne.event;
58
59 import java.util.EventListener JavaDoc;
60
61 import org.objectstyle.cayenne.util.IDUtil;
62
63 /**
64  * A bridge between Cayenne EventManager and other possible event sources.
65  * Prime example of using EventBridge is for routing events dispatched locally by EventManager
66  * to the remote JVMs via some transport mechanism (e.g. JMS). EventBridge maintains two
67  * event subjects. A "local" subject - to communicate with local EventManager, and a "remote"
68  * subject - to work with an external events interface.
69  *
70  * <p>If a subclass needs to prepare itself to receive incoming events it should
71  * properly implement <code>startup(EventManager)</code> method.</p>
72  *
73  * <p>This class is an example of the <a HREF="http://en.wikipedia.org/wiki/Bridge_pattern">"bridge"</a>
74  * design pattern, hence the name.
75  * </p>
76  *
77  * @author Andrei Adamchik
78  * @since 1.1
79  */

80 public abstract class EventBridge implements EventListener JavaDoc {
81     public static final String JavaDoc VM_ID = new String JavaDoc(IDUtil.pseudoUniqueByteSequence16());
82     public static final String JavaDoc VM_ID_PROPERRTY = "VM_ID";
83
84     public static final int RECEIVE_LOCAL = 1;
85     public static final int RECEIVE_EXTERNAL = 2;
86     public static final int RECEIVE_LOCAL_EXTERNAL = 3;
87
88     protected String JavaDoc externalSubject;
89     protected EventSubject localSubject;
90     protected EventManager eventManager;
91     protected int mode;
92
93     /**
94      * Performs consistent translation from EventSubjects to a String that can be used
95      * by external transport as subject for distributed communications. Substitutes all
96      * chars that can be incorrectly interpreted by whoever (JNDI, ...?).
97      */

98     public static String JavaDoc convertToExternalSubject(EventSubject localSubject) {
99         char[] chars = localSubject.getSubjectName().toCharArray();
100         for (int i = 0; i < chars.length; i++) {
101             if (chars[i] == '/' || chars[i] == '.') {
102                 chars[i] = '_';
103             }
104         }
105
106         return new String JavaDoc(chars);
107     }
108
109     public EventBridge(EventSubject localSubject, String JavaDoc externalSubject) {
110         this.localSubject = localSubject;
111         this.externalSubject = externalSubject;
112     }
113
114     /**
115      * Returns a String subject used to post distributed events.
116      */

117     public String JavaDoc getExternalSubject() {
118         return externalSubject;
119     }
120
121     /**
122      * Returns a subject used for events within the local JVM.
123      */

124     public EventSubject getLocalSubject() {
125         return localSubject;
126     }
127
128     public boolean receivesLocalEvents() {
129         return mode == RECEIVE_LOCAL_EXTERNAL || mode == RECEIVE_LOCAL;
130     }
131
132     public boolean receivesExternalEvents() {
133         return mode == RECEIVE_LOCAL_EXTERNAL || mode == RECEIVE_EXTERNAL;
134     }
135
136     /**
137      * Sets up this EventBridge to receive local events from the instance of
138      * EventManager. Internally calls "startupExternal".
139      */

140     public void startup(EventManager eventManager, int mode) throws Exception JavaDoc {
141         this.startup(eventManager, mode, null);
142     }
143
144     public void startup(EventManager eventManager, int mode, Object JavaDoc eventsSource)
145         throws Exception JavaDoc {
146         // uninstall old event manager
147
if (this.eventManager != null) {
148             // maybe leave external interface open?
149
// on the other hand, the approach below is probably cleaner
150
// since nothing is known about the previous state
151
shutdown();
152         }
153
154         if (eventManager == null) {
155             throw new NullPointerException JavaDoc("'eventManager' can't be null.");
156         }
157
158         this.eventManager = eventManager;
159         this.mode = mode;
160
161         if (receivesLocalEvents()) {
162             // by default set as a non-blocking listener
163
// also, listen only for source events
164
eventManager.addNonBlockingListener(
165                 this,
166                 "onLocalEvent",
167                 CayenneEvent.class,
168                 localSubject,
169                 eventsSource);
170         }
171
172         startupExternal();
173     }
174
175     /**
176       * Starts the external interface of the EventBridge.
177       */

178     protected abstract void startupExternal() throws Exception JavaDoc;
179
180     /**
181      * Stops receiving events on both local and external interfaces.
182      */

183     public void shutdown() throws Exception JavaDoc {
184         this.eventManager.removeListener(this);
185         this.eventManager = null;
186
187         shutdownExternal();
188     }
189
190     /**
191      * Shuts down the external interface of the EventBridge, cleaning up
192      * and releasing any resources used to communicate external events.
193      */

194     protected abstract void shutdownExternal() throws Exception JavaDoc;
195
196     /**
197      * Helper method for sucblasses to asynchronously post an event obtained from a remote
198      * source. Subclasses do not have to use this method, but they probably should for
199      * consistency.
200      */

201     public void onExternalEvent(CayenneEvent event) {
202         if (eventManager != null) {
203
204             // initialize event sources
205
event.setPostedBy(this);
206             if (event.getSource() == null) {
207                 event.setSource(this);
208             }
209
210             // inject external eveny to the event manager queue.. leave it up to the
211
// listeners to figure out correct synchronization.
212
eventManager.postEvent(event, localSubject);
213         }
214         else {
215             throw new IllegalStateException JavaDoc(
216                     "Can't post events. EventBridge was not started properly. "
217                             + "EventManager is null.");
218         }
219     }
220
221     /**
222      * Invoked by local EventManager when a local event of interest occurred.
223      * Internally delegates to "sendExternalEvent" abstract method.
224      */

225     public void onLocalEvent(CayenneEvent event) throws Exception JavaDoc {
226         if (event.getSource() != this) {
227             sendExternalEvent(event);
228         }
229     }
230
231     protected abstract void sendExternalEvent(CayenneEvent localEvent) throws Exception JavaDoc;
232 }
233
Popular Tags