/*
* 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.jpa.embedded.eclipselink;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceUnitInfo;
import javax.persistence.spi.PersistenceUnitTransactionType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.compass.core.Compass;
import org.compass.core.CompassException;
import org.compass.core.config.CompassConfiguration;
import org.compass.core.config.CompassConfigurationFactory;
import org.compass.core.config.CompassEnvironment;
import org.compass.core.config.CompassSettings;
import org.compass.core.transaction.JTASyncTransactionFactory;
import org.compass.core.transaction.LocalTransactionFactory;
import org.compass.core.util.ClassUtils;
import org.compass.gps.device.jpa.JpaGpsDevice;
import org.compass.gps.device.jpa.JtaEntityManagerWrapper;
import org.compass.gps.device.jpa.ResourceLocalEntityManagerWrapper;
import org.compass.gps.device.jpa.embedded.DefaultJpaCompassGps;
import org.compass.gps.device.jpa.lifecycle.EclipseLinkJpaEntityLifecycleInjector;
import org.eclipse.persistence.config.SessionCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.jpa.EntityManagerFactoryImpl;
import org.eclipse.persistence.internal.jpa.EntityManagerFactoryProvider;
import org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.sessions.server.ServerSession;
/**
* A EclipseLink SessionCustomizer allowing to integrate in an "embedded" mode
* Compass with EclipseLink. The single required setting (for example, within the persistence.xml
* file) is the Compass connection property ({@link org.compass.core.config.CompassEnvironment#CONNECTION}
* and at least one Searchable class mapped out of the classes mapped in EclipseLink.
*
*
The embedded EclipseLink support uses Compass GPS and adds an "embedded" Compass, or adds a searchable
* feature to EclipseLink by registering a {@link org.compass.core.Compass} instance and a {@link org.compass.gps.device.jpa.JpaGpsDevice}
* instance with EclipseLink. It registers mirroring listeners (after delete/store/persist) to automatically
* mirror changes done through EclipseLink to the Compass index. It also registeres an event listener
* ({@link org.compass.gps.device.hibernate.embedded.CompassEventListener} to syncronize with transactions.
*
*
Use {@link EclipseLinkHelper} in order to access the Compass instance or the
* JpaGpsDevice instance attached to a given entity manager.
*
*
The Compass instnace used for mirroring can be configured by adding compass prefixed settings.
* Additional settings that only control the Compass instnace created for indexing should be set using
* gps.index.compass.. For more information on indexing and mirroring Compass please check
* {@link org.compass.gps.impl.SingleCompassGps}.
*
*
This customizer tries to find the persistence info in order to read the properties out of it. In order
* for it to find it, it uses the naming convention EclipseLink has at naming Sessions. Note, if you change the
* name of the Session using EclipseLink setting, this customizer will not be able to operate.
*
*
This session customizer will also identify if the persistence info is configured to work with JTA or
* with RESOURCE LOCAL transaction and adjust itsefl accordingly. If JTA is used, it will automatically
* use Compass {@link org.compass.core.transaction.JTASyncTransactionFactory} and if RESOURCE LOCAL is used it will automatically use
* {@link org.compass.core.transaction.LocalTransactionFactory}. Note, this is only set if the transaction factory is not explicitly set
* using Compass settings.
*
*
Specific properties that this plugin can use:
*
*
compass.EclipseLink.indexQuery.[entity name/class]: Specific select query that will be used to perform the indexing
* for the mentioned specific entity name / class. Note, before calling {@link org.compass.gps.CompassGps#index()} there
* is an option the programmatically control this.
*
compass.EclipseLink.config: A classpath that points to Compass configuration.
*
compass.EclipseLink.session.customizer: If there is another EclipseLink SessionCustomizer that needs
* to be applied, its class FQN should be specified with this setting.
*
*
* @author kimchy
*/
public class CompassSessionCustomizer implements SessionCustomizer {
private static final Log log = LogFactory.getLog(CompassSessionCustomizer.class);
private static final String COMPASS_PREFIX = "compass";
private static final String COMPASS_GPS_INDEX_PREFIX = "gps.index.";
public static final String INDEX_QUERY_PREFIX = "compass.eclipselink.indexQuery.";
public static final String COMPASS_CONFIG_LOCATION = "compass.eclipselink.config";
public static final String COMPASS_SESSION_CUSTOMIZER = "compass.eclipselink.session.customizer";
public void customize(Session session) throws Exception {
if (log.isInfoEnabled()) {
log.info("Compass embedded EclipseLink support enabled, initializing for session [" + session + "]");
}
PersistenceUnitInfo persistenceUnitInfo = findPersistenceUnitInfo(session);
if (persistenceUnitInfo == null) {
throw new CompassException("Failed to find Persistence Unit Info");
}
Map