net.hydromatic.optiq.model.ModelHandler.java Source code

Java tutorial

Introduction

Here is the source code for net.hydromatic.optiq.model.ModelHandler.java

Source

/*
// Licensed to Julian Hyde under one or more contributor license
// agreements. See the NOTICE file distributed with this work for
// additional information regarding copyright ownership.
//
// Julian Hyde licenses this file to you 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 net.hydromatic.optiq.model;

import net.hydromatic.optiq.*;
import net.hydromatic.optiq.impl.TableInSchemaImpl;
import net.hydromatic.optiq.impl.ViewTable;
import net.hydromatic.optiq.impl.java.MapSchema;
import net.hydromatic.optiq.impl.jdbc.JdbcSchema;
import net.hydromatic.optiq.jdbc.OptiqConnection;

import org.apache.commons.dbcp.BasicDataSource;

import org.eigenbase.util.Pair;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.*;
import javax.sql.DataSource;

/**
 * Reads a model and creates schema objects accordingly.
 */
public class ModelHandler {
    private final OptiqConnection connection;
    private final List<Pair<String, Schema>> schemaStack = new ArrayList<Pair<String, Schema>>();

    public ModelHandler(OptiqConnection connection, String uri) throws IOException {
        super();
        this.connection = connection;
        final ObjectMapper mapper = new ObjectMapper();
        mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        JsonRoot root;
        if (uri.startsWith("inline:")) {
            root = mapper.readValue(uri.substring("inline:".length()), JsonRoot.class);
        } else {
            root = mapper.readValue(new File(uri), JsonRoot.class);
        }
        visit(root);
    }

    public void visit(JsonRoot root) {
        final Pair<String, Schema> pair = Pair.<String, Schema>of(null, connection.getRootSchema());
        push(schemaStack, pair);
        for (JsonSchema schema : root.schemas) {
            schema.accept(this);
        }
        pop(schemaStack, pair);
        if (root.defaultSchema != null) {
            try {
                connection.setSchema(root.defaultSchema);
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }

    public void visit(JsonMapSchema jsonSchema) {
        final MutableSchema parentSchema = currentMutableSchema("schema");
        final MapSchema schema = MapSchema.create(parentSchema, jsonSchema.name);
        schema.initialize();
        populateSchema(jsonSchema, schema);
    }

    private void populateSchema(JsonMapSchema jsonSchema, Schema schema) {
        final Pair<String, Schema> pair = Pair.of(jsonSchema.name, schema);
        push(schemaStack, pair);
        for (JsonTable jsonTable : jsonSchema.tables) {
            jsonTable.accept(this);
        }
        pop(schemaStack, pair);
    }

    public void visit(JsonCustomSchema jsonSchema) {
        try {
            final MutableSchema parentSchema = currentMutableSchema("sub-schema");
            final Class clazz = Class.forName(jsonSchema.factory);
            final SchemaFactory schemaFactory = (SchemaFactory) clazz.newInstance();
            final Schema schema = schemaFactory.create(parentSchema, jsonSchema.name, jsonSchema.operand);
            parentSchema.addSchema(jsonSchema.name, schema);
            if (schema instanceof MapSchema) {
                ((MapSchema) schema).initialize();
            }
            populateSchema(jsonSchema, schema);
        } catch (Exception e) {
            throw new RuntimeException("Error instantiating " + jsonSchema, e);
        }
    }

    public void visit(JsonJdbcSchema jsonSchema) {
        JdbcSchema.create(currentMutableSchema("jdbc schema"), dataSource(jsonSchema), jsonSchema.jdbcCatalog,
                jsonSchema.jdbcSchema, jsonSchema.name);
    }

    private DataSource dataSource(JsonJdbcSchema jsonJdbcSchema) {
        BasicDataSource dataSource = new BasicDataSource();
        dataSource.setUrl(jsonJdbcSchema.jdbcUrl);
        dataSource.setUsername(jsonJdbcSchema.jdbcUser);
        dataSource.setPassword(jsonJdbcSchema.jdbcPassword);
        return dataSource;
    }

    private <T> T peek(List<T> stack) {
        return stack.get(stack.size() - 1);
    }

    private <T> void push(List<T> stack, T element) {
        stack.add(element);
    }

    private <T> void pop(List<T> stack, T element) {
        assert stack.get(stack.size() - 1) == element;
        stack.remove(stack.size() - 1);
    }

    public void visit(JsonCustomTable jsonTable) {
        try {
            final MutableSchema schema = currentMutableSchema("table");
            final Class clazz = Class.forName(jsonTable.factory);
            final TableFactory tableFactory = (TableFactory) clazz.newInstance();
            final Table table = tableFactory.create(schema, jsonTable.name, jsonTable.operand, null);
            schema.addTable(new TableInSchemaImpl(schema, jsonTable.name, Schema.TableType.TABLE, table));
        } catch (Exception e) {
            throw new RuntimeException("Error instantiating " + jsonTable, e);
        }
    }

    public void visit(JsonView jsonView) {
        try {
            final MutableSchema schema = currentMutableSchema("view");
            final List<String> path = jsonView.path == null ? Collections.singletonList(peek(schemaStack).left)
                    : jsonView.path;
            schema.addTableFunction(jsonView.name,
                    ViewTable.viewFunction(schema, jsonView.name, jsonView.sql, path));
        } catch (Exception e) {
            throw new RuntimeException("Error instantiating " + jsonView, e);
        }
    }

    private Schema currentSchema() {
        return peek(schemaStack).right;
    }

    private MutableSchema currentMutableSchema(String elementType) {
        final Schema schema = currentSchema();
        if (schema instanceof MutableSchema) {
            return (MutableSchema) schema;
        }
        throw new RuntimeException(
                "Cannot define " + elementType + "; parent schema " + schema + " is not mutable");
    }
}

// End ModelHandler.java