at.ac.univie.isc.asio.nest.NestBluePrint.java Source code

Java tutorial

Introduction

Here is the source code for at.ac.univie.isc.asio.nest.NestBluePrint.java

Source

/*
 * #%L
 * asio server
 * %%
 * Copyright (C) 2013 - 2015 Research Group Scientific Computing, University of Vienna
 * %%
 * 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.
 * #L%
 */
package at.ac.univie.isc.asio.nest;

import at.ac.univie.isc.asio.Scope;
import at.ac.univie.isc.asio.SqlSchema;
import at.ac.univie.isc.asio.d2rq.D2rqConfigModel;
import at.ac.univie.isc.asio.d2rq.pool.PooledD2rqFactory;
import at.ac.univie.isc.asio.database.DatabaseInspector;
import at.ac.univie.isc.asio.database.DefinitionService;
import at.ac.univie.isc.asio.database.Jdbc;
import at.ac.univie.isc.asio.database.MysqlUserRepository;
import at.ac.univie.isc.asio.engine.sparql.JenaEngine;
import at.ac.univie.isc.asio.engine.sparql.JenaFactory;
import at.ac.univie.isc.asio.engine.sql.CommandWhitelist;
import at.ac.univie.isc.asio.engine.sql.JdbcSpec;
import at.ac.univie.isc.asio.engine.sql.JooqEngine;
import at.ac.univie.isc.asio.metadata.DescriptorService;
import at.ac.univie.isc.asio.metadata.SchemaDescriptor;
import at.ac.univie.isc.asio.spring.ExplicitWiring;
import at.ac.univie.isc.asio.tool.JdbcTools;
import at.ac.univie.isc.asio.tool.Timeout;
import com.google.common.base.Predicate;
import com.hp.hpl.jena.rdf.model.Model;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import rx.Observable;
import rx.functions.Func0;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.net.URI;
import java.util.concurrent.TimeUnit;

import static org.slf4j.LoggerFactory.getLogger;

@Configuration
@ExplicitWiring
class NestBluePrint {
    private static final Logger log = getLogger(NestBluePrint.class);

    static final String BEAN_DEFINITION_SOURCE = "definition";
    static final String BEAN_DESCRIPTOR_SOURCE = "metadata";
    static final String BEAN_MAPPING_SOURCE = "mapping";

    @Autowired(required = false)
    @Qualifier("sqlCommandWhitelist")
    private Predicate<String> whitelist = CommandWhitelist.any();

    @Bean(destroyMethod = "close")
    public JooqEngine jooqEngine(final Jdbc jdbc, final DataSource pool, final Timeout timeout) {
        final JdbcSpec spec = JdbcSpec.connectTo(jdbc.getUrl()).authenticateAs(jdbc.getUrl(), jdbc.getPassword())
                .use(timeout).complete();
        final JooqEngine engine = JooqEngine.create(ClosableDataSourceProxy.wrap(pool), spec);
        engine.setWhitelist(whitelist);
        return engine;
    }

    @Bean(destroyMethod = "close")
    public JenaEngine jenaEngine(final Dataset dataset, final D2rqConfigModel d2rq, final Jdbc jdbc,
            final Timeout timeout, final Environment env) {
        final Integer poolSize = env.getProperty("asio.d2rq.pool-size", Integer.class, 1);
        final JenaFactory factory = PooledD2rqFactory.using(d2rq, jdbc, timeout, poolSize);
        return JenaEngine.using(factory, dataset.isFederationEnabled());
    }

    @Bean(name = BEAN_DEFINITION_SOURCE)
    public Observable<SqlSchema> definition(final Jdbc jdbc, final DefinitionService definitionService) {
        return Observable.defer(new CallDefinitionService(definitionService, jdbc.getSchema()));
    }

    @Bean(name = BEAN_DESCRIPTOR_SOURCE)
    public Observable<SchemaDescriptor> metadata(final Dataset dataset, final DescriptorService descriptorService) {
        return Observable.defer(new CallDescriptorService(descriptorService, dataset.getIdentifier()));
    }

    @Bean(name = BEAN_MAPPING_SOURCE)
    public Observable<Model> mapping(final D2rqConfigModel d2rq) {
        return Observable.just(d2rq.getDefinition());
    }

    @Bean
    @ConditionalOnMissingBean
    public DescriptorService nullDescriptorService() {
        log.info(Scope.SYSTEM.marker(), "creating static fallback DescriptorService");
        return new DescriptorService() {
            @Override
            public Observable<SchemaDescriptor> metadata(final URI identifier) {
                return Observable.empty();
            }
        };
    }

    @Bean
    @ConditionalOnMissingBean
    public DefinitionService localDefinitionService(final Jdbc jdbc, final DataSource dataSource) {
        log.info(Scope.SYSTEM.marker(), "creating local DefinitionService from {}", jdbc);
        return DatabaseInspector.create(jdbc.getUrl(), dataSource);
    }

    @Bean(destroyMethod = "close")
    @Primary
    public DataSource dataSource(final HikariConfig base, final Dataset dataset, final Jdbc jdbc,
            final Timeout timeout) {
        final HikariConfig config = JdbcTools.populate(base, dataset.getName().asString(), jdbc);
        config.setConnectionTimeout(timeout.getAs(TimeUnit.MILLISECONDS, 0));
        return new HikariDataSource(config);
    }

    @Bean
    @Primary
    public Timeout localTimeout(final Dataset dataset, final Timeout global) {
        final Timeout local = dataset.getTimeout();
        log.debug(Scope.SYSTEM.marker(), "choosing timeout (local:{}) (global:{})", local, global);
        return local.orIfUndefined(global);
    }

    // fix mysql user management conflict on re-deployments
    // TODO formalize initializer || fix assembly/destruction inerleaving in another way

    @Autowired(required = false)
    private MysqlUserRepository mysql;
    @Autowired
    private Jdbc jdbc;

    @PostConstruct
    public void ensureMysqlUserPresent() {
        if (mysql != null) {
            final String schema = jdbc.getSchema();
            log.info(Scope.SYSTEM.marker(), "ensure mysql user for {} is present", schema);
            mysql.createUserFor(schema);
        }
    }

    // Observable factories as nest static classes to avoid inner classes with implicit references.

    private static class CallDescriptorService implements Func0<Observable<? extends SchemaDescriptor>> {
        private final DescriptorService service;
        private final URI identifier;

        public CallDescriptorService(final DescriptorService serviceRef, final URI identifierRef) {
            this.service = serviceRef;
            this.identifier = identifierRef;
        }

        @Override
        public Observable<? extends SchemaDescriptor> call() {
            return service.metadata(identifier);
        }
    }

    private static class CallDefinitionService implements Func0<Observable<? extends SqlSchema>> {
        private final DefinitionService service;
        private final String schema;

        public CallDefinitionService(final DefinitionService serviceRef, final String schemaRef) {
            this.service = serviceRef;
            this.schema = schemaRef;
        }

        @Override
        public Observable<? extends SqlSchema> call() {
            return service.definition(schema);
        }
    }
}