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

org.dbflute.s2dao.extension.TnBeanMetaDataFactoryExtension Maven / Gradle / Ivy

/*
 * Copyright 2014-2020 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.dbflute.s2dao.extension;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.dbflute.Entity;
import org.dbflute.bhv.core.context.ResourceContext;
import org.dbflute.dbmeta.DBMeta;
import org.dbflute.helper.beans.DfBeanDesc;
import org.dbflute.helper.beans.DfPropertyDesc;
import org.dbflute.helper.beans.factory.DfBeanDescFactory;
import org.dbflute.jdbc.LazyDatabaseMetaDataWrapper;
import org.dbflute.jdbc.ManualThreadDataSourceHandler;
import org.dbflute.jdbc.MetaDataConnectionProvider;
import org.dbflute.optional.RelationOptionalFactory;
import org.dbflute.s2dao.identity.TnIdentifierGenerator;
import org.dbflute.s2dao.identity.TnIdentifierGeneratorFactory;
import org.dbflute.s2dao.metadata.TnBeanAnnotationReader;
import org.dbflute.s2dao.metadata.TnBeanMetaData;
import org.dbflute.s2dao.metadata.TnModifiedPropertySupport;
import org.dbflute.s2dao.metadata.TnPropertyType;
import org.dbflute.s2dao.metadata.TnRelationPropertyTypeFactory;
import org.dbflute.s2dao.metadata.TnRelationPropertyTypeFactoryBuilder;
import org.dbflute.s2dao.metadata.impl.TnBeanMetaDataFactoryImpl;
import org.dbflute.s2dao.metadata.impl.TnBeanMetaDataImpl;
import org.dbflute.s2dao.metadata.impl.TnDBMetaBeanAnnotationReader;
import org.dbflute.s2dao.metadata.impl.TnRelationPropertyTypeFactoryBuilderImpl;
import org.dbflute.util.DfCollectionUtil;
import org.dbflute.util.DfTypeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The DBFlute extension of factory of bean meta data.
 * @author jflute
 */
public class TnBeanMetaDataFactoryExtension extends TnBeanMetaDataFactoryImpl {

    // ===================================================================================
    //                                                                          Definition
    //                                                                          ==========
    /** Log instance for internal debug. (XLog should be used instead for execute-status log) */
    private static final Logger _log = LoggerFactory.getLogger(TnBeanMetaDataFactoryExtension.class);

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    /** The cached instance of relation optional factory. (NotNull) */
    protected final TnRelationRowOptionalHandler _relationRowOptionalHandler;

    /** The map of bean meta data for cache. (NotNull) */
    protected final Map, TnBeanMetaData> _metaMap = newConcurrentHashMap();

    /** Is internal debug enabled? */
    protected boolean _internalDebug;

    // ===================================================================================
    //                                                                         Constructor
    //                                                                         ===========
    /**
     * @param relationOptionalFactory The factory of relation optional. (NotNull)
     */
    public TnBeanMetaDataFactoryExtension(RelationOptionalFactory relationOptionalFactory) {
        _relationRowOptionalHandler = createRelationRowOptionalHandler(relationOptionalFactory);
    }

    // ===================================================================================
    //                                                                  Override for Cache
    //                                                                  ==================
    @Override
    public TnBeanMetaData createBeanMetaData(Class beanClass) {
        final TnBeanMetaData cachedMeta = findCachedMeta(beanClass);
        if (cachedMeta != null) {
            return cachedMeta;
        } else {
            return super.createBeanMetaData(beanClass);
        }
    }

    @Override
    public TnBeanMetaData createBeanMetaData(Class beanClass, int relationNestLevel) {
        final TnBeanMetaData cachedMeta = findCachedMeta(beanClass);
        if (cachedMeta != null) {
            return cachedMeta;
        } else {
            return super.createBeanMetaData(beanClass, relationNestLevel);
        }
    }

    @Override
    protected LazyDatabaseMetaDataWrapper createLazyDatabaseMetaDataWrapper(Class beanClass) {
        final MetaDataConnectionProvider connectionProvider = createMetaDataConnectionProvider();
        final LazyDatabaseMetaDataWrapper metaDataWrapper = new LazyDatabaseMetaDataWrapper(connectionProvider);
        metaDataWrapper.restrictMetaData(); // because DBFlute completely does not use dynamic meta data
        return metaDataWrapper;
    }

    /**
     * Create the provider of connection for database meta data. 
* The provider might provide connection from manual thread. * @return The instance of the connection provider. (NotNull) */ protected MetaDataConnectionProvider createMetaDataConnectionProvider() { return new MetaDataConnectionProvider() { public Connection getConnection() throws SQLException { final ManualThreadDataSourceHandler handler = getManualThreadDataSourceHandler(); if (handler != null) { return handler.getConnection(_dataSource); } return _dataSource.getConnection(); } }; } /** * Get the data source handler of manual thread. * @return The instance of the data source handler. (NullAllowed: if null, no manual thread handling) */ protected ManualThreadDataSourceHandler getManualThreadDataSourceHandler() { return ManualThreadDataSourceHandler.getDataSourceHandler(); } @Override public TnBeanMetaData createBeanMetaData(DatabaseMetaData dbMetaData, Class beanClass, int relationNestLevel) { final TnBeanMetaData cachedMeta = findOrCreateCachedMetaIfNeeds(dbMetaData, beanClass, relationNestLevel); if (cachedMeta != null) { return cachedMeta; } else { return super.createBeanMetaData(dbMetaData, beanClass, relationNestLevel); } } protected TnBeanMetaData findCachedMeta(Class beanClass) { if (isDBFluteEntity(beanClass)) { final TnBeanMetaData cachedMeta = getMetaFromCache(beanClass); if (cachedMeta != null) { return cachedMeta; } } return null; } protected TnBeanMetaData findOrCreateCachedMetaIfNeeds(DatabaseMetaData dbMetaData, Class beanClass, int relationNestLevel) { if (isDBFluteEntity(beanClass)) { final TnBeanMetaData cachedMeta = getMetaFromCache(beanClass); if (cachedMeta != null) { return cachedMeta; } else { return super.createBeanMetaData(dbMetaData, beanClass, 0); } } return null; } @Override protected TnBeanMetaDataImpl createBeanMetaDataImpl(Class beanClass) { // /= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = // for ConditionBean and insert() and update() and delete() and so on... // = = = = = = = = = =/ final DBMeta dbmeta = provideDBMeta(beanClass); return new TnBeanMetaDataImpl(beanClass, dbmeta) { /** The internal list of identifier generator. Elements of this list should be added when initializing. */ protected final List _internalIdentifierGeneratorList = new ArrayList(); /** The internal map of identifier generator by property name. */ protected final Map _internalIdentifierGeneratorsByPropertyName = newConcurrentHashMap(); // /= = = = = = = // for cache // = = = = =/ @Override public void initialize() { // non thread safe so this is called immediately after creation final Class myBeanClass = getBeanClass(); if (isDBFluteEntity(myBeanClass)) { final TnBeanMetaData cachedMeta = getMetaFromCache(myBeanClass); if (cachedMeta == null) { if (isInternalDebugEnabled()) { _log.debug("...Caching the bean: " + DfTypeUtil.toClassTitle(myBeanClass)); } _metaMap.put(myBeanClass, this); } } super.initialize(); } // /= = = = = = = // for insert() // = = = = =/ // The attributes 'identifierGenerators' and 'identifierGeneratorsByPropertyName' // of super class are unused. It prepares original attributes here. @Override protected void setupIdentifierGenerator(TnPropertyType propertyType) { // only called in the initialize() process final DfPropertyDesc pd = propertyType.getPropertyDesc(); final String propertyName = propertyType.getPropertyName(); final String idType = _beanAnnotationReader.getId(pd); final TnIdentifierGenerator generator = createInternalIdentifierGenerator(propertyType, idType); _internalIdentifierGeneratorList.add(generator); _internalIdentifierGeneratorsByPropertyName.put(propertyName, generator); } protected TnIdentifierGenerator createInternalIdentifierGenerator(TnPropertyType propertyType, String idType) { return TnIdentifierGeneratorFactory.createIdentifierGenerator(propertyType, idType); } @Override public TnIdentifierGenerator getIdentifierGenerator(int index) { return _internalIdentifierGeneratorList.get(index); } @Override public int getIdentifierGeneratorSize() { return _internalIdentifierGeneratorList.size(); } @Override public TnIdentifierGenerator getIdentifierGenerator(String propertyName) { return _internalIdentifierGeneratorsByPropertyName.get(propertyName); } }; } // =================================================================================== // Override for ModifiedProperty // ============================= @Override protected TnModifiedPropertySupport createModifiedPropertySupport() { return new TnModifiedPropertySupport() { public Set getModifiedPropertyNames(Object bean) { if (bean instanceof Entity) { // all entities of DBFlute are here return ((Entity) bean).mymodifiedProperties(); } else { // basically no way on DBFlute (S2Dao's route) final DfBeanDesc beanDesc = DfBeanDescFactory.getBeanDesc(bean.getClass()); final String propertyName = MODIFIED_PROPERTY_PROPERTY_NAME; if (!beanDesc.hasPropertyDesc(propertyName)) { return DfCollectionUtil.emptySet(); } else { final DfPropertyDesc propertyDesc = beanDesc.getPropertyDesc(propertyName); final Object value = propertyDesc.getValue(bean); if (value != null) { @SuppressWarnings("unchecked") final Set extractedSet = (Set) value; return extractedSet; } else { return DfCollectionUtil.emptySet(); } } } } }; } // =================================================================================== // Annotation Reader // ================= @Override protected TnBeanAnnotationReader createBeanAnnotationReader(Class beanClass) { // the DBMeta annotation reader also has field annotation reader's functions // so fixedly creates and returns return new TnDBMetaBeanAnnotationReader(beanClass); } // =================================================================================== // Property Type // ============= protected TnRelationPropertyTypeFactory createRelationPropertyTypeFactory(Class beanClass, TnBeanMetaDataImpl localBeanMetaData, TnBeanAnnotationReader beanAnnotationReader, DatabaseMetaData dbMetaData, int relationNestLevel, boolean stopRelationCreation) { // DBFlute needs local BeanMetaData for relation property type final TnRelationPropertyTypeFactoryBuilder builder = createRelationPropertyTypeFactoryBuilder(); return builder.build(beanClass, localBeanMetaData, beanAnnotationReader, dbMetaData, relationNestLevel, stopRelationCreation, getRelationOptionalEntityType()); } protected TnRelationPropertyTypeFactoryBuilder createRelationPropertyTypeFactoryBuilder() { return new TnRelationPropertyTypeFactoryBuilderImpl(this); // is already customized for DBFlute } protected Class getRelationOptionalEntityType() { return _relationRowOptionalHandler.getOptionalEntityType(); } // =================================================================================== // Relation Next Level // =================== /** * Get the limit nest level of relation. * @return The limit nest level of relation. */ @Override protected int getLimitRelationNestLevel() { // for Compatible to old version DBFlute // and this is actually unused on ConditionBean for now // CB covers an infinity nest level scope by its own original way // this method is used only when you use runtime classes as plain S2Dao return 2; } // =================================================================================== // Optional Handling // ================= public TnRelationRowOptionalHandler getRelationRowOptionalHandler() { return _relationRowOptionalHandler; } protected TnRelationRowOptionalHandler createRelationRowOptionalHandler(RelationOptionalFactory factory) { return new TnRelationRowOptionalHandler(factory); } // =================================================================================== // Assist Helper // ============= protected boolean isDBFluteEntity(Class beanClass) { return Entity.class.isAssignableFrom(beanClass); } protected DBMeta provideDBMeta(Class entityType) { return ResourceContext.provideDBMeta(entityType); // exists when DBFlute entity } protected TnBeanMetaData getMetaFromCache(Class beanClass) { return _metaMap.get(beanClass); } // =================================================================================== // Internal Debug // ============== private boolean isInternalDebugEnabled() { // because log instance is private return ResourceContext.isInternalDebug() && _log.isDebugEnabled(); } // =================================================================================== // General Helper // ============== protected ConcurrentHashMap newConcurrentHashMap() { return new ConcurrentHashMap(); } // =================================================================================== // Accessor // ======== public void setInternalDebug(boolean internalDebug) { _internalDebug = internalDebug; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy