package org.apache.commons.jcs.utils.discovery; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ import org.apache.commons.jcs.engine.CacheInfo; import org.apache.commons.jcs.utils.discovery.UDPDiscoveryMessage.BroadcastType; import org.apache.commons.jcs.utils.serialization.StandardSerializer; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; import java.util.ArrayList; /** * This is a generic sender for the UDPDiscovery process. * <p> * @author Aaron Smuts */ public class UDPDiscoverySender { /** The logger. */ private static final Log log = LogFactory.getLog( UDPDiscoverySender.class ); /** The socket */ private MulticastSocket localSocket; /** The address */ private InetAddress multicastAddress; /** The port */ private final int multicastPort; /** Used to serialize messages */ private final StandardSerializer serializer = new StandardSerializer(); /** * Constructor for the UDPDiscoverySender object * <p> * This sender can be used to send multiple messages. * <p> * When you are done sending, you should destroy the socket sender. * <p> * @param host * @param port * @throws IOException */ public UDPDiscoverySender( String host, int port ) throws IOException { try { if ( log.isDebugEnabled() ) { log.debug( "Constructing socket for sender on port [" + port + "]" ); } localSocket = new MulticastSocket( port ); // Remote address. multicastAddress = InetAddress.getByName( host ); } catch ( IOException e ) { log.error( "Could not bind to multicast address [" + host + "]", e ); throw e; } multicastPort = port; } /** * Closes the socket connection. */ public void destroy() { try { if ( this.localSocket != null && !this.localSocket.isClosed() ) { this.localSocket.close(); } } catch ( Exception e ) { log.error( "Problem destrying sender", e ); } } /** * Just being careful about closing the socket. * <p> * @throws Throwable */ @Override protected void finalize() throws Throwable { super.finalize(); destroy(); } /** * Send messages. * <p> * @param message * @throws IOException */ public void send( UDPDiscoveryMessage message ) throws IOException { if ( this.localSocket == null ) { throw new IOException( "Socket is null, cannot send message." ); } if ( this.localSocket.isClosed() ) { throw new IOException( "Socket is closed, cannot send message." ); } if ( log.isDebugEnabled() ) { log.debug( "sending UDPDiscoveryMessage, address [" + multicastAddress + "], port [" + multicastPort + "], message = " + message ); } try { final byte[] bytes = serializer.serialize( message ); // put the byte array in a packet final DatagramPacket packet = new DatagramPacket( bytes, bytes.length, multicastAddress, multicastPort ); if ( log.isDebugEnabled() ) { log.debug( "Sending DatagramPacket. bytes.length [" + bytes.length + "] to " + multicastAddress + ":" + multicastPort ); } localSocket.send( packet ); } catch ( IOException e ) { log.error( "Error sending message", e ); throw e; } } /** * Ask other to broadcast their info the the multicast address. If a lateral is non receiving it * can use this. This is also called on startup so we can get info. * <p> * @throws IOException */ public void requestBroadcast() throws IOException { if ( log.isDebugEnabled() ) { log.debug( "sending requestBroadcast " ); } UDPDiscoveryMessage message = new UDPDiscoveryMessage(); message.setRequesterId( CacheInfo.listenerId ); message.setMessageType( BroadcastType.REQUEST ); send( message ); } /** * This sends a message broadcasting out that the host and port is available for connections. * <p> * It uses the vmid as the requesterDI * @param host * @param port * @param cacheNames * @throws IOException */ public void passiveBroadcast( String host, int port, ArrayList<String> cacheNames ) throws IOException { passiveBroadcast( host, port, cacheNames, CacheInfo.listenerId ); } /** * This allows you to set the sender id. This is mainly for testing. * <p> * @param host * @param port * @param cacheNames names of the cache regions * @param listenerId * @throws IOException */ protected void passiveBroadcast( String host, int port, ArrayList<String> cacheNames, long listenerId ) throws IOException { if ( log.isDebugEnabled() ) { log.debug( "sending passiveBroadcast " ); } UDPDiscoveryMessage message = new UDPDiscoveryMessage(); message.setHost( host ); message.setPort( port ); message.setCacheNames( cacheNames ); message.setRequesterId( listenerId ); message.setMessageType( BroadcastType.PASSIVE ); send( message ); } /** * This sends a message broadcasting our that the host and port is no longer available. * <p> * It uses the vmid as the requesterID * <p> * @param host host * @param port port * @param cacheNames names of the cache regions * @throws IOException on error */ public void removeBroadcast( String host, int port, ArrayList<String> cacheNames ) throws IOException { removeBroadcast( host, port, cacheNames, CacheInfo.listenerId ); } /** * This allows you to set the sender id. This is mainly for testing. * <p> * @param host host * @param port port * @param cacheNames names of the cache regions * @param listenerId listener ID * @throws IOException on error */ protected void removeBroadcast( String host, int port, ArrayList<String> cacheNames, long listenerId ) throws IOException { if ( log.isDebugEnabled() ) { log.debug( "sending removeBroadcast " ); } UDPDiscoveryMessage message = new UDPDiscoveryMessage(); message.setHost( host ); message.setPort( port ); message.setCacheNames( cacheNames ); message.setRequesterId( listenerId ); message.setMessageType( BroadcastType.REMOVE ); send( message ); } } /** * This allows us to get the byte array from an output stream. * <p> * @author asmuts * @created January 15, 2002 */ class MyByteArrayOutputStream extends ByteArrayOutputStream { /** * Gets the bytes attribute of the MyByteArrayOutputStream object * @return The bytes value */ public byte[] getBytes() { return buf; } }