org.yccheok.jstock.gui.IndicatorProjectManager.java Source code

Java tutorial

Introduction

Here is the source code for org.yccheok.jstock.gui.IndicatorProjectManager.java

Source

/*
 * JStock - Free Stock Market Software
 * Copyright (C) 2009 Yan Cheng Cheok <yccheok@yahoo.com>
 *
 * 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 org.yccheok.jstock.gui;

import java.util.*;
import java.io.*;

import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.yccheok.jstock.analysis.OperatorIndicator;

/**
 *
 * @author yccheok
 */
public class IndicatorProjectManager {

    /**
     * @return the operatorIndicatorType
     */
    public OperatorIndicator.Type getPreferredOperatorIndicatorType() {
        return preferredOperatorIndicatorType;
    }

    public enum PreInstallStatus {
        Safe, // Zipped file with correct format.
        Unsafe, // Zipper file with bad format.
        Collision // Zipped file with correct format. However, we may overwrite
                  // our existing project.
    }

    /** Creates a new instance of IndicatorProjectManager */
    public IndicatorProjectManager(String directory, OperatorIndicator.Type preferredOperatorIndicatorType) {
        org.yccheok.jstock.gui.Utils.createCompleteDirectoryHierarchyIfDoesNotExist(directory);

        this.preferredOperatorIndicatorType = preferredOperatorIndicatorType;
        this.directory = directory;
    }

    public int getNumOfProject() {
        return projects.size();
    }

    public String getProject(int index) {
        return projects.get(index);
    }

    // Overwrite is allowed.
    public boolean addProject(IndicatorDefaultDrawing drawing, String project) {
        // Avoid naming crashing.
        final int reserve_word_length = JHOTDRAW_RESERVE_WORD.length();
        if (project.length() >= reserve_word_length) {
            final String substring = project.substring(project.length() - reserve_word_length, project.length());
            if (substring.equalsIgnoreCase(JHOTDRAW_RESERVE_WORD)) {
                return false;
            }
        }

        if (this.contains(project) == false) {
            projects.add(project);
        }
        try {
            drawing.write(project, getJHotDrawFilename(project), getOperatorIndicatorFilename(project));
        } catch (IOException exp) {
            projects.remove(project);
            log.error(null, exp);
            return false;
        }

        return true;
    }

    private String getJHotDrawFilename(String project) {
        return directory + File.separator + project + JHOTDRAW_RESERVE_WORD + ".xml";
    }

    private String getOperatorIndicatorFilename(String project) {
        return directory + File.separator + project + ".xml";
    }

    public boolean removeProject(String project) {
        if (new File(getJHotDrawFilename(project)).delete() == false) {
            // No return. We may need to remove a corrupted project. Continue.
            // return false;
        }

        if (new File(getOperatorIndicatorFilename(project)).delete() == false) {
            // No return. We may need to remove a corrupted project. Continue.
            // return false;
        }

        return projects.remove(project);
    }

    public boolean renameProject(String newProject, String oldProject) {
        if (newProject.equals(oldProject)) {
            // Nothing to be done. We will consider this as success.
            return true;
        }

        File oldJHotDrawFile = new File(getJHotDrawFilename(oldProject));
        File oldOperatorIndicatorFile = new File(getOperatorIndicatorFilename(oldProject));
        File newJHotDrawFile = new File(getJHotDrawFilename(newProject));
        File newOperatorIndicatorFile = new File(getOperatorIndicatorFilename(newProject));

        if (oldJHotDrawFile.renameTo(newJHotDrawFile) == false) {
            return false;
        }

        if (oldOperatorIndicatorFile.renameTo(newOperatorIndicatorFile) == false) {
            return false;
        }

        final int index = projects.indexOf(oldProject);
        if (index == -1) {
            return false;
        }

        boolean status = projects.remove(oldProject);
        if (status == false) {
            return false;
        }

        projects.add(index, newProject);

        // ********************************************
        // Hacking way to rename the OperatorIndicator.
        // ********************************************
        org.yccheok.jstock.analysis.OperatorIndicator operatorIndicator = getOperatorIndicator(newProject);
        operatorIndicator.setName(newProject);
        return Utils.toXML(operatorIndicator, this.getOperatorIndicatorFilename(newProject));
    }

    public IndicatorDefaultDrawing getIndicatorDefaultDrawing(String project) {
        if (this.contains(project) == false) {
            return null;
        }
        final IndicatorDefaultDrawing drawing = new IndicatorDefaultDrawing();
        try {
            drawing.read(this.getJHotDrawFilename(project), this.getOperatorIndicatorFilename(project));
        } catch (java.io.IOException exp) {
            log.error(null, exp);
            return null;
        }
        return drawing;
    }

    public org.yccheok.jstock.analysis.OperatorIndicator getOperatorIndicator(String project) {
        if (this.contains(project) == false) {
            return null;
        }
        File operatorIndicatorFile = new File(getOperatorIndicatorFilename(project));
        return Utils.fromXML(org.yccheok.jstock.analysis.OperatorIndicator.class, operatorIndicatorFile);
    }

    public boolean contains(String project) {
        // Do not use
        // projects.contains(project);
        // as it is case sensitive.
        // We need case in-sensitive comparison.
        for (String p : projects) {
            if (p.equalsIgnoreCase(project)) {
                return true;
            }
        }
        return false;
    }

    public boolean install(File zipFile) {
        // First, get the project name.
        final String projectName = IndicatorProjectManager.getProjectName(zipFile);
        if (projectName == null) {
            return false;
        }

        final String jHotDrawFilename = projectName + JHOTDRAW_RESERVE_WORD + ".xml";
        final String operatorIndicatorFilename = projectName + ".xml";

        boolean status = true;
        /* projectName, operatorIndicatorFilename, jHotDrawFilename */
        ZipInputStream in = null;
        try {
            in = new ZipInputStream(new FileInputStream(zipFile));
            // Get the first entry
            ZipEntry zipEntry = null;

            while ((zipEntry = in.getNextEntry()) != null) {
                final String name = zipEntry.getName();
                String outFilename = null;

                if (name.equalsIgnoreCase(operatorIndicatorFilename)) {
                    outFilename = this.getOperatorIndicatorFilename(projectName);
                } else if (name.equalsIgnoreCase(jHotDrawFilename)) {
                    outFilename = this.getJHotDrawFilename(projectName);
                } else {
                    assert (false);
                }

                OutputStream out = null;

                try {
                    out = new FileOutputStream(outFilename);

                    // Transfer bytes from the ZIP file to the output file
                    byte[] buf = new byte[1024];
                    int len;
                    while ((len = in.read(buf)) > 0) {
                        out.write(buf, 0, len);
                    }
                } finally {
                    org.yccheok.jstock.file.Utils.close(out);
                    org.yccheok.jstock.file.Utils.closeEntry(in);
                }
            }
        } catch (IOException ex) {
            log.error(null, ex);
            status = false;
        } finally {
            org.yccheok.jstock.file.Utils.close(in);
        }

        if (status == false) {
            new File(this.getOperatorIndicatorFilename(projectName)).delete();
            new File(this.getJHotDrawFilename(projectName)).delete();
            return false;
        }

        final OperatorIndicator operatorIndicator = (OperatorIndicator) Utils.fromXML(OperatorIndicator.class,
                this.getOperatorIndicatorFilename(projectName));
        if (operatorIndicator == null || operatorIndicator.getType() != this.preferredOperatorIndicatorType) {
            new File(this.getOperatorIndicatorFilename(projectName)).delete();
            new File(this.getJHotDrawFilename(projectName)).delete();
            return false;
        }

        if (this.contains(projectName) == false) {
            this.projects.add(projectName);
        }
        return true;
    }

    public static String getProjectName(File zipFile) {
        final List<String> names = new ArrayList<String>();

        try {
            ZipFile zf = new ZipFile(zipFile);
            for (Enumeration entries = zf.entries(); entries.hasMoreElements();) {
                // Get the entry name
                final ZipEntry zipEntry = (ZipEntry) entries.nextElement();
                final String name = zipEntry.getName();
                final boolean isDirectory = zipEntry.isDirectory();
                if (isDirectory) {
                    return null;
                }
                names.add(name);
            }
        } catch (IOException ex) {
            log.error(null, ex);
            return null;
        }

        // operatorIndicatorFilename and jHotDrawFilename
        if (names.size() != 2) {
            return null;
        }

        String projectName = null;
        for (String name : names) {
            final int index = name.indexOf(".xml");
            if (index < 0) {
                continue;
            }
            final String _projectName = name.substring(0, index);
            projectName = projectName == null ? _projectName
                    : (projectName.length() > _projectName.length() ? _projectName : projectName);
        }

        if (projectName == null || projectName.length() <= 0) {
            return null;
        }

        final String operatorIndicatorFilename = projectName + ".xml";
        final String jHotDrawFilename = projectName + JHOTDRAW_RESERVE_WORD + ".xml";

        for (String name : names) {
            if (!name.equalsIgnoreCase(operatorIndicatorFilename) && !name.equalsIgnoreCase(jHotDrawFilename)) {
                return null;
            }
        }
        return projectName;
    }

    public PreInstallStatus getPreInstallStatus(File zipFile) {
        final String projectName = IndicatorProjectManager.getProjectName(zipFile);
        if (projectName == null) {
            return PreInstallStatus.Unsafe;
        }
        return this.contains(projectName) ? PreInstallStatus.Collision : PreInstallStatus.Safe;
    }

    private Object readResolve() {
        /* For backward compatible */
        if (this.preferredOperatorIndicatorType == null) {
            this.preferredOperatorIndicatorType = OperatorIndicator.Type.AlertIndicator;
        }

        /* When we load IndicatorProjectManager from cloud, we may face the problem
         * where directory is no longer valid.
         * This is the hacking way to solve above mentioned problem.
         */
        if (this.directory.endsWith("indicator")) {
            this.directory = org.yccheok.jstock.gui.Utils.getUserDataDirectory() + "indicator";
        } else if (this.directory.endsWith("module")) {
            this.directory = org.yccheok.jstock.gui.Utils.getUserDataDirectory() + "module";
        } else {
            log.error("Something goes wrong during directory initialization");
            assert (false);
        }

        return this;
    }

    public boolean export(String project, File zipFile) {
        // Create a buffer for reading the files
        final byte[] buf = new byte[1024];
        ZipOutputStream out = null;
        try {
            // Create the ZIP file
            out = new ZipOutputStream(new FileOutputStream(zipFile));

            final List<String> filenames = new ArrayList<String>();
            filenames.add(this.getOperatorIndicatorFilename(project));
            filenames.add(this.getJHotDrawFilename(project));
            // Compress the files
            for (String filename : filenames) {
                FileInputStream in = null;
                try {
                    in = new FileInputStream(filename);
                    // Add ZIP entry to output stream.
                    // I do not want full path. I just want filename.
                    out.putNextEntry(new ZipEntry(new File(filename).getName()));

                    // Transfer bytes from the file to the ZIP file
                    int len;
                    while ((len = in.read(buf)) > 0) {
                        out.write(buf, 0, len);
                    }
                } finally {
                    // Complete the entry
                    org.yccheok.jstock.file.Utils.closeEntry(out);
                    org.yccheok.jstock.file.Utils.close(in);
                }
            }
        } catch (IOException ex) {
            log.error(null, ex);
            return false;
        } finally {
            org.yccheok.jstock.file.Utils.close(out);
        }
        return true;
    }

    /* For backward compatible. Make it final in later version. */
    private OperatorIndicator.Type preferredOperatorIndicatorType;

    private static final Log log = LogFactory.getLog(IndicatorProjectManager.class);

    private static final String JHOTDRAW_RESERVE_WORD = "-jhotdraw";

    private final List<String> projects = new ArrayList<String>();
    /* When we load IndicatorProjectManager from cloud, we may face the problem
     * where directory is no longer valid.
     * This is the hacking way to solve above mentioned problem.
     */
    private String directory;
}