@Override public BigInteger next(ErraiEntityManager entityManager) { BigInteger nextAvailableId = nextCandidateId; while (entityManager.isKeyInUse(new Key<X, BigInteger>((ErraiIdentifiableType<X>) attr.getDeclaringType(), nextAvailableId))) { nextAvailableId = nextAvailableId.add(new BigInteger(String.valueOf(Math.random() * probeJumpSize))); } nextCandidateId = nextAvailableId.add(BigInteger.ONE); return nextAvailableId; }
@Override public Long next(ErraiEntityManager entityManager) { while (entityManager.isKeyInUse(new Key<X, Long>((ErraiIdentifiableType<X>) attr.getDeclaringType(), nextCandidateId))) { nextCandidateId += (long) (Math.random() * probeJumpSize); // control rollover in case we run out of values if (nextCandidateId >= Long.MAX_VALUE - probeJumpSize) { nextCandidateId = 0; } } return nextCandidateId++; } }
@Override public Integer next(ErraiEntityManager entityManager) { while (entityManager.isKeyInUse(new Key<X, Integer>((ErraiIdentifiableType<X>) attr.getDeclaringType(), nextCandidateId))) { nextCandidateId += (int) (Math.random() * probeJumpSize); // control rollover in case we run out of values if (nextCandidateId >= Integer.MAX_VALUE - probeJumpSize) { nextCandidateId = 1; } } return nextCandidateId++; }
/** * Returns a Key instance corresponding to the runtime type of the given * object, and the given ID value. * * @param object * The object to get the type information from. If it is a proxy * (WrappedPortable) it will be unwrapped. Must not be null. * @param id * The ID value for the key. Must not be null. * @return A key for the given ID and the exact type of the given object. */ @SuppressWarnings("unchecked") private <X, Y> Key<X, Y> normalizedKey(X object, Y id) { X unwrapped = object; if (object instanceof WrappedPortable) { unwrapped = (X) ((WrappedPortable) object).unwrap(); } ErraiManagedType<X> actualEntityType = (ErraiManagedType<X>) mm.entity(unwrapped.getClass()); Key<X, Y> normalizedKey = new Key<X, Y>(actualEntityType, id); return normalizedKey; }
/** * Returns a Key instance for the entity type of the given class. * * @param em * The entity manager (required for looking up the EntityType for the * given class). Must not be null. * @param entityClass * The class of the entity for the key. Must not be null. * @param id * The ID value for the entity. Must not be null. * @return A Key instance for the given entity type and ID value. * @throws NullPointerException * if any argument is null. * @throws IllegalArgumentException * if {@code entityClass} is not a known JPA entity type. */ public static <X, T> Key<X, T> get(ErraiEntityManager em, Class<X> entityClass, T id) { ErraiIdentifiableType<X> entityType = em.getMetamodel().entity(entityClass); return new Key<X, T>(entityType, id); }
/** * Looks up and returns the entity that matches the given key. The key's type * need not be an exact match; any supertype of the requested entity will * suffice. * * @param key * the key to look up. The entity type portion can be any supertype * of the matched entity. The ID is always an exact match. Must not * be null. * @return The entity that matches the ID and has the same type or a subtype * of the type specified in the key. */ @SuppressWarnings("unchecked") public <X> X get(Key<X, ?> key) { for (ErraiManagedType<? extends X> mt : key.getEntityType().getSubtypes()) { Key<? super X, ?> k = new Key<Object, Object>((ErraiManagedType<Object>) mt, key.getId()); X o = (X) contents.get(k); if (o != null) { return o; } } return null; }
@Override public <X, Y> boolean contains(Key<X, Y> key) { boolean contains = false; for (ErraiManagedType<X> type : key.getEntityType().getSubtypes()) { Key<?, ?> k = new Key<X, Y>(type, key.getId()); String keyJson = namespace + k.toJson(); contains = LocalStorage.get(keyJson) != null; logger.trace("<<<contains '" + keyJson + "' : " + contains); if (contains) break; } return contains; }
/** * Tests if this entity manager's storage backend contains an entity that * could conflict with the given key. This method is free of side effects: it * will not affect the contents of the persistence context, and it will not * affect the persistence state of any entity (hence it will not deliver any * events to JPA lifecycle listeners). * * @param key * The key to test for in backend storage. Not null. * @return true if and only if this entity manager's storage backend contains * an entity with the given key. */ public boolean isKeyInUse(final Key<?, ?> key) { // search up the supertype chain for the most generic entity type reachable from the type given in the key ErraiManagedType<?> superManagedType = key.getEntityType(); Class<?> javaType = key.getEntityType().getJavaType().getSuperclass(); while (javaType != null) { final ErraiManagedType<?> mt = metamodel.entity(javaType.getName(), false); if (mt != null) { superManagedType = mt; } javaType = javaType.getSuperclass(); } final Key<?, ?> mostGenericKey = new Key<Object, Object>((ErraiManagedType<Object>) superManagedType, key.getId()); return backend.contains(mostGenericKey); }
@Override public <X> X get(Key<X, ?> requestedKey) { for (ErraiManagedType<? extends X> entityType : requestedKey.getEntityType().getSubtypes()) { Key<X, ?> key = new Key<X, Object>((ErraiManagedType<X>) entityType, (Object) requestedKey.getId()); String keyJson = namespace + key.toJson(); String valueJson = LocalStorage.get(keyJson); logger.trace("<<<get '" + keyJson + "' : " + valueJson); X entity; if (valueJson != null) { entity = entityType.fromJson(em, JSONParser.parseStrict(valueJson)); logger.trace(" returning " + entity); return entity; } } return null; }
private Key<X, ?> keyFromJson(JSONValue json) { JSONValue keyJson = json.isObject().get(id.getName()); Object idValue = JsonUtil.basicValueFromJson(keyJson, id.getJavaType()); return new Key<X, Object>(this, idValue); }
/** * Creates the key that describes the given entity, <b>generating and setting * it if it is presently unset and the given entity type's ID is configured to * be generated on demand</b>. * * @param entityType * The entity type of the entity * @param entity * The entity instance. <b>Side effect: this instance may have its ID * value initialized as a result of this call</b>. * @return The key for the given entity, which--for generated values--may have * just been set on the entity. */ public <X> Key<X, ?> keyFor(final ErraiIdentifiableType<X> entityType, final X entity) { ErraiSingularAttribute<? super X, ?> idAttr; switch (entityType.getIdType().getPersistenceType()) { case BASIC: idAttr = entityType.getId(entityType.getIdType().getJavaType()); break; default: throw new RuntimeException(entityType.getIdType().getPersistenceType() + " ids are not yet supported"); } Object id = idAttr.get(entity); if ( idAttr.isGeneratedValue() && (id == null || (id instanceof Number && ((Number) id).doubleValue() == 0.0)) ) { id = generateAndSetLocalId(entity, idAttr); // TODO track this generated ID for later reconciliation with the server } return new Key<>(entityType, id); }
ref = new Key<Y, Object>(attrEntityType, idToReference).toJsonObject();
/** * Returns a Key instance based on the given JSON object. * * @param em * The entity manager that can be used to look up the entity type * corresponding with the key. * @param key * The properties of the key to create. * @param failIfNotFound * If true, and the entity type given in {@code key} is not known to * {@code em}, an IllegalArgumentException will be thrown. * @return An instance of Key that corresponds with the entity type and ID of * the given JSON object. */ public static Key<?, ?> fromJsonObject(ErraiEntityManager em, JSONObject key, boolean failIfNotFound) { String entityClassName = key.get("entityType").isString().stringValue(); ErraiIdentifiableType<Object> et = em.getMetamodel().entity(entityClassName, failIfNotFound); if (et == null) { return null; } ErraiSingularAttribute<?, Object> idAttr = et.getId(Object.class); Object id = JsonUtil.basicValueFromJson(key.get("id"), idAttr.getJavaType()); return new Key<Object, Object>(et, id); } }
ref = new Key<E, Object>(attrEntityType, idToReference).toJsonObject();