001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 2005 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or modify it
007: * under the terms of the GNU Lesser General Public License as published by the
008: * Free Software Foundation; either version 2.1 of the License, or any later
009: * version.
010: *
011: * This library is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
014: * for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public License
017: * along with this library; if not, write to the Free Software Foundation,
018: * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
019: * --------------------------------------------------------------------------
020: * $Id: DiscoveryGreetingResponder.java 9361 2006-08-04 12:20:51Z durieuxp $
021: * --------------------------------------------------------------------------
022: */package org.objectweb.jonas.discovery;
023:
024: import java.io.IOException;
025: import java.net.DatagramPacket;
026: import java.net.DatagramSocket;
027: import java.net.SocketException;
028: import java.net.SocketTimeoutException;
029: import java.net.UnknownHostException;
030:
031: import org.objectweb.jonas.common.Log;
032: import org.objectweb.jonas.common.NetUtils;
033: import org.objectweb.jonas.service.ServiceException;
034: import org.objectweb.util.monolog.api.BasicLevel;
035: import org.objectweb.util.monolog.api.Logger;
036:
037: /**
038: * This class sends a multicast message stating the servername and
039: * the port at which it will listen for messages. It listens at the
040: * unicast port for a pre-determined time (greetingTimeOut) and if
041: * it receives a message indicating that a server with the same ID
042: * already exists in the domain then it terminates the discovery service.
043: *
044: * @author Vivek Lakshmanan
045: * @version 1.0
046: */
047: public class DiscoveryGreetingResponder extends DiscoveryComm {
048: /**
049: * Used to recieve responses to the initial greeting message sent out on the multicast port.
050: */
051: protected DatagramSocket recvUnicastSocket;
052:
053: /**
054: * Port to listen to for greeting responses.
055: */
056: protected int greetingPort;
057:
058: /**
059: * Time out period to listen to greetingPort for replies.
060: */
061: protected int greetingTimeOut;
062:
063: /**
064: * The greeting to be sent out identifying the server.
065: */
066: private DiscGreeting greeting = null;
067:
068: /**
069: * logger
070: */
071: private static Logger logger = Log
072: .getLogger(Log.JONAS_DISCOVERY_PREFIX);
073:
074: /**
075: * Constructs a DiscoveryGreetingResponder associated to the DiscoveryManager
076: *
077: * @param dm
078: * DiscoveryManager to which this instance is associated
079: */
080: public DiscoveryGreetingResponder(DiscoveryManager dm) {
081: super (dm);
082: this .greetingPort = dm.getGreetingListeningPort();
083: this .greetingTimeOut = dm.getGreetingAckTimeOut();
084: }
085:
086: /**
087: * Create a discovery greeting message
088: *
089: * @param startup -
090: * true: means that is a greeting message at the point of start
091: * up of the discovery service. false: means this is a reply to
092: * a previous greeting message.
093: * @return a Discovery Greeting message.
094: */
095: protected DiscGreeting createDiscGreeting(boolean startup) {
096: String theHostAddress;
097: try {
098: theHostAddress = NetUtils.getLocalAddress();
099: } catch (UnknownHostException e) {
100: logger.log(BasicLevel.ERROR, "Unknown host", e);
101: return null;
102: }
103:
104: return new DiscGreeting(theHostAddress, this .greetingPort,
105: this .jonasName, this .domainName, startup, this .serverId);
106: }
107:
108: /**
109: * Handle the case where the received DiscGreeting indicates that a server
110: * with the same name already exists in the domain.
111: *
112: * @param msg
113: * a discovery greeting received.
114: *
115: * @throws DuplicateServerNameException
116: */
117: private void handleReceivedMessage(DiscGreeting msg)
118: throws DuplicateServerNameException {
119:
120: if (logger.isLoggable(BasicLevel.ERROR)) {
121: logger
122: .log(
123: BasicLevel.ERROR,
124: "A server with the given name already"
125: + " exists in the domain, received a rejection message: "
126: + msg);
127: }
128: stop();
129:
130: }
131:
132: /* (non-Javadoc)
133: * @see java.lang.Runnable#run()
134: */
135: public void run() {
136: if (logger.isLoggable(BasicLevel.DEBUG)) {
137: logger.log(BasicLevel.DEBUG, "Sending the greeting.");
138: }
139: // Send the greeting out.
140: if (greeting != null) {
141: sendNotif(greeting);
142: }
143: }
144:
145: /**
146: *
147: * Creates a new thread to send the greeting message and listens for
148: * rejection messages in response.
149: * @throws DuplicateServerNameException - If a server with the same ID
150: * is found in the domain.
151: */
152: public void handleGreeting() throws DuplicateServerNameException {
153: // Join the group in order to receive multicast messages
154: join();
155: // Create the greeting representing a start up.
156: greeting = createDiscGreeting(true);
157:
158: // Create a unicast socket to receive responses
159: try {
160: recvUnicastSocket = new DatagramSocket(greetingPort);
161: } catch (SocketException e2) {
162: logger
163: .log(
164: BasicLevel.ERROR,
165: "DiscComm : Unable to create a Datagram socket",
166: e2);
167: // If the port is used throw a service exception.
168: throw new ServiceException(
169: "Unable to create a datagram socket on port "
170: + greetingPort
171: + " to listen for rejections. Port is still in use.");
172: }
173:
174: try {
175: // Set timeout for reading from the socket. If responses take longer
176: // than the timeout set, they will now be ignored.
177: recvUnicastSocket.setSoTimeout(greetingTimeOut);
178:
179: // Dont wait for messages beyond a pre-defined period of lapsed time.
180: long lastTime = greetingTimeOut
181: + System.currentTimeMillis();
182:
183: // Create thread which will send the greeting message out.
184: Thread sender = new Thread(this , "greeting sender");
185:
186: boolean msgSent = false;
187:
188: // Listen for a specified amount of time to see if there
189: // is a server already present with the ID used.
190: while ((notStopped)
191: && System.currentTimeMillis() <= lastTime) {
192: // Send the discovery message out in a seperate thread
193: // if it has not been sent.
194: if (!msgSent) {
195: sender.start();
196: msgSent = true;
197: }
198: // TODO: Should ideally be listening in a seperate thread and sending
199: // the discovery message shortly afterwards.
200: DatagramPacket datagram = getDatagram(RECEIVE_BUFFER_SIZE);
201: recvUnicastSocket.receive(datagram);
202: Object objReceived = DiscoveryHelper
203: .bytesToObject(datagram.getData());
204: if (objReceived != null) {
205: if (objReceived instanceof DiscGreeting) {
206: DiscGreeting greet = (DiscGreeting) objReceived;
207: // Trust the datagram packet instead of the message for address.
208: greet.setSourceAddress(datagram.getAddress()
209: .getHostAddress());
210: handleReceivedMessage(greet);
211: }
212: }
213: datagram = null;
214: }
215:
216: } catch (SocketException e) {
217: logger.log(BasicLevel.ERROR,
218: "DiscoveryGreetingResponder : Socket closed", e);
219: notStopped = false;
220: } catch (IOException e1) {
221: if (e1 instanceof SocketTimeoutException) {
222: if (logger.isLoggable(BasicLevel.DEBUG)) {
223: logger
224: .log(
225: BasicLevel.DEBUG,
226: "No rejections receieved within the set timeout period: "
227: + greetingTimeOut
228: + " ms. Assuming the server ID used is unique in the domain."
229: + " The timeout period can be changed under jonas.properties:"
230: + " jonas.service.discovery.greeting.timeout");
231: }
232: } else {
233: logger.log(BasicLevel.ERROR,
234: "DiscoveryGreetingResponder IOException", e1);
235: }
236: } catch (ClassNotFoundException e) {
237: logger
238: .log(
239: BasicLevel.ERROR,
240: "DiscoveryGreetingResponder ClassNotFoundException ",
241: e);
242: }
243:
244: }
245:
246: /**
247: * Throw the run time exception to state that a server with the same
248: * name already exists.
249: */
250: public void stop() {
251: throw new DuplicateServerNameException();
252: }
253:
254: }
|