⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 relayserver.java

📁 jxme的一些相关程序,主要是手机上程序开发以及手机和计算机通信的一些程序资料,程序编译需要Ant支持
💻 JAVA
字号:
/************************************************************************
 *
 * $Id: RelayServer.java,v 1.14 2002/06/05 18:34:51 jice Exp $
 *
 * Copyright (c) 2001 Sun Microsystems, Inc.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *       Sun Microsystems, Inc. for Project JXTA."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA"
 *    must not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact Project JXTA at http://www.jxta.org.
 *
 * 5. Products derived from this software may not be called "JXTA",
 *    nor may "JXTA" appear in their name, without prior written
 *    permission of Sun.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL SUN MICROSYSTEMS OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of Project JXTA.  For more
 * information on Project JXTA, please see
 * <http://www.jxta.org/>.
 *
 * This license is based on the BSD license adopted by the Apache Foundation.
 */

package net.jxta.impl.relay;

import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Properties;
import java.security.SecureRandom;
import java.security.NoSuchAlgorithmException;

import net.jxta.id.ID;
import net.jxta.endpoint.EndpointService;
import net.jxta.impl.util.BoundedQueue;
import net.jxta.impl.util.Base64;

import org.apache.log4j.Category; import org.apache.log4j.Priority;

/**
 * Relay server that maintains outgoing message queues, leases, etc.
 */
public class RelayServer  {

    private static final Category LOG =
	Category.getInstance(RelayServer.class.getName());

    /** global timer used for lease expiration tasks **/
    private static Timer timer = new Timer();

    private static final String LEASE_LEN_KEY = "RelayServer.LeaseLength";

    /** Default lease length. **/
    private int leaseLength = 30 * 60 * 1000;

    /** random number generator **/
    private SecureRandom random = null;

    /** the endpoint that we're relaying for **/
    private EndpointService endpoint = null;

    /** map of (leaseId, RelayLease) **/
    private HashMap leaseMap = new HashMap();

    /** map of (client peerId, RelayLease) **/
    private HashMap peerMap = new HashMap();

    /** Returns the peer ID that this relay server is running on **/
    public ID getPeerID() {
        return endpoint.getGroup().getPeerID();
    }

    /**
     * Constructs the relay server given the endpoint that it is serving
     */
    public RelayServer(EndpointService endpoint, Properties prop) {
	this.endpoint = endpoint;
	try {
	    random = SecureRandom.getInstance("SHA1PRNG");
	} catch(NoSuchAlgorithmException e) {
	    if (LOG.isEnabledFor(Priority.ERROR)) LOG.error("RelayServer does not have SHA1PRNG crypto algorithm");
	    throw new RuntimeException("RelayServer does not have SHA1PRNG crypto algorithm");
	}

	// read the lease length from the properties file
	//
	if (prop != null) {	    
	    String leaseLenStr = prop.getProperty (LEASE_LEN_KEY);
	    if (leaseLenStr != null) {
		try {
		    leaseLength = Integer.parseInt (leaseLenStr);
		} catch (NumberFormatException e) {
		    if (LOG.isEnabledFor(Priority.INFO)) LOG.info ("Illegal value specified for " + LEASE_LEN_KEY);
		}
	    } else {
		if (LOG.isEnabledFor(Priority.INFO)) LOG.info ("Using default value for lease length");
	    }
	}
	if (LOG.isEnabledFor(Priority.INFO)) LOG.info ("lease length = " + leaseLength);

	// this will seed the secure random algorithm. Otherwise, the first
	// client connect will take a long time.
	if (LOG.isEnabledFor(Priority.INFO)) LOG.info ("Generating initial lease key");
	generateLeaseId();
    }

    /**
     * Issues a new lease to the peer. If the peer has any outstanding leases,
     * we will remove the lease.  Also, if there are any queued messages
     * on the old lease, they will be removed. When a new lease is issueed,
     * we schedule a task for the expiration of it.
     *
     * Now does remove the old lease.
     */
    public RelayLease issueNewLease(String clientPeerId) {

	RelayLease newLease = null;
	RelayLease oldLease = null;

	synchronized(this) {
	    oldLease = (RelayLease) peerMap.remove(clientPeerId);
	    
	    if (oldLease != null) {
		if (LOG.isEnabledFor(Priority.INFO)) {
		    LOG.info("Peer " + clientPeerId + " already has a lease");
		}

		// Remove the old lease from the lease map.
		leaseMap.remove (oldLease.getLeaseId());
	    }


	    // Install the new lease and timer.
	    String newLeaseId = generateLeaseId();
	    newLease = new RelayLease (clientPeerId,
				       newLeaseId,
				       leaseLength);
	    leaseMap.put (newLeaseId, newLease);
	    peerMap.put (clientPeerId, newLease);

	    newLease.setTimerTask(new LeaseExpirationTask (newLease));
	    timer.schedule (newLease.getTimerTask(), leaseLength);
	}

	// If there still was an oldLease, close it.
	// We do that out of sync because it takes clearing the queue etc.
	// whih has a different synchronization.

	// Disable. Future ticking is not problem, but we want the
	// lease object to be GCed and the timer task may stay around
	// for long time, so we need the ref to the lease to be cleared
	// and also make sure it is not going to get re-scheduled; that'd be
	// stupid.
	if (oldLease != null) {
	    ((LeaseExpirationTask) oldLease.getTimerTask()).disable();
	    oldLease.close();
	}

        return newLease;
    }
    
    /**
     * Renews the lease for clientPeerId
     * @throws RelayLeaseException This exception is thrown if the client
     *   does not already have a valid lease with the relay
     */
    public synchronized RelayLease renewLease(String leaseId)
	throws RelayLeaseException {

	if (LOG.isEnabledFor(Priority.DEBUG)) LOG.debug("attempting to renew lease " + leaseId);

	// check for validiting of existing lease
	RelayLease currLease = (RelayLease) leaseMap.get (leaseId);

	if (currLease == null || ! currLease.isValid()) {
	    throw new RelayLeaseException ("Existing lease is not valid");
        }

        // Renew the lease.
	// NOTE: The expiration event will still occur as scheduled
	// previously, but instead of terminating the lease, it will
	// reschedule a task for this new expiration date. The reason for doing
	// it that way is that timerTask.cancel does keep the task in the timer
	// queue until the end anyway.
        currLease.refresh();

        return currLease;
    }


    // For the sole use of the timer task.
    private void leaseEvent(RelayLease lease) {

	synchronized(this) {
	    if (! leaseMap.containsKey(lease.getLeaseId())) {
		// It has been removed already but the timer task
		// has not yet been disabled. Ignore.
		return;
	    }
	    if (lease.isValid()) {
		// The lease has been prorogated. Reschedule.
		lease.setTimerTask(new LeaseExpirationTask (lease));
		timer.schedule (lease.getTimerTask(), lease.getTimeLeft());
		return;
	    }

	    // The end. Remove that lease from our maps. Then close it.
	    peerMap.remove(lease.getPeerId());
	    leaseMap.remove(lease.getLeaseId());
	}

	// Note:
	// The timer task is no-longer in the timer queue, so there's no
	// need to disable it or anything. Just let it go.

	lease.close();
    }

    /**
     * Tells whether the client has a valid lease
     */
    public synchronized boolean hasLease (String clientPeerId) {

	return (peerMap.get(clientPeerId) != null);
    }

    /**
     * Returns the leaseId for the client
     */
    public synchronized String getLeaseId (String clientPeerId) {
	RelayLease lease = (RelayLease) peerMap.get(clientPeerId);
	if (lease == null) return null;
	return lease.getLeaseId();
    }

    /**
     * Returns the outbound message queue for the specified client
     */
    public synchronized BoundedQueue
	getOutboundMessageQueueByPeerId (String clientPeerId)
    {
	RelayLease lease = (RelayLease) peerMap.get(clientPeerId);
	if (lease == null) return null;
	return lease.getQueue();
    }

    /**
     * Returns the outbound message queue for the specified client
     */
    public synchronized BoundedQueue getOutboundMessageQueueByLeaseId (String leaseId) {
	RelayLease lease = (RelayLease) leaseMap.get(leaseId);
	if (lease == null) return null;
	return lease.getQueue();
    }


    /**
     * Generates a 128-bit base64-encoded random lease key
     */
    private String generateLeaseId() {
	byte[] buf = new byte[16];
	random.nextBytes(buf);
	return new String (Base64.encodeBase64 (buf)).trim();
    }

    public void removeLease (String leaseId) {

	RelayLease lease = null;

        synchronized(this) {
            lease = (RelayLease) leaseMap.remove (leaseId);
	    if (lease == null) return;

            peerMap.remove (lease.getPeerId());
        }

	// Disable. Future ticking is not problem, but we want the
	// lease object to be GCed and the timer task may stay around
	// for long time, so we need the ref to the lease to be cleared
	// and also make sure it is not going to get re-scheduled; that'd be
	// stupid.
	((LeaseExpirationTask) lease.getTimerTask()).disable();
	lease.close();
    }

    /**
     * Task that removes clients from the relay server.
     * Cancelation via the Timer class upon lease renewal is way too expensive.
     * instead, we let the event happen but reschedule if the lease has been
     * renewed. (see LeaseEvent).
     */
    class LeaseExpirationTask extends TimerTask {

	RelayLease lease = null;

	LeaseExpirationTask(RelayLease lease) {
	    this.lease = lease;
	}

	/** It's time! **/
	public void run() {
	    // Make tmp copy top avoid invoking leaseEvent
	    // with a null argument. Could happen after the lease
	    // has called disable() to clear our ref to it.
	    RelayLease tmp = lease;
	    if (tmp != null) leaseEvent(tmp);
	}

	/** Let the lease object go. This is equivalent to canceling
	 ** the task, but cheaper.
	 **/
	
	public void disable() {
	    lease = null;
	}

    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -