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

org.integratedmodelling.engine.kbox.sql.h2.H2Kbox Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (C) 2007, 2015:
 * 
 * - Ferdinando Villa  - integratedmodelling.org - any
 * other authors listed in @author annotations
 *
 * All rights reserved. This file is part of the k.LAB software suite, meant to enable
 * modular, collaborative, integrated development of interoperable data and model
 * components. For details, see http://integratedmodelling.org.
 * 
 * This program is free software; you can redistribute it and/or modify it under the terms
 * of the Affero General Public License Version 3 or any later version.
 *
 * This program is distributed in the hope that it will be useful, but without any
 * warranty; without even the implied warranty of merchantability or fitness for a
 * particular purpose. See the Affero General Public License for more details.
 * 
 * You should have received a copy of the Affero General Public License along with this
 * program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite
 * 330, Boston, MA 02111-1307, USA. The license is also available at:
 * https://www.gnu.org/licenses/agpl.html
 *******************************************************************************/
package org.integratedmodelling.engine.kbox.sql.h2;

import java.io.File;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.integratedmodelling.api.monitoring.IMonitor;
import org.integratedmodelling.api.persistence.IKbox;
import org.integratedmodelling.api.persistence.IQuery;
import org.integratedmodelling.engine.kbox.sql.SQL;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabRuntimeException;

/**
 * Poor-man hybernate with Thinklab-specialized query language, aware of semantics and
 * time/space, using assumptions and conventions to allow IKbox clean model with little or
 * no configuration.
 * 
 * @author ferdinando.villa
 *
 */
public abstract class H2Kbox implements IKbox {

    protected H2Database                     database;
    protected Map, Serializer>      serializers   = new HashMap<>();
    protected Map, Deserializer> deserializers = new HashMap<>();

    protected QueryBuilder                   queryBuilder;
    protected IMonitor                       monitor;

    private static Map       kboxes        = new HashMap<>();

    protected static IKbox set(String name, H2Kbox kbox) {
        kboxes.put(name, kbox);
        return kbox;
    }

    protected static IKbox get(String name) {
        if (kboxes.containsKey(name)) {
            return kboxes.get(name);
        }
        return null;
    };

    public H2Kbox(String name, IMonitor monitor) {
        database = H2Database.get(name);
        this.monitor = monitor;
    }

    public H2Kbox(String name, File directory, IMonitor monitor) {
        database = H2Database.get(directory, name);
        this.monitor = monitor;
    }

    @Override
    public  List query(IQuery query, Class cls) throws KlabException {
        return queryBuilder == null ? new ArrayList<>() : querySql(queryBuilder.getSQL(query), cls);
    }

    /**
     * Call the H2 recover tool.
     * 
     * @throws KlabException
     */
    public void recover() throws KlabException {
        database.recover();
    }

    public  List querySql(String query, Class cls) throws KlabException {

        Deserializer deserializer = getDeserializer(cls);

        final List ret = deserializer instanceof DeferredDeserializer ? new H2Result(this, monitor)
                : new ArrayList<>();

        deserializer.setKbox(this);
        database.query(query, new SQL.ResultHandler() {

            @Override
            public void onRow(ResultSet rs) {
                if (deserializer instanceof DeferredDeserializer) {
                    try {
                        ((DeferredDeserializer) deserializer).addId(rs.getLong(H2Schema.FIELD_PKEY));
                    } catch (SQLException e) {
                        throw new KlabRuntimeException(e);
                    }
                } else {
                    ret.add(((DirectDeserializer) deserializer).deserialize(rs));
                }
            }

            @Override
            public void nResults(int nres) {
            }
        });

        return ret;
    }

    private  Deserializer getDeserializer(Class cls) {
        Deserializer ret = null;
        for (Class cl : deserializers.keySet()) {
            if (cl.isAssignableFrom(cls)) {
                ret = (Deserializer) deserializers.get(cl);
            }
        }
        if (ret == null) {
            throw new KlabRuntimeException("kbox: no deserializer for class " + cls.getCanonicalName());
        }
        return ret;
    }

    @Override
    public long store(Object o) throws KlabException {
        return database.storeObject(o, 0l, getSerializer(o.getClass()), monitor);
    }

    private  Serializer getSerializer(Class cls) {
        Serializer ret = null;
        for (Class cl : serializers.keySet()) {
            if (cl.isAssignableFrom(cls)) {
                ret = serializers.get(cl);
            }
        }
        if (ret == null) {
            throw new KlabRuntimeException("kbox: no serializer for class " + cls.getCanonicalName());
        }
        return ret;
    }

    @Override
    public  T retrieve(long id, Class cls) throws KlabException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void remove(long id) throws KlabException {
        // TODO Auto-generated method stub

    }

    @Override
    public void remove(IQuery query) throws KlabException {
        // TODO Auto-generated method stub

    }

    @Override
    public void clear() throws KlabException {
        // TODO Auto-generated method stub

    }

    protected void setSerializer(Class cls, Serializer serializer) {
        this.serializers.put(cls, serializer);
    }

    protected void setDeserializer(Class cls, Deserializer deserializer) {
        this.deserializers.put(cls, deserializer);
    }

    protected void setQueryBuilder(QueryBuilder querybuilder) {
        this.queryBuilder = querybuilder;
    }

    protected void setSchema(Class cls, Schema schema) {
        database.setSchema(cls, schema);
    }

    // TODO these interfaces should go in implementation.

    /**
     * Turns an object into SQL instructions to store it.
     * 
     * @author ferdinando.villa
     *
     */
    public static interface Serializer {

        /**
         * 
         * @param o
         * @param schema
         * @param primaryKey
         * @param foreignKey
         * @return SQL instructions to serialize object
         */
        String serialize(T o, Schema schema, long primaryKey, long foreignKey);
    }

    /**
     * Turns a SQL result into an object. Only a tag interface: the actual working API is
     * in the two derived ones.
     * 
     * @author ferdinando.villa
     *
     */
    public static abstract interface Deserializer {

        void setKbox(IKbox h2Kbox);

    }

    /**
     * Builds the object directly in the query result list. Use when building the objects
     * is fast and cheap.
     * 
     * @author ferdinando.villa
     *
     */
    public static interface DirectDeserializer extends Deserializer {

        /**
         * Passed a result set localized on a valid match. Just get your things from it
         * and return - its lifetime is controlled outside. Should return null in error.
         * 
         * @param rs
         * @return deserialized object
         */
        T deserialize(ResultSet rs);

    }

    /**
     * Turns a database unique ID into an object. Use when building objects is complex,
     * requiring more than one query, or when performance is an issue when creating
     * objects. In this case, the query strategy will return the OID field for all matches
     * to it, and the serializer will have to behave like a list that lazily extracts the
     * objects when get() is called.
     * 
     * @author ferdinando.villa
     *
     */
    public static interface DeferredDeserializer extends Deserializer, List {
        void addId(long id);
    }

    public static interface QueryBuilder {

        String getSQL(IQuery query);

    }

    public static interface Schema {

        /**
         * Return non-null if this schema creates a whole table.
         * 
         * @return SQL to create schema
         */
        String getCreateSQL();

        /*
         * Return non-null if this schema is only for a field.
         * 
         * @return field name if only a field
         */
        String getFieldName();

        /*
         * Same
         * 
         * @return type
         */
        String getFieldType();

        /**
         * Return the name of the primary table created by this schema, if
         * any, or null. Used to check for the need of creating the corresponding 
         * tableset.
         * 
         * @return
         */
        String getTableName();

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy