001package 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. 002 003import java.sql.*; 004import java.util.*; 005 006 007/** A tracer of trust edges. 008 */ 009public class NetworkTracer 010{ 011 012 013 /** Constructs a NetworkTracer. 014 */ 015 public NetworkTracer( TraceNodeW.Table _traceNodeTable, TrustEdge.Table _trustEdgeTable ) 016 { 017 if( _traceNodeTable == null || _trustEdgeTable == null ) throw new NullPointerException(); // fail fast 018 019 traceNodeTable = _traceNodeTable; 020 trustEdgeTable = _trustEdgeTable; 021 } 022 023 024 025 // ------------------------------------------------------------------------------------ 026 027 028 /** Extends a change in trust level from the specified node. Does nothing if no 029 * change actually occured (current level equals old0Level). Otherwise, recursively 030 * extends the change into the network. For this to work, the node table must 031 * already contain a node for each registered voter. Furthermore, each trust edge 032 * that is barred must already be {@linkplain TrustEdge#setBar(String) marked as 033 * barred}. 034 * 035 * @param node0 a source node 036 * @param old0Level its trust level prior to the change 037 */ 038 public void extendLevelChange( final TraceNodeW node0, final int old0Level ) throws SQLException 039 { 040 try{ _extendLevelChange( node0, old0Level ); } 041 finally{ loopDetector.clear(); } // failsafe, for sake of re-calls (probably redundant) 042 } 043 044 045 046 /** The trace-node table for the trace. 047 */ 048 public TraceNodeW.Table traceNodeTable() { return traceNodeTable; } 049 050 051 private final TraceNodeW.Table traceNodeTable; 052 053 054 055 /** The trust-edge table for the trace. 056 */ 057 TrustEdge.Table trustEdgeTable() { return trustEdgeTable; } 058 059 060 private final TrustEdge.Table trustEdgeTable; 061 062 063 064//// P r i v a t e /////////////////////////////////////////////////////////////////////// 065 066 067 private void _extendLevelChange( final TraceNodeW node0, final int old0Level ) throws SQLException 068 { 069 final int new0Level = node0.trustLevel(); 070 if( new0Level == old0Level ) return; // no change, nothing to do 071 072 // if( new0Level == 0 ) 073 // { 074 // assert false: "only trusted nodes are reached in a trace"; 075 // return; 076 // } 077 ///// detaching edges (in future) may result in zero levels 078 079 { 080 TraceNodeW node0Original = loopDetector.put( node0.registrant().email(), node0 ); 081 if( node0Original != null ) 082 { 083 loopDetector.put( node0.registrant().email(), node0Original ); // put it back 084 assert false: "trace loops are logically impossible"; 085 return; 086 } 087 } 088 try 089 { 090 for( final TrustEdge edge: trustEdgeTable.listEdgesFrom( node0.registrant() )) 091 { 092 if( edge.getBar() != null ) continue; // barred edges are not extended 093 094 final TraceNodeW node1 = traceNodeTable.get( edge.registrant1() ); 095 if( node1 == null ) 096 { 097 assert false: "all edges to unregistered (null) destinations are barred"; 098 continue; 099 } 100 101 final int old1Level = node1.trustLevel(); 102 if( old0Level != 0 ) node1.detachTrustEdge( old0Level ); 103 if( new0Level != 0 ) node1.attachTrustEdge( new0Level ); 104 node1.write( traceNodeTable ); 105 _extendLevelChange( node1, old1Level ); 106 } 107 } 108 finally { loopDetector.remove( node0.registrant().email() ); } 109 } 110 111 112 113 /** Loops are logically impossible, but I detect them for sake of robustness. They 114 * are impossible because the maximum trust level that any node can be increased to, 115 * during a trace, is limited to the level of the previous node. Therefore, the 116 * level of a node cannot be affected by cyclic trace. 117 * 118 * <p>A cyclic trace can attach a reverse direction edge to a prior node, from 119 * earlier in the trace. It will have no effect on trust level, because the prior 120 * node would already be at the same level (or higher) of the edge source. The edge 121 * must still be attached, to permit clean detachment later, in the event that an 122 * intermediate node detaches an edge, and the effect cascades back to prior nodes 123 * (which may be undetected by this loop detector, unless the detachment trace began 124 * from the root, and therefore included all nodes).</p> 125 */ 126 private final HashMap<String,TraceNodeW> loopDetector = new HashMap<String,TraceNodeW>(); 127 128 129 130}