/*****************************************************************
* 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.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.swing.DefaultComboBoxModel;
import org.apache.cayenne.access.DataDomain;
import org.apache.cayenne.access.DataNode;
import org.apache.cayenne.conf.Configuration;
import org.apache.cayenne.conf.DBCPDataSourceFactory;
import org.apache.cayenne.conf.DriverDataSourceFactory;
import org.apache.cayenne.conf.JNDIDataSourceFactory;
import org.apache.cayenne.map.event.DataNodeEvent;
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.util.CayenneController;
import org.apache.cayenne.modeler.util.ProjectUtil;
import org.apache.cayenne.project.ApplicationProject;
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.
*
* @author Andrus Adamchik
*/
public class MainDataNodeEditor extends CayenneController {
protected static final String NO_LOCAL_DATA_SOURCE = "Select DataSource for Local Work...";
final static String[] standardDataSourceFactories = new String[] {
DriverDataSourceFactory.class.getName(),
JNDIDataSourceFactory.class.getName(), DBCPDataSourceFactory.class.getName()
};
protected MainDataNodeView view;
protected DataNode node;
protected Map datasourceEditors;
protected Map localDataSources;
protected DataSourceEditor defaultSubeditor;
protected BindingDelegate nodeChangeProcessor;
protected ObjectBinding[] bindings;
protected ObjectBinding localDataSourceBinding;
public MainDataNodeEditor(ProjectController parent) {
super(parent);
this.view = new MainDataNodeView();
this.datasourceEditors = new HashMap();
this.localDataSources = new HashMap();
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.getDataSourceFactory() : null;
}
public void setFactoryName(String factoryName) {
if (node != null) {
node.setDataSourceFactory(factoryName);
showDataSourceSubview(factoryName);
}
}
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();
Configuration config = ((ApplicationProject) parent.getProject())
.getConfiguration();
DataNode matchingNode = null;
Iterator it = config.getDomains().iterator();
while (it.hasNext()) {
DataDomain domain = (DataDomain) it.next();
DataNode nextNode = domain.getNode(newName);
if (nextNode == node) {
continue;
}
if (nextNode != null) {
matchingNode = nextNode;
break;
}
}
if (matchingNode != null) {
// 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(parent.getCurrentDataDomain(), node, newName);
}
// ======== other stuff
protected void initController() {
view.getDataSourceDetail().add(defaultSubeditor.getView(), "default");
view.getFactories().setEditable(true);
// init combo box choices
view.getFactories().setModel(
new DefaultComboBoxModel(standardDataSourceFactories));
// 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[2];
bindings[0] = builder.bindToTextField(view.getDataNodeName(), "nodeName");
bindings[1] = builder.bindToComboSelection(view.getFactories(), "factoryName");
// 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();
Collection sources = getApplication().getPreferenceDomain().getDetails(
DBConnectionInfo.class);
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;
Iterator it = sources.iterator();
for (int i = 1; i <= len; i++) {
DBConnectionInfo info = (DBConnectionInfo) it.next();
keys[i] = info.getKey();
localDataSources.put(keys[i], info);
}
view.getLocalDataSources().setModel(new DefaultComboBoxModel(keys));
localDataSourceBinding.updateView();
}
/**
* Reinitializes widgets to display selected DataNode.
*/
protected void refreshView(DataNode node) {
this.node = node;
if (node == null) {
getView().setVisible(false);
return;
}
refreshLocalDataSources();
for (int i = 0; i < bindings.length; i++) {
bindings[i].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 (DriverDataSourceFactory.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 (DBCPDataSourceFactory.class.getName().equals(factoryName)) {
c = new DBCPDataSourceEditor(
(ProjectController) getParent(),
nodeChangeProcessor);
}
else {
// special case - no detail view, just show it and bail..
defaultSubeditor.setNode(node);
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);
// display the right subview...
view.getDataSourceDetailLayout().show(view.getDataSourceDetail(), factoryName);
}
}