edu.ku.brc.specify.utilapps.DataModelClassGenerator.java Source code

Java tutorial

Introduction

Here is the source code for edu.ku.brc.specify.utilapps.DataModelClassGenerator.java

Source

/* Copyright (C) 2015, University of Kansas Center for Research
 * 
 * Specify Software Project, specify@ku.edu, Biodiversity Institute,
 * 1345 Jayhawk Boulevard, Lawrence, Kansas, 66045, USA
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package edu.ku.brc.specify.utilapps;

import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Hashtable;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.WindowConstants;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;

import com.jgoodies.forms.builder.PanelBuilder;
import com.jgoodies.forms.factories.ButtonBarFactory;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.looks.plastic.PlasticLookAndFeel;
import com.jgoodies.looks.plastic.theme.ExperienceBlue;

import edu.ku.brc.specify.datamodel.Appraisal;
import edu.ku.brc.ui.UIHelper;

/**
 * @author rods
 *
 * @code_status Alpha
 *
 * Created Date: Aug 28, 2007
 *
 */
public class DataModelClassGenerator extends JFrame {
    enum DataType {
        String, Memo, Set
    }

    private Hashtable<String, Boolean> baseClassHash = new Hashtable<String, Boolean>();

    protected Class<?> dataClass;

    protected JTextArea logArea;
    protected JTextField tableIdTxt;
    protected JTextField devTxt;

    protected Vector<UIRow> rows = new Vector<UIRow>();
    protected Hashtable<Field, UIRow> fieldRowhash = new Hashtable<Field, UIRow>();

    /**
     * @param dataClass
     * @param tableId
     */
    public DataModelClassGenerator(final Class<?> dataClass) {
        this.dataClass = dataClass;

        Class<?>[] baseClasses = { Boolean.class, Integer.class, Double.class, String.class, Float.class,
                Character.class, Short.class, Byte.class, BigDecimal.class, Date.class, Calendar.class };
        for (Class<?> cls : baseClasses) {
            baseClassHash.put(cls.getSimpleName(), true);
        }

        int cnt = 0;
        for (Field field : dataClass.getDeclaredFields()) {
            if (field.getType() == String.class || Collection.class.isAssignableFrom(field.getType())) {
                cnt++;
            }
        }
        Font font = new Font("Courier", Font.PLAIN, 10);

        logArea = new JTextArea();
        logArea.setFont(font);

        tableIdTxt = new JTextField(10);
        devTxt = new JTextField(10);

        PanelBuilder outer = new PanelBuilder(new FormLayout("p,2px,p,2px,f:p:g", "200px:g,4px,f:300px:g,4px,p"));

        PanelBuilder pb = new PanelBuilder(new FormLayout("p,2px,p,2px,l:p:g,2px,l:p",
                UIHelper.createDuplicateJGoodiesDef("p", "2px", cnt + 2)));
        CellConstraints cc = new CellConstraints();

        pb.add(new JLabel("Table Id"), cc.xy(1, 1));
        pb.add(tableIdTxt, cc.xywh(3, 1, 3, 1));

        pb.add(new JLabel("Dev"), cc.xy(1, 3));
        pb.add(devTxt, cc.xywh(3, 3, 3, 1));

        int y = 5;
        for (Field field : dataClass.getDeclaredFields()) {
            if (field.getType() == String.class) {
                UIRow row = new UIRow(DataType.String, field);
                pb.add(new JLabel(field.getName()), cc.xy(1, y));
                pb.add(row.getSizetxt(), cc.xywh(3, y, 1, 1));
                y += 2;
                rows.add(row);
                fieldRowhash.put(field, row);
            }

            if (Collection.class.isAssignableFrom(field.getType())) {
                UIRow row = new UIRow(DataType.Set, field);
                pb.add(new JLabel(field.getName()), cc.xy(1, y));
                pb.add(row.getSizetxt(), cc.xywh(3, y, 3, 1));
                pb.add(new JLabel("(Set)", SwingConstants.LEFT), cc.xy(7, y));
                y += 2;
                rows.add(row);
                fieldRowhash.put(field, row);
            }
        }

        JButton processBtn = UIHelper.createButton("Process");
        JButton cancelBtn = UIHelper.createButton("Cancel");

        processBtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                process();
            }
        });

        cancelBtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                setVisible(false);
            }
        });
        pb.getPanel().setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));

        JPanel panel = ButtonBarFactory.buildGrowingBar(new JButton[] { processBtn, cancelBtn });

        outer.add(new JScrollPane(pb.getPanel(), ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED), cc.xywh(1, 1, 5, 1));
        outer.add(new JScrollPane(logArea, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED), cc.xywh(1, 3, 5, 1));
        outer.add(panel, cc.xy(5, 5));
        setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

        JPanel p = new JPanel(new BorderLayout());
        p.add(outer.getPanel(), BorderLayout.CENTER);
        setContentPane(p);
        //setSize(500,500);
        pack();
        setSize(500, getSize().height);
    }

    public void process() {

        String template = "";

        try {
            File templateFile = new File("src/edu/ku/brc/specify/utilapps/DataModelGenTemplate.txt");
            template = FileUtils.readFileToString(templateFile);

        } catch (IOException ex) {
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(DataModelClassGenerator.class, ex);
            ex.printStackTrace();
            return;
        }

        String className = dataClass.getSimpleName();
        String noCapClassName = className.substring(0, 1).toLowerCase() + className.substring(1);
        String idName = className.substring(0, 1).toLowerCase() + className.substring(1) + "Id";

        SimpleDateFormat sdf = new SimpleDateFormat("MMM dd, yyyy");

        template = StringUtils.replace(template, "<!-- TableName -->", className.toLowerCase());
        template = StringUtils.replace(template, "<!-- ClassName -->", className);
        template = StringUtils.replace(template, "<!-- Id -->", idName);
        template = StringUtils.replace(template, "<!-- IdNum -->", tableIdTxt.getText());
        template = StringUtils.replace(template, "<!-- Dev -->", devTxt.getText());
        template = StringUtils.replace(template, "<!-- Date -->", sdf.format(Calendar.getInstance().getTime()));

        Hashtable<String, Boolean> duplicateClassNames = new Hashtable<String, Boolean>();
        for (Field field : dataClass.getDeclaredFields()) {
            UIRow row = fieldRowhash.get(field);
            String fieldsType = (row != null && row.getSizetxt() != null) ? row.getSizetxt().getText()
                    : field.getType().getSimpleName();
            Boolean bool = duplicateClassNames.get(fieldsType);
            if (bool == null) {
                duplicateClassNames.put(fieldsType, false);
            } else if (!bool) {
                duplicateClassNames.put(fieldsType, true);
            }
        }
        StringBuilder declarationsSB = new StringBuilder();
        StringBuilder initersSB = new StringBuilder();
        StringBuilder methodsSB = new StringBuilder();

        StringBuilder osDeclarationsSB = new StringBuilder();
        StringBuilder osInitersSB = new StringBuilder();
        StringBuilder osMethodsSB = new StringBuilder();

        // Initializer
        int maxWidth = 0;
        for (Field field : dataClass.getDeclaredFields()) {
            String typeStr;
            UIRow row = fieldRowhash.get(field);
            if (row != null && row.isSet()) {
                typeStr = field.getType().getSimpleName() + "<" + row.getSizetxt().getText() + ">";
            } else {
                typeStr = field.getType().getSimpleName();
            }
            maxWidth = Math.max(maxWidth, typeStr.length());
        }

        int initerMaxWidth = 0;
        for (Field field : dataClass.getDeclaredFields()) {
            initerMaxWidth = Math.max(initerMaxWidth, field.getName().length());
        }

        String prevType = "";

        for (Field field : dataClass.getDeclaredFields()) {
            String fieldName = field.getName();
            UIRow row = fieldRowhash.get(field);
            boolean isSet = row != null && row.isSet();

            boolean isThereMoreThanOne = false;
            String othersideClassType = "";
            String othersideFieldName = "";
            String othersideMethodName = "";
            String otherSideID = "";
            boolean isFieldObj = false;
            String fieldsType;
            if (row != null) {
                fieldsType = isSet ? row.getSizetxt().getText() : field.getType().getSimpleName();
            } else {
                fieldsType = field.getType().getSimpleName();
            }
            //System.out.println("isField["+fieldsType+"]["+isFieldObj + "] " + fieldName);

            //String checkClass = "";
            if (!isSet) {
                // Check to see if the field is a basic Java type we should ignore 
                // or a Data Object we need to hook up
                isFieldObj = baseClassHash.get(fieldsType) != null;// Check to see if it is a basic type
                if (!isFieldObj) {
                    othersideClassType = "Set<" + className + ">";

                    isThereMoreThanOne = duplicateClassNames.get(fieldsType) != null
                            && duplicateClassNames.get(fieldsType);
                    if (isThereMoreThanOne) { // OK since it isn't a basic field than it is a Set of this class
                        String fName = fieldName.substring(0, fieldName.length() - 1);
                        othersideFieldName = fName + className + "s";
                        othersideMethodName = StringUtils.capitalize(fName) + className + "s";
                        otherSideID = fName + className + "ID";
                    } else {
                        othersideFieldName = noCapClassName + "s";
                        othersideMethodName = className + "s";
                        otherSideID = className + "ID";
                    }
                }

            } else {
                // Since this side is a Set than the otherside will be just this class
                othersideClassType = className;

                isThereMoreThanOne = duplicateClassNames.get(fieldsType) != null
                        && duplicateClassNames.get(fieldsType);
                if (isThereMoreThanOne) {
                    String fName = fieldName.substring(0, fieldName.length() - 1);
                    othersideFieldName = fName + className;
                    othersideMethodName = StringUtils.capitalize(fName) + className;
                    otherSideID = fName + className + "ID";
                } else {
                    othersideFieldName = noCapClassName;
                    othersideMethodName = className;
                    otherSideID = className + "ID";
                }
            }

            boolean isNewOSClassType = !fieldsType.equals(prevType);
            if (isNewOSClassType) {
                prevType = fieldsType;
            }

            boolean doOtherSide = isSet || !isFieldObj;

            //-------------------------------------
            // Declarations
            //-------------------------------------
            String typeStr;

            if (row != null && row.isSet()) {
                typeStr = field.getType().getSimpleName() + "<" + row.getSizetxt().getText() + ">";
            } else {
                typeStr = field.getType().getSimpleName();
            }
            declarationsSB.append("    protected ");
            declarationsSB.append(typeStr);
            for (int i = 0; i < (maxWidth - typeStr.length() + 1); i++) {
                declarationsSB.append(' ');
            }
            declarationsSB.append(field.getName());
            declarationsSB.append(";\n");

            if (doOtherSide) {
                if (isNewOSClassType) {
                    osDeclarationsSB.append("\n\n    // Copy this Code into Class " + fieldsType + "\n\n");
                }
                // use the same width (just because)
                osDeclarationsSB.append("    protected ");
                osDeclarationsSB.append(othersideClassType);
                for (int i = 0; i < (maxWidth - typeStr.length() + 1); i++) {
                    osDeclarationsSB.append(' ');
                }
                osDeclarationsSB.append(othersideFieldName);
                osDeclarationsSB.append(";\n");
            }

            //-------------------------------------
            // Initers
            //-------------------------------------
            if (row != null && row.isSet()) {
                typeStr = "new HashSet<" + row.getSizetxt().getText() + ">()";
            } else {
                typeStr = "null";
            }
            initersSB.append("        ");
            initersSB.append(field.getName());
            for (int i = 0; i < (initerMaxWidth - field.getName().length() + 1); i++) {
                initersSB.append(' ');
            }
            initersSB.append(" = ");
            initersSB.append(typeStr);
            initersSB.append(";\n");

            if (doOtherSide && !isFieldObj) {
                if (isNewOSClassType) {
                    osInitersSB.append("\n\n    // Copy this Code into Class " + fieldsType + "\n\n");
                }
                osInitersSB.append("        ");
                osInitersSB.append(othersideFieldName);
                for (int i = 0; i < (initerMaxWidth - field.getName().length() + 1); i++) {
                    osInitersSB.append(' ');
                }
                osInitersSB.append(" = ");
                if (othersideClassType.startsWith("Set")) {
                    osInitersSB.append(
                            "new HashSet<" + (row != null ? row.getSizetxt().getText() : className) + ">()");
                } else {
                    osInitersSB.append("null");
                }

                osInitersSB.append(";\n");
            }

            // Do Methods

            if (isSet) {
                typeStr = field.getType().getSimpleName() + "<" + row.getSizetxt().getText() + ">";
                isSet = true;

            } else {
                typeStr = field.getType().getSimpleName();
            }

            methodsSB.append("    /**\n");
            methodsSB.append("     *\n");
            methodsSB.append("     */\n");

            String size = "";
            if (row != null) {
                if (row.isCBXString()) {
                    size = row.getSizetxt().getText();
                } else if (row.getType() != DataType.Set) {
                    methodsSB.append("    @Lob\n");
                }
            } else if (field.getType() == Date.class || field.getType() == Calendar.class) {
                methodsSB.append("    @Temporal(TemporalType.DATE)\n");
            }

            if (isSet) {
                String singularFieldName = field.getName().substring(0, fieldName.length() - 1);
                methodsSB.append("    @OneToMany(cascade = {}, fetch = FetchType.LAZY, mappedBy = \""
                        + singularFieldName + "\")\n");

            } else if (baseClassHash.get(field.getType()) != null) {
                methodsSB.append("    @Column(name = \"" + StringUtils.capitalize(fieldName)
                        + "\", unique = false, nullable = true, insertable = true, updatable = true"
                        + (StringUtils.isNotEmpty(size) ? (", length = " + size + "") : "") + ")\n");
            } else {
                methodsSB.append("    @ManyToOne(cascade = {}, fetch = FetchType.LAZY)\n");
                methodsSB.append(
                        "    @Cascade( { CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.LOCK })\n");
                methodsSB.append("    @JoinColumn(name = \"" + className
                        + "ID\", unique = false, nullable = true, insertable = true, updatable = true)\n");
            }
            methodsSB.append("    public " + typeStr + " get" + StringUtils.capitalize(fieldName) + "()\n    {\n");
            methodsSB.append("        return this." + fieldName + ";\n");
            methodsSB.append("    }\n\n");
            methodsSB.append("    public void set" + StringUtils.capitalize(fieldName) + "(final " + typeStr + " "
                    + fieldName + ")\n    {\n");
            methodsSB.append("        this." + fieldName + " = " + fieldName + ";\n");
            methodsSB.append("    }\n\n");

            if (fieldsType.startsWith("Agent")) {
                int x = 0;
                x++;
            }
            if (doOtherSide && !isFieldObj) {
                if (isNewOSClassType) {
                    osMethodsSB.append("\n\n    // Copy this Code into Class " + fieldsType + "\n\n");
                }

                osMethodsSB.append("    /**\n");
                osMethodsSB.append("     *\n");
                osMethodsSB.append("     */\n");
                if (isSet) {
                    osMethodsSB.append("    @OneToMany(cascade = {}, fetch = FetchType.LAZY, mappedBy = \""
                            + fieldName + "\")\n");

                } else {
                    osMethodsSB.append("    @ManyToOne(cascade = {}, fetch = FetchType.LAZY)\n");
                    osMethodsSB.append(
                            "    @Cascade( { CascadeType.SAVE_UPDATE, CascadeType.MERGE, CascadeType.LOCK })\n");
                    osMethodsSB.append("    @JoinColumn(name = \"" + otherSideID
                            + "\", unique = false, nullable = true, insertable = true, updatable = true)\n");
                }

                osMethodsSB
                        .append("    public " + othersideClassType + " get" + othersideMethodName + "()\n    {\n");
                osMethodsSB.append("        return this." + othersideFieldName + ";\n");
                osMethodsSB.append("    }\n\n");
                osMethodsSB.append("    public void set" + othersideMethodName + "(final " + othersideClassType
                        + " " + othersideFieldName + ")\n    {\n");
                osMethodsSB.append("        this." + othersideFieldName + " = " + othersideFieldName + ";\n");
                osMethodsSB.append("    }\n\n");

            }
        }
        template = StringUtils.replace(template, "<!-- Fields -->", declarationsSB.toString());
        template = StringUtils.replace(template, "<!-- Initers -->", initersSB.toString());
        template = StringUtils.replace(template, "<!-- Methods -->", methodsSB.toString());

        StringBuilder sb = new StringBuilder();
        sb.append("/* ---------------------------------------------\n");
        sb.append(osDeclarationsSB);
        sb.append(osInitersSB);
        sb.append(osMethodsSB);
        sb.append("\n*/");

        logArea.setText(template + sb.toString());

        try {
            File outFile = new File(className + ".java");
            FileUtils.writeStringToFile(outFile, template + sb.toString());

        } catch (IOException ex) {
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(DataModelClassGenerator.class, ex);
            ex.printStackTrace();
        }

    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @SuppressWarnings("synthetic-access")
            public void run() {
                try {
                    UIHelper.OSTYPE osType = UIHelper.getOSType();
                    if (osType == UIHelper.OSTYPE.Windows) {
                        //UIManager.setLookAndFeel(new WindowsLookAndFeel());
                        UIManager.setLookAndFeel(new PlasticLookAndFeel());
                        PlasticLookAndFeel.setPlasticTheme(new ExperienceBlue());

                    } else if (osType == UIHelper.OSTYPE.Linux) {
                        //UIManager.setLookAndFeel(new GTKLookAndFeel());
                        UIManager.setLookAndFeel(new PlasticLookAndFeel());
                        //PlasticLookAndFeel.setPlasticTheme(new SkyKrupp());
                        //PlasticLookAndFeel.setPlasticTheme(new DesertBlue());
                        //PlasticLookAndFeel.setPlasticTheme(new ExperienceBlue());
                        //PlasticLookAndFeel.setPlasticTheme(new DesertGreen());

                    }
                } catch (Exception e) {
                    edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                    edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(DataModelClassGenerator.class, e);
                    //log.error("Can't change L&F: ", e);
                }
                DataModelClassGenerator dmcg = new DataModelClassGenerator(Appraisal.class);
                UIHelper.centerAndShow(dmcg);

            }
        });
    }

    class UIRow {
        protected Field field;
        protected JTextField sizetxt;
        protected JComboBox typeCBX = null;
        protected DataType type;

        public UIRow(final DataType type, final Field field) {
            this.type = type;

            /*String[] options = new String[DataType.values().length];
            int i = 0;
            for (DataType dt : DataType.values())
            {
            options[i++] = dt.toString();
            }*/
            this.field = field;
            sizetxt = new JTextField(type == DataType.String ? 5 : 15);
            if (type != DataType.Set) {
                typeCBX = UIHelper.createComboBox(new String[] { "Memo", "String" });
                typeCBX.setSelectedIndex(0);
            }
        }

        /**
         * @return the sizetxt
         */
        public JTextField getSizetxt() {
            return sizetxt;
        }

        /**
         * @return the typeCBX
         */
        public JComboBox getTypeCBX() {
            return typeCBX;
        }

        /**
         * @return the field
         */
        public Field getField() {
            return field;
        }

        /**
         * @param field the field to set
         */
        public void setField(Field field) {
            this.field = field;
        }

        public boolean isSet() {
            return this.type == DataType.Set;
        }

        public boolean isCBXString() {
            return sizetxt.getText() != null;
            /*
            if (typeCBX != null)
            {
            String value = (String)typeCBX.getSelectedItem();
            DataType dt = value != null ? DataType.valueOf(value) : DataType.Memo;
            return dt == DataType.String;
            }
            return false;*/
        }

        /**
         * @return the type
         */
        public DataType getType() {
            return type;
        }

    }

}