org.apache.cayenne.modeler.action.ImportEOModelAction.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.cayenne.modeler.action.ImportEOModelAction.java

Source

/*****************************************************************
 *   Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 ****************************************************************/

package org.apache.cayenne.modeler.action;

import org.apache.cayenne.configuration.ConfigurationNode;
import org.apache.cayenne.configuration.DataChannelDescriptor;
import org.apache.cayenne.configuration.DataNodeDescriptor;
import org.apache.cayenne.configuration.event.DataNodeEvent;
import org.apache.cayenne.configuration.event.QueryEvent;
import org.apache.cayenne.configuration.server.JNDIDataSourceFactory;
import org.apache.cayenne.configuration.server.XMLPoolingDataSourceFactory;
import org.apache.cayenne.conn.DataSourceInfo;
import org.apache.cayenne.dba.DbAdapter;
import org.apache.cayenne.dbsync.naming.NameBuilder;
import org.apache.cayenne.map.DataMap;
import org.apache.cayenne.map.Entity;
import org.apache.cayenne.map.QueryDescriptor;
import org.apache.cayenne.map.event.EntityEvent;
import org.apache.cayenne.map.event.MapEvent;
import org.apache.cayenne.modeler.Application;
import org.apache.cayenne.modeler.ProjectController;
import org.apache.cayenne.modeler.dialog.ErrorDebugDialog;
import org.apache.cayenne.modeler.event.DataMapDisplayEvent;
import org.apache.cayenne.modeler.event.DataNodeDisplayEvent;
import org.apache.cayenne.modeler.pref.FSPath;
import org.apache.cayenne.modeler.util.AdapterMapping;
import org.apache.cayenne.modeler.util.CayenneAction;
import org.apache.cayenne.modeler.util.FileFilters;
import org.apache.cayenne.wocompat.EOModelProcessor;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

/**
 * Action handler for WebObjects EOModel import function.
 * 
 */
public class ImportEOModelAction extends CayenneAction {

    private static Logger logObj = LoggerFactory.getLogger(ImportEOModelAction.class);

    public static String getActionName() {
        return "Import EOModel";
    }

    protected JFileChooser eoModelChooser;

    public ImportEOModelAction(Application application) {
        super(getActionName(), application);
    }

    public String getIconName() {
        return "icon-eomodel.gif";
    }

    public void performAction(ActionEvent event) {
        importEOModel();
    }

    /**
     * Allows user to select an EOModel, then imports it as a DataMap.
     */
    protected void importEOModel() {
        JFileChooser fileChooser = getEOModelChooser();
        int status = fileChooser.showOpenDialog(Application.getFrame());

        if (status == JFileChooser.APPROVE_OPTION) {

            // save preferences
            FSPath lastDir = getApplication().getFrameController().getLastEOModelDirectory();
            lastDir.updateFromChooser(fileChooser);

            File file = fileChooser.getSelectedFile();
            if (file.isFile()) {
                file = file.getParentFile();
            }

            DataMap currentMap = getProjectController().getCurrentDataMap();

            try {
                URL url = file.toURI().toURL();

                EOModelProcessor processor = new EOModelProcessor();

                // load DataNode if we are not merging with an existing map
                if (currentMap == null) {
                    loadDataNode(processor.loadModeIndex(url));
                }

                // load DataMap
                DataMap map = processor.loadEOModel(url);
                addDataMap(map, currentMap);

            } catch (Exception ex) {
                logObj.info("EOModel Loading Exception", ex);
                ErrorDebugDialog.guiException(ex);
            }

        }
    }

    protected void loadDataNode(Map eomodelIndex) {
        // if this is JDBC or JNDI node and connection dictionary is specified, load a
        // DataNode, otherwise ignore it (meaning that pre 5.* EOModels will not have a
        // node).

        String adapter = (String) eomodelIndex.get("adaptorName");
        Map connection = (Map) eomodelIndex.get("connectionDictionary");

        if (adapter != null && connection != null) {
            CreateNodeAction nodeBuilder = (CreateNodeAction) getApplication().getActionManager()
                    .getAction(CreateNodeAction.class);

            // this should make created node current, resulting in the new map being added
            // to the node automatically once it is loaded
            DataNodeDescriptor node = nodeBuilder.buildDataNode();

            // configure node...
            if ("JNDI".equalsIgnoreCase(adapter)) {
                node.setDataSourceFactoryType(JNDIDataSourceFactory.class.getName());
                node.setParameters((String) connection.get("serverUrl"));
            } else {
                // guess adapter from plugin or driver
                AdapterMapping adapterDefaults = getApplication().getAdapterMapping();
                String cayenneAdapter = adapterDefaults.adapterForEOFPluginOrDriver(
                        (String) connection.get("plugin"), (String) connection.get("driver"));
                if (cayenneAdapter != null) {
                    try {
                        Class<DbAdapter> adapterClass = getApplication().getClassLoadingService()
                                .loadClass(DbAdapter.class, cayenneAdapter);
                        node.setAdapterType(adapterClass.toString());
                    } catch (Throwable ex) {
                        // ignore...
                    }
                }

                node.setDataSourceFactoryType(XMLPoolingDataSourceFactory.class.getName());

                DataSourceInfo dsi = node.getDataSourceDescriptor();

                dsi.setDataSourceUrl(keyAsString(connection, "URL"));
                dsi.setJdbcDriver(keyAsString(connection, "driver"));
                dsi.setPassword(keyAsString(connection, "password"));
                dsi.setUserName(keyAsString(connection, "username"));
            }

            DataChannelDescriptor domain = (DataChannelDescriptor) getProjectController().getProject()
                    .getRootNode();
            domain.getNodeDescriptors().add(node);

            // send events after the node creation is complete
            getProjectController().fireDataNodeEvent(new DataNodeEvent(this, node, MapEvent.ADD));
            getProjectController().fireDataNodeDisplayEvent(new DataNodeDisplayEvent(this,
                    (DataChannelDescriptor) getProjectController().getProject().getRootNode(), node));
        }
    }

    // CAY-246 - if user name or password is all numeric, it will
    // be returned as number, so we can't cast dictionary keys to String
    private String keyAsString(Map map, String key) {
        Object value = map.get(key);
        return (value != null) ? value.toString() : null;
    }

    /**
     * Adds DataMap into the project.
     */
    protected void addDataMap(DataMap map, DataMap currentMap) {

        ProjectController mediator = getProjectController();

        if (currentMap != null) {
            // merge with existing map... have to memorize map state before and after
            // to do the right events

            Collection originalOE = new ArrayList(currentMap.getObjEntities());
            Collection originalDE = new ArrayList(currentMap.getDbEntities());
            Collection originalQueries = new ArrayList(currentMap.getQueryDescriptors());

            currentMap.mergeWithDataMap(map);
            map = currentMap;

            // postprocess changes
            Collection newOE = new ArrayList(currentMap.getObjEntities());
            Collection newDE = new ArrayList(currentMap.getDbEntities());
            Collection newQueries = new ArrayList(currentMap.getQueryDescriptors());

            EntityEvent entityEvent = new EntityEvent(Application.getFrame(), null);
            QueryEvent queryEvent = new QueryEvent(Application.getFrame(), null);

            Collection addedOE = CollectionUtils.subtract(newOE, originalOE);
            Iterator it = addedOE.iterator();
            while (it.hasNext()) {
                Entity e = (Entity) it.next();
                entityEvent.setEntity(e);
                entityEvent.setId(MapEvent.ADD);
                mediator.fireObjEntityEvent(entityEvent);
            }

            Collection removedOE = CollectionUtils.subtract(originalOE, newOE);
            it = removedOE.iterator();
            while (it.hasNext()) {
                Entity e = (Entity) it.next();
                entityEvent.setEntity(e);
                entityEvent.setId(MapEvent.REMOVE);
                mediator.fireObjEntityEvent(entityEvent);
            }

            Collection addedDE = CollectionUtils.subtract(newDE, originalDE);
            it = addedDE.iterator();
            while (it.hasNext()) {
                Entity e = (Entity) it.next();
                entityEvent.setEntity(e);
                entityEvent.setId(MapEvent.ADD);
                mediator.fireDbEntityEvent(entityEvent);
            }

            Collection removedDE = CollectionUtils.subtract(originalDE, newDE);
            it = removedDE.iterator();
            while (it.hasNext()) {
                Entity e = (Entity) it.next();
                entityEvent.setEntity(e);
                entityEvent.setId(MapEvent.REMOVE);
                mediator.fireDbEntityEvent(entityEvent);
            }

            // queries
            Collection addedQueries = CollectionUtils.subtract(newQueries, originalQueries);
            it = addedQueries.iterator();
            while (it.hasNext()) {
                QueryDescriptor q = (QueryDescriptor) it.next();
                queryEvent.setQuery(q);
                queryEvent.setId(MapEvent.ADD);
                mediator.fireQueryEvent(queryEvent);
            }

            Collection removedQueries = CollectionUtils.subtract(originalQueries, newQueries);
            it = removedQueries.iterator();
            while (it.hasNext()) {
                QueryDescriptor q = (QueryDescriptor) it.next();
                queryEvent.setQuery(q);
                queryEvent.setId(MapEvent.REMOVE);
                mediator.fireQueryEvent(queryEvent);
            }

            mediator.fireDataMapDisplayEvent(new DataMapDisplayEvent(Application.getFrame(), map,
                    (DataChannelDescriptor) mediator.getProject().getRootNode(), mediator.getCurrentDataNode()));
        } else {
            // fix DataMap name, as there maybe a map with the same name already
            ConfigurationNode root = (DataChannelDescriptor) mediator.getProject().getRootNode();
            map.setName(NameBuilder.builder(map, root).baseName(map.getName()).name());

            // side effect of this operation is that if a node was created, this DataMap
            // will be linked with it...
            mediator.addDataMap(Application.getFrame(), map);
        }
    }

    /**
     * Returns EOModel chooser.
     */
    public JFileChooser getEOModelChooser() {

        if (eoModelChooser == null) {
            eoModelChooser = new EOModelChooser("Select EOModel");
        }

        FSPath lastDir = getApplication().getFrameController().getLastEOModelDirectory();
        lastDir.updateChooser(eoModelChooser);

        return eoModelChooser;
    }

    /**
     * Custom file chooser that will pop up again if a bad directory is selected.
     */
    class EOModelChooser extends JFileChooser {

        protected FileFilter selectFilter;
        protected JDialog cachedDialog;

        public EOModelChooser(String title) {
            super.setFileFilter(FileFilters.getEOModelFilter());
            super.setDialogTitle(title);
            super.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);

            this.selectFilter = FileFilters.getEOModelSelectFilter();
        }

        public int showOpenDialog(Component parent) {
            int status = super.showOpenDialog(parent);
            if (status != JFileChooser.APPROVE_OPTION) {
                cachedDialog = null;
                return status;
            }

            // make sure invalid directory is not selected
            File file = this.getSelectedFile();
            if (selectFilter.accept(file)) {
                cachedDialog = null;
                return JFileChooser.APPROVE_OPTION;
            } else {
                if (file.isDirectory()) {
                    this.setCurrentDirectory(file);
                }

                return this.showOpenDialog(parent);
            }
        }

        protected JDialog createDialog(Component parent) throws HeadlessException {

            if (cachedDialog == null) {
                cachedDialog = super.createDialog(parent);
            }
            return cachedDialog;
        }
    }
}