package votorola.a.trust; // Copyright 2008, 2010, Michael Allan. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Votorola Software"), to deal in the Votorola Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Votorola Software, and to permit persons to whom the Votorola Software is furnished to do so, subject to the following conditions: The preceding copyright notice and this permission notice shall be included in all copies or substantial portions of the Votorola Software. THE VOTOROLA SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE VOTOROLA SOFTWARE OR THE USE OR OTHER DEALINGS IN THE VOTOROLA SOFTWARE. import java.sql.*; import java.util.*; /** A tracer of trust edges. */ public class NetworkTracer { /** Constructs a NetworkTracer. */ public NetworkTracer( TraceNodeW.Table _traceNodeTable, TrustEdge.Table _trustEdgeTable ) { if( _traceNodeTable == null || _trustEdgeTable == null ) throw new NullPointerException(); // fail fast traceNodeTable = _traceNodeTable; trustEdgeTable = _trustEdgeTable; } // ------------------------------------------------------------------------------------ /** Extends a change in trust level from the specified node. Does nothing if no * change actually occured (current level equals old0Level). Otherwise, recursively * extends the change into the network. For this to work, the node table must * already contain a node for each registered voter. Furthermore, each trust edge * that is barred must already be {@linkplain TrustEdge#setBar(String) marked as * barred}. * * @param node0 a source node * @param old0Level its trust level prior to the change */ public void extendLevelChange( final TraceNodeW node0, final int old0Level ) throws SQLException { try{ _extendLevelChange( node0, old0Level ); } finally{ loopDetector.clear(); } // failsafe, for sake of re-calls (probably redundant) } /** The trace-node table for the trace. */ public TraceNodeW.Table traceNodeTable() { return traceNodeTable; } private final TraceNodeW.Table traceNodeTable; /** The trust-edge table for the trace. */ TrustEdge.Table trustEdgeTable() { return trustEdgeTable; } private final TrustEdge.Table trustEdgeTable; //// P r i v a t e /////////////////////////////////////////////////////////////////////// private void _extendLevelChange( final TraceNodeW node0, final int old0Level ) throws SQLException { final int new0Level = node0.trustLevel(); if( new0Level == old0Level ) return; // no change, nothing to do // if( new0Level == 0 ) // { // assert false: "only trusted nodes are reached in a trace"; // return; // } ///// detaching edges (in future) may result in zero levels { TraceNodeW node0Original = loopDetector.put( node0.registrant().email(), node0 ); if( node0Original != null ) { loopDetector.put( node0.registrant().email(), node0Original ); // put it back assert false: "trace loops are logically impossible"; return; } } try { for( final TrustEdge edge: trustEdgeTable.listEdgesFrom( node0.registrant() )) { if( edge.getBar() != null ) continue; // barred edges are not extended final TraceNodeW node1 = traceNodeTable.get( edge.registrant1() ); if( node1 == null ) { assert false: "all edges to unregistered (null) destinations are barred"; continue; } final int old1Level = node1.trustLevel(); if( old0Level != 0 ) node1.detachTrustEdge( old0Level ); if( new0Level != 0 ) node1.attachTrustEdge( new0Level ); node1.write( traceNodeTable ); _extendLevelChange( node1, old1Level ); } } finally { loopDetector.remove( node0.registrant().email() ); } } /** Loops are logically impossible, but I detect them for sake of robustness. They * are impossible because the maximum trust level that any node can be increased to, * during a trace, is limited to the level of the previous node. Therefore, the * level of a node cannot be affected by cyclic trace. * *

A cyclic trace can attach a reverse direction edge to a prior node, from * earlier in the trace. It will have no effect on trust level, because the prior * node would already be at the same level (or higher) of the edge source. The edge * must still be attached, to permit clean detachment later, in the event that an * intermediate node detaches an edge, and the effect cascades back to prior nodes * (which may be undetected by this loop detector, unless the detachment trace began * from the root, and therefore included all nodes).

*/ private final HashMap loopDetector = new HashMap(); }