001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.catalina.cluster.mcast;
018:
019: import org.apache.catalina.cluster.MembershipService;
020: import java.util.Properties;
021: import org.apache.catalina.cluster.Member;
022: import org.apache.catalina.cluster.MembershipListener;
023: import java.util.Properties;
024:
025: /**
026: * A <b>membership</b> implementation using simple multicast.
027: * This is the representation of a multicast membership service.
028: * This class is responsible for maintaining a list of active cluster nodes in the cluster.
029: * If a node fails to send out a heartbeat, the node will be dismissed.
030: *
031: * @author Filip Hanik
032: * @version $Revision: 1.11 $, $Date: 2004/05/26 16:36:03 $
033: */
034:
035: public class McastService implements MembershipService,
036: MembershipListener {
037:
038: private static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
039: .getLog(McastService.class);
040: /**
041: * The implementation specific properties
042: */
043: protected Properties properties = new Properties();
044: /**
045: * A handle to the actual low level implementation
046: */
047: protected McastServiceImpl impl;
048: /**
049: * A membership listener delegate (should be the cluster :)
050: */
051: protected MembershipListener listener;
052: /**
053: * The local member
054: */
055: protected McastMember localMember;
056: private int mcastSoTimeout;
057: private int mcastTTL;
058:
059: /**
060: * Create a membership service.
061: */
062: public McastService() {
063: }
064:
065: /**
066: *
067: * @param properties<BR>All are required<BR>
068: * 1. mcastPort - the port to listen to<BR>
069: * 2. mcastAddress - the mcast group address<BR>
070: * 3. bindAddress - the bind address if any - only one that can be null<BR>
071: * 4. memberDropTime - the time a member is gone before it is considered gone.<BR>
072: * 5. msgFrequency - the frequency of sending messages<BR>
073: * 6. tcpListenPort - the port this member listens to<BR>
074: * 7. tcpListenHost - the bind address of this member<BR>
075: * @exception java.lang.IllegalArgumentException if a property is missing.
076: */
077: public void setProperties(Properties properties) {
078: hasProperty(properties, "mcastPort");
079: hasProperty(properties, "mcastAddress");
080: hasProperty(properties, "memberDropTime");
081: hasProperty(properties, "msgFrequency");
082: hasProperty(properties, "tcpListenPort");
083: hasProperty(properties, "tcpListenHost");
084: this .properties = properties;
085: }
086:
087: /**
088: * Return the properties, see setProperties
089: */
090: public Properties getProperties() {
091: return properties;
092: }
093:
094: /**
095: * Return the local member
096: */
097: public Member getLocalMember() {
098: localMember.setMemberAliveTime(System.currentTimeMillis()
099: - impl.getServiceStartTime());
100: return localMember;
101: }
102:
103: /**
104: * Sets the local member properties for broadcasting
105: */
106: public void setLocalMemberProperties(String listenHost,
107: int listenPort) {
108: properties.setProperty("tcpListenHost", listenHost);
109: properties.setProperty("tcpListenPort", String
110: .valueOf(listenPort));
111: }
112:
113: public void setMcastAddr(String addr) {
114: properties.setProperty("mcastAddress", addr);
115: }
116:
117: public void setMcastBindAddress(String bindaddr) {
118: properties.setProperty("mcastBindAddress", bindaddr);
119: }
120:
121: public void setMcastPort(int port) {
122: properties.setProperty("mcastPort", String.valueOf(port));
123: }
124:
125: public void setMcastFrequency(long time) {
126: properties.setProperty("msgFrequency", String.valueOf(time));
127: }
128:
129: public void setMcastDropTime(long time) {
130: properties.setProperty("memberDropTime", String.valueOf(time));
131: }
132:
133: /**
134: * Check if a required property is available.
135: * @param properties The set of properties
136: * @param name The property to check for
137: */
138: protected void hasProperty(Properties properties, String name) {
139: if (properties.getProperty(name) == null)
140: throw new IllegalArgumentException("Required property \""
141: + name + "\" is missing.");
142: }
143:
144: /**
145: * Start broadcasting and listening to membership pings
146: * @throws java.lang.Exception if a IO error occurs
147: */
148: public void start() throws java.lang.Exception {
149: start(1);
150: start(2);
151: }
152:
153: public void start(int level) throws java.lang.Exception {
154: if (impl != null) {
155: impl.start(level);
156: return;
157: }
158: String host = getProperties().getProperty("tcpListenHost");
159: int port = Integer.parseInt(getProperties().getProperty(
160: "tcpListenPort"));
161: String name = "tcp://" + host + ":" + port;
162: if (localMember == null) {
163: localMember = new McastMember(name, host, port, 100);
164: } else {
165: localMember.setName(name);
166: localMember.setHost(host);
167: localMember.setPort(port);
168: localMember.setMemberAliveTime(100);
169: }
170: java.net.InetAddress bind = null;
171: if (properties.getProperty("mcastBindAddress") != null) {
172: bind = java.net.InetAddress.getByName(properties
173: .getProperty("mcastBindAddress"));
174: }
175: int ttl = -1;
176: int soTimeout = -1;
177: if (properties.getProperty("mcastTTL") != null) {
178: try {
179: ttl = Integer.parseInt(properties
180: .getProperty("mcastTTL"));
181: } catch (Exception x) {
182: log.error("Unable to parse mcastTTL="
183: + properties.getProperty("mcastTTL"), x);
184: }
185: }
186: if (properties.getProperty("mcastSoTimeout") != null) {
187: try {
188: soTimeout = Integer.parseInt(properties
189: .getProperty("mcastSoTimeout"));
190: } catch (Exception x) {
191: log.error("Unable to parse mcastSoTimeout="
192: + properties.getProperty("mcastSoTimeout"), x);
193: }
194: }
195:
196: impl = new McastServiceImpl((McastMember) localMember, Long
197: .parseLong(properties.getProperty("msgFrequency")),
198: Long
199: .parseLong(properties
200: .getProperty("memberDropTime")),
201: Integer.parseInt(properties.getProperty("mcastPort")),
202: bind, java.net.InetAddress.getByName(properties
203: .getProperty("mcastAddress")), ttl, soTimeout,
204: this );
205:
206: impl.start(level);
207: log.info("Sleeping for "
208: + (Long.parseLong(properties
209: .getProperty("msgFrequency")) * 4)
210: + " secs to establish cluster membership");
211: Thread.currentThread()
212: .sleep(
213: (Long.parseLong(properties
214: .getProperty("msgFrequency")) * 4));
215:
216: }
217:
218: /**
219: * Stop broadcasting and listening to membership pings
220: */
221: public void stop() {
222: try {
223: if (impl != null)
224: impl.stop();
225: } catch (Exception x) {
226: log.error("Unable to stop the mcast service.", x);
227: }
228: impl = null;
229: }
230:
231: /**
232: * Return all the members
233: */
234: public Member[] getMembers() {
235: if (impl == null || impl.membership == null)
236: return null;
237: return impl.membership.getMembers();
238: }
239:
240: /**
241: * Add a membership listener, this version only supports one listener per service,
242: * so calling this method twice will result in only the second listener being active.
243: * @param listener The listener
244: */
245: public void addMembershipListener(MembershipListener listener) {
246: this .listener = listener;
247: }
248:
249: /**
250: * Remove the membership listener
251: */
252: public void removeMembershipListener() {
253: listener = null;
254: }
255:
256: public void memberAdded(Member member) {
257: if (listener != null)
258: listener.memberAdded(member);
259: }
260:
261: /**
262: * Callback from the impl when a new member has been received
263: * @param member The member
264: */
265: public void memberDisappeared(Member member) {
266: if (listener != null)
267: listener.memberDisappeared(member);
268: }
269:
270: /**
271: * Simple test program
272: * @param args Command-line arguments
273: * @throws Exception If an error occurs
274: */
275: public static void main(String args[]) throws Exception {
276: log.info("Usage McastService hostname tcpport");
277: McastService service = new McastService();
278: java.util.Properties p = new java.util.Properties();
279: p.setProperty("mcastPort", "5555");
280: p.setProperty("mcastAddress", "224.10.10.10");
281: p.setProperty("bindAddress", "localhost");
282: p.setProperty("memberDropTime", "3000");
283: p.setProperty("msgFrequency", "500");
284: p.setProperty("tcpListenPort", args[1]);
285: p.setProperty("tcpListenHost", args[0]);
286: service.setProperties(p);
287: service.start();
288: Thread.currentThread().sleep(60 * 1000 * 60);
289: }
290:
291: public int getMcastSoTimeout() {
292: return mcastSoTimeout;
293: }
294:
295: public void setMcastSoTimeout(int mcastSoTimeout) {
296: this .mcastSoTimeout = mcastSoTimeout;
297: properties.setProperty("mcastSoTimeout", String
298: .valueOf(mcastSoTimeout));
299: }
300:
301: public int getMcastTTL() {
302: return mcastTTL;
303: }
304:
305: public void setMcastTTL(int mcastTTL) {
306: this .mcastTTL = mcastTTL;
307: properties.setProperty("mcastTTL", String.valueOf(mcastTTL));
308: }
309: }
|