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}