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

org.swan.plugin.DbMojo Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF 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 org.swan.plugin;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.type.MapType;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.swan.plugin.bean.Field;
import org.swan.plugin.bean.Pojo;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.regex.Pattern;

import static org.swan.plugin.ConfigFileMojo.DEFAULT_CONFIG_JSON;

/**
 * Goal which generate pojo file from db
 */
@Mojo(name = "db", defaultPhase = LifecyclePhase.PROCESS_SOURCES,threadSafe = true)
public class DbMojo extends AbstractMojo {
    public static final String TABLE_NAME = "TABLE_NAME";
    @Parameter(defaultValue = "${project.basedir}/template", property = "db.dataPath", required = true)
    private File basedir;
    @Parameter(defaultValue = "", property = "db.driver", required = true)
    private String driver;
    @Parameter(defaultValue = "", property = "db.url", required = true)
    private String url;
    @Parameter(defaultValue = "", property = "db.user", required = true)
    private String user;
    @Parameter(defaultValue = "", property = "db.password", required = true)
    private String password;
    @Parameter(defaultValue = "", property = "db.database", required = true)
    private String database;
    @Parameter(defaultValue = "", property = "db.schema", required = true)
    private String schema;
    @Parameter(defaultValue = "", property = "db.packageName", required = true)
    private String packageName;

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        Map defaultData = new TreeMap<>(Comparator.comparingInt(String::length));
        defaultData.putAll(loadDefaultData());
        try {
            Class.forName(driver);
            try (Connection connection = DriverManager.getConnection(url, user, password)) {
                DatabaseMetaData metaData = connection.getMetaData();
                getLog().info("database:" + database + "\tschema:" + schema);
                ResultSet resultSet = metaData.getColumns(database, schema, null, null);
                processDbColumn(resultSet, (tableName, fields) -> exportPojo(defaultData, tableName, getNewPojo(tableName).setFields(fields)));
            }
        } catch (ClassNotFoundException | SQLException e) {
            getLog().error(e);
        }
    }

    /**
     * export pojo to file/files
     *
     * @param defaultData default data in config file
     * @param tableName   table name
     * @param pojo        pojo instance
     * @throws IOException
     */
    private void exportPojo(Map defaultData, String tableName, Pojo pojo) {
        if (pojo != null) {
            //Save to file
            File f = basedir;
            if (!f.exists())
                f.mkdirs();
            f = new File(f, tableName + ".pojo.json");
            if (!f.exists()) {
                ObjectMapper om = new ObjectMapper();
                AtomicReference tmp = new AtomicReference<>();
                final Pojo finalPojo = pojo;
                defaultData.entrySet().stream().filter(entry -> Pattern.compile(entry.getKey()).matcher(finalPojo.getId()).matches()).forEach(entry -> tmp.set(mergePojo(tmp.get(), entry.getValue(), om)));
                tmp.set(mergePojo(tmp.get(), pojo, om));
                try {
                    new ObjectMapper().writerWithDefaultPrettyPrinter().writeValue(new FileWriter(f), new Pojo[]{tmp.get()});
                    getLog().info(f.getName() + " created successfully.");
                } catch (IOException e) {
                    getLog().info(f.getName() + " created fail with exception:" + e.getMessage());
                }
            }
        }
    }

    /**
     * Create Pojo instance from table information
     *
     * @param tableName table information
     * @return
     */
    private Pojo getNewPojo(String tableName) {
        String className = tableName;
        className = Character.toUpperCase(className.charAt(0)) + className.substring(1);
        Pojo.TemplateBean templateBean = new Pojo.TemplateBean().setClassName(className);
        Pojo newPojo = new Pojo().setId(className).addTemplate(templateBean);
        if (packageName != null && !packageName.trim().isEmpty()) {
            templateBean.setPackageName(packageName);
        }
        return newPojo;
    }

    private Pojo mergePojo(Pojo source, Pojo override, ObjectMapper objectMapper) {
        if (source == null) {
            return override;
        }
        if (override == null)
            return source;
        ObjectReader updater = objectMapper.readerForUpdating(source);
        try {
            return updater.readValue(objectMapper.writeValueAsString(override));
        } catch (JsonProcessingException e) {
            return source;
        }
    }

    private Map loadDefaultData() {
        ObjectMapper om = new ObjectMapper();
        MapType mapType = om.getTypeFactory().constructMapType(Map.class, String.class, Pojo.class);
        File f = new File(basedir, DEFAULT_CONFIG_JSON);
        if (f.exists()) {
            try {
                return om.readValue(f, mapType);
            } catch (IOException e) {
                return new HashMap<>();
            }
        }
        return new HashMap<>();
    }

    private Map> processDbColumn(ResultSet resultSet, BiConsumer> consumer) throws SQLException {
        Map> result = new HashMap<>();
        String tableName = null;
        List fields = new ArrayList<>();
        while (resultSet.next()) {
            if (!resultSet.getString(TABLE_NAME).equals(tableName)) {
                getLog().info("table:" + resultSet.getString(TABLE_NAME));
                result.put(tableName, fields);
                if (consumer != null)
                    consumer.accept(tableName, fields);
                fields = new ArrayList<>();
            }
            fields.add(new Field(resultSet.getString("COLUMN_NAME"), resultSet.getString("REMARKS"), typeMapper(resultSet.getInt("DATA_TYPE"))));
            tableName = resultSet.getString(TABLE_NAME);
        }
        if (tableName != null) {
            result.put(tableName, fields);
            if (consumer != null)
                consumer.accept(tableName, fields);
        }
        return result;
    }


    public static String typeMapper(int type) {
        switch (type) {
            case Types.BIT:
            case Types.BOOLEAN:
                return "boolean";
            case Types.INTEGER:
            case Types.TINYINT:
                return "int";
            case Types.BIGINT:
                return "long";
            case Types.DECIMAL:
            case Types.DOUBLE:
            case Types.FLOAT:
                return "double";
            case Types.BLOB:
            case Types.CLOB:
            case Types.VARBINARY:
            case Types.BINARY:
            case Types.LONGVARBINARY:
                return "byte[]";
            case Types.VARCHAR:
            case Types.NVARCHAR:
            case Types.LONGVARCHAR:
            case Types.LONGNVARCHAR:
                return "String";
            case Types.TIMESTAMP:
            case Types.DATE:
            case Types.TIME:
                return "LocalDateTime";
            default:
                return "String";

        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy