org.objectstyle.cayenne.modeler.Application.java Source code

Java tutorial

Introduction

Here is the source code for org.objectstyle.cayenne.modeler.Application.java

Source

/* ====================================================================
 * 
 * The ObjectStyle Group Software License, version 1.1
 * ObjectStyle Group - http://objectstyle.org/
 * 
 * Copyright (c) 2002-2004, Andrei (Andrus) Adamchik and individual authors
 * of the software. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 
 * 3. The end-user documentation included with the redistribution, if any,
 *    must include the following acknowlegement:
 *    "This product includes software developed by independent contributors
 *    and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 * 
 * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
 *    or promote products derived from this software without prior written
 *    permission. For written permission, email
 *    "andrus at objectstyle dot org".
 * 
 * 5. Products derived from this software may not be called "ObjectStyle"
 *    or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
 *    names without prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 * 
 * This software consists of voluntary contributions made by many
 * individuals and hosted on ObjectStyle Group web site.  For more
 * information on the ObjectStyle Group, please see
 * <http://objectstyle.org/>.
 */
package org.objectstyle.cayenne.modeler;

import java.awt.Dialog;
import java.awt.Frame;
import java.awt.Window;
import java.io.File;
import java.util.Collection;

import javax.swing.ActionMap;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JRootPane;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Transformer;
import org.objectstyle.cayenne.modeler.action.AboutAction;
import org.objectstyle.cayenne.modeler.action.ConfigurePreferencesAction;
import org.objectstyle.cayenne.modeler.action.CreateAttributeAction;
import org.objectstyle.cayenne.modeler.action.CreateDataMapAction;
import org.objectstyle.cayenne.modeler.action.CreateDbEntityAction;
import org.objectstyle.cayenne.modeler.action.CreateDerivedDbEntityAction;
import org.objectstyle.cayenne.modeler.action.CreateDomainAction;
import org.objectstyle.cayenne.modeler.action.CreateNodeAction;
import org.objectstyle.cayenne.modeler.action.CreateObjEntityAction;
import org.objectstyle.cayenne.modeler.action.CreateProcedureAction;
import org.objectstyle.cayenne.modeler.action.CreateQueryAction;
import org.objectstyle.cayenne.modeler.action.CreateRelationshipAction;
import org.objectstyle.cayenne.modeler.action.DerivedEntitySyncAction;
import org.objectstyle.cayenne.modeler.action.ExitAction;
import org.objectstyle.cayenne.modeler.action.GenerateClassesAction;
import org.objectstyle.cayenne.modeler.action.GenerateDBAction;
import org.objectstyle.cayenne.modeler.action.ImportDataMapAction;
import org.objectstyle.cayenne.modeler.action.ImportDBAction;
import org.objectstyle.cayenne.modeler.action.ImportEOModelAction;
import org.objectstyle.cayenne.modeler.action.NewProjectAction;
import org.objectstyle.cayenne.modeler.action.ObjEntitySyncAction;
import org.objectstyle.cayenne.modeler.action.OpenProjectAction;
import org.objectstyle.cayenne.modeler.action.ProjectAction;
import org.objectstyle.cayenne.modeler.action.RemoveAction;
import org.objectstyle.cayenne.modeler.action.RevertAction;
import org.objectstyle.cayenne.modeler.action.SaveAction;
import org.objectstyle.cayenne.modeler.action.SaveAsAction;
import org.objectstyle.cayenne.modeler.action.ValidateAction;
import org.objectstyle.cayenne.modeler.util.CayenneAction;
import org.objectstyle.cayenne.modeler.util.CayenneDialog;
import org.objectstyle.cayenne.pref.Domain;
import org.objectstyle.cayenne.pref.DomainPreference;
import org.objectstyle.cayenne.pref.HSQLEmbeddedPreferenceEditor;
import org.objectstyle.cayenne.pref.HSQLEmbeddedPreferenceService;
import org.objectstyle.cayenne.pref.PreferenceService;
import org.objectstyle.cayenne.project.CayenneUserDir;
import org.objectstyle.cayenne.project.Project;
import org.objectstyle.cayenne.swing.BindingFactory;
import org.scopemvc.controller.basic.ViewContext;
import org.scopemvc.controller.swing.SwingContext;
import org.scopemvc.core.View;
import org.scopemvc.util.UIStrings;
import org.scopemvc.view.swing.SwingView;

/**
 * A main modeler application class that provides a number of services to the Modeler
 * components. Configuration properties:
 * <ul>
 * <li>cayenne.modeler.application.name - name of the application, 'CayenneModeler' is
 * default. Used to locate prerferences domain among other things.</li>
 * <li>cayenne.modeler.pref.version - a version of the preferences DB schema. Default is
 * "1.1".</li>
 * </ul>
 * 
 * @author Andrei Adamchik
 */
public class Application {

    public static final String PREFERENCES_VERSION = "1.1";
    public static final String APPLICATION_NAME_PROPERTY = "cayenne.modeler.application.name";
    public static final String PREFERENCES_VERSION_PROPERTY = "cayenne.modeler.pref.version";

    public static final String DEFAULT_APPLICATION_NAME = "CayenneModeler";

    // TODO: implement cleaner IoC approach to avoid using this singleton...
    protected static Application instance;

    protected FileClassLoadingService modelerClassLoader;
    protected HSQLEmbeddedPreferenceService preferenceService;
    protected CayenneModelerController frameController;
    protected ActionMap actionMap;
    protected File initialProject;
    protected String name;
    protected String preferencesDB;
    protected BindingFactory bindingFactory;
    protected AdapterMapping adapterMapping;

    public static Application getInstance() {
        return instance;
    }

    // static methods that should probabaly go away eventually...

    public static CayenneModelerFrame getFrame() {
        return (CayenneModelerFrame) getInstance().getFrameController().getView();
    }

    public static Project getProject() {
        return getInstance().getFrameController().getProjectController().getProject();
    }

    public Application(File initialProject) {
        this.initialProject = initialProject;

        // configure startup settings
        String configuredName = System.getProperty(APPLICATION_NAME_PROPERTY);
        this.name = (configuredName != null) ? configuredName : DEFAULT_APPLICATION_NAME;

        String subdir = System.getProperty(PREFERENCES_VERSION_PROPERTY);

        if (subdir == null) {
            subdir = PREFERENCES_VERSION;
        }

        File dbDir = new File(CayenneUserDir.getInstance().resolveFile("prefs"), subdir);
        dbDir.mkdirs();
        this.preferencesDB = new File(dbDir, "db").getAbsolutePath();

    }

    public String getName() {
        return name;
    }

    public ClassLoadingService getClassLoadingService() {
        return modelerClassLoader;
    }

    public AdapterMapping getAdapterMapping() {
        return adapterMapping;
    }

    /**
     * Returns an action for key.
     */
    public CayenneAction getAction(String key) {
        return (CayenneAction) actionMap.get(key);
    }

    /**
     * Returns Application ActionMap.
     */
    public ActionMap getActionMap() {
        return actionMap;
    }

    /**
     * Returns controller for the main frame.
     */
    public CayenneModelerController getFrameController() {
        return frameController;
    }

    /**
     * Starts the application.
     */
    public void startup() {
        // init subsystems
        initPreferences();
        initClassLoader();
        initActions();
        this.bindingFactory = new BindingFactory();
        this.adapterMapping = new AdapterMapping();

        // ...Scope

        // TODO: this will go away if switch away from Scope
        // force Scope to use CayenneModeler properties
        UIStrings.setPropertiesName(ModelerConstants.DEFAULT_MESSAGE_BUNDLE);
        ViewContext.clearThreadContext();

        // ...create main frame
        this.frameController = new CayenneModelerController(this, initialProject);

        // update Scope to work nicely with main frame
        ViewContext.setGlobalContext(new ModelerContext(frameController.getFrame()));

        // open up
        frameController.startupAction();
    }

    public BindingFactory getBindingFactory() {
        return bindingFactory;
    }

    /**
     * Returns Application preferences service.
     */
    public PreferenceService getPreferenceService() {
        return preferenceService;
    }

    /**
     * Returns top preferences Domain for the application.
     */
    public Domain getPreferenceDomain() {
        return getPreferenceService().getDomain(getName(), true);
    }

    /**
     * Reinitializes ModelerClassLoader from preferences.
     */
    public void initClassLoader() {
        FileClassLoadingService classLoader = new FileClassLoadingService();

        // init from preferences...
        Domain classLoaderDomain = getPreferenceDomain().getSubdomain(FileClassLoadingService.class);

        Collection details = classLoaderDomain.getPreferences();
        if (details.size() > 0) {

            // transform preference to file...
            Transformer transformer = new Transformer() {

                public Object transform(Object object) {
                    DomainPreference pref = (DomainPreference) object;
                    return new File(pref.getKey());
                }
            };

            classLoader.setPathFiles(CollectionUtils.collect(details, transformer));
        }

        this.modelerClassLoader = classLoader;
    }

    protected void initPreferences() {
        HSQLEmbeddedPreferenceService service = new HSQLEmbeddedPreferenceService(preferencesDB, "pref", getName());
        service.stopOnShutdown();
        this.preferenceService = service;
        this.preferenceService.startService();

        // test service
        getPreferenceDomain();
    }

    protected void initActions() {
        // build action map
        actionMap = new ActionMap();

        registerAction(new ProjectAction(this));
        registerAction(new NewProjectAction(this)).setAlwaysOn(true);
        registerAction(new OpenProjectAction(this)).setAlwaysOn(true);
        registerAction(new ImportDataMapAction(this));
        registerAction(new SaveAction(this));
        registerAction(new SaveAsAction(this));
        registerAction(new RevertAction(this));
        registerAction(new ValidateAction(this));
        registerAction(new RemoveAction(this));
        registerAction(new CreateDomainAction(this));
        registerAction(new CreateNodeAction(this));
        registerAction(new CreateDataMapAction(this));
        registerAction(new GenerateClassesAction(this));
        registerAction(new CreateObjEntityAction(this));
        registerAction(new CreateDbEntityAction(this));
        registerAction(new CreateDerivedDbEntityAction(this));
        registerAction(new CreateProcedureAction(this));
        registerAction(new CreateQueryAction(this));
        registerAction(new CreateAttributeAction(this));
        registerAction(new CreateRelationshipAction(this));
        registerAction(new ObjEntitySyncAction(this));
        registerAction(new DerivedEntitySyncAction(this));
        registerAction(new ImportDBAction(this));
        registerAction(new ImportEOModelAction(this));
        registerAction(new GenerateDBAction(this));
        registerAction(new AboutAction(this)).setAlwaysOn(true);
        registerAction(new ConfigurePreferencesAction(this)).setAlwaysOn(true);
        registerAction(new ExitAction(this)).setAlwaysOn(true);
    }

    private CayenneAction registerAction(CayenneAction action) {
        actionMap.put(action.getKey(), action);
        return action;
    }

    static final class PreferencesDelegate implements HSQLEmbeddedPreferenceEditor.Delegate {

        static final String message = "Preferences Database is locked by another application. "
                + "Do you want to remove the lock?";
        static final String failureMessage = "Failed to remove database lock. "
                + "Preferences will we saved for this session only.";

        static final HSQLEmbeddedPreferenceEditor.Delegate sharedInstance = new PreferencesDelegate();

        public boolean deleteMasterLock(File lock) {
            int result = JOptionPane.showConfirmDialog(null, message);
            if (result == JOptionPane.YES_OPTION || result == JOptionPane.OK_OPTION) {
                if (!lock.delete()) {
                    JOptionPane.showMessageDialog(null, failureMessage);
                    return false;
                }
            }

            return true;
        }
    }

    final class ModelerContext extends SwingContext {

        JFrame frame;

        public ModelerContext(JFrame frame) {
            this.frame = frame;
        }

        protected void showViewInPrimaryWindow(SwingView view) {
        }

        /**
         * Creates closeable dialogs.
         */
        protected void showViewInDialog(SwingView inView) {
            // NOTE:
            // copied from superclass, except that JDialog is substituted for
            // CayenneDialog
            // Keep in mind when upgrading Scope to the newer versions.

            // Make a JDialog to contain the view.
            Window parentWindow = getDefaultParentWindow();

            final CayenneDialog dialog;
            if (parentWindow instanceof Dialog) {
                dialog = new CayenneDialog((Dialog) parentWindow);
            } else {
                dialog = new CayenneDialog((Frame) parentWindow);
            }

            // Set title, modality, resizability
            if (inView.getTitle() != null) {
                dialog.setTitle(inView.getTitle());
            }
            if (inView.getDisplayMode() == SwingView.MODAL_DIALOG) {
                dialog.setModal(true);
            } else {
                dialog.setModal(false);
            }
            dialog.setResizable(inView.isResizable());

            setupWindow(dialog.getRootPane(), inView, true);
            dialog.toFront();
        }

        /**
         * Overrides super implementation to allow using Scope together with normal Swing
         * code that CayenneModeler already has.
         */
        public JRootPane findRootPaneFor(View view) {
            JRootPane pane = super.findRootPaneFor(view);

            if (pane != null) {
                return pane;
            }

            if (((SwingView) view).getDisplayMode() != SwingView.PRIMARY_WINDOW) {
                return pane;
            }

            return frame.getRootPane();
        }

        protected Window getDefaultParentWindow() {
            return frame;
        }
    }
}