All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ca.odell.glazedlists.impl.rbp.PeerConnection Maven / Gradle / Ivy

There is a newer version: 1.9.1
Show newest version
/* Glazed Lists                                                 (c) 2003-2006 */
/* http://publicobject.com/glazedlists/                      publicobject.com,*/
/*                                                     O'Dell Engineering Ltd.*/
package ca.odell.glazedlists.impl.rbp;

// NIO is used for BRP
import java.util.*;
import java.nio.*;
import java.io.*;
import java.text.ParseException;
import ca.odell.glazedlists.impl.io.Bufferlo;
// BRP sits atop Chunk Transfer Protocol
import ca.odell.glazedlists.impl.ctp.*;
// logging
import java.util.logging.*;


/**
 * Models a connection to a local peer.
 *
 * 

A connection is multiplexed and serves multiple resources. It contains a map * of resources being published and resources being subscribed to. * * @author Jesse Wilson */ class PeerConnection implements CTPHandler { /** logging */ private static Logger logger = Logger.getLogger(PeerConnection.class.toString()); /** the peer that owns all connections */ private Peer peer; /** the lower level connection to this peer */ private CTPConnection connection = null; /** the state of this connection */ private static final int AWAITING_CONNECT = 0; private static final int READY = 1; private static final int AWAITING_CLOSE = 2; private static final int CLOSED = 3; private int state = AWAITING_CONNECT; /** the incoming bytes pending a full block */ private Bufferlo currentBlock = new Bufferlo(); /** the outgoing bytes pending a connection */ private Bufferlo pendingConnect = new Bufferlo(); /** locally subscribed resources by resource name */ Map incomingSubscriptions = new TreeMap(); /** locally published resources by resource name */ Map outgoingPublications = new TreeMap(); /** * Creates a new PeerConnection for the specified peer. */ public PeerConnection(Peer peer) { this.peer = peer; } /** * Handles the connection being ready for chunks to be sent. */ public void connectionReady(CTPConnection connection) { // know where we were before int priorState = state; // now that we're connected this.connection = connection; this.state = READY; // handle any pending operations: data if(pendingConnect.length() > 0) { connection.sendChunk(pendingConnect); } // handle any pending operations: close if(priorState == AWAITING_CLOSE) { close(); } } /** * Handles the connection being closed by the remote client. This will also * be called if there is a connection error, which is the case when a remote * host sends data that cannot be interpretted by CTPConnection. * * @param reason An exception if the connection was closed as the result of * a failure. This may be null. */ public void connectionClosed(CTPConnection source, Exception reason) { this.connection = null; this.state = CLOSED; peer.connections.remove(this); // notify resources of the close List resourcesToNotify = new ArrayList(); resourcesToNotify.addAll(incomingSubscriptions.values()); resourcesToNotify.addAll(outgoingPublications.values()); for(Iterator r = resourcesToNotify.iterator(); r.hasNext(); ) { ResourceConnection resource = (ResourceConnection)r.next(); resource.getResource().connectionClosed(resource, reason); } } /** * Handles reception of the specified chunk of data. This chunk should be able * to be cleanly concatenated with the previous and following chunks without * problem by the reader. * * @param data A non-empty ByteBuffer containing the bytes for this chunk. The * relevant bytes start at data.position() and end at data.limit(). This * buffer is only valid for the duration of this method call. */ public void receiveChunk(CTPConnection source, Bufferlo data) { // get all the data in the working block currentBlock.append(data); // handle all blocks try { PeerBlock block = null; while((block = PeerBlock.fromBytes(currentBlock, source.getLocalHost(), source.getLocalPort())) != null) { ResourceUri resourceUri = block.getResourceUri(); // get the resource for this connection ResourceConnection resource = null; if(block.isSubscribe()) { resource = new ResourceConnection(this, peer.getPublishedResource(resourceUri)); } else if(block.isUnsubscribe()) { resource = (ResourceConnection)outgoingPublications.get(resourceUri); } else if(block.isSubscribeConfirm() || block.isUpdate() || block.isUnpublish()) { resource = (ResourceConnection)incomingSubscriptions.get(resourceUri); } else { throw new UnsupportedOperationException(); } // handle an unknown resource name if(resource == null) { logger.warning("Unknown resource: \"" + resourceUri + "\""); close(); return; } // handle the block resource.getResource().incomingBlock(resource, block); } // if the data is corrupted, close the connection } catch(ParseException e) { source.close(e); // if any other error happened, close the connection } catch(RuntimeException e) { logger.log(Level.WARNING, "Unexpected error handling block", e.getMessage()); source.close(e); } } /** * Test whether this connection is being used by incoming subscriptions or * outgoing publications. */ boolean isIdle() { return (incomingSubscriptions.isEmpty() && outgoingPublications.isEmpty()); } /** * Close this peer connection. */ public void close() { // if we're already done if(state == CLOSED) { logger.warning("Closing a closed connection"); return; } // close now state = AWAITING_CLOSE; if(connection != null) { connection.close(); peer.connections.remove(this); } } /** * Writes the specified block to this peer. */ public void writeBlock(PeerResource resource, PeerBlock block) { if(state == AWAITING_CONNECT) { pendingConnect.append(block.toBytes(null, -1)); } else if(state == READY) { connection.sendChunk(block.toBytes(connection.getLocalHost(), connection.getLocalPort())); } else if(state == CLOSED || state == AWAITING_CLOSE) { logger.warning("Write block to closed connection: " + this); } else { throw new IllegalStateException(); } } /** * Gets this connection as a String. */ public String toString() { if(state == AWAITING_CONNECT) return "pending"; else if(state == READY) return connection.toString(); else if(state == CLOSED) return "closed"; else if(state == AWAITING_CLOSE) return "closing"; else throw new IllegalStateException(); } /** * Prints the current state of this connection. */ void print() { System.out.print(this); System.out.print(": "); System.out.print("Incoming {"); for(Iterator s = incomingSubscriptions.keySet().iterator(); s.hasNext(); ) { ResourceUri resourceUri = (ResourceUri)s.next(); System.out.print(resourceUri); if(s.hasNext()) System.out.print(", "); } System.out.print("}, "); System.out.print("Outgoing {"); for(Iterator s = outgoingPublications.keySet().iterator(); s.hasNext(); ) { ResourceUri resourceUri = (ResourceUri)s.next(); System.out.print(resourceUri); if(s.hasNext()) System.out.print(", "); } System.out.println("}"); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy