/* * Kontalk Java client * Copyright (C) 2016 Kontalk Devteam <devteam@kontalk.org> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.kontalk.model.message; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import org.kontalk.misc.JID; import org.kontalk.model.Contact; import org.kontalk.model.Model; import org.kontalk.persistence.Database; /** * A transmission of a message. * * This class represents the sending information of a message: receiver (in message) recipient * (out message) and received timestamp. * * @author Alexander Bikadorov {@literal <bikaejkb@mail.tu-berlin.de>} */ final public class Transmission { private static final Logger LOGGER = Logger.getLogger(Transmission.class.getName()); public static final String TABLE = "transmissions"; public static final String COL_MESSAGE_ID = "message_id"; private static final String COL_CONTACT_ID = "user_id"; private static final String COL_JID = "jid"; private static final String COL_REC_DATE = "received_date"; public static final String SCHEMA = "( " + Database.SQL_ID + COL_MESSAGE_ID + " INTEGER NOT NULL, " + // from or to contact COL_CONTACT_ID + " INTEGER NOT NULL, " + // full jid with resource // TODO do we really need this anywhere? COL_JID + " TEXT NOT NULL, " + // received date, if received yet COL_REC_DATE + " INTEGER, " + "FOREIGN KEY ("+COL_MESSAGE_ID+") REFERENCES "+KonMessage.TABLE+" (_id) " + "FOREIGN KEY ("+COL_CONTACT_ID+") REFERENCES "+Contact.TABLE+" (_id) " + ")"; private final int mID; private final Contact mContact; private final JID mJID; private Date mReceivedDate; Transmission(Contact contact, JID jid, int messageID) { mContact = contact; mJID = jid; mReceivedDate = null; mID = this.insert(messageID); } private Transmission(int id, Contact contact, JID jid, Date receivedDate) { mID = id; mContact = contact; mJID = jid; mReceivedDate = receivedDate; } public Contact getContact() { return mContact; } public JID getJID() { return mJID; } public Optional<Date> getReceivedDate() { return Optional.ofNullable(mReceivedDate); } boolean isReceived() { return mReceivedDate != null; } void setReceived(Date date) { mReceivedDate = date; this.save(); } private int insert(int messageID) { List<Object> values = Arrays.asList( messageID, mContact.getID(), mJID, mReceivedDate); int id = Model.database().execInsert(TABLE, values); if (id <= 0) { LOGGER.log(Level.WARNING, "could not insert"); return -2; } return id; } private void save() { Map<String, Object> set = new HashMap<>(); set.put(COL_REC_DATE, mReceivedDate); Model.database().execUpdate(TABLE, set, mID); } boolean delete() { if (mID < 0) { LOGGER.warning("not in database: "+this); return true; } return Model.database().execDelete(TABLE, mID); } @Override public String toString() { return "T:id="+mID+",contact="+mContact+",jid="+mJID+",recdate="+mReceivedDate; } static Set<Transmission> load(int messageID, Map<Integer, Contact> contactMap) { HashSet<Transmission> ts = new HashSet<>(); try (ResultSet transmissionRS = Model.database().execSelectWhereInsecure(TABLE, COL_MESSAGE_ID + " == " + messageID)) { while (transmissionRS.next()) { ts.add(load(transmissionRS, contactMap)); } } catch (SQLException ex) { LOGGER.log(Level.WARNING, "can't load transmission(s) from db", ex); return Collections.emptySet(); } if (ts.isEmpty()) LOGGER.warning("no transmission(s) found, messageID: "+messageID); return ts; } private static Transmission load(ResultSet resultSet, Map<Integer, Contact> contactMap) throws SQLException { int id = resultSet.getInt("_id"); int contactID = resultSet.getInt(COL_CONTACT_ID); Contact contact = contactMap.get(contactID); if (contact == null) { LOGGER.warning("can't find contact in db, id: "+contactID); return null; } JID jid = JID.full(resultSet.getString(COL_JID)); long rDate = resultSet.getLong(COL_REC_DATE); Date receivedDate = rDate == 0 ? null : new Date(rDate); return new Transmission(id, contact, jid, receivedDate); } @Override public final boolean equals(Object o) { if (o == this) return true; if (!(o instanceof Transmission)) return false; Transmission oTransmission = (Transmission) o; return mContact.equals(oTransmission.mContact) && mJID.equals(oTransmission.mJID); } @Override public int hashCode() { return Objects.hash(mContact, mJID); } }