View Javadoc

1   package org.apache.jcs.auxiliary.lateral.socket.tcp.discovery;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.ByteArrayOutputStream;
23  import java.io.IOException;
24  import java.io.ObjectOutputStream;
25  import java.net.DatagramPacket;
26  import java.net.InetAddress;
27  import java.net.MulticastSocket;
28  import java.util.ArrayList;
29  
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.jcs.auxiliary.lateral.LateralCacheInfo;
33  
34  /***
35   * This is a generic sender for the UDPDiscovery process.
36   *
37   * @author Aaron Smuts
38   *
39   */
40  public class UDPDiscoverySender
41  {
42      private final static Log log = LogFactory.getLog( UDPDiscoverySender.class );
43  
44      private MulticastSocket m_localSocket;
45  
46      private InetAddress m_multicastAddress;
47  
48      private int m_multicastPort;
49  
50      /***
51       * Constructor for the UDPDiscoverySender object
52       * <p>
53       * This sender can be used to send multiple messages.
54       * <p>
55       * When you are done sending, you should destroy the socket sender.
56       *
57       * @param host
58       * @param port
59       *
60       * @exception IOException
61       */
62      public UDPDiscoverySender( String host, int port )
63          throws IOException
64      {
65          try
66          {
67              m_localSocket = new MulticastSocket();
68  
69              // Remote address.
70              m_multicastAddress = InetAddress.getByName( host );
71          }
72          catch ( IOException e )
73          {
74              log.error( "Could not bind to multicast address [" + host + "]", e );
75  
76              throw e;
77          }
78  
79          m_multicastPort = port;
80      }
81  
82      /***
83       * Closes the socket connection.
84       *
85       */
86      public void destroy()
87      {
88          try
89          {
90              // TODO when we move to jdk 1.4 reinstate the isClosed check
91              if ( this.m_localSocket != null )
92              // && !this.m_localSocket.isClosed() )
93              {
94                  this.m_localSocket.close();
95              }
96          }
97          catch ( Exception e )
98          {
99              log.error( "Problem destrying sender", e );
100         }
101     }
102 
103     /***
104      * Just being careful about closing the socket.
105      *
106      * @throws Throwable
107      */
108     public void finalize()
109         throws Throwable
110     {
111         super.finalize();
112         destroy();
113     }
114 
115     /***
116      * Send messages.
117      *
118      * @param message
119      * @throws IOException
120      */
121     public void send( UDPDiscoveryMessage message )
122         throws IOException
123     {
124         if ( this.m_localSocket == null )
125         {
126             throw new IOException( "Socket is null, cannot send message." );
127         }
128 
129         // TODO when we move to jdk 1.4 reinstate the isClosed check
130         // if (this.m_localSocket.isClosed() )
131         // {
132         // throw new IOException( "Socket is closed, cannot send message." );
133         // }
134 
135         if ( log.isDebugEnabled() )
136         {
137             log.debug( "sending UDPDiscoveryMessage, message = " + message );
138         }
139 
140         try
141         {
142             // write the object to a byte array.
143             final MyByteArrayOutputStream byteStream = new MyByteArrayOutputStream();
144             final ObjectOutputStream objectStream = new ObjectOutputStream( byteStream );
145             objectStream.writeObject( message );
146             objectStream.flush();
147             final byte[] bytes = byteStream.getBytes();
148 
149             // put the byte array in a packet
150             final DatagramPacket packet = new DatagramPacket( bytes, bytes.length, m_multicastAddress, m_multicastPort );
151 
152             m_localSocket.send( packet );
153         }
154         catch ( IOException e )
155         {
156             log.error( "Error sending message", e );
157             throw e;
158         }
159     }
160 
161     /***
162      * Ask other to broadcast their info the the multicast address. If a lateral
163      * is non receiving it can use this. This is also called on startup so we
164      * can get info.
165      *
166      * @throws IOException
167      */
168     public void requestBroadcast()
169         throws IOException
170     {
171         if ( log.isDebugEnabled() )
172         {
173             log.debug( "sending requestBroadcast " );
174         }
175 
176         UDPDiscoveryMessage message = new UDPDiscoveryMessage();
177         message.setRequesterId( LateralCacheInfo.listenerId );
178         message.setMessageType( UDPDiscoveryMessage.REQUEST_BROADCAST );
179         send( message );
180     }
181 
182     /***
183      * This sends a message braodcasting our that the host and port is available
184      * for connections.
185      * <p>
186      * It uses the vmid as the requesterDI
187      *
188      * @param host
189      * @param port
190      * @param cacheNames
191      * @throws IOException
192      */
193     public void passiveBroadcast( String host, int port, ArrayList cacheNames )
194         throws IOException
195     {
196         passiveBroadcast( host, port, cacheNames, LateralCacheInfo.listenerId );
197     }
198 
199     /***
200      * This allows you to set the sender id. This is mainly for testing.
201      *
202      * @param host
203      * @param port
204      * @param cacheNames
205      * @param listenerId
206      * @throws IOException
207      */
208     protected void passiveBroadcast( String host, int port, ArrayList cacheNames, long listenerId )
209         throws IOException
210     {
211         if ( log.isDebugEnabled() )
212         {
213             log.debug( "sending passiveBroadcast " );
214         }
215 
216         UDPDiscoveryMessage message = new UDPDiscoveryMessage();
217         message.setHost( host );
218         message.setPort( port );
219         message.setCacheNames( cacheNames );
220         message.setRequesterId( listenerId );
221         message.setMessageType( UDPDiscoveryMessage.PASSIVE_BROADCAST );
222         send( message );
223     }
224 }
225 
226 /***
227  * This allows us to get the byte array from an output stream.
228  *
229  * @author asmuts
230  * @created January 15, 2002
231  */
232 
233 class MyByteArrayOutputStream
234     extends ByteArrayOutputStream
235 {
236     /***
237      * Gets the bytes attribute of the MyByteArrayOutputStream object
238      *
239      * @return The bytes value
240      */
241     public byte[] getBytes()
242     {
243         return buf;
244     }
245 }
246 // end class