package votorola.a.election; // Copyright 2007, 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.io.*; import votorola.g.lang.*; /** The tallied results of an election. */ public @ThreadSafe final class Count implements Serializable { // Cf. a/register/VoterList private static final long serialVersionUID = 5L; // Also depends on the structure of the relational table, as well as the structure of this class. /** Constructs a Count. * * @param readyDirectory per {@linkplain #readyDirectory() readyDirectory}() */ Count( ReadyDirectory readyDirectory, CountNode.Table.RankedCumulate rankedCumulate ) { this.readyDirectory = readyDirectory; candidateCount = rankedCumulate.candidateCount; nodeCount = rankedCumulate.nodeCount; rankCount = rankedCumulate.rankCount; singleCastCount = rankedCumulate.singleCastCount; assert singleCastCount == rankedCumulate.holdCount; } /** @see #writeObjectToMountedCountFile() */ static Count readObjectFromMountedCountFile( ReadyDirectory readyDirectory ) throws IOException { final ObjectInputStream in = new ObjectInputStream ( new BufferedInputStream( new FileInputStream( readyDirectory.mountedFile() ))); final Count count; try { count = (Count)in.readObject(); } catch( ClassNotFoundException x ) { throw new RuntimeException( x ); } finally{ in.close(); } count.readyDirectory = readyDirectory; return count; } /** @see #readObjectFromMountedCountFile(ReadyDirectory) */ void writeObjectToMountedCountFile() throws IOException { ObjectOutputStream out = new ObjectOutputStream( new BufferedOutputStream( new FileOutputStream( readyDirectory.mountedFile() ))); try { out.writeObject( Count.this ); } finally{ out.close(); } } /** @see #countNodeTable() */ @ThreadRestricted("constructor") void init( CountNode.Table countNodeTable ) { this.countNodeTable = countNodeTable; } // ------------------------------------------------------------------------------------ /** The number of nodes with a receive count of 1 or higher. * * @see CountNode#receiveCount() */ public long candidateCount() { return candidateCount; } private final long candidateCount; /** The relational store of count nodes that (in part) backs this count. * It is a schema.table named * "{@linkplain Election#name() election-name}.date-count_node-date", * stored in the count database. * * @return reference to relational store; or null, if the count * was not initialized with a reference * * @see Election#countDatabase() * @see #init(CountNode.Table) */ public CountNode.Table countNodeTable() { return countNodeTable; } private transient CountNode.Table countNodeTable; // final after init /** The total hold count for all nodes. This is identical * to the {@linkplain #singleCastCount() number of votes cast}. * * @see CountNode#holdCount() */ public long holdCount() { return singleCastCount; } /** The number of recorded nodes, corresponding to rows in the node table. It * includes eligible and ineligible voters. It might (in future) include voters who * are not participating at all in the election, but have set some particular flag * (such as non-cascading). This value is not meaningful, therefore, except to * administrators. * * @see CountNode */ public long nodeCount() { return nodeCount; } private final long nodeCount; /** The total number of ranks. This is also the value of the bottom rank, * that of the node(s) receiving the lowest number (normally zero) of votes. * * @see CountNode#getRank() * @return count of 1 or larger; or 0, if there are no nodes at all */ public long rankCount() { return rankCount; } private final long rankCount; /** The file part of the backing for this count. */ public ReadyDirectory readyDirectory() { return readyDirectory; } private transient ReadyDirectory readyDirectory; // final after init /** The total number of votes cast. This is identical * to the {@linkplain #holdCount() hold count}. * * @see CountNode#singleCastCount() */ public long singleCastCount() { return singleCastCount; } private final long singleCastCount; }