net.ontopia.persistence.rdbms.DatabaseProjectReader.java Source code

Java tutorial

Introduction

Here is the source code for net.ontopia.persistence.rdbms.DatabaseProjectReader.java

Source

/*
 * #!
 * Ontopia Engine
 * #-
 * Copyright (C) 2001 - 2013 The Ontopia Project
 * #-
 * 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 net.ontopia.persistence.rdbms;

import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import net.ontopia.utils.OntopiaRuntimeException;
import net.ontopia.utils.StreamUtils;
import net.ontopia.xml.DefaultXMLReaderFactory;
import net.ontopia.xml.PrettyPrinter;
import net.ontopia.xml.SAXTracker;
import org.apache.commons.lang3.StringUtils;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl;

/** 
 * INTERNAL: Class that can read a database schema definition from an
 * XML representation.
 */

public class DatabaseProjectReader {
    private static final String PROPERTY = "property";
    private static final String VALUE = "value";
    private static final String SIZE = "size";
    private static final String TYPE = "type";
    private static final String NAME = "name";
    private static final String PLATFORM = "platform";
    private static final String CDATA = "CDATA";

    protected static final AttributesImpl EMPTY_ATTR_LIST = new AttributesImpl();
    protected static final String EMPTY_NAMESPACE = "";
    protected static final String EMPTY_LOCALNAME = "";

    private DatabaseProjectReader() {
    }

    /**
     * INTERNAL: Reads the database schema definition from the specified file.
     */
    public static Project loadProject(String filename) throws IOException, SAXException {
        return loadProject(StreamUtils.getInputStream(filename));
    }

    public static Project loadProject(InputStream istream) throws IOException, SAXException {
        return loadProject(new InputSource(istream));
    }

    public static Project loadProject(InputSource isource) throws IOException, SAXException {

        ProjectHandler handler = new ProjectHandler();
        XMLReader parser = DefaultXMLReaderFactory.createXMLReader();
        parser.setContentHandler(handler);
        parser.parse(isource);

        return handler.project;
    }

    public static void saveProject(Project project, String filename) throws IOException, SAXException {
        saveProject(project, filename, "utf-8");
    }

    public static void saveProject(Project project, String filename, String encoding)
            throws IOException, SAXException {
        PrintWriter print = new PrintWriter(new FileWriter(filename));
        saveProject(project, new PrettyPrinter(print, encoding));
        print.close();
    }

    public static void saveProject(Project project, ContentHandler dh) throws SAXException {
        AttributesImpl atts = new AttributesImpl();

        dh.startDocument();

        dh.startElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "dbschema", EMPTY_ATTR_LIST);

        Iterator<String> platforms = project.getDataTypePlatforms().iterator();
        if (platforms.hasNext()) {
            while (platforms.hasNext()) {
                String platform = platforms.next();

                atts.clear();
                atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, PLATFORM, CDATA, platform);
                dh.startElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "datatypes", atts);

                Iterator<DataType> datatypes = project.getDataTypes(platform).iterator();
                while (datatypes.hasNext()) {
                    // Platform datatypes
                    DataType datatype = datatypes.next();
                    atts.clear();
                    atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, NAME, CDATA, (datatype.getName()));
                    atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, TYPE, CDATA, (datatype.getType()));
                    atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, SIZE, CDATA,
                            (datatype.getSize() == null ? "" : datatype.getSize()));
                    atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "class", CDATA,
                            (datatype.isVariable() ? "variable" : "constant"));

                    dh.startElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "datatype", atts);

                    // Datatype properties
                    Iterator<String> properties = datatype.getProperties().iterator();
                    while (properties.hasNext()) {
                        String name = properties.next();
                        String value = datatype.getProperty(name);
                        if (value != null) {
                            atts.clear();
                            atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, NAME, CDATA, name);
                            atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, VALUE, CDATA, value);
                            dh.startElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, PROPERTY, atts);
                            dh.endElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, PROPERTY);
                        }
                    }

                    dh.endElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "datatype");

                }
            }
            dh.endElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "datatypes");
        }

        Iterator<Table> tables = project.getTables().iterator();
        while (tables.hasNext()) {
            Table table = tables.next();

            // Table attributes
            atts.clear();
            atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, NAME, CDATA, table.getName());
            if (table.getShortName() != null)
                atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "short", CDATA, table.getShortName());
            if (table.getPrimaryKeys() != null)
                atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "pks", CDATA,
                        StringUtils.join(table.getPrimaryKeys(), " "));
            dh.startElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "table", atts);

            // Table properties
            Iterator<String> properties = table.getProperties().iterator();
            while (properties.hasNext()) {
                String name = properties.next();
                String value = table.getProperty(name);
                if (value != null) {
                    atts.clear();
                    atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, NAME, CDATA, name);
                    atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, VALUE, CDATA, value);
                    dh.startElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, PROPERTY, atts);
                    dh.endElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, PROPERTY);
                }
            }

            Iterator<Column> columns = table.getColumns().iterator();
            while (columns.hasNext()) {
                Column column = columns.next();

                // Column attributes
                atts.clear();
                atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, NAME, CDATA, column.getName());
                atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, TYPE, CDATA, column.getType());

                if (column.isReference()) {
                    atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "reftab", CDATA,
                            column.getReferencedTable());
                    atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "refcol", CDATA,
                            column.getReferencedColumn());
                }

                if (column.getSize() != null)
                    atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, SIZE, CDATA, column.getName());
                if (column.isNullable())
                    atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "null", CDATA, "yes");
                if (column.getDefault() != null)
                    atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "default", CDATA, column.getDefault());
                dh.startElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "column", atts);

                // Column properties
                Iterator<String> properties2 = column.getProperties().iterator();
                while (properties2.hasNext()) {
                    String name = properties2.next();
                    String value = column.getProperty(name);
                    if (value != null) {
                        atts.clear();
                        atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, NAME, CDATA, name);
                        atts.addAttribute(EMPTY_NAMESPACE, EMPTY_LOCALNAME, VALUE, CDATA, value);
                        dh.startElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, PROPERTY, atts);
                        dh.endElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, PROPERTY);
                    }
                }
                dh.endElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "column");
            }

            dh.endElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "table");
        }

        dh.endElement(EMPTY_NAMESPACE, EMPTY_LOCALNAME, "dbschema");
        dh.endDocument();
    }

    static class ProjectHandler extends SAXTracker {

        private static final String EL_DBSCHEMA = "dbschema";
        private static final String EL_DATATYPES = "datatypes";
        private static final String EL_DATATYPE = "datatype";
        private static final String EL_TABLE = "table";
        private static final String EL_COLUMN = "column";
        private static final String EL_INDEX = "index";
        private static final String EL_PROPERTY = PROPERTY;
        private static final String EL_CREATE_ACTION = "create-action";
        private static final String EL_DROP_ACTION = "drop-action";

        protected Project project;
        protected Map<String, Object> info;

        public ProjectHandler() {
            keepContentsOf("create-action");
            keepContentsOf("drop-action");
        }

        @Override
        public void startDocument() {
            project = new Project();
            info = new HashMap<String, Object>();
        }

        @Override
        public void endDocument() {
            info = null;
        }

        @Override
        public void startElement(String uri, String name, String qname, Attributes atts) throws SAXException {
            super.startElement(uri, name, qname, atts);

            // System.out.println("S: " + name + ":" + openElements);

            if (EL_COLUMN.equals(qname)) {
                // Instantiate new column instance
                Column column = new Column();

                String cname = atts.getValue(NAME);
                if (cname == null)
                    throw new OntopiaRuntimeException("column.name must be specified: " + cname);
                column.setName(cname);

                String type = atts.getValue(TYPE);
                if (type == null)
                    throw new OntopiaRuntimeException("column.type must be specified: " + cname);

                // if (project.getDataTypeByName(type) == null)
                //   throw new OntopiaRuntimeException("Unknown datatype:: " + type);

                column.setType(type);

                String size = atts.getValue(SIZE);
                if (size != null)
                    column.setSize(size);

                String default_value = atts.getValue("default");
                if (default_value != null)
                    column.setDefault(default_value);

                String reftable = atts.getValue("reftab");
                if (reftable != null)
                    column.setReferencedTable(reftable);

                String refcol = atts.getValue("refcol");
                if ((refcol == null && reftable != null) || (refcol != null && reftable == null))
                    throw new OntopiaRuntimeException("column.refcol and reftable must both specified:" + cname);
                if (refcol != null)
                    column.setReferencedColumn(refcol);

                String nullable = atts.getValue("null");
                if (nullable == null || nullable.equals("no"))
                    column.setNullable(false);
                else
                    column.setNullable(true);

                Table table = (Table) info.get(EL_TABLE);
                // Add column to table
                table.addColumn(column);

                info.put(EL_COLUMN, column);

            } else if (EL_INDEX.equals(qname)) {
                // Instantiate new index instance
                Index index = new Index();

                String iname = atts.getValue(NAME);
                if (iname == null)
                    throw new OntopiaRuntimeException("index.name must be specified: " + iname);
                index.setName(iname);

                String isname = atts.getValue("short");
                index.setShortName(isname);

                String icolumns = atts.getValue("columns");
                if (icolumns == null)
                    throw new OntopiaRuntimeException("index.columns must be specified: " + icolumns);
                index.setColumns(StringUtils.split(icolumns, ","));

                Table table = (Table) info.get(EL_TABLE);
                // Add index to table
                table.addIndex(index);

                info.put(EL_INDEX, index);

            } else if (EL_TABLE.equals(qname)) {
                // Instantiate new table instance
                Table table = new Table();

                String tname = atts.getValue(NAME);
                if (tname == null)
                    throw new OntopiaRuntimeException("table.name must be specified: " + tname);
                table.setName(tname);

                String tsname = atts.getValue("short");
                table.setShortName(tsname);

                String pkeys = atts.getValue("pks");
                if (pkeys != null)
                    table.setPrimaryKeys(StringUtils.split(pkeys));

                // Add table to project
                project.addTable(table);
                info.put(EL_TABLE, table);

            } else if (EL_DATATYPES.equals(qname)) {
                String platform = atts.getValue(PLATFORM);
                if (platform == null)
                    throw new OntopiaRuntimeException("datatypes.platform must be specified: " + platform);

                info.put(EL_DATATYPES, platform);

            } else if (EL_DATATYPE.equals(qname)) {
                // Instantiate new datatype instance
                DataType datatype = new DataType();
                String platform = (String) info.get(EL_DATATYPES);

                String dname = atts.getValue(NAME);
                if (dname == null)
                    throw new OntopiaRuntimeException("datatype.name must be specified: " + dname);
                datatype.setName(dname);

                String type = atts.getValue(TYPE);
                if (type == null)
                    throw new OntopiaRuntimeException("datatype.type must be specified: " + dname);
                datatype.setType(type);

                String klass = atts.getValue("class");
                if (klass == null || klass.equals("variable"))
                    datatype.setVariable(true);
                else
                    datatype.setVariable(false);

                String size = atts.getValue(SIZE);
                if (datatype.isVariable()) {
                    if (size == null)
                        throw new OntopiaRuntimeException("datatype.size must be specified: " + dname);
                    datatype.setSize(size);
                }

                // Add table to project
                project.addDataType(datatype, platform);
                info.put(EL_DATATYPE, datatype);

            } else if (EL_PROPERTY.equals(qname)) {
                if (info.containsKey(EL_DATATYPE)) {
                    String propname = atts.getValue(NAME);
                    if (propname == null)
                        throw new OntopiaRuntimeException("property.name must be specified.");
                    String value = atts.getValue(VALUE);
                    if (value == null)
                        throw new OntopiaRuntimeException("property.value must be specified.");
                    DataType datatype = (DataType) info.get(EL_DATATYPE);
                    datatype.addProperty(propname, value);
                } else if (info.containsKey(EL_COLUMN)) {
                    String propname = atts.getValue(NAME);
                    if (propname == null)
                        throw new OntopiaRuntimeException("property.name must be specified.");
                    String value = atts.getValue(VALUE);
                    if (value == null)
                        throw new OntopiaRuntimeException("property.value must be specified.");
                    Column column = (Column) info.get(EL_COLUMN);
                    column.addProperty(propname, value);
                } else if (info.containsKey(EL_TABLE)) {
                    String propname = atts.getValue(NAME);
                    if (propname == null)
                        throw new OntopiaRuntimeException("property.name must be specified.");
                    String value = atts.getValue(VALUE);
                    if (value == null)
                        throw new OntopiaRuntimeException("property.value must be specified.");
                    Table table = (Table) info.get(EL_TABLE);
                    table.addProperty(propname, value);
                } else
                    throw new OntopiaRuntimeException("property element in unknown parent." + info);

            } else if (EL_CREATE_ACTION.equals(qname)) {
                String platform = atts.getValue(PLATFORM);
                if (platform == null)
                    throw new OntopiaRuntimeException("create-action.platform must be specified: " + platform);

                info.put(EL_CREATE_ACTION, platform);
            } else if (EL_DROP_ACTION.equals(qname)) {
                String platform = atts.getValue(PLATFORM);
                if (platform == null)
                    throw new OntopiaRuntimeException("drop-action.platform must be specified: " + platform);

                info.put(EL_DROP_ACTION, platform);
            } else if (EL_DBSCHEMA.equals(qname)) {
            }
        }

        @Override
        public void endElement(String uri, String name, String qname) throws SAXException {
            super.endElement(uri, name, qname);

            if (EL_DATATYPES.equals(qname)) {
                // Remove types entry
                info.remove(EL_DATATYPES);
            } else if (EL_DATATYPE.equals(qname)) {
                // Remove type entry
                info.remove(EL_DATATYPE);
            } else if (EL_TABLE.equals(qname)) {
                // Remove table entry
                info.remove(EL_TABLE);
            } else if (EL_COLUMN.equals(qname)) {
                // Remove column entry
                info.remove(EL_COLUMN);
            } else if (EL_INDEX.equals(qname)) {
                // Remove index entry
                info.remove(EL_INDEX);
            } else if (EL_CREATE_ACTION.equals(qname)) {
                project.addCreateAction((String) info.get(EL_CREATE_ACTION), content.toString());
                // Remove table entry
                info.remove(EL_CREATE_ACTION);
            } else if (EL_DROP_ACTION.equals(qname)) {
                project.addDropAction((String) info.get(EL_DROP_ACTION), content.toString());
                // Remove table entry
                info.remove(EL_DROP_ACTION);
            } else if (EL_PROPERTY.equals(qname)) {
            } else if (EL_DBSCHEMA.equals(qname)) {
            } else {
                System.out.println("Ignoring: " + name);
            }
            // System.out.println("E: " + name);

        }

        protected Map<String, String> parseAttribs(String content) {
            Map<String, String> result = new HashMap<String, String>();

            String[] fields = StringUtils.split(content.toString());
            for (int i = 0; i < fields.length; i++) {
                String field = fields[i];
                String[] entry = StringUtils.split(field, "=");
                if (entry.length != 2) {
                    // System.out.println("Ignoring: '" + field + "' (" + entry.length + ")");
                    continue;
                }
                result.put(entry[0], entry[1]);
            }
            return result;
        }

    }

    public static void main(String[] args) throws IOException, SAXException {
        DatabaseProjectReader preader = new DatabaseProjectReader();
        preader.loadProject(args[0]);
    }

}