org.eclipsetrader.repository.hibernate.HibernateRepository.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipsetrader.repository.hibernate.HibernateRepository.java

Source

/*
 * Copyright (c) 2004-2011 Marco Maccaferri and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Marco Maccaferri - initial API and implementation
 */

package org.eclipsetrader.repository.hibernate;

import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobManager;
import org.eclipse.core.runtime.jobs.ILock;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.MultiRule;
import org.eclipse.core.variables.IStringVariableManager;
import org.eclipse.core.variables.IValueVariable;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.osgi.util.NLS;
import org.eclipsetrader.core.feed.IFeedIdentifier;
import org.eclipsetrader.core.repositories.IRepository;
import org.eclipsetrader.core.repositories.IRepositoryRunnable;
import org.eclipsetrader.core.repositories.IStore;
import org.eclipsetrader.repository.hibernate.internal.Activator;
import org.eclipsetrader.repository.hibernate.internal.RepositoryDefinition;
import org.eclipsetrader.repository.hibernate.internal.RepositoryValidator;
import org.eclipsetrader.repository.hibernate.internal.stores.HistoryStore;
import org.eclipsetrader.repository.hibernate.internal.stores.IntradayHistoryStore;
import org.eclipsetrader.repository.hibernate.internal.stores.RepositoryStore;
import org.eclipsetrader.repository.hibernate.internal.stores.ScriptStore;
import org.eclipsetrader.repository.hibernate.internal.stores.SecurityStore;
import org.eclipsetrader.repository.hibernate.internal.stores.StrategyScriptProperties;
import org.eclipsetrader.repository.hibernate.internal.stores.StrategyScriptStore;
import org.eclipsetrader.repository.hibernate.internal.stores.TradeStore;
import org.eclipsetrader.repository.hibernate.internal.stores.WatchListStore;
import org.eclipsetrader.repository.hibernate.internal.types.DividendType;
import org.eclipsetrader.repository.hibernate.internal.types.HistoryData;
import org.eclipsetrader.repository.hibernate.internal.types.IdentifierPropertyType;
import org.eclipsetrader.repository.hibernate.internal.types.IdentifierType;
import org.eclipsetrader.repository.hibernate.internal.types.SecurityUnknownPropertyType;
import org.eclipsetrader.repository.hibernate.internal.types.SplitData;
import org.eclipsetrader.repository.hibernate.internal.types.WatchListColumn;
import org.eclipsetrader.repository.hibernate.internal.types.WatchListHolding;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.event.PostDeleteEvent;
import org.hibernate.event.PostDeleteEventListener;
import org.hibernate.event.PostInsertEvent;
import org.hibernate.event.PostInsertEventListener;
import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;

public class HibernateRepository implements IRepository, ISchedulingRule, IExecutableExtension {

    public static final String URI_SECURITY_PART = "securities";
    public static final String URI_SECURITY_HISTORY_PART = "securities/history";
    public static final String URI_SECURITY_INTRADAY_HISTORY_PART = "securities/history/{0}/{1}";
    public static final String URI_WATCHLIST_PART = "watchlists";
    public static final String URI_TRADE_PART = "trades";
    public static final String URI_SCRIPT_PART = "scripts";
    public static final String URI_STRATEGY_PART = "strategies";

    private static final String ERROR_MESSAGE = "Errors occurred updating database";

    private String schema;
    private String name;
    private Properties properties;
    private RepositoryDefinition repositoryDefinition;
    private Session session;

    private Map<String, IdentifierType> identifiersMap;
    private List<WatchListStore> watchlists;
    private Map<URI, IStore> uriMap = new HashMap<URI, IStore>();

    private IJobManager jobManager;
    private final ILock lock;

    public HibernateRepository() {
        this(null, null, new Properties());
    }

    public HibernateRepository(RepositoryDefinition repositoryDefinition) {
        this(repositoryDefinition.getSchema(), repositoryDefinition.getLabel(),
                repositoryDefinition.getProperties());
        this.repositoryDefinition = repositoryDefinition;
    }

    public HibernateRepository(String schema, String name, Properties properties) {
        this.schema = schema;
        this.name = name;
        this.properties = properties;

        this.identifiersMap = new HashMap<String, IdentifierType>();

        jobManager = Job.getJobManager();
        lock = jobManager.newLock();
    }

    /* (non-Javadoc)
     * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object)
     */
    @Override
    public void setInitializationData(IConfigurationElement config, String propertyName, Object data)
            throws CoreException {
        this.schema = config.getAttribute("scheme");
        this.name = config.getAttribute("name");

        IStringVariableManager variableManager = VariablesPlugin.getDefault().getStringVariableManager();

        String[] propertyNames = new String[] { "file.encoding", "file.separator", "java.home", "user.dir",
                "user.home", "user.language", "user.name", "user.timezone", };

        List<IValueVariable> variables = new ArrayList<IValueVariable>();
        if (variableManager.getValueVariable("workspace_loc") == null) {
            variables.add(variableManager.newValueVariable("workspace_loc",
                    "Returns the absolute file system path of the workspace root.", true,
                    Platform.getLocation().toOSString()));
        }
        for (String k : propertyNames) {
            if (variableManager.getValueVariable(k) == null) {
                variables.add(variableManager.newValueVariable(k, "", true, System.getProperty(k)));
            }
        }
        variableManager.addVariables(variables.toArray(new IValueVariable[variables.size()]));

        for (IConfigurationElement element : config.getChildren()) {
            String key = element.getAttribute("name");
            String value = element.getAttribute("value");
            this.properties.put(key, variableManager.performStringSubstitution(value));
        }

        try {
            startUp(null);
            Activator.getDefault().getRepositories().add(this);
        } catch (Exception e) {
            String message = NLS.bind("Error loading repository '{1}' ({0})", new Object[] { schema, name });
            Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, message, e);
            Activator.log(status);
        }
    }

    /* (non-Javadoc)
     * @see org.eclipsetrader.core.repositories.IRepository#getSchema()
     */
    @Override
    public String getSchema() {
        return schema;
    }

    @SuppressWarnings("serial")
    protected AnnotationConfiguration buildConfiguration() {
        AnnotationConfiguration cfg = new AnnotationConfiguration();
        cfg.setProperties(properties);

        cfg.addAnnotatedClass(IdentifierPropertyType.class);
        cfg.addAnnotatedClass(IdentifierType.class);
        cfg.addAnnotatedClass(WatchListColumn.class);
        cfg.addAnnotatedClass(WatchListHolding.class);
        cfg.addAnnotatedClass(HistoryData.class);
        cfg.addAnnotatedClass(DividendType.class);
        cfg.addAnnotatedClass(SplitData.class);
        cfg.addAnnotatedClass(SecurityUnknownPropertyType.class);

        cfg.addAnnotatedClass(SecurityStore.class);
        cfg.addAnnotatedClass(WatchListStore.class);
        cfg.addAnnotatedClass(HistoryStore.class);
        cfg.addAnnotatedClass(IntradayHistoryStore.class);
        cfg.addAnnotatedClass(TradeStore.class);
        cfg.addAnnotatedClass(ScriptStore.class);
        cfg.addAnnotatedClass(StrategyScriptStore.class);
        cfg.addAnnotatedClass(StrategyScriptProperties.class);

        cfg.getEventListeners()
                .setPostInsertEventListeners(new PostInsertEventListener[] { new PostInsertEventListener() {

                    @Override
                    public void onPostInsert(PostInsertEvent event) {
                        if (event.getEntity() instanceof IdentifierType) {
                            identifiersMap.put(((IdentifierType) event.getEntity()).getSymbol(),
                                    (IdentifierType) event.getEntity());
                        }
                        if (event.getEntity() instanceof SecurityStore) {
                            uriMap.put(((SecurityStore) event.getEntity()).toURI(),
                                    (SecurityStore) event.getEntity());
                        }
                        if (event.getEntity() instanceof WatchListStore) {
                            uriMap.put(((WatchListStore) event.getEntity()).toURI(),
                                    (WatchListStore) event.getEntity());
                        }
                        if (event.getEntity() instanceof ScriptStore) {
                            uriMap.put(((ScriptStore) event.getEntity()).toURI(), (ScriptStore) event.getEntity());
                        }
                        if (event.getEntity() instanceof StrategyScriptStore) {
                            uriMap.put(((StrategyScriptStore) event.getEntity()).toURI(),
                                    (StrategyScriptStore) event.getEntity());
                        }
                    }
                }, });
        cfg.getEventListeners()
                .setPostDeleteEventListeners(new PostDeleteEventListener[] { new PostDeleteEventListener() {

                    @Override
                    public void onPostDelete(PostDeleteEvent event) {
                        if (event.getEntity() instanceof IdentifierType) {
                            identifiersMap.remove(((IdentifierType) event.getEntity()).getSymbol());
                        }
                        if (event.getEntity() instanceof SecurityStore) {
                            uriMap.remove(((SecurityStore) event.getEntity()).toURI());
                        }
                        if (event.getEntity() instanceof WatchListStore) {
                            uriMap.remove(((WatchListStore) event.getEntity()).toURI());
                        }
                        if (event.getEntity() instanceof ScriptStore) {
                            uriMap.remove(((ScriptStore) event.getEntity()).toURI());
                        }
                        if (event.getEntity() instanceof StrategyScriptStore) {
                            uriMap.remove(((StrategyScriptStore) event.getEntity()).toURI());
                        }
                    }
                }, });

        return cfg;
    }

    public void startUp(IProgressMonitor monitor) {
        properties.put("hibernate.query.factory_class", "org.hibernate.hql.classic.ClassicQueryTranslatorFactory");
        properties.put("hibernate.connection.pool_size", "5");
        properties.put("hibernate.jdbc.batch_size", "20");
        properties.put("hibernate.show_sql", "false");

        // Build suitable defaults for file-based databases (Apache Derby and HSQL)
        if (!properties.containsKey("hibernate.connection.url") && Activator.getDefault() != null) {
            if ("org.apache.derby.jdbc.EmbeddedDriver"
                    .equals(properties.get("hibernate.connection.driver_class"))) {
                properties.put("hibernate.connection.url", "jdbc:derby:"
                        + Activator.getDefault().getStateLocation().toOSString() + "/.derby;create=true");
            }
            if ("org.hsqldb.jdbcDriver".equals(properties.get("hibernate.connection.driver_class"))) {
                properties.put("hibernate.connection.url",
                        "jdbc:hsqldb:file:" + Activator.getDefault().getStateLocation().toOSString() + "/.hsqldb");
            }
        }

        AnnotationConfiguration cfg = buildConfiguration();
        try {
            initializeDatabase(cfg);
        } catch (Exception e) {
            String message = NLS.bind("Error initializing repository '{1}' ({0})", new Object[] { schema, name });
            Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, message, e);
            Activator.log(status);

            int userChoice = new RepositoryValidator(name, cfg).validate();

            switch (userChoice) {
            case RepositoryValidator.UPDATE_ID:
                SchemaUpdate schemaUpdate = new SchemaUpdate(cfg);
                schemaUpdate.execute(true, true);
                if (schemaUpdate.getExceptions().size() != 0) {
                    MultiStatus multiStatus = new MultiStatus(Activator.PLUGIN_ID, 0, new IStatus[0], ERROR_MESSAGE,
                            null);
                    for (Object o : schemaUpdate.getExceptions()) {
                        multiStatus.add(new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, null, (Exception) o));
                    }
                    Activator.log(multiStatus);
                }
                break;
            case RepositoryValidator.CREATE_ID:
                SchemaExport schemaExport = new SchemaExport(cfg);
                schemaExport.create(true, true);
                if (schemaExport.getExceptions().size() != 0) {
                    MultiStatus multiStatus = new MultiStatus(Activator.PLUGIN_ID, 0, new IStatus[0], ERROR_MESSAGE,
                            null);
                    for (Object o : schemaExport.getExceptions()) {
                        multiStatus.add(new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, null, (Exception) o));
                    }
                    Activator.log(multiStatus);
                }
                break;
            }
        }
        initializeDatabase(cfg);
    }

    @SuppressWarnings("unchecked")
    void initializeDatabase(AnnotationConfiguration cfg) {
        SessionFactory sessionFactory = cfg.buildSessionFactory();
        session = sessionFactory.openSession();

        List<IdentifierType> identifiers = session.createCriteria(IdentifierType.class).list();
        for (IdentifierType identifierType : identifiers) {
            identifiersMap.put(identifierType.getSymbol(), identifierType);
        }

        List<SecurityStore> securities = session.createCriteria(SecurityStore.class).list();
        for (SecurityStore store : securities) {
            store.setRepository(this);
            uriMap.put(store.toURI(), store);
        }

        List<ScriptStore> scripts = session.createCriteria(ScriptStore.class).list();
        for (ScriptStore store : scripts) {
            store.setRepository(this);
            uriMap.put(store.toURI(), store);
        }

        List<StrategyScriptStore> strategies = session.createCriteria(StrategyScriptStore.class).list();
        for (StrategyScriptStore store : strategies) {
            store.setRepository(this);
            uriMap.put(store.toURI(), store);
        }
    }

    public void shutDown(IProgressMonitor monitor) {
        try {
            if (session != null) {
                session.close();
            }
        } catch (Exception e) {
            String message = NLS.bind("Error shutting down repository {0}:{1}", new Object[] { schema, name });
            Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, message, e);
            Activator.log(status);
        }
    }

    @SuppressWarnings("unchecked")
    protected synchronized void initializeWatchListsCollections() {
        if (watchlists == null) {
            try {
                watchlists = session.createCriteria(WatchListStore.class).list();
                for (WatchListStore store : watchlists) {
                    store.setRepository(this);
                    uriMap.put(store.toURI(), store);
                }
            } catch (Exception e) {
                String message = NLS.bind("Error loading repository {0}:{1}", new Object[] { schema, name });
                Status status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, message, e);
                Activator.log(status);
            }
        }
        if (watchlists == null) {
            watchlists = new ArrayList<WatchListStore>();
        }
    }

    public Session getSession() {
        return session;
    }

    public IdentifierType getIdentifierTypeFromFeedIdentifier(IFeedIdentifier feedIdentifier) {
        IdentifierType type = identifiersMap.get(feedIdentifier.getSymbol());
        if (type == null) {
            type = new IdentifierType(feedIdentifier);
            identifiersMap.put(type.getSymbol(), type);
        }
        return type;
    }

    /* (non-Javadoc)
     * @see org.eclipsetrader.core.repositories.IRepository#canDelete()
     */
    @Override
    public boolean canDelete() {
        return true;
    }

    /* (non-Javadoc)
     * @see org.eclipsetrader.core.repositories.IRepository#canWrite()
     */
    @Override
    public boolean canWrite() {
        return true;
    }

    /* (non-Javadoc)
     * @see org.eclipsetrader.core.repositories.IRepository#createObject()
     */
    @Override
    public IStore createObject() {
        return new RepositoryStore(this);
    }

    /* (non-Javadoc)
     * @see org.eclipsetrader.core.repositories.IRepository#fetchObjects(org.eclipse.core.runtime.IProgressMonitor)
     */
    @Override
    public IStore[] fetchObjects(IProgressMonitor monitor) {
        if (watchlists == null) {
            initializeWatchListsCollections();
        }

        List<IStore> list = new ArrayList<IStore>();
        list.addAll(uriMap.values());
        return list.toArray(new IStore[list.size()]);
    }

    /* (non-Javadoc)
     * @see org.eclipsetrader.core.repositories.IRepository#getObject(java.net.URI)
     */
    @Override
    public IStore getObject(URI uri) {
        if (URI_WATCHLIST_PART.equals(uri.getSchemeSpecificPart())) {
            if (watchlists == null) {
                initializeWatchListsCollections();
            }
        }
        return uriMap.get(uri);
    }

    /* (non-Javadoc)
     * @see org.eclipsetrader.core.repositories.IRepository#runInRepository(org.eclipsetrader.core.repositories.IRepositoryRunnable, org.eclipse.core.runtime.IProgressMonitor)
     */
    @Override
    public IStatus runInRepository(IRepositoryRunnable runnable, IProgressMonitor monitor) {
        return runInRepository(runnable, this, monitor);
    }

    /* (non-Javadoc)
     * @see org.eclipsetrader.core.repositories.IRepository#runInRepository(org.eclipsetrader.core.repositories.IRepositoryRunnable, org.eclipse.core.runtime.jobs.ISchedulingRule, org.eclipse.core.runtime.IProgressMonitor)
     */
    @Override
    public IStatus runInRepository(IRepositoryRunnable runnable, ISchedulingRule rule, IProgressMonitor monitor) {
        IStatus status;

        jobManager.beginRule(rule, monitor);
        Transaction currentTransaction = null;

        try {
            lock.acquire();
            currentTransaction = session.beginTransaction();
            try {
                status = runnable.run(monitor);

                session.flush();

                currentTransaction.commit();
                currentTransaction = null;
            } catch (Exception e) {
                status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, "Error running repository task", e); //$NON-NLS-1$
                Activator.log(status);
            } catch (LinkageError e) {
                status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, "Error running repository task", e); //$NON-NLS-1$
                Activator.log(status);
            }
        } catch (Exception e) {
            status = new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, "Error running repository task", e); //$NON-NLS-1$
            Activator.log(status);
            try {
                currentTransaction.rollback();
            } catch (Exception e1) {
                Status status1 = new Status(IStatus.ERROR, Activator.PLUGIN_ID, 0, "Error rolling back transaction", //$NON-NLS-1$
                        e1);
                Activator.log(status1);
            }
        } finally {
            lock.release();
            jobManager.endRule(rule);
        }

        session.clear();

        return status;
    }

    /* (non-Javadoc)
     * @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(org.eclipse.core.runtime.jobs.ISchedulingRule)
     */
    @Override
    public boolean contains(ISchedulingRule rule) {
        if (this == rule) {
            return true;
        }
        if (rule instanceof MultiRule) {
            MultiRule multi = (MultiRule) rule;
            ISchedulingRule[] children = multi.getChildren();
            for (int i = 0; i < children.length; i++) {
                if (!contains(children[i])) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.core.runtime.jobs.ISchedulingRule#isConflicting(org.eclipse.core.runtime.jobs.ISchedulingRule)
     */
    @Override
    public boolean isConflicting(ISchedulingRule rule) {
        if (this == rule) {
            return true;
        }
        return false;
    }

    /* (non-Javadoc)
     * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
     */
    @Override
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public Object getAdapter(Class adapter) {
        if (repositoryDefinition != null && adapter.isAssignableFrom(repositoryDefinition.getClass())) {
            return repositoryDefinition;
        }

        if (adapter.isAssignableFrom(getClass())) {
            return this;
        }

        return null;
    }

    public RepositoryDefinition getRepositoryDefinition() {
        return repositoryDefinition;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return name;
    }
}