public void delete(long id) { sharedLock(); try { failIfReadonlyTx(); validateId(id); Rec old = data.data.get(id); Object entity = obj(old); secureDelete(entity); boolean removed = data.data.remove(id, old); occErrorIf( !removed, "Concurrent modification occured while deleting the object with ID=%s!", id); if (data.insideTx.get()) { data.txChanges.putIfAbsent(id, old); } deleteRelsFor(entity); data.lastChangedOn.set(System.currentTimeMillis()); Log.audit("Deleted DB record", "id", id); } finally { sharedUnlock(); } }
private long _insert(Object record, boolean failOnReadOnlyTx) { U.notNull(record, "record"); secureInsert(record); sharedLock(); try { if (failOnReadOnlyTx) { failIfReadonlyTx(); } long id = data.ids.incrementAndGet(); Beany.setId(record, id); // Optimistic concurrency control through the "version" property if (Beany.hasProperty(record, VERSION)) { // FIXME rollback version in TX fails Beany.setPropValue(record, VERSION, 1); } Date now = new Date(); if (Beany.hasProperty(record, CREATED_BY)) { Beany.setPropValue(record, CREATED_BY, username()); } if (Beany.hasProperty(record, CREATED_ON)) { Beany.setPropValue(record, CREATED_ON, now); } if (Beany.hasProperty(record, LAST_UPDATED_BY)) { Beany.setPropValue(record, LAST_UPDATED_BY, username()); } if (Beany.hasProperty(record, LAST_UPDATED_ON)) { Beany.setPropValue(record, LAST_UPDATED_ON, now); } if (data.insideTx.get()) { if (data.txInsertions.putIfAbsent(id, INSERTION) != null) { throw new IllegalStateException("Cannot insert changelog record with existing ID: " + id); } } if (data.data.putIfAbsent(id, rec(record)) != null) { throw new IllegalStateException("Cannot insert record with existing ID: " + id); } updateChangesFromRels(record); data.lastChangedOn.set(System.currentTimeMillis()); Log.audit("Inserted DB record", "id", id); return id; } finally { sharedUnlock(); } }
private void update_(long id, Object record, boolean reflectRelChanges, boolean checkSecurity) { failIfReadonlyTx(); validateId(id); Rec old = data.data.get(id); Object entity = obj(old); if (checkSecurity) { secureUpdate(entity); } // Optimistic concurrency control through the "version" property Long oldVersion = U.or(Beany.getPropValueOfType(entity, VERSION, Long.class, null), 0L); Long recordVersion = U.or(Beany.getPropValueOfType(record, VERSION, Long.class, null), 0L); occErrorIf( !U.eq(oldVersion, recordVersion), "Concurrent modification occured while updating the object with ID=%s!", id); Beany.setId(record, id); if (!sudo && checkSecurity) { boolean canUpdate = false; for (Prop prop : Beany.propertiesOf(record)) { if (!Secure.getPropertyPermissions(username(), entity.getClass(), entity, prop.getName()) .change) { prop.set(record, prop.get(entity)); } else { canUpdate = true; } } U.secure( canUpdate, "Not enough privileges to update any column of %s!", entity.getClass().getSimpleName()); } // Optimistic concurrency control through the "version" property if (Beany.hasProperty(record, VERSION)) { Beany.setPropValue(record, VERSION, oldVersion + 1); } if (checkSecurity) { secureUpdate(record); } if (Beany.hasProperty(record, LAST_UPDATED_BY)) { Beany.setPropValue(record, LAST_UPDATED_BY, username()); } if (Beany.hasProperty(record, LAST_UPDATED_ON)) { Beany.setPropValue(record, LAST_UPDATED_ON, new Date()); } boolean updated = data.data.replace(id, old, rec(record)); occErrorIf( !updated, "Concurrent modification occured while updating the object with ID=%s!", id); if (data.insideTx.get()) { data.txChanges.putIfAbsent(id, old); } if (old == null) { throw new IllegalStateException("Cannot update non-existing record with ID=" + id); } if (reflectRelChanges) { updateChangesFromRels(record); } data.lastChangedOn.set(System.currentTimeMillis()); Log.audit("Updated DB record", "id", id); }