@Override public <Y> void addAttribute(Attribute<X, Y> attribute) { if (attribute instanceof SingularAttribute) { SingularAttribute<? super X, ?> sa = (SingularAttribute<? super X, ?>) attribute; if (sa.isId()) id = sa; if (sa.isVersion()) version = sa; } super.addAttribute(attribute); }
for (Attribute<? super X, ?> a : getAttributes()) { ErraiAttribute<? super X, ?> attr = (ErraiAttribute<? super X, ?>) a; switch (attr.getPersistentAttributeType()) { case EMBEDDED: case BASIC: copyAttribute(attr, targetEntity, sourceEntity); break; copyPluralAssociation(em, ((ErraiPluralAttribute<X, ?, ?>) attr), targetEntity, sourceEntity); break; copySingularAssociation(em, attr, targetEntity, sourceEntity); break; default:
@Override public String toString() { return "[ManagedType " + getJavaType().getName() + "]"; }
public JSONValue toJson(EntityManager em, X sourceEntity) { final ErraiEntityManager eem = (ErraiEntityManager) em; JSONObject jsonValue = new JSONObject(); for (Attribute<? super X, ?> a : getAttributes()) { ErraiAttribute<? super X, ?> attr = (ErraiAttribute<? super X, ?>) a; switch (attr.getPersistentAttributeType()) { case ELEMENT_COLLECTION: case EMBEDDED: case BASIC: jsonValue.put(attr.getName(), makeInlineJson(sourceEntity, attr, eem)); break; case MANY_TO_MANY: case MANY_TO_ONE: case ONE_TO_MANY: case ONE_TO_ONE: JSONValue attributeValue; if (attr instanceof ErraiSingularAttribute) { attributeValue = makeJsonReference(sourceEntity, (ErraiSingularAttribute<? super X, ?>) attr, eem); } else if (attr instanceof ErraiPluralAttribute) { attributeValue = makeJsonReference(sourceEntity, (ErraiPluralAttribute<? super X, ?, ?>) attr, eem); } else { throw new PersistenceException("Unknown attribute type " + attr); } jsonValue.put(attr.getName(), attributeValue); } } return jsonValue; }
@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; }
/** * 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; }
/** * Creates and returns a new instance of the represented type. This * implementation always throws an exception; subclasses that represent * instantiable types should override this method with one that creates a new * instance of that type. * * @return a new instance of type X. * @throws UnsupportedOperationException * if the represented type is abstract. */ public X newInstance() { // subclasses override when this operation is possible throw new RuntimeException("Can't create an instance of " + getJavaType().getName()); }
/** * Returns true if this managed type represents the same Java class or a * superclass of the given type. * * @param other * the ManagedType to check * @return true if the Java type of this managed is a superclass of the Java * type of the other managed type. */ public boolean isSuperclassOf(ManagedType<?> other) { Class<?> myClass = getJavaType(); Class<?> otherClass = other.getJavaType(); while (otherClass != null) { if (myClass == otherClass) { return true; } otherClass = otherClass.getSuperclass(); } return false; }
@SuppressWarnings("unchecked") @Override public <Y> ErraiSingularAttribute<? super X, Y> getSingularAttribute(String name, Class<Y> type) { for (Attribute<? super X, ?> attr : singularAttributes) { if (attr.getName().equals(name)) { if (attr.getJavaType() != type) { throw new ClassCastException("Attribute \"" + name + "\" of entity " + getJavaType() + " is not of the requested type " + type); } return (ErraiSingularAttribute<? super X, Y>) attr; } } return null; }
/** * Returns a JSONObject representation of this key which can be turned back * into a Key instance via * {@link Key#fromJsonObject(ErraiEntityManager, JSONObject, boolean)}. * * @see #toJson() * @return a JSON object that represents this key. Never null. */ public JSONObject toJsonObject() { JSONObject keyJson = new JSONObject(); keyJson.put("entityType", new JSONString(entityType.getJavaType().getName())); keyJson.put("id", JsonUtil.basicValueToJson(id)); return keyJson; }
/** * 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 void visit(String key, String value) { Key<?, ?> k = parseNamespacedKey(em, key, false); if (k == null) return; logger.trace("getAll(): considering " + value); if (type.isSuperclassOf(k.getEntityType())) { logger.trace(" --> correct type"); JSONObject candidate = JSONParser.parseStrict(value).isObject(); Assert.notNull(candidate); if (matcher.matches(candidate)) { @SuppressWarnings("unchecked") Key<X, ?> typedKey = (Key<X, ?>) k; // Unfortunately, this throws away a lot of work we've already done (getting the entity type, // creating the key, doing a backend.get(), parsing the JSON value, ...) // it would be nice to avoid this, but we have to go back to the entity manager in case the // thing we want is in the persistence context. entities.add((X) em.find(k.getEntityType().getJavaType(), typedKey.getId())); } else { logger.trace(" --> but not a match"); } } else { logger.trace(" --> wrong type"); } } });
/** * Retrieves the entity instance identified by the given Key. * * @param key The key to look up. Must not be null. * @param properties JPA hints (standard and Errai-specific) for the lookup. * @return the entity instance, or null if the entity cannot be found. */ public <X> X find(final Key<X, ?> key, final Map<String, Object> properties) { X entity = cast(key.getEntityType().getJavaType(), persistenceContext.get(key)); if (entity == null) { entity = backend.get(key); if (entity != null) { persistenceContext.put(key, entity); ((ErraiIdentifiableType<X>) key.getEntityType()).deliverPostLoad(entity); } } return entity; }