Java tutorial
/* Copyright (C) 2010 SpringSource * * 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.grails.datastore.mapping.core; import groovy.lang.GroovySystem; import groovy.lang.MetaClassRegistry; import groovy.util.ConfigObject; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.grails.datastore.mapping.cache.TPCacheAdapterRepository; import org.grails.datastore.mapping.config.Property; import org.grails.datastore.mapping.model.MappingContext; import org.grails.datastore.mapping.model.PersistentEntity; import org.grails.datastore.mapping.model.PersistentProperty; import org.grails.datastore.mapping.model.PropertyMapping; import org.grails.datastore.mapping.model.types.BasicTypeConverterRegistrar; import org.grails.datastore.mapping.reflect.ClassPropertyFetcher; import org.grails.datastore.mapping.reflect.FieldEntityAccess; import org.grails.datastore.mapping.transactions.SessionHolder; import org.springframework.beans.factory.DisposableBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.convert.converter.ConverterRegistry; import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertyResolver; import org.springframework.core.env.StandardEnvironment; import org.springframework.transaction.support.TransactionSynchronizationManager; import java.util.Map; /** * Abstract Datastore implementation that deals with binding the Session to thread locale upon creation. * * @author Graeme Rocher * @since 1.0 */ @SuppressWarnings({ "rawtypes", "unchecked" }) public abstract class AbstractDatastore implements Datastore, StatelessDatastore, DisposableBean { protected static final Log LOG = LogFactory.getLog(AbstractDatastore.class); private ApplicationContext applicationContext; protected final MappingContext mappingContext; protected final PropertyResolver connectionDetails; protected final TPCacheAdapterRepository cacheAdapterRepository; public AbstractDatastore(MappingContext mappingContext) { this(mappingContext, (PropertyResolver) null, null); } public AbstractDatastore(MappingContext mappingContext, Map<String, Object> connectionDetails, ConfigurableApplicationContext ctx) { this(mappingContext, connectionDetails, ctx, null); } public AbstractDatastore(MappingContext mappingContext, PropertyResolver connectionDetails, ConfigurableApplicationContext ctx) { this(mappingContext, connectionDetails, ctx, null); } public AbstractDatastore(MappingContext mappingContext, PropertyResolver connectionDetails, ConfigurableApplicationContext ctx, TPCacheAdapterRepository cacheAdapterRepository) { this.mappingContext = mappingContext; this.connectionDetails = connectionDetails; setApplicationContext(ctx); this.cacheAdapterRepository = cacheAdapterRepository; } public AbstractDatastore(MappingContext mappingContext, Map<String, Object> connectionDetails, ConfigurableApplicationContext ctx, TPCacheAdapterRepository cacheAdapterRepository) { this(mappingContext, mapToPropertyResolver(connectionDetails), ctx, cacheAdapterRepository); } protected static PropertyResolver mapToPropertyResolver(Map<String, Object> connectionDetails) { if (connectionDetails instanceof PropertyResolver) { return (PropertyResolver) connectionDetails; } else { StandardEnvironment env = new StandardEnvironment(); if (connectionDetails != null) { MutablePropertySources propertySources = env.getPropertySources(); propertySources.addFirst(new MapPropertySource("datastoreConfig", connectionDetails)); if (connectionDetails instanceof ConfigObject) { propertySources.addFirst(new MapPropertySource("datastoreConfigFlat", ((ConfigObject) connectionDetails).flatten())); } } return env; } } public void destroy() throws Exception { FieldEntityAccess.clearReflectors(); final MetaClassRegistry registry = GroovySystem.getMetaClassRegistry(); for (PersistentEntity persistentEntity : getMappingContext().getPersistentEntities()) { final Class cls = persistentEntity.getJavaClass(); try { registry.removeMetaClass(cls); } catch (Exception e) { LOG.warn("There was an error shutting down GORM for entity [" + cls.getName() + "]: " + e.getMessage(), e); } } ClassPropertyFetcher.clearCache(); } public void setApplicationContext(ApplicationContext ctx) { applicationContext = ctx; } public Session connect() { return connect(connectionDetails); } public final Session connect(PropertyResolver connDetails) { Session session = createSession(connDetails); publishSessionCreationEvent(session); return session; } private void publishSessionCreationEvent(Session session) { ApplicationEventPublisher applicationEventPublisher = getApplicationEventPublisher(); if (applicationEventPublisher != null) { applicationEventPublisher.publishEvent(new SessionCreationEvent(session)); } } @Override public Session connectStateless() { Session session = createStatelessSession(connectionDetails); publishSessionCreationEvent(session); return session; } /** * Creates the native session * * @param connectionDetails The session details * @return The session object */ protected abstract Session createSession(PropertyResolver connectionDetails); /** * Creates the native stateless session * * @param connectionDetails The session details * @return The session object */ protected Session createStatelessSession(PropertyResolver connectionDetails) { return createSession(connectionDetails); } public Session getCurrentSession() throws ConnectionNotFoundException { return DatastoreUtils.doGetSession(this, false); } public boolean hasCurrentSession() { return TransactionSynchronizationManager.hasResource(this); } /** * Static way to retrieve the session * @return The session instance * @throws ConnectionNotFoundException If no session has been created */ public static Session retrieveSession() throws ConnectionNotFoundException { return retrieveSession(Datastore.class); } /** * Static way to retrieve the session * @param datastoreClass The type of datastore * @return The session instance * @throws ConnectionNotFoundException If no session has been created */ public static Session retrieveSession(Class datastoreClass) throws ConnectionNotFoundException { final Map<Object, Object> resourceMap = TransactionSynchronizationManager.getResourceMap(); Session session = null; if (resourceMap != null && !resourceMap.isEmpty()) { for (Object key : resourceMap.keySet()) { if (datastoreClass.isInstance(key)) { SessionHolder sessionHolder = (SessionHolder) resourceMap.get(key); if (sessionHolder != null) { session = sessionHolder.getSession(); } } } } if (session == null) { throw new ConnectionNotFoundException( "No datastore session found. Call Datastore.connect(..) before calling Datastore.getCurrentSession()"); } return session; } public MappingContext getMappingContext() { return mappingContext; } public ConfigurableApplicationContext getApplicationContext() { return (ConfigurableApplicationContext) applicationContext; } public ApplicationEventPublisher getApplicationEventPublisher() { return getApplicationContext(); } protected void initializeConverters(MappingContext mappingContext) { final ConverterRegistry conversionService = mappingContext.getConverterRegistry(); BasicTypeConverterRegistrar registrar = new BasicTypeConverterRegistrar(); registrar.register(conversionService); } protected boolean isIndexed(PersistentProperty property) { PropertyMapping<Property> pm = property.getMapping(); final Property keyValue = pm.getMappedForm(); return keyValue != null && keyValue.isIndex(); } public boolean isSchemaless() { return false; } }