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

org.refcodes.p2p.AbstractPeer Maven / Gradle / Ivy

Go to download

Artifact providing generic protocol and interface agnostic P2P (Peer-to-Peer) functionality (messaging, routing).

The newest version!
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// /////////////////////////////////////////////////////////////////////////////
// This code is copyright (c) by Siegfried Steiner, Munich, Germany, distributed
// on an "AS IS" BASIS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, and licen-
// sed under the following (see "http://en.wikipedia.org/wiki/Multi-licensing")
// licenses:
// -----------------------------------------------------------------------------
// GNU General Public License, v3.0 ("http://www.gnu.org/licenses/gpl-3.0.html")
// -----------------------------------------------------------------------------
// Apache License, v2.0 ("http://www.apache.org/licenses/TEXT-2.0")
// -----------------------------------------------------------------------------
// Please contact the copyright holding author(s) of the software artifacts in
// question for licensing issues not being covered by the above listed licenses,
// also regarding commercial licensing models or regarding the compatibility
// with other open source licenses.
// /////////////////////////////////////////////////////////////////////////////

package org.refcodes.p2p;

import java.io.IOException;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * The {@link AbstractPeer} class implements the {@link Peer} interface and is a
 * concrete implementation of a physical Peer.
 * 
 * @param  The {@link PeerRouter} type to use when routing
 *        {@link P2PMessage} instances.
 * @param  Defines the type of the locators identifying a peer.
 * @param 
The {@link P2PHeader} defines the static attributes addressed * for the target of the {@link P2PMessage} (a header might be signed as * it is not modified during dispatch). * @param The {@link P2PTail} describes the dynamic attributes required * during dispatch of a {@link P2PMessage} (a tail is modified during * dispatch by having the visited hops appended). * @param The (sub-)type of the {@link P2PMessage} being processed by the * according {@link Peer} (sub-)type. */ public abstract class AbstractPeer, TAIL extends P2PTail, MSG extends P2PMessage, CONSUMER extends P2PMessageConsumer, PEER extends Peer, ROUTER extends PeerRouter> implements Peer { // ///////////////////////////////////////////////////////////////////////// // VARIABLES: // ///////////////////////////////////////////////////////////////////////// protected LOCATOR _locator; protected Set _peerRouter = new HashSet<>(); protected CONSUMER _messageConsumer = null; // ///////////////////////////////////////////////////////////////////////// // CONSTRUCTORS: // ///////////////////////////////////////////////////////////////////////// /** * Constructs the {@link Peer} instance with the given initial state. * * @param aLocator the locator * @param aMessageConsumer the message consumer */ // public AbstractPeer( LOCATOR aId ) { // this( aId, msg -> System.out.println( "Received message at <" + aId + "> : " + msg.toString() ) ); // } /** * Constructs the {@link Peer} instance with the given initial state. The * {@link P2PMessageConsumer} is your business logic to be invoked upon * receivel of a message. * * @param aLocator The LOCATOR of the {@link Peer} being constructed. * Messages targeted to this {@link Peer} will be addressed to the * given LOCATOR. * @param aMessageConsumer The consumer (being the functional * {@link P2PMessageConsumer} interface) of the {@link P2PMessage} * instances targeted at this {@link Peer} instance. */ public AbstractPeer( LOCATOR aLocator, CONSUMER aMessageConsumer ) { _locator = aLocator; _messageConsumer = aMessageConsumer; } // ///////////////////////////////////////////////////////////////////////// // METHODS: // ///////////////////////////////////////////////////////////////////////// /** * {@inheritDoc} */ @Override public LOCATOR getLocator() { return _locator; } /** * {@inheritDoc} */ @Override public int getHopCount( LOCATOR aDestination, LOCATOR[] aTrail ) throws IOException { if ( getLocator().equals( aDestination ) ) { return 0; } Set thePeerIdTrail = null; if ( aTrail != null && aTrail.length != 0 ) { for ( LOCATOR anATrail : aTrail ) { if ( getLocator().equals( anATrail ) ) { return -1; } } thePeerIdTrail = new HashSet<>(); thePeerIdTrail.addAll( Arrays.asList( aTrail ) ); } int theMinHopCount = -1; if ( thePeerIdTrail == null || !thePeerIdTrail.contains( getLocator() ) ) { int eHopCount; for ( ROUTER eRouter : _peerRouter ) { eHopCount = eRouter.getHopCount( aDestination, appendHop( getLocator(), aTrail ) ); if ( theMinHopCount == -1 || eHopCount != -1 && eHopCount < theMinHopCount ) { theMinHopCount = eHopCount; } } } return theMinHopCount != -1 ? theMinHopCount + 1 : -1; } /** * {@inheritDoc} */ @Override public Set peerRouters() { return _peerRouter; } /** * {@inheritDoc} */ @Override public boolean addPeerRouter( ROUTER aPeerRouter ) { return _peerRouter.add( aPeerRouter ); } /** * {@inheritDoc} */ @Override public boolean removePeerRouter( ROUTER aPeerRouter ) { return _peerRouter.remove( aPeerRouter ); } /** * {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public void sendMessage( MSG aMessage ) throws NoSuchDestinationException, IOException { aMessage.getTail().appendHop( getLocator() ); if ( aMessage.getHeader().getDestination().equals( getLocator() ) ) { if ( _messageConsumer != null ) { _messageConsumer.onP2PMessage( aMessage, (PEER) this ); } } else { int theMinHopCount = -1; final List theTargetProxies = new ArrayList<>(); int eHopCount; for ( ROUTER eRouter : _peerRouter ) { eHopCount = eRouter.getHopCount( aMessage.getHeader().getDestination(), aMessage.getTail().getHops() ); if ( eHopCount != -1 ) { if ( theMinHopCount == -1 || eHopCount < theMinHopCount ) { theTargetProxies.clear(); theTargetProxies.add( eRouter ); theMinHopCount = eHopCount; } // Do not always use the same route |--> else if ( theMinHopCount == eHopCount ) { theTargetProxies.add( eRouter ); } // <--| Do not always use the same route } } if ( theTargetProxies.size() > 0 ) { // Random equivalent route |--> Collections.shuffle( theTargetProxies ); // Random equivalent route <--| theTargetProxies.get( 0 ).sendMessage( aMessage ); } else { throw new NoSuchDestinationException( "Cannot dispatch the message <" + aMessage.toString() + "> to destination <" + aMessage.getHeader().getDestination() + ">!", aMessage.getHeader().getDestination() ); } } } /** * {@inheritDoc} */ @Override public String toString() { return getClass().getSimpleName() + " [id=" + _locator + "]"; } // ///////////////////////////////////////////////////////////////////////// // HELPER: // ///////////////////////////////////////////////////////////////////////// /** * Appends an element to the given array and returns the grown array. * * @param aLocator The element by which the array is to grow. * @param aIdTrail The array which to grow by one. * * @return The grown resulting array. */ @SuppressWarnings("unchecked") private LOCATOR[] appendHop( LOCATOR aLocator, LOCATOR[] aIdTrail ) { final LOCATOR[] theIdTrail = (LOCATOR[]) Array.newInstance( aLocator.getClass(), aIdTrail.length + 1 ); // LOCATOR[] theIdTrail = (LOCATOR[]) new Object[aIdTrail.length + 1]; theIdTrail[theIdTrail.length - 1] = aLocator; for ( int i = 0; i < aIdTrail.length; i++ ) { theIdTrail[i] = aIdTrail[i]; } return theIdTrail; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy