All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vaadin.addon.jpacontainer.provider.MutableLocalEntityProvider Maven / Gradle / Ivy

The newest version!
/*
 * JPAContainer
 * Copyright (C) 2010 Oy IT Mill Ltd
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see .
 */
package com.vaadin.addon.jpacontainer.provider;

import java.lang.ref.WeakReference;
import java.util.Iterator;
import java.util.LinkedList;

import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;

import com.vaadin.addon.jpacontainer.EntityProviderChangeEvent;
import com.vaadin.addon.jpacontainer.EntityProviderChangeListener;
import com.vaadin.addon.jpacontainer.EntityProviderChangeNotifier;
import com.vaadin.addon.jpacontainer.MutableEntityProvider;

/**
 * Extended version of {@link LocalEntityProvider} that provides editing
 * support. Transactions can either be handled internally by the provider, or by
 * an external container such as Spring or EJB (see the JPAContainer manual for
 * examples of how to do this). By default, transactions are handled internally
 * by invoking the transaction methods of the EntityManager.
 * 

* This entity provider fires {@link EntityProviderChangeEvent}s every time an * entity is added, updated or deleted. * * @author Petter Holmström (IT Mill) * @since 1.0 */ public class MutableLocalEntityProvider extends LocalEntityProvider implements MutableEntityProvider, EntityProviderChangeNotifier { private static final long serialVersionUID = -6628293930338167750L; /** * Creates a new MutableLocalEntityProvider. The entity manager * must be set using * {@link #setEntityManager(javax.persistence.EntityManager) }. * * @param entityClass * the entity class (must not be null). */ public MutableLocalEntityProvider(Class entityClass) { super(entityClass); } /** * Creates a new MutableLocalEntityProvider. * * @param entityClass * the entity class (must not be null). * @param entityManager * the entity manager to use (must not be null). */ public MutableLocalEntityProvider(Class entityClass, EntityManager entityManager) { super(entityClass, entityManager); } private boolean transactionsHandled = true; /** * Specifies whether the entity provider should handle transactions itself * or whether they should be handled outside (e.g. if declarative * transactions are used). * * @param transactionsHandled * true to handle the transactions internally, false to rely on * external transaction handling. */ public void setTransactionsHandledByProvider(boolean transactionsHandled) { this.transactionsHandled = transactionsHandled; } /** * Returns whether the entity provider is handling transactions internally * (the default) or relies on external transaction handling. * * @return true if transactions are handled internally, false if not. */ public boolean isTransactionsHandledByProvider() { return transactionsHandled; } /** * If {@link #isTransactionsHandledByProvider() } is true, * operation will be executed inside a transaction that is * commited after the operation is completed. Otherwise, * operation will just be executed. * * @param operation * the operation to run (must not be null). */ protected void runInTransaction(Runnable operation) { assert operation != null : "operation must not be null"; if (isTransactionsHandledByProvider()) { EntityTransaction et = getEntityManager().getTransaction(); if (et.isActive()) { // The transaction has been started outside of this method // and should also be committed/rolled back outside of // this method operation.run(); } else { try { et.begin(); operation.run(); et.commit(); } finally { if (et.isActive()) { et.rollback(); } } } } else { operation.run(); } } @SuppressWarnings("unchecked") public T addEntity(final T entity) { assert entity != null; final Object[] entityA = new Object[1]; runInTransaction(new Runnable() { public void run() { EntityManager em = getEntityManager(); entityA[0] = em.merge(entity); em.flush(); } }); T dEntity = detachEntity((T) entityA[0]); fireEntityProviderChangeEvent(new EntitiesAddedEvent(this, dEntity)); return dEntity; } @SuppressWarnings("unchecked") public void removeEntity(final Object entityId) { assert entityId != null; final Object[] entityA = new Object[1]; runInTransaction(new Runnable() { public void run() { EntityManager em = getEntityManager(); T entity = em.find(getEntityClassMetadata().getMappedClass(), entityId); if (entity != null) { em.remove(em.merge(entity)); em.flush(); entityA[0] = detachEntity(entity); } } }); if (entityA[0] != null) { fireEntityProviderChangeEvent(new EntitiesRemovedEvent(this, (T) entityA[0])); } } @SuppressWarnings("unchecked") public T updateEntity(final T entity) { assert entity != null : "entity must not be null"; final Object[] entityA = new Object[1]; runInTransaction(new Runnable() { public void run() { EntityManager em = getEntityManager(); entityA[0] = em.merge(entity); em.flush(); } }); T dEntity = detachEntity((T) entityA[0]); fireEntityProviderChangeEvent(new EntitiesUpdatedEvent(this, dEntity)); return dEntity; } @SuppressWarnings("unchecked") public void updateEntityProperty(final Object entityId, final String propertyName, final Object propertyValue) throws IllegalArgumentException { assert entityId != null : "entityId must not be null"; assert propertyName != null : "propertyName must not be null"; final Object[] entityA = new Object[1]; runInTransaction(new Runnable() { public void run() { EntityManager em = getEntityManager(); T entity = em.find(getEntityClassMetadata().getMappedClass(), entityId); if (entity != null) { // make sure we are working with the latest versions em.refresh(entity); getEntityClassMetadata().setPropertyValue(entity, propertyName, propertyValue); // re-attach also referenced entities to the persistence // context entity = em.merge(entity); em.flush(); entityA[0] = detachEntity(entity); } } }); if (entityA[0] != null) { fireEntityProviderChangeEvent(new EntitiesUpdatedEvent(this, (T) entityA[0])); } } private LinkedList>> listeners = new LinkedList>>(); public void addListener(EntityProviderChangeListener listener) { synchronized (listeners) { assert listener != null : "listener must not be null"; listeners.add(new WeakReference>( listener)); } } public void removeListener(EntityProviderChangeListener listener) { synchronized (listeners) { assert listener != null : "listener must not be null"; Iterator>> it = listeners .iterator(); while (it.hasNext()) { EntityProviderChangeListener l = it.next().get(); // also clean up old references if (null == l || listener.equals(l)) { it.remove(); } } } } private boolean fireEntityProviderChangeEvent = true; /** * Sets whether {@link EntityProviderChangeEvent}s should be fired by this * entity provider. */ protected void setFireEntityProviderChangeEvents(boolean fireEvents) { this.fireEntityProviderChangeEvent = fireEvents; } /** * Returns whether {@link EntityProviderChangeEvent}s should be fired by * this entity provider. */ protected boolean isFireEntityProviderChangeEvent() { return fireEntityProviderChangeEvent; } /** * Sends event to all registered listeners if * {@link #isFireEntityProviderChangeEvent() } is true. * * @param event * the event to send (must not be null). */ @SuppressWarnings("unchecked") protected void fireEntityProviderChangeEvent( final EntityProviderChangeEvent event) { LinkedList>> list; synchronized (listeners) { assert event != null : "event must not be null"; if (listeners.isEmpty() && !isFireEntityProviderChangeEvent()) { return; } // cleanup Iterator>> it = listeners .iterator(); while (it.hasNext()) { if (null == it.next().get()) { it.remove(); } } // copy list to use outside the synchronized block list = (LinkedList>>) listeners .clone(); } for (WeakReference> ref : list) { EntityProviderChangeListener listener = ref.get(); if (null != listener) { listener.entityProviderChange(event); } } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy