/* * Copyright 2004-2009 the original author or authors. * * 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.compass.gps.device.hibernate.lifecycle; import java.io.Serializable; import org.compass.core.CompassCallbackWithoutResult; import org.compass.core.CompassException; import org.compass.core.CompassSession; import org.compass.core.mapping.Cascade; import org.compass.gps.device.hibernate.HibernateGpsDevice; import org.compass.gps.device.hibernate.HibernateGpsDeviceException; import org.compass.gps.spi.CompassGpsInterfaceDevice; import org.hibernate.engine.CollectionEntry; import org.hibernate.engine.EntityEntry; import org.hibernate.event.AbstractCollectionEvent; import org.hibernate.event.PostCollectionRecreateEvent; import org.hibernate.event.PostCollectionRecreateEventListener; import org.hibernate.event.PostCollectionRemoveEvent; import org.hibernate.event.PostCollectionRemoveEventListener; import org.hibernate.event.PostCollectionUpdateEvent; import org.hibernate.event.PostCollectionUpdateEventListener; /** * @author kimchy */ public class HibernateCollectionEventListener extends HibernateEventListener implements PostCollectionRecreateEventListener, PostCollectionRemoveEventListener, PostCollectionUpdateEventListener { public HibernateCollectionEventListener(HibernateGpsDevice device, boolean marshallIds, boolean pendingCascades, boolean processCollections) { super(device, marshallIds, pendingCascades, processCollections); } public void onPostRecreateCollection(PostCollectionRecreateEvent postCollectionRecreateEvent) { processCollectionEvent(postCollectionRecreateEvent); } public void onPostRemoveCollection(PostCollectionRemoveEvent postCollectionRemoveEvent) { processCollectionEvent(postCollectionRemoveEvent); } public void onPostUpdateCollection(PostCollectionUpdateEvent postCollectionUpdateEvent) { processCollectionEvent(postCollectionUpdateEvent); } private void processCollectionEvent(final AbstractCollectionEvent event) { final Object entity = event.getAffectedOwnerOrNull(); if (entity == null) { //Hibernate cannot determine every single time the owner especially incase detached objects are involved // or property-ref is used //Should log really but we don't know if we're interested in this collection for indexing return; } CollectionEntry collectionEntry = event.getSession().getPersistenceContext().getCollectionEntry(event.getCollection()); if (collectionEntry != null && collectionEntry.getLoadedPersister() == null) { // ignore this entry, since Hibernate will cause NPE when doing SAVE // TODO is there a better way to solve this? return; } if (mirrorFilter != null) { if (mirrorFilter.shouldFilterCollection(event)) { return; } } final CompassGpsInterfaceDevice compassGps = (CompassGpsInterfaceDevice) device.getGps(); if (!compassGps.hasMappingForEntityForMirror(entity.getClass(), Cascade.SAVE)) { return; } Serializable id = getId(entity, event); if (id == null) { log.warn("Unable to reindex entity on collection change, id cannot be extracted: " + event.getAffectedOwnerEntityName()); return; } try { if (log.isTraceEnabled()) { log.trace(device.buildMessage("Updating [" + entity + "]")); } compassGps.executeForMirror(new CompassCallbackWithoutResult() { protected void doInCompassWithoutResult(CompassSession session) throws CompassException { doUpdate(session, compassGps, entity, event.getSession()); } }); } catch (Exception e) { if (device.isIgnoreMirrorExceptions()) { log.error(device.buildMessage("Failed while updating [" + entity + "]"), e); } else { throw new HibernateGpsDeviceException(device.buildMessage("Failed while updating [" + entity + "]"), e); } } } private Serializable getId(Object entity, AbstractCollectionEvent event) { Serializable id = event.getAffectedOwnerIdOrNull(); if (id == null) { //most likely this recovery is unnecessary since Hibernate Core probably try that EntityEntry entityEntry = event.getSession().getPersistenceContext().getEntry(entity); id = entityEntry == null ? null : entityEntry.getId(); } return id; } }