net.redwarp.library.database.TableInfo.java Source code

Java tutorial

Introduction

Here is the source code for net.redwarp.library.database.TableInfo.java

Source

/*
 * 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.
 *
 * Copyright 2015 Redwarp
 */

package net.redwarp.library.database;

import net.redwarp.library.database.annotation.Chain;
import net.redwarp.library.database.annotation.PrimaryKey;
import net.redwarp.library.database.annotation.Version;

import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * @param <T> The type of the object to be stored
 */
public class TableInfo<T> {

    private Class<T> mClass;
    //    private Map<Field, SQLiteUtils.SQLiteType> mFieldMap;
    private Map<Field, Column> mColumns;
    private List<Field> mObjectFields;
    public Column primaryKey = null;
    private String[] mColumnNames;
    private Field[] mFields;
    private Field[] mChainDeleteFields;
    private long mVersion;

    private static HashMap<Class, TableInfo> allTableInfo = new HashMap<>();

    @SuppressWarnings("unchecked")
    public static <T> TableInfo<T> getTableInfo(Class<T> tClass) {
        TableInfo<T> tableInfo = allTableInfo.get(tClass);
        if (tableInfo == null) {
            tableInfo = new TableInfo<>(tClass);
            allTableInfo.put(tClass, tableInfo);
        }
        return tableInfo;
    }

    @SuppressWarnings("unchecked")
    private TableInfo(Class<T> c) {
        mClass = c;

        if (c.isAnnotationPresent(Version.class)) {
            final Version version = c.getAnnotation(Version.class);
            mVersion = version.value();
        } else {
            mVersion = 1;
        }

        Field[] fields = mClass.getDeclaredFields();
        //        mFieldMap = new HashMap<>(fields.length);
        mColumns = new HashMap<>(fields.length);
        mObjectFields = new ArrayList<>();

        List<String> columnNames = new ArrayList<>(fields.length);
        List<Field> finalFields = new ArrayList<>(fields.length);
        List<Field> chainDeleteFields = new ArrayList<>(fields.length);

        for (Field field : fields) {
            if (!Modifier.isStatic(field.getModifiers())) {
                SQLiteUtils.SQLiteType type = SQLiteUtils.getSqlLiteTypeForField(field);
                if (type != null) {
                    field.setAccessible(true);
                    if (field.isAnnotationPresent(PrimaryKey.class)) {
                        if (primaryKey != null) {
                            throw new RuntimeException("There can be only one primary key");
                        }
                        final PrimaryKey primaryKeyAnnotation = field.getAnnotation(PrimaryKey.class);
                        String name = primaryKeyAnnotation.name();
                        if ("".equals(name)) {
                            name = getColumnName(field);
                        }
                        columnNames.add(name);
                        primaryKey = new Column(name, field, SQLiteUtils.SQLiteType.INTEGER);
                    } else {
                        final String name = getColumnName(field);
                        columnNames.add(name);
                        mColumns.put(field, new Column(name, field, type));
                    }

                    finalFields.add(field);
                } else {
                    // Not a basic field;
                    if (field.isAnnotationPresent(Chain.class)) {
                        // We must serialize/unserialize this as well
                        final Chain chainAnnotation = field.getAnnotation(Chain.class);
                        if (chainAnnotation.delete()) {
                            chainDeleteFields.add(field);
                        }
                        final String name = getColumnName(field);
                        columnNames.add(name);
                        Column column = new Column(name, field, SQLiteUtils.SQLiteType.INTEGER);
                        mColumns.put(field, column);
                        mObjectFields.add(field);
                        finalFields.add(field);
                    }
                }
            }
        }
        mColumnNames = columnNames.toArray(new String[columnNames.size()]);
        mFields = finalFields.toArray(new Field[finalFields.size()]);
        mChainDeleteFields = chainDeleteFields.toArray(new Field[chainDeleteFields.size()]);
    }

    public String getName() {
        return mClass.getCanonicalName().replace('.', '_');
    }

    public long getVersion() {
        return mVersion;
    }

    public String getCreateRequest() {
        final StringBuilder builder = new StringBuilder("CREATE TABLE ").append(getName()).append(" (");
        List<String> columnList = new ArrayList<>(mColumns.size());

        if (primaryKey != null) {
            columnList.add(getColumnDefinition(primaryKey) + " PRIMARY KEY AUTOINCREMENT");
        }

        for (Field field : mColumns.keySet()) {
            columnList.add(getColumnDefinition(mColumns.get(field)));
        }

        builder.append(StringUtils.join(columnList, ", "));

        builder.append(" );");

        return builder.toString();
    }

    public List<String> getCreateTriggerRequests() {
        if (mChainDeleteFields != null) {
            List<String> triggers = new ArrayList<>(mChainDeleteFields.length);
            for (Field field : mChainDeleteFields) {
                TableInfo fieldInfo = TableInfo.getTableInfo(field.getType());
                String trigger = "CREATE TRIGGER delete_" + fieldInfo.getName() + "_FROM_" + getName() + "\n"
                        + "AFTER DELETE ON " + getName() + "\n" + "FOR EACH ROW\n" + " BEGIN\n" + "  DELETE FROM "
                        + fieldInfo.getName() + " WHERE " + fieldInfo.primaryKey.name + " = OLD." + primaryKey.name
                        + ";\n" + " END;";
                if (!triggers.contains(trigger)) {
                    // No need to add the same trigger twice, if a class as multiple instance of the same object
                    triggers.add(trigger);
                }
            }
            return triggers;
        } else {
            return new ArrayList<>(0);
        }
    }

    private String getColumnDefinition(Column column) {
        return column.name + " " + column.type;
    }

    private String getColumnName(Field field) {
        return "key_" + field.getName();
    }

    public String getUpdateRequest() {
        return null;
    }

    public boolean hasPrimaryKey() {
        return primaryKey != null;
    }

    public static class Column {

        public Field field;
        public SQLiteUtils.SQLiteType type;
        public String name;

        public Column(String name, Field field, SQLiteUtils.SQLiteType type) {
            this.name = name;
            this.field = field;
            this.type = type;
        }
    }

    public Set<Field> getFields() {
        return mColumns.keySet();
    }

    public List<Field> getObjectFields() {
        return mObjectFields;
    }

    public String[] getColumnNames() {
        return mColumnNames;
    }

    public Field[] getAllFields() {
        return mFields;
    }

    public Column getColumn(Field field) {
        return mColumns.get(field);
    }

    public Field[] getChainDeleteFields() {
        return mChainDeleteFields;
    }

    public Class<T> getInfoClass() {
        return mClass;
    }

}