package org.bitseal.core; import java.util.ArrayList; import org.bitseal.data.Payload; import org.bitseal.database.PayloadProvider; import org.bitseal.database.PayloadsTable; import org.bitseal.network.ServerCommunicator; import org.bitseal.util.ArrayCopier; import android.util.Log; /** * This class handles all the processing that needs to be * done for handling acknowledgements. * * @author Jonathan Coe */ public class AckProcessor { private static final String TAG = "ACK_PROCESSOR"; /** * This method will look in the application database's "Payloads" table * for any acknowledgement payloads that 'belong to me', and are thus * acknowledgements that are waiting to be sent for messages that the user * of the app has received. * * @return - A boolean indicating whether or not all outstanding acknowledgements * were successfully processed */ public boolean sendAcknowledgments() { PayloadProvider payProv = PayloadProvider.get(App.getContext()); ArrayList<Payload> allAcks = payProv.searchPayloads(PayloadsTable.COLUMN_ACK, String.valueOf(1)); // 1 stands for true in the database if (allAcks.size() > 0) { ArrayList<Payload> acksToSend = new ArrayList<Payload>(); for (Payload p : allAcks) { if (p.belongsToMe() == false) { acksToSend.add(p); } } Log.i(TAG, "Number of acknowledgment messages that I need to send: " + acksToSend.size()); // Attempt to send each ack payload retrieved from the database. If any of these payloads // are not processed successfully, that failure is recorded in 'numberOfAcksNotProcessedSuccessfully' int numberOfAcksNotProcessedSuccessfully = 0; for (Payload p : acksToSend) { boolean ackProcessedSuccessfully = false; try { ackProcessedSuccessfully = checkAndSendAcknowledgment(p); } catch (Exception e) { Log.e(TAG, "While running AckProcessor.checkAndSendAcknowledgment(), and Exception was thrown. \n" + "The exception message was: " + e.getMessage()); } if (ackProcessedSuccessfully == false) { numberOfAcksNotProcessedSuccessfully = numberOfAcksNotProcessedSuccessfully + 1; } } if (numberOfAcksNotProcessedSuccessfully > 0) { // If we failed to process all acks successfully return false; } else { // If we processed all acks successfully return true; } } else { // If there are no acks to process return true; } } /** * This method checks an acknowledgement message and, if it is found to be valid, * attempts to disseminate it to the Bitmessage network. * * @param p - A Payload object containing the acknowledgement msg to be sent * * @return - A boolean indicating whether or not the acknowledgement was successfully * processed */ private boolean checkAndSendAcknowledgment(Payload p) { byte[] fullAckMessage = p.getPayload(); // Bitmessage acknowledgements are full Message objects, including the header data (magic bytes, command, length, checksum). // We only need the payload, so we will skip over the first 24 bytes. byte[] ackObjectBytes = ArrayCopier.copyOfRange(fullAckMessage, 24, fullAckMessage.length); // Check whether this ack is a valid Bitmessage Object try { new ObjectProcessor().parseObject(ackObjectBytes); } catch (RuntimeException e) { Log.e(TAG, "Runtime exception occurred while running ObjectProcessor.parseObject() from AckProcessor.checkAndSendAcknowledgment(). " + "This indicates that the acknowledgement payload is not a valid Bitmessage object. Therefore the ack payload will be deleted " + "and the attempt to send it will be cancelled. The full RuntimeException message was:\n" + e.getMessage()); PayloadProvider.get(App.getContext()).deletePayload(p); return false; } // Attempt to send the acknowledgement. ServerCommunicator servCom = new ServerCommunicator(); boolean disseminationSuccessful = servCom.disseminateMsg(ackObjectBytes); // If it is sent successfully, delete it from the database. If not, it will be kept // and we will try to send it again later. if (disseminationSuccessful) { PayloadProvider payProv = PayloadProvider.get(App.getContext()); payProv.deletePayload(p); return true; } else { return false; } } }