/* * Copyright (C) 2015 Red Hat, Inc. and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.errai.jpa.client.local; import java.util.Set; import javax.persistence.EntityManager; import javax.persistence.PersistenceException; import javax.persistence.PostLoad; import javax.persistence.PostPersist; import javax.persistence.PostRemove; import javax.persistence.PostUpdate; import javax.persistence.PrePersist; import javax.persistence.PreRemove; import javax.persistence.PreUpdate; import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.IdentifiableType; import javax.persistence.metamodel.SingularAttribute; import javax.persistence.metamodel.Type; import com.google.gwt.json.client.JSONValue; /** * Errai implementation of the JPA IdentifiableType metamodel interface. Specializes * ManagedType by adding properties related to ID and version attributes. * * @author Jonathan Fuerth <jfuerth@redhat.com> * * @param <X> The actual type described by this metatype. */ public abstract class ErraiIdentifiableType<X> extends ErraiManagedType<X> implements IdentifiableType<X> { private SingularAttribute<? super X, ?> id; private SingularAttribute<? super X, ?> version; public ErraiIdentifiableType(Class<X> javaType) { super(javaType); } /** * Delivers the {@link PrePersist} event to the pre-persist listeners on the given * instance of this entity. * * @param targetEntity * The entity instance to deliver the PrePersist event to. */ public abstract void deliverPrePersist(X targetEntity); /** * Delivers the {@link PostPersist} event to the post-persist listeners on the given * instance of this entity. * * @param targetEntity * The entity instance to deliver the PostPersist event to. */ public abstract void deliverPostPersist(X targetEntity); /** * Delivers the {@link PreUpdate} event to the pre-Update listeners on the given * instance of this entity. * * @param targetEntity * The entity instance to deliver the PreUpdate event to. */ public abstract void deliverPreUpdate(X targetEntity); /** * Delivers the {@link PostUpdate} event to the post-Update listeners on the given * instance of this entity. * * @param targetEntity * The entity instance to deliver the PostUpdate event to. */ public abstract void deliverPostUpdate(X targetEntity); /** * Delivers the {@link PreRemove} event to the pre-Remove listeners on the given * instance of this entity. * * @param targetEntity * The entity instance to deliver the PreRemove event to. */ public abstract void deliverPreRemove(X targetEntity); /** * Delivers the {@link PostRemove} event to the post-Remove listeners on the given * instance of this entity. * * @param targetEntity * The entity instance to deliver the PostRemove event to. */ public abstract void deliverPostRemove(X targetEntity); /** * Delivers the {@link PostLoad} event to the post-load listeners on the given * instance of this entity. * * @param targetEntity * The entity instance to deliver the PostLoad event to. */ public abstract <Y> void deliverPostLoad(X targetEntity); /** * Converts the given JSONValue, which represents an instance of this entity * type, into the actual instance of this entity type that exists in the given * EntityManager's persistence context. References to other entities are * recursively retrieved from the EntityManager. * * @param em * The EntityManager that owns this entity type and houses the * persistence context. * @param jsonValue * A value that represents an instance of this entity type. * @return A managed entity that is in the given EntityManager's persistence * context. */ @Override public X fromJson(EntityManager em, JSONValue jsonValue) { final ErraiEntityManager eem = (ErraiEntityManager) em; Key<X, ?> key = keyFromJson(jsonValue); X entity = eem.getPartiallyConstructedEntity(key); if (entity != null) { return entity; } entity = newInstance(); try { eem.putPartiallyConstructedEntity(key, entity); for (Attribute<? super X, ?> a : getAttributes()) { ErraiAttribute<? super X, ?> attr = (ErraiAttribute<? super X, ?>) a; JSONValue attrJsonValue = jsonValue.isObject().get(attr.getName()); // this attribute did not exist when the entity was originally persisted; skip it. if (attrJsonValue == null) continue; switch (attr.getPersistentAttributeType()) { case ELEMENT_COLLECTION: case EMBEDDED: case BASIC: parseInlineJson(entity, attr, attrJsonValue, eem); break; case MANY_TO_MANY: case MANY_TO_ONE: case ONE_TO_MANY: case ONE_TO_ONE: if (attr instanceof ErraiSingularAttribute) { parseSingularJsonReference(entity, (ErraiSingularAttribute<? super X, ?>) attr, attrJsonValue, eem); } else if (attr instanceof ErraiPluralAttribute) { parsePluralJsonReference(entity, (ErraiPluralAttribute<? super X, ?, ?>) attr, attrJsonValue.isArray(), eem); } else { throw new PersistenceException("Unknown attribute type " + attr); } } } return entity; } finally { eem.removePartiallyConstructedEntity(key); } } 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); } @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); } // ---------- JPA API Below This Line ------------- @SuppressWarnings("unchecked") @Override public <Y> ErraiSingularAttribute<? super X, Y> getId(Class<Y> type) { return (ErraiSingularAttribute<? super X, Y>) id; } @SuppressWarnings("unchecked") @Override public <Y> SingularAttribute<X, Y> getDeclaredId(Class<Y> type) { // XXX the JPA spec is not clear on the difference between id and declaredId return (SingularAttribute<X, Y>) id; } @SuppressWarnings("unchecked") @Override public <Y> SingularAttribute<? super X, Y> getVersion(Class<Y> type) { return (SingularAttribute<? super X, Y>) version; } @SuppressWarnings("unchecked") @Override public <Y> SingularAttribute<X, Y> getDeclaredVersion(Class<Y> type) { // XXX the JPA spec is not clear on the difference between version and declaredVersion return (SingularAttribute<X, Y>) version; } @Override public IdentifiableType<? super X> getSupertype() { throw new RuntimeException("Not implemented"); } @Override public boolean hasSingleIdAttribute() { return id != null; } @Override public boolean hasVersionAttribute() { return version != null; } @Override public Set<SingularAttribute<? super X, ?>> getIdClassAttributes() { // TODO Auto-generated method stub throw new UnsupportedOperationException(); } @Override public Type<?> getIdType() { return id.getType(); } @Override public javax.persistence.metamodel.Type.PersistenceType getPersistenceType() { return PersistenceType.ENTITY; } @Override public String toString() { return "[IdentifiableType " + getJavaType().getName() + "]"; } }