org.teiid.translator.mongodb.MongoDBMetadataProcessor.java Source code

Java tutorial

Introduction

Here is the source code for org.teiid.translator.mongodb.MongoDBMetadataProcessor.java

Source

/*
 * JBoss, Home of Professional Open Source.
 * See the COPYRIGHT.txt file distributed with this work for information
 * regarding copyright ownership.  Some portions may be licensed
 * to Red Hat, Inc. under one or more contributor license agreements.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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 GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 */
package org.teiid.translator.mongodb;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;

import org.bson.types.Binary;
import org.teiid.metadata.*;
import org.teiid.metadata.Column.SearchType;
import org.teiid.mongodb.MongoDBConnection;
import org.teiid.translator.MetadataProcessor;
import org.teiid.translator.TranslatorException;
import org.teiid.translator.TypeFacility;

import com.mongodb.*;

public class MongoDBMetadataProcessor implements MetadataProcessor<MongoDBConnection> {

    @ExtensionMetadataProperty(applicable = Table.class, datatype = String.class, display = "Merge Into Table", description = "Declare the name of table that this table needs to be merged into. No separate copy maintained")
    public static final String MERGE = MetadataFactory.MONGO_URI + "MERGE"; //$NON-NLS-1$

    @ExtensionMetadataProperty(applicable = Table.class, datatype = String.class, display = "Embedded Into Table", description = "Declare the name of table that this table needs to be embedded into. A separate copy is also maintained")
    public static final String EMBEDDABLE = MetadataFactory.MONGO_URI + "EMBEDDABLE"; //$NON-NLS-1$

    private static final String ID = "_id"; //$NON-NLS-1$
    private static final String TOP_LEVEL_DOC = "TOP_LEVEL_DOC"; //$NON-NLS-1$
    private static final String ASSOSIATION = "ASSOSIATION"; //$NON-NLS-1$

    @Override
    public void process(MetadataFactory metadataFactory, MongoDBConnection connection) throws TranslatorException {
        DB db = connection.getDatabase();
        for (String tableName : db.getCollectionNames()) {

            DBCollection rows = db.getCollection(tableName);
            BasicDBObject row = (BasicDBObject) rows.findOne();
            Table table = addTable(metadataFactory, tableName, row);

            // top level documents can not be seen as merged
            table.setProperty(TOP_LEVEL_DOC, String.valueOf(Boolean.TRUE));
        }

        for (Table table : metadataFactory.getSchema().getTables().values()) {
            String merge = table.getProperty(MERGE, false);
            if (merge != null) {
                addForeignKey(metadataFactory, table, metadataFactory.getSchema().getTable(merge));
            }
        }

        for (Table table : metadataFactory.getSchema().getTables().values()) {
            String top = table.getProperty(TOP_LEVEL_DOC, false);
            String merge = table.getProperty(MERGE, false);
            if (top != null) {
                table.setProperty(TOP_LEVEL_DOC, null);
                if (merge != null) {
                    table.setProperty(MERGE, null);
                    table.setProperty(EMBEDDABLE, "true"); //$NON-NLS-1$
                }
            }
        }
    }

    private Table addTable(MetadataFactory metadataFactory, String tableName, BasicDBObject row) {
        if (metadataFactory.getSchema().getTable(tableName) != null) {
            Table t = metadataFactory.getSchema().getTable(tableName);
            return t;
        }

        Table table = metadataFactory.addTable(tableName);
        table.setSupportsUpdate(true);

        for (String columnKey : row.keySet()) {
            Object value = row.get(columnKey);

            Column column = addColumn(metadataFactory, table, columnKey, value);

            if (column != null) {
                column.setUpdatable(true);
            }
        }
        return table;
    }

    private Column addColumn(MetadataFactory metadataFactory, Table table, String columnKey, Object value) {
        Column column = null;

        if (columnKey.equals(ID)) {
            if (value instanceof BasicDBObject) {
                BasicDBObject compositeKey = (BasicDBObject) value;
                for (String key : compositeKey.keySet()) {
                    column = addColumn(metadataFactory, table, key, compositeKey.get(key));
                    column.setUpdatable(true);
                }
            }
        }

        if (!columnKey.equals(ID) && value instanceof BasicDBObject) {
            // embedded doc - one to one
            Table childTable = addTable(metadataFactory, columnKey, (BasicDBObject) value);
            childTable.setProperty(MERGE, table.getName());
            childTable.setProperty(ASSOSIATION, MergeDetails.Association.ONE.name());
        } else if (value instanceof BasicDBList) {
            // embedded doc, list one to many
            if (((BasicDBList) value).get(0) instanceof BasicDBObject) {
                Table childTable = addTable(metadataFactory, columnKey,
                        (BasicDBObject) ((BasicDBList) value).get(0));
                childTable.setProperty(MERGE, table.getName());
                childTable.setProperty(ASSOSIATION, MergeDetails.Association.MANY.name());
            } else {
                column = metadataFactory.addColumn(columnKey, TypeFacility.RUNTIME_NAMES.OBJECT + "[]", table); //$NON-NLS-1$
                column.setSearchType(SearchType.Unsearchable);
            }
        } else if (value instanceof DBRef) {
            Object obj = ((DBRef) value).getId();
            column = addColumn(metadataFactory, table, columnKey, obj);
            String ref = ((DBRef) value).getRef();
            metadataFactory.addForiegnKey("FK_" + columnKey, Arrays.asList(columnKey), ref, table); //$NON-NLS-1$
        } else {
            column = metadataFactory.addColumn(columnKey, getDataType(value), table);
        }

        // create a PK out of _id
        if (columnKey.equals(ID)) {
            if (value instanceof BasicDBObject) {
                BasicDBObject compositeKey = (BasicDBObject) value;
                ArrayList<String> columns = new ArrayList<String>();
                for (String key : compositeKey.keySet()) {
                    columns.add(key);
                }
                metadataFactory.addPrimaryKey("PK0", columns, table); //$NON-NLS-1$
            } else {
                metadataFactory.addPrimaryKey("PK0", Arrays.asList(ID), table); //$NON-NLS-1$
            }
        }
        return column;
    }

    private void addForeignKey(MetadataFactory metadataFactory, Table childTable, Table table) {
        MergeDetails.Association association = MergeDetails.Association
                .valueOf(childTable.getProperty(ASSOSIATION, false));
        childTable.setProperty(ASSOSIATION, null);
        if (association == MergeDetails.Association.ONE) {
            KeyRecord record = table.getPrimaryKey();
            if (record != null) {
                ArrayList<String> pkColumns = new ArrayList<String>();
                for (Column column : record.getColumns()) {
                    Column c = metadataFactory.getSchema().getTable(childTable.getName())
                            .getColumnByName(column.getName());
                    if (c == null) {
                        c = metadataFactory.addColumn(column.getName(), column.getRuntimeType(), childTable);
                    }
                    pkColumns.add(c.getName());
                }
                metadataFactory.addPrimaryKey("PK0", pkColumns, childTable); //$NON-NLS-1$
            }
        } else {
            KeyRecord record = table.getPrimaryKey();
            if (record != null) {
                ArrayList<String> pkColumns = new ArrayList<String>();
                for (Column column : record.getColumns()) {
                    Column c = metadataFactory.getSchema().getTable(childTable.getName())
                            .getColumnByName(table.getName() + "_" + column.getName()); //$NON-NLS-1$
                    if (c == null) {
                        c = metadataFactory.addColumn(table.getName() + "_" + column.getName(), //$NON-NLS-1$
                                column.getRuntimeType(), childTable);
                    }
                    pkColumns.add(c.getName());
                }
                metadataFactory.addForiegnKey("FK0", pkColumns, table.getName(), childTable); //$NON-NLS-1$                
            }
        }
    }

    private String getDataType(Object value) {
        if (value instanceof Integer) {
            return TypeFacility.RUNTIME_NAMES.INTEGER;
        } else if (value instanceof Double) {
            return TypeFacility.RUNTIME_NAMES.DOUBLE;
        } else if (value instanceof Boolean) {
            return TypeFacility.RUNTIME_NAMES.BOOLEAN;
        } else if (value instanceof Long) {
            return TypeFacility.RUNTIME_NAMES.LONG;
        } else if (value instanceof String) {
            return TypeFacility.RUNTIME_NAMES.STRING;
        } else if (value instanceof Date) {
            return TypeFacility.RUNTIME_NAMES.TIMESTAMP;
        } else if (value instanceof Binary || value instanceof byte[]) {
            return TypeFacility.RUNTIME_NAMES.VARBINARY;
        } else {
            return TypeFacility.RUNTIME_NAMES.OBJECT;
        }
    }
}