Package com.nexirius.framework.datamodel.persistence

Source Code of com.nexirius.framework.datamodel.persistence.FileSystemPersistence

//{HEADER
/**
* This class is part of jnex 'Nexirius Application Framework for Java'
* Copyright (C) Nexirius GmbH, CH-4450 Sissach, Switzerland (www.nexirius.ch)
*
* <p>This library is free software; you can redistribute it and/or<br>
* modify it under the terms of the GNU Lesser General Public<br>
* License as published by the Free Software Foundation; either<br>
* version 2.1 of the License, or (at your option) any later version.</p>
*
* <p>This library is distributed in the hope that it will be useful,<br>
* but WITHOUT ANY WARRANTY; without even the implied warranty of<br>
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br>
* Lesser General Public License for more details.</p>
*
* <p>You should have received a copy of the GNU Lesser General Public<br>
* License along with this library; if not, write to the Free Software<br>
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA</p>
* </blockquote>
*
* <p>
* Nexirius GmbH, hereby disclaims all copyright interest in<br>
* the library jnex' 'Nexirius Application Framework for Java' written<br>
* by Marcel Baumann.</p>
*/
//}HEADER
package com.nexirius.framework.datamodel.persistence;

import com.nexirius.framework.datamodel.DataModel;
import com.nexirius.framework.datamodel.DataModelEnumeration;
import com.nexirius.framework.datamodel.DataModelVector;
import com.nexirius.util.*;

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

/**
* This class defines a persistence manager which stores models to files
*
* @author Marcel Baumann
*/
public class FileSystemPersistence implements PersistenceManager {

    public static final String DEFAULT_FILE_EXTENSION = ".pm";
    private static FileSystemPersistence instance = null;

    String rootDirectory;
    PersistenceEnvironmentTable environments = new PersistenceEnvironmentTable();
    PersistentModelTable openModels = new PersistentModelTable();

    boolean checkMagicNumber = true;
    boolean verbose = false;

    /**
     * Create a new file system based persistence manager (rootDirectory is only relevant
     * if relative relative DirectoryEnvironments are used)
     */
    private FileSystemPersistence(String rootDirectory) {
        if (rootDirectory.endsWith(File.separator)) {
            this.rootDirectory = rootDirectory;
        } else {
            this.rootDirectory = rootDirectory + File.separator;
        }
    }

    public static void init(String rootDirectory) {
        instance = new FileSystemPersistence(rootDirectory);
    }

    public static PersistenceManager instance() {
        if (instance == null) {
            throw new RuntimeException("Can't call instance before init");
        }

        return instance;
    }

    public void setCheckMagicNumber(boolean on) {
        checkMagicNumber = on;
    }

    public PersistenceEnvironment getEnvironment(String name)
            throws Exception {
        return environments.getEnvironment(name);
    }

    public void addEnvironment(PersistenceEnvironment e)
            throws Exception {
        PersistenceEnvironment oldEnvironment = (PersistenceEnvironment) environments.get(e.getName());

        if (oldEnvironment != null) {
            storeAll();
        }

        environments.putEnvironment(e);
        ((DirectoryEnvironment) e).createDirectory(rootDirectory);
    }

    public boolean isOpen(String environmentName, String identifier) {
        return null != getOpenModel(environmentName, identifier);
    }

    /**
     * Get a model from the list of open models
     *
     * @param environmentName
     * @param identifier
     * @return null if model is not open
     */
    public DataModel getOpenModel(String environmentName, String identifier) {
        PersistentModelTableEntry persistentModelTableEntry = openModels.get(environmentName, identifier);

        if (persistentModelTableEntry != null) {
            return persistentModelTableEntry.getDataModel();
        }

        return null;
    }

    public DataModelEnumeration getNotSaved() {
        DataModelVector v = new DataModelVector();
        Iterator iter = environments.getEnvironments().iterator();

        while (iter.hasNext()) {
            DirectoryEnvironment de = (DirectoryEnvironment) iter.next();

            de.getNotSaved(v);
        }

        return v.getEnumeration();
    }

    protected XFile makeXFile(DirectoryEnvironment environment, String identifier) {
        String extension = environment.getExtension();

        if (extension == null) {
            extension = DEFAULT_FILE_EXTENSION;
        }

        return new XFile(environment.getDirectory(rootDirectory), identifier + extension);
    }

    protected String getIdentifier(DirectoryEnvironment environment, String filename) {
        String extension = environment.getExtension();

        if (extension == null) {
            extension = DEFAULT_FILE_EXTENSION;
        }

        return filename.substring(0, filename.length() - extension.length());
    }

    /**
     * If the model is open then it will be saved and closed.
     * If the model is not open then create a new file and close the model.
     *
     * @param model
     * @param environmentName
     * @throws Exception
     */
    public void store(DataModel model, String environmentName)
            throws Exception {
        synchronized (model) {
            p("store", model.getInstanceName(), environmentName);

            if (model.getInstanceName() == null) {
                throw new Exception("Cannot store model with null instance name");
            }

            DirectoryEnvironment environment = (DirectoryEnvironment) getEnvironment(environmentName);
            PersistentModelTableEntry e = openModels.get(environmentName, model.getInstanceName());
            XFile file = makeXFile(environment, model.getInstanceName());

            if (e == null) {
                // look if the file already existst
                if (file.exists()) {
                    throw new Exception("Can't overwrite existing file '" + file.getAbsolutePath() + "'");
                }
                e = openModels.put(model, environment);
            }

            doSave(file, environment, model);
        }
    }

    /**
     * @param model
     * @param environmentName
     * @throws Exception
     */
    public void save(DataModel model, String environmentName)
            throws Exception {
        synchronized (model) {
            p("save", model.getInstanceName(), environmentName);

            if (model.getInstanceName() == null) {
                throw new Exception("Cannot save model with null instance name");
            }

            DirectoryEnvironment environment = (DirectoryEnvironment) getEnvironment(environmentName);
            XFile file = makeXFile(environment, model.getInstanceName());

            if (!file.exists()) {
                throw new Exception("Can't create file (use store) '" + file.getAbsolutePath() + "'");
            }

            doSave(file, environment, model);
        }
    }

    private void doSave(XFile file, DirectoryEnvironment environment, DataModel model) throws Exception {
        OutputStream out = new FileOutputStream(file);

        if (environment.useMagicNumber()) {
            out = new MagicNumberOutputStream(out);
        }

        // write to the file
        TextToken className = new TextToken(model.getClass().getName(), TextToken.STRING);
        className.writeTo(out);
        model.writeDataTo(out);
        out.close();
        environment.removeNeedSaving(model.getInstanceName());
    }

    public DataModel load(String environmentName, String identifier)
            throws Exception {
        p("load", identifier, environmentName);

        if (isOpen(environmentName, identifier)) {
            return openModels.get(environmentName, identifier).getDataModel();
        }

        DirectoryEnvironment environment = (DirectoryEnvironment) getEnvironment(environmentName);

        DataModel m = readDataModel(environment, identifier, environment.useMagicNumber);

        openModels.put(m, environment);
        m.addSoftDataModelListener(environment.getChangeListener());

        return m;
    }

    public void remove(String environmentName, String identifier)
            throws Exception {
        p("remove", identifier, environmentName);

        if (isOpen(environmentName, identifier)) {
            throw new Exception("Can't remove '" + identifier + "' from '" + environmentName + "' because it is still open");
        }

        DirectoryEnvironment environment = (DirectoryEnvironment) getEnvironment(environmentName);
        XFile file = makeXFile(environment, identifier);

        if (!file.exists()) {
            throw new Exception("Can't remove '" + identifier + "' file not found: " + file.getAbsolutePath());
        }

        String directory = environment.getDirectory(this.rootDirectory);

        XFile dir = new XFile(directory, "deleted");

        if (!dir.exists()) {
            dir.mkdir();
        }

        if (dir.isDirectory()) {
            XFile target = new XFile(dir, file.getName());

            target.createFrom(file, false);
        }

        if (!file.delete()) {
            throw new Exception("Can't remove '" + identifier + "' file: " + file.getAbsolutePath());
        }

        environment.removeNeedSaving(identifier);
    }

    public void close(String environmentName, DataModel model, boolean looseChanges)
            throws Exception {
        p("close", model.getInstanceName(), "-");

        DirectoryEnvironment de = (DirectoryEnvironment) environments.getEnvironment(environmentName);
        String identifier = model.getInstanceName();
        PersistentModelTableEntry e = openModels.get(environmentName, identifier);

        if (e == null) {
            throw new Exception("Can't close '" + environmentName + '.' + identifier + "' it is not open");
        }

        if (!looseChanges) {
            synchronized (e.model) {

                if (de.needSaving(identifier)) {
                    throw new Exception("Can't close '" + environmentName + identifier + "' because it needs saving");
                }
            }
        }

        openModels.remove(environmentName, identifier);
        de.removeNeedSaving(identifier);
    }

    public void storeAll() throws Exception {
        p("storeAll", "", "");

        Iterator iter = openModels.getAllEntries().iterator();

        while (iter.hasNext()) {
            PersistentModelTableEntry entry = (PersistentModelTableEntry) iter.next();

            store(entry.getDataModel(), entry.getEnvironment().getName());
        }
    }

    public DataModelVector loadAll(String environmentName)
            throws Exception {
        p("loadAll", "", environmentName);

        DirectoryEnvironment de = (DirectoryEnvironment) getEnvironment(environmentName);
        StringVector files = de.getFiles(rootDirectory, true);
        DataModelVector v = new DataModelVector();

        for (String f = files.firstItem(); f != null; f = files.nextItem()) {
            try {
                String identifier = getIdentifier(de, f);
                DataModel m = readDataModel(de, identifier, de.useMagicNumber());

                if (m != null) {
                    v.append(m);
                }
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        return v;
    }

    private DataModel readDataModel(DirectoryEnvironment environment, String identifier, boolean useMagicNumber)
            throws Exception {
        p("readDataModel", identifier, environment.getName());
        DataModel m = null;
        XFile file = makeXFile(environment, identifier);

        if (!file.exists()) {
            throw new Exception("Can't load '" + identifier + "' file not found: " + file.getAbsolutePath());
        }

        BufferedInputStream fileIn = new BufferedInputStream(new FileInputStream(file));
        PushbackInputStream in = null;

        if (useMagicNumber) {
            in = new MagicNumberInputStream(fileIn);
        } else {
            in = new PushbackInputStream(fileIn);
        }

        TextToken className = TextToken.nextToken(in);

        if (className.isString()) {
            Class cl = Class.forName(className.getString());

            m = (DataModel) cl.newInstance();
            m.readDataFrom(in);
        } else {
            throw new Exception("Expecting String literal (class name) at beginning of file but have: " + className);
        }

        if (useMagicNumber) {
            MagicNumberInputStream ms = (MagicNumberInputStream) in;

            while (!ms.hasMagic()) {

                if (-1 == ms.read()) {
                    // no magic number found
                    break;
                }
            }

            if (!ms.checkMagic()) {
                in.close();
                throw new MagicNumberException("Wrong magic number in: " + file.getAbsolutePath());
            }
        }

        in.close();
        m.setInstanceName(identifier);

        return m;
    }

    public StringVector getEnvironments() {
        return environments.getEnvironmentNames();
    }

    public void setVerbose(boolean verbose) {
        this.verbose = verbose;
    }

    private void p(String method, String model, String env) {
        if (verbose) {
            System.out.println(method + " " + model + " " + env);

            DataModelEnumeration e = openModels.getEnumeration();

            System.out.print("open[");

            while (e.hasMore()) {
                System.out.print(e.next().getInstanceName() + " ");
            }

            System.out.println("]");

            StringVector envs = getEnvironments();

            for (env = envs.firstItem(); env != null; env = envs.nextItem()) {
                try {
                    System.out.print(env + ": ");
                    ((DirectoryEnvironment) getEnvironment(env)).p();
                } catch (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
    }
}
TOP

Related Classes of com.nexirius.framework.datamodel.persistence.FileSystemPersistence

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.