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

org.teiid.spring.autoconfigure.TeiidAutoConfiguration Maven / Gradle / Ivy

There is a newer version: 1.7.2
Show newest version
/*
 * Copyright 2012-2017 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.teiid.spring.autoconfigure;

import static org.teiid.spring.autoconfigure.TeiidConstants.VDBNAME;
import static org.teiid.spring.autoconfigure.TeiidConstants.VDBVERSION;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.net.URL;
import java.sql.Driver;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.sql.DataSource;
import javax.transaction.TransactionManager;
import javax.xml.stream.XMLStreamException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Scope;
import org.springframework.core.Ordered;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
import org.springframework.jdbc.datasource.embedded.ConnectionProperties;
import org.springframework.jdbc.datasource.embedded.DataSourceFactory;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory;
import org.teiid.adminapi.impl.VDBMetaData;
import org.teiid.adminapi.impl.VDBMetadataParser;
import org.teiid.cache.Cache;
import org.teiid.cache.CacheFactory;
import org.teiid.core.util.ObjectConverterUtil;
import org.teiid.deployers.VDBRepository;
import org.teiid.deployers.VirtualDatabaseException;
import org.teiid.dqp.internal.datamgr.ConnectorManagerRepository.ConnectorManagerException;
import org.teiid.metadatastore.DeploymentBasedDatabaseStore;
import org.teiid.query.metadata.NioZipFileSystem;
import org.teiid.query.metadata.VDBResources;
import org.teiid.query.metadata.VirtualFile;
import org.teiid.runtime.EmbeddedConfiguration;
import org.teiid.runtime.EmbeddedServer;
import org.teiid.spring.autoconfigure.TeiidPostProcessor.Registrar;
import org.teiid.spring.data.file.FileConnectionFactory;
import org.teiid.spring.identity.SpringSecurityHelper;
import org.teiid.translator.ExecutionFactory;
import org.teiid.translator.TranslatorException;
import org.teiid.transport.SocketConfiguration;
import org.teiid.transport.WireProtocol;
import org.xml.sax.SAXException;

import com.github.benmanes.caffeine.cache.Caffeine;

@Configuration
@ConditionalOnClass({EmbeddedServer.class, ExecutionFactory.class})
@EnableConfigurationProperties(TeiidProperties.class)
@Import({ Registrar.class })
@PropertySource("classpath:teiid.properties")
public class TeiidAutoConfiguration implements Ordered {

    public static ThreadLocal serverContext = new ThreadLocal<>();

    private static final Log logger = LogFactory.getLog(TeiidAutoConfiguration.class);

    @Autowired(required = false)
    private EmbeddedConfiguration embeddedConfiguration;

    @Autowired
    private TeiidProperties properties;

    @Autowired
    ApplicationContext context;

    @Value("${spring.jpa.hibernate.naming.physical-strategy:org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy}")
    private String hibernateNamingClass;

    @Autowired(required=false)
    private TransactionManager transactionManager;

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }

    @Bean
    @ConditionalOnMissingBean
    public TeiidInitializer teiidInitializer(ApplicationContext applicationContext) {
        return new TeiidInitializer(applicationContext);
    }

    @Bean(name="dataSource")
    @Primary
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource getDataSource(TeiidServer server, VDBMetaData vdb) {
        EmbeddedDatabaseFactory edf = new EmbeddedDatabaseFactory();
        edf.setDatabaseConfigurer(new TeiidDatabaseConfigurer(server));
        edf.setDataSourceFactory(new DataSourceFactory() {
            @Override
            public DataSource getDataSource() {
                String url = context.getEnvironment().getProperty("spring.datasource.teiid.url");
                return new SimpleDriverDataSource(new TeiidSpringDriver(server.getDriver(), server, vdb), url);
            }

            @Override
            public ConnectionProperties getConnectionProperties() {
                return new ConnectionProperties() {
                    @Override
                    public void setDriverClass(Class driverClass) {
                    }
                    @Override
                    public void setUrl(String url) {
                    }
                    @Override
                    public void setUsername(String username) {
                    }
                    @Override
                    public void setPassword(String password) {
                    }
                };
            }
        });
        return edf.getDatabase();
    }

    @Bean
    @ConditionalOnMissingBean
    public VDBMetaData teiidVDB() {
        List resources = TeiidInitializer.getClasspathResources(this.context, this.properties.getVdbFile(), "teiid.ddl", "teiid.vdb");

        VDBMetaData vdb = null;
        if (!resources.isEmpty()) {
            Resource resource = resources.iterator().next();
            if (resource.getFilename().endsWith(".ddl")) {
                try {
                    DeploymentBasedDatabaseStore store = new DeploymentBasedDatabaseStore(new VDBRepository());
                    String db = ObjectConverterUtil.convertToString(resources.get(0).getInputStream());
                    vdb = store.getVDBMetadata(db);
                    logger.info("Predefined VDB found :" + resources.get(0).getFilename());
                } catch (IOException e) {
                    throw new IllegalStateException("Failed to parse the VDB defined");
                }
            } else if (resource.getFilename().endsWith("-vdb.xml")) {
                try {
                    vdb =  VDBMetadataParser.unmarshell(resources.get(0).getInputStream());
                } catch (XMLStreamException | IOException e) {
                    throw new IllegalStateException("Failed to load the VDB defined", e);
                }
            } else if (resource.getFilename().endsWith(".vdb")) {
                try {
                    vdb = loadVDB(resource.getURL());
                } catch (VirtualDatabaseException | ConnectorManagerException | TranslatorException | IOException
                        | URISyntaxException e) {
                    throw new IllegalStateException("Failed to load the VDB defined", e);
                }
            }
        }

        if (vdb == null) {
            vdb =  new VDBMetaData();
            vdb.addProperty("implicit", "true");
            vdb.setName(VDBNAME);
            vdb.setVersion(VDBVERSION);
        }
        return vdb;
    }

    private VDBMetaData loadVDB(URL url) throws VirtualDatabaseException, ConnectorManagerException, TranslatorException,
    IOException, URISyntaxException {
        VirtualFile root = NioZipFileSystem.mount(url);
        VDBMetaData metadata;

        VirtualFile vdbMetadata = root.getChild("/vdb.xml"); //$NON-NLS-1$
        if (!vdbMetadata.exists()) {
            vdbMetadata = root.getChild("/META-INF/vdb.xml"); //$NON-NLS-1$
        }
        if (vdbMetadata.exists()) {
            try {
                VDBMetadataParser.validate(vdbMetadata.openStream());
            } catch (SAXException e) {
                throw new VirtualDatabaseException(e);
            }
            InputStream is = vdbMetadata.openStream();
            try {
                metadata = VDBMetadataParser.unmarshell(is);
            } catch (XMLStreamException e) {
                throw new VirtualDatabaseException(e);
            }
        } else {
            vdbMetadata = root.getChild("/vdb.ddl"); //$NON-NLS-1$
            if (!vdbMetadata.exists()) {
                vdbMetadata = root.getChild("/META-INF/vdb.ddl"); //$NON-NLS-1$
            }
            DeploymentBasedDatabaseStore store = new DeploymentBasedDatabaseStore(new VDBRepository());
            try {
                metadata = store.getVDBMetadata(ObjectConverterUtil.convertToString(vdbMetadata.openStream()));
            } catch (IOException e) {
                throw new VirtualDatabaseException("Could not find a vdb.xml or vdb.ddl file in " + url);
            }
        }
        VDBResources resources = new VDBResources(root);
        metadata.addAttchment(VDBResources.class, resources);
        return metadata;
    }

    @Bean(name = "teiid")
    @ConditionalOnMissingBean
    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
    public TeiidServer teiidServer(SpringSecurityHelper securityHelper) {
        logger.info("Starting Teiid Server.");

        // turning off PostgreSQL support
        System.setProperty("org.teiid.addPGMetadata", Boolean.toString(this.properties.isPgEnable() || this.properties.isPgSecureEnable()));
        System.setProperty("org.teiid.hiddenMetadataResolvable", "false");
        System.setProperty("org.teiid.allowAlter", Boolean.toString(this.properties.isAllowAlter()));

        final TeiidServer server = new TeiidServer();

        if(embeddedConfiguration == null) {
            embeddedConfiguration = new EmbeddedConfiguration();
            embeddedConfiguration.setCacheFactory(new CaffeineCacheFactory());
            // add ability for remote jdbc connections
            if (this.properties.isJdbcEnable()) {
                SocketConfiguration sc = new SocketConfiguration();
                sc.setBindAddress(this.properties.getHostName());
                sc.setPortNumber(this.properties.getJdbcPort());
                sc.setProtocol(WireProtocol.teiid);
                embeddedConfiguration.addTransport(sc);
                logger.info("JDBC is opened on = " + this.properties.getHostName() + ":"
                        + this.properties.getJdbcPort());

            }

            if (this.properties.isJdbcSecureEnable()) {
                SocketConfiguration sc = new SocketConfiguration();
                sc.setBindAddress(this.properties.getHostName());
                sc.setPortNumber(this.properties.getJdbcSecurePort());
                sc.setProtocol(WireProtocol.teiid);
                sc.setSSLConfiguration(this.properties.getSsl());
                embeddedConfiguration.addTransport(sc);
                logger.info("Secure JDBC is opened on = " + this.properties.getHostName() + ":"
                        + this.properties.getJdbcSecurePort());
            }

            if (this.properties.isPgEnable()) {
                SocketConfiguration sc = new SocketConfiguration();
                sc.setBindAddress(this.properties.getHostName());
                sc.setPortNumber(this.properties.getPgPort());
                sc.setProtocol(WireProtocol.pg);
                embeddedConfiguration.addTransport(sc);
                logger.info("PG is opened on = " + this.properties.getHostName() + ":"
                        + this.properties.getPgPort());

            }

            if (this.properties.isPgSecureEnable()) {
                SocketConfiguration sc = new SocketConfiguration();
                sc.setBindAddress(this.properties.getHostName());
                sc.setPortNumber(this.properties.getPgSecurePort());
                sc.setProtocol(WireProtocol.pg);
                sc.setSSLConfiguration(this.properties.getSsl());
                embeddedConfiguration.addTransport(sc);
                logger.info("Secure PG is opened on = " + this.properties.getHostName() + ":"
                        + this.properties.getPgPort());
            }
        }

        if (embeddedConfiguration.getTransactionManager() == null) {
            if (this.transactionManager != null) {
                logger.info("Transaction Manager found and being registed into Teiid.");
                embeddedConfiguration.setTransactionManager(this.transactionManager);
            } else {
                PlatformTransactionManagerAdapter ptma = server.getPlatformTransactionManagerAdapter();
                this.embeddedConfiguration.setTransactionManager(ptma);
                server.setUsingPlatformTransactionManager(true);
            }
        } else if (this.transactionManager != null && this.transactionManager != embeddedConfiguration.getTransactionManager()) {
            throw new IllegalStateException("TransactionManager defined in both Spring and on the EmbeddedConfiguration.  Only one is expected.");
        }

        if (embeddedConfiguration.getSecurityHelper() == null) {
            embeddedConfiguration.setSecurityDomain(TeiidConstants.SPRING_SECURITY);
            embeddedConfiguration.setSecurityHelper(securityHelper);
        }

        server.start(embeddedConfiguration);

        // this is dummy vdb to satisfy the boot process to create the connections
        VDBMetaData vdb =  new VDBMetaData();
        vdb.setName(VDBNAME);
        vdb.setVersion(VDBVERSION);
        server.deployVDB(vdb, false, this.context);

        serverContext.set(server);
        return server;
    }

    @Bean
    @ConditionalOnMissingBean
    @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
    public SpringSecurityHelper securityHelper() {
        return new SpringSecurityHelper();
    }

    @SuppressWarnings({"rawtypes", "unchecked"})
    static class CaffeineCacheFactory implements CacheFactory {
        Map map = new HashMap<>();
        @Override
        public  Cache get(String name) {
            map.put(name, new CaffeineCache(name, 256));
            return map.get(name);
        }
        @Override
        public void destroy() {
            Set keys = new HashSet<>(map.keySet());
            keys.forEach(k -> map.get(k).clear());
            map.clear();
        }
    }
    static class CaffeineCache implements Cache {
        private String name;
        private com.github.benmanes.caffeine.cache.Cache delegate;

        CaffeineCache(String cacheName, int maxSize) {
            this.name = cacheName;
            this.delegate = Caffeine.newBuilder()
                    .weakKeys()
                    .weakValues()
                    .maximumSize(maxSize < 0 ? 10000 : maxSize)
                    .build();
        }

        @Override
        public V put(K key, V value, Long ttl) {
            delegate.put(key, value);
            return delegate.getIfPresent(key);
        }

        @Override
        public String getName() {
            return this.name;
        }

        @Override
        public boolean isTransactional() {
            return false;
        }

        @Override
        public V get(K key) {
            return delegate.getIfPresent(key);
        }

        @Override
        public V remove(K key) {
            V v = delegate.getIfPresent(key);
            delegate.invalidate(key);
            return v;
        }

        @Override
        public int size() {
            return Math.toIntExact(delegate.estimatedSize());
        }

        @Override
        public void clear() {
            delegate.invalidateAll();
        }

        @Override
        public Set keySet() {
            return delegate.asMap().keySet();
        }
    }

    @Bean(name="file")
    @ConditionalOnMissingBean
    public FileConnectionFactory fileConnectionFactory() {
        return new FileConnectionFactory();
    }

    @Bean(name = "teiidNamingStrategy")
    public PhysicalNamingStrategy teiidNamingStrategy() {
        try {
            return (PhysicalNamingStrategy) Class.forName(hibernateNamingClass).getDeclaredConstructors()[0]
                    .newInstance();
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException
                | InvocationTargetException e) {
            return null;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy