/* * 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.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.jboss.errai.common.client.api.Assert; import org.jboss.errai.common.client.api.WrappedPortable; /** * A container for all the live, in-memory objects in a particular entity manager. * * @author Jonathan Fuerth <jfuerth@redhat.com> */ public class PersistenceContext { private final ErraiMetamodel mm; /** * Maps the key for an entity in the persistence context to the actual object that the key refers to. */ private final Map<Key<?, ?>, Object> contents = new HashMap<Key<?, ?>, Object>(); /** * Creates a new PersistenceContext that can track entities represented within * the given metamodel. * * @param mm * The metamodel that knows about all the entity types that will be * stored in this Persistence Context. Not null. */ public PersistenceContext(ErraiMetamodel mm) { this.mm = Assert.notNull(mm); } /** * Stores the given object in the persistence context. Discovers its correct * runtime class and builds the correct Key instance for it. * * @param key * The key to store the entity under. Care must be taken that this * key type reflects the actual runtime type of the given object. * @param object * The object to put into the persistence context. */ public <X, Y> void put(Key<X, Y> key, X object) { contents.put(key, object); } /** * 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; } /** * Removes the entity having the given key from this persistence context. * * @param key * The key of the entity to remove. The key type must be an exact * match for the target object's runtime type. */ public void remove(Key<?, ?> key) { contents.remove(key); } /** * 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; } /** * Returns true if this persistence context contains an entity retrievable by * the given key. The type matching is done in the same way as described in * {@link #get(Key)}. * * @param key * the identity of the entity to look for. Must not be null. * @return True if and only if this persistence context contains an entity * retrievable by the given key. */ public boolean contains(Key<?, ?> key) { return get(key) != null; } /** * Returns the set of all entities in this persistence context. The type * portion of the keys reflect the actual runtime type of the entity. */ public Set<Map.Entry<Key<?, ?>, Object>> entrySet() { return contents.entrySet(); } /** * Returns the collection of all entities in this persistence context. */ public Collection<Object> values() { return contents.values(); } }