private Prop findRelProperty(Class<?> fromCls, String rel, Class<?> toCls) { Object entity = !fromCls.isInterface() ? data.constructor.create(fromCls) : null; for (Prop prop : Beany.propertiesOf(fromCls).select(data.relPropSelector)) { String relName = null; if (!fromCls.isInterface()) { Object value = prop.getRaw(entity); if (hasEntityLinks(value)) { EntityLinks links = entityLinks(value); relName = links.relationName(); } } else { Rel relation = prop.getAnnotation(Rel.class); if (relation != null) { relName = relation.value(); } } if (relName != null && relName.equals(rel)) { if (prop.getRawTypeArg(0).equals(toCls)) { return prop; } } } Log.warn( "Didn't find inverse relation property!", "relation", rel, "from", fromCls, "to", toCls); return null; }
public long insertOrGetId(Object record) { Long id = Beany.getLongIdIfExists(record); if (id == null || id <= 0) { return insert(record); } else { return id; } }
public long persist(Object record) { Long id = Beany.getLongIdIfExists(record); if (id == null || id <= 0) { return insert(record); } else { update(id, record); return id; } }
private void deleteRelsFor(Object entity) { for (Prop prop : Beany.propertiesOf(entity).select(data.relPropSelector)) { Object value = prop.getRaw(entity); if (hasEntityLinks(value)) { EntityLinks links = entityLinks(value); long fromId = links.fromId(); propageteRelChanges(entity, prop, links, fromId, null, links.allRelIds()); } } }
private <T> T get_(long id, Class<T> clazz) { validateId(id); Rec rec = data.data.get(id); if (rec != null) { T record = obj(rec, clazz); Beany.setId(record, id); return record; } else { return null; } }
public <T> T readColumn(long id, String column) { sharedLock(); try { Object record = getIfAllowed(id, true); secureReadColumn(record, column); T value = Beany.getPropValue(record, column); return value; } finally { sharedUnlock(); } }
public static boolean matches(Object record, String query, Object... args) { if (query == null || query.isEmpty()) { return true; } if (P_WORD.matcher(query).matches() && args.length == 1) { Object val = Beany.getPropValue(record, query, null); Object arg = args[0]; return val == arg || (val != null && val.equals(arg)); } throw new RuntimeException("Query not supported: " + query); }
private <E> E get_(long id, boolean validateId) { if (validateId) { validateId(id); } Rec rec = data.data.get(id); if (rec != null) { E record = obj(rec); Beany.setId(record, id); return record; } else { return null; } }
public void refresh(Object record) { sharedLock(); try { long id = Beany.getLongId(record); validateId(id); Rec rec = getRec(id); Object tmp = obj(rec); secureRead(tmp); obj(rec, record); resetInvisibleColumns(record); } finally { sharedUnlock(); } }
public <E> void each(final Operation<E> lambda) { sharedLock(); try { for (Entry<Long, Rec> entry : data.data.entrySet()) { E record = obj(entry.getValue()); Beany.setId(record, entry.getKey()); if (canRead(record)) { try { lambda.execute(record); } catch (ClassCastException e) { // ignore, cast exceptions are expected } catch (Exception e) { throw new RuntimeException(e); } } } } finally { sharedUnlock(); } }
public static <T> Items all(Predicate<T> match) { return all(match, Beany.<T>comparator("id")); }
public static <T> Items all(Class<T> type, Predicate<T> match, String orderBy) { return new DbItems<T>(type, match, Beany.<T>comparator(orderBy)); }
public static <T> Items all(Class<T> type, String orderBy) { return new DbItems<T>(type, null, Beany.<T>comparator(orderBy)); }
public static <T> Items all(Class<T> type) { return new DbItems<T>(type, null, Beany.<T>comparator("id")); }
public void delete(Object record) { U.validateArg("record", Cls.kindOf(record) == TypeKind.OBJECT); delete(Beany.getLongId(record)); }
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(); } }
public void update(Object record) { update(Beany.getLongId(record), record); }
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); }