/***************************************************************** * 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.editor.datanode; import java.awt.Component; import java.awt.event.ComponentAdapter; import java.awt.event.ComponentEvent; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.swing.DefaultComboBoxModel; import org.apache.cayenne.access.dbsync.CreateIfNoSchemaStrategy; import org.apache.cayenne.access.dbsync.SkipSchemaUpdateStrategy; import org.apache.cayenne.access.dbsync.ThrowOnPartialOrCreateSchemaStrategy; import org.apache.cayenne.access.dbsync.ThrowOnPartialSchemaStrategy; import org.apache.cayenne.configuration.DataChannelDescriptor; import org.apache.cayenne.configuration.DataNodeDescriptor; import org.apache.cayenne.configuration.event.DataNodeEvent; import org.apache.cayenne.configuration.server.JNDIDataSourceFactory; import org.apache.cayenne.configuration.server.XMLPoolingDataSourceFactory; import org.apache.cayenne.modeler.ProjectController; import org.apache.cayenne.modeler.dialog.pref.PreferenceDialog; import org.apache.cayenne.modeler.event.DataNodeDisplayEvent; import org.apache.cayenne.modeler.event.DataNodeDisplayListener; import org.apache.cayenne.modeler.pref.DBConnectionInfo; import org.apache.cayenne.modeler.pref.DataNodeDefaults; import org.apache.cayenne.modeler.util.CayenneController; import org.apache.cayenne.modeler.util.ProjectUtil; import org.apache.cayenne.swing.BindingBuilder; import org.apache.cayenne.swing.BindingDelegate; import org.apache.cayenne.swing.ObjectBinding; import org.apache.cayenne.validation.ValidationException; /** * A controller for the main tab of the DataNode editor panel. * */ public class MainDataNodeEditor extends CayenneController { protected static final String NO_LOCAL_DATA_SOURCE = "Select DataSource for Local Work..."; private static final String DBCP_DATA_SOURCE_FACTORY = "org.apache.cayenne.configuration.server.DBCPDataSourceFactory"; final static String[] standardDataSourceFactories = new String[] { XMLPoolingDataSourceFactory.class.getName(), JNDIDataSourceFactory.class.getName(), DBCP_DATA_SOURCE_FACTORY }; final static String[] standardSchemaUpdateStrategy = new String[] { SkipSchemaUpdateStrategy.class.getName(), CreateIfNoSchemaStrategy.class.getName(), ThrowOnPartialSchemaStrategy.class.getName(), ThrowOnPartialOrCreateSchemaStrategy.class.getName() }; protected MainDataNodeView view; protected DataNodeEditor tabbedPaneController; protected DataNodeDescriptor node; protected Map datasourceEditors; protected List localDataSources; protected DataSourceEditor defaultSubeditor; protected BindingDelegate nodeChangeProcessor; protected ObjectBinding[] bindings; protected ObjectBinding localDataSourceBinding; public MainDataNodeEditor(ProjectController parent, DataNodeEditor tabController) { super(parent); this.tabbedPaneController = tabController; this.view = new MainDataNodeView((ProjectController) getParent()); this.datasourceEditors = new HashMap(); this.localDataSources = new ArrayList<String>(); this.nodeChangeProcessor = new BindingDelegate() { public void modelUpdated(ObjectBinding binding, Object oldValue, Object newValue) { DataNodeEvent e = new DataNodeEvent(MainDataNodeEditor.this, node); if (binding != null && binding.getView() == view.getDataNodeName()) { e.setOldName(oldValue != null ? oldValue.toString() : null); } ((ProjectController) getParent()).fireDataNodeEvent(e); } }; this.defaultSubeditor = new CustomDataSourceEditor(parent, nodeChangeProcessor); initController(); } // ======= properties public Component getView() { return view; } public String getFactoryName() { return (node != null) ? node.getDataSourceFactoryType() : null; } public void setFactoryName(String factoryName) { if (node != null) { node.setDataSourceFactoryType(factoryName); showDataSourceSubview(factoryName); } } public String getSchemaUpdateStrategy() { return (node != null) ? node.getSchemaUpdateStrategyType() : null; } public void setSchemaUpdateStrategy(String schemaUpdateStrategy) { if (node != null) { node.setSchemaUpdateStrategyType(schemaUpdateStrategy); } } public String getNodeName() { return (node != null) ? node.getName() : null; } public void setNodeName(String newName) { if (node == null) { return; } // validate... if (newName == null) { throw new ValidationException("Empty DataNode Name"); } ProjectController parent = (ProjectController) getParent(); DataNodeDefaults oldPref = parent.getDataNodePreferences(); DataChannelDescriptor dataChannelDescriptor = (DataChannelDescriptor) getApplication().getProject() .getRootNode(); Collection<DataNodeDescriptor> matchingNode = dataChannelDescriptor.getNodeDescriptors(); Iterator<DataNodeDescriptor> it = matchingNode.iterator(); while (it.hasNext()) { DataNodeDescriptor node = it.next(); if (node.getName().equals(newName)) { // there is an entity with the same name throw new ValidationException("There is another DataNode named '" + newName + "'. Use a different name."); } } // passed validation, set value... // TODO: fixme....there is a slight chance that domain is different than // the one // cached node belongs to ProjectUtil.setDataNodeName((DataChannelDescriptor) parent.getProject().getRootNode(), node, newName); oldPref.copyPreferences(newName); } protected void initController() { view.getDataSourceDetail().add(defaultSubeditor.getView(), "default"); view.getFactories().setEditable(true); // init combo box choices view.getFactories().setModel(new DefaultComboBoxModel(standardDataSourceFactories)); view.getSchemaUpdateStrategy().setEditable(true); view.getSchemaUpdateStrategy().setModel(new DefaultComboBoxModel(standardSchemaUpdateStrategy)); // init listeners ((ProjectController) getParent()).addDataNodeDisplayListener(new DataNodeDisplayListener() { public void currentDataNodeChanged(DataNodeDisplayEvent e) { refreshView(e.getDataNode()); } }); getView().addComponentListener(new ComponentAdapter() { public void componentShown(ComponentEvent e) { refreshView(node != null ? node : ((ProjectController) getParent()).getCurrentDataNode()); } }); BindingBuilder builder = new BindingBuilder(getApplication().getBindingFactory(), this); localDataSourceBinding = builder.bindToComboSelection(view.getLocalDataSources(), "parent.dataNodePreferences.localDataSource", NO_LOCAL_DATA_SOURCE); // use delegate for the rest of them builder.setDelegate(nodeChangeProcessor); bindings = new ObjectBinding[3]; bindings[0] = builder.bindToTextField(view.getDataNodeName(), "nodeName"); bindings[1] = builder.bindToComboSelection(view.getFactories(), "factoryName"); bindings[2] = builder.bindToComboSelection(view.getSchemaUpdateStrategy(), "schemaUpdateStrategy"); // one way bindings builder.bindToAction(view.getConfigLocalDataSources(), "dataSourceConfigAction()"); } public void dataSourceConfigAction() { PreferenceDialog prefs = new PreferenceDialog(this); prefs.showDataSourceEditorAction(view.getLocalDataSources().getSelectedItem()); refreshLocalDataSources(); } protected void refreshLocalDataSources() { localDataSources.clear(); Map sources = getApplication().getCayenneProjectPreferences().getDetailObject(DBConnectionInfo.class) .getChildrenPreferences(); int len = sources.size(); Object[] keys = new Object[len + 1]; // a slight chance that a real datasource is called // NO_LOCAL_DATA_SOURCE... keys[0] = NO_LOCAL_DATA_SOURCE; Object[] dataSources = sources.keySet().toArray(); localDataSources.add(dataSources); for (int i = 0; i < dataSources.length; i++) { keys[i + 1] = dataSources[i]; } view.getLocalDataSources().setModel(new DefaultComboBoxModel(keys)); localDataSourceBinding.updateView(); } /** * Reinitializes widgets to display selected DataNode. */ protected void refreshView(DataNodeDescriptor node) { this.node = node; if (node == null) { getView().setVisible(false); return; } refreshLocalDataSources(); for (ObjectBinding binding : bindings) { binding.updateView(); } showDataSourceSubview(getFactoryName()); } /** * Selects a subview for a currently selected DataSource factory. */ protected void showDataSourceSubview(String factoryName) { DataSourceEditor c = (DataSourceEditor) datasourceEditors.get(factoryName); // create subview dynamically... if (c == null) { if (XMLPoolingDataSourceFactory.class.getName().equals(factoryName)) { c = new JDBCDataSourceEditor((ProjectController) getParent(), nodeChangeProcessor); } else if (JNDIDataSourceFactory.class.getName().equals(factoryName)) { c = new JNDIDataSourceEditor((ProjectController) getParent(), nodeChangeProcessor); } else if (DBCP_DATA_SOURCE_FACTORY.equals(factoryName)) { c = new DBCP2DataSourceEditor((ProjectController) getParent(), nodeChangeProcessor); } else { // special case - no detail view, just show it and bail.. defaultSubeditor.setNode(node); disabledTab("default"); view.getDataSourceDetailLayout().show(view.getDataSourceDetail(), "default"); return; } datasourceEditors.put(factoryName, c); view.getDataSourceDetail().add(c.getView(), factoryName); // this is needed to display freshly added panel... view.getDataSourceDetail().getParent().validate(); } // this will refresh subview... c.setNode(node); disabledTab(factoryName); // display the right subview... view.getDataSourceDetailLayout().show(view.getDataSourceDetail(), factoryName); } protected void disabledTab(String name) { if (name.equals(standardDataSourceFactories[0])) { tabbedPaneController.getTabComponent().setEnabledAt(2, true); } else { tabbedPaneController.getTabComponent().setEnabledAt(2, false); } } }