/*! ******************************************************************************
*
* Pentaho Data Integration
*
* Copyright (C) 2002-2013 by Pentaho : http://www.pentaho.com
*
*******************************************************************************
*
* Licensed 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.pentaho.di.ui.core.auth.controller;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.ResourceBundle;
import org.pentaho.di.core.logging.LogChannel;
import org.pentaho.di.core.logging.LogChannelInterface;
import org.pentaho.di.ui.core.auth.model.AuthProvider;
import org.pentaho.di.ui.core.auth.model.BasicAuthProvider;
import org.pentaho.di.ui.core.auth.model.KerberosAuthProvider;
import org.pentaho.di.ui.core.auth.model.NamedModelObject;
import org.pentaho.di.ui.core.auth.model.NamedProvider;
import org.pentaho.di.ui.core.auth.model.NoAuthAuthProvider;
import org.pentaho.di.ui.core.auth.model.ObjectListModel;
import org.pentaho.ui.xul.XulException;
import org.pentaho.ui.xul.binding.Binding;
import org.pentaho.ui.xul.binding.BindingConvertor;
import org.pentaho.ui.xul.binding.BindingFactory;
import org.pentaho.ui.xul.components.XulFileDialog;
import org.pentaho.ui.xul.components.XulTextbox;
import org.pentaho.ui.xul.containers.XulDialog;
import org.pentaho.ui.xul.impl.AbstractXulEventHandler;
@SuppressWarnings( { "unchecked" } )
public class AuthProviderController extends AbstractXulEventHandler {
protected BindingConvertor<NamedModelObject<NamedProvider>, String> selectedItemsNameBinding =
new SelectedToStringConvertor();
protected BindingConvertor<NamedModelObject<NamedProvider>, Object> selectedItemsItemBinding =
new SelectedToItemConvertor();
protected BindingConvertor<Collection<NamedModelObject<NamedProvider>>, Boolean> itemCountBinding =
new RowCountToBooleanConvertor<NamedModelObject<NamedProvider>>();
private XulDialog xulDialog;
private BindingFactory bf;
private ObjectListModel model = new ObjectListModel();
AuthProvider activeProvider = null;
private static LogChannelInterface log;
ResourceBundle resourceBundle;
public AuthProviderController() {
log = new LogChannel( "AuthProviderController" );
setName( "handler" );
}
public void setBindingFactory( BindingFactory bf ) {
this.bf = bf;
}
public BindingFactory getBindingFactory() {
return bf;
}
public void init() {
xulDialog = ( (XulDialog) getXulDomContainer().getDocumentRoot().getRootElement() );
if ( bf != null ) {
bind();
}
}
public void setResourceBundle( ResourceBundle res ) {
resourceBundle = res;
}
public void open() {
if ( xulDialog != null ) {
xulDialog.show();
}
}
/**
* This will change to pull providers from the auth persistencemanager
*
* @return Collection<AuthProvider>
*/
public Collection<AuthProvider> getPossibleTypes() {
ArrayList<AuthProvider> types = new ArrayList<AuthProvider>();
types.add( new NoAuthAuthProvider( bf ) );
types.add( new KerberosAuthProvider( bf ) );
types.add( new BasicAuthProvider( bf ) );
return types;
}
public void setNewOverlay( AuthProvider provider ) throws XulException {
if ( provider == null ) {
provider = new NoAuthAuthProvider( bf );
}
// Don't use this provider... it is the one that is created to populate
// the combobox. Only use it to select the proper overlay, then
// bind the provider associated with the NamedObject selected
// in the main authProvider list.
if ( this.activeProvider != null ) {
getXulDomContainer().removeOverlay( activeProvider.getOverlay() );
}
getXulDomContainer().loadOverlay( provider.getOverlay() );
if ( model.getSelectedItem() != null ) {
AuthProvider current = (AuthProvider) model.getSelectedItem().getItem();
// Only bind the selected provider if it matches the overlay... the selected
// provider may not have been updated and cloned yet.
if ( current.getOverlay().equalsIgnoreCase( provider.getOverlay() ) ) {
try {
current.bind();
} catch ( Exception e ) {
log.logError( resourceBundle.getString( "error.on_bind" ), e );
}
}
}
this.activeProvider = provider;
}
public String getNewOverlay() {
return "";
}
private void bind() {
try {
this.bf.setBindingType( Binding.Type.ONE_WAY );
// Loads the authorization types into the "Method" combobox
bf.createBinding( this, "possibleTypes", "method_list", "elements" ).fireSourceChanged();
// Manage enabling/disabling layout based on item availability in the main authProvider list.
bf.createBinding( model.getModelObjects(), "children", "remove_button", "disabled", itemCountBinding )
.fireSourceChanged();
bf.createBinding( model.getModelObjects(), "children", "name", "disabled", itemCountBinding ).fireSourceChanged();
bf.createBinding( model.getModelObjects(), "children", "method_list", "disabled", itemCountBinding )
.fireSourceChanged();
// Manage enabling/disabling layout based on selection in the main authProvider list.
bf.createBinding( "auth_list", "selectedItem", "name", "!disabled", BindingConvertor.object2Boolean() )
.fireSourceChanged();
bf.createBinding( "auth_list", "selectedItem", "method_list", "!disabled", BindingConvertor.object2Boolean() )
.fireSourceChanged();
bf.createBinding( "auth_list", "selectedItem", "remove_button", "!disabled", BindingConvertor.object2Boolean() )
.fireSourceChanged();
bf.setBindingType( Binding.Type.BI_DIRECTIONAL );
// When an authorization entry is selected, select entry in model
bf.createBinding( "auth_list", "selectedItem", this.model, "selectedItem" );
// Syncs elements in the model and lists them in the authorization entry list
Binding listBinding = this.bf.createBinding( this.model.getModelObjects(), "children", "auth_list", "elements" );
listBinding.fireSourceChanged();
// Update the entry name textbox when a new entry is selected in the authorization entry list
bf.createBinding( this.model, "selectedItem", "name", "value", selectedItemsNameBinding ).fireSourceChanged();
// Change the overlay when the user changes the "Method" in the method combobox
bf.createBinding( this, "newOverlay", "method_list", "selectedItem" ).fireSourceChanged();
// Update the method combobox with the appropriate selection for the selected authorization entry
bf.createBinding( this.model, "selectedItem", "method_list", "selectedItem", selectedItemsItemBinding )
.fireSourceChanged();
// Because the programmatic selection of the item in the combobox does not fire events, we need
// to bind the main authProvider selection to the changing of the overlay
bf.createBinding( this.model, "selectedItem", this, "newOverlay", selectedItemsItemBinding );
} catch ( XulException e ) {
log.logError( resourceBundle.getString( "error.on_bind" ), e );
} catch ( InvocationTargetException e ) {
log.logError( resourceBundle.getString( "error.on_execution" ), e );
}
}
public void onAccept() {
// save model via PersistenceManager here ...
this.xulDialog.hide();
}
public void onCancel() {
this.xulDialog.hide();
}
public void addNew() {
NamedProvider provider = new NamedProvider( generateUniqueName(), new NoAuthAuthProvider( bf ) );
this.model.add( provider );
this.model.setSelectedItem( provider );
}
private String generateUniqueName() {
String name = resourceBundle.getString( "uniquename.provider" );
int index = 0;
boolean good = false;
String potentialName = null;
while ( !good ) {
potentialName = name.concat( Integer.toString( ++index ) );
boolean found = false;
for ( NamedModelObject<NamedProvider> o : model.getModelObjects() ) {
if ( o.getName().equalsIgnoreCase( potentialName ) ) {
found = true;
break;
}
}
good = !found;
}
return potentialName;
}
public void remove() {
int index = this.model.getModelObjects().indexOf( this.model.getSelectedItem() );
if ( index >= 1 ) {
index -= 1;
}
this.model.getModelObjects().remove( this.model.getSelectedItem() );
if ( !model.getModelObjects().isEmpty() ) {
this.model.setSelectedItem( model.getModelObjects().get( index ) );
} else {
this.model.setSelectedItem( null );
}
}
public void browse() {
try {
XulTextbox filename = (XulTextbox) document.getElementById( "keytab" );
XulFileDialog dialog = (XulFileDialog) document.createElement( "filedialog" );
XulFileDialog.RETURN_CODE retval = dialog.showOpenDialog();
if ( retval == XulFileDialog.RETURN_CODE.OK ) {
File file = (File) dialog.getFile();
filename.setValue( file.getAbsolutePath() );
}
} catch ( XulException e ) {
log.logError( resourceBundle.getString( "error.file_browse" ), e );
}
}
public void addProviders( List<NamedProvider> providers ) {
if ( providers == null || providers.isEmpty() ) {
return;
}
for ( NamedProvider provider : providers ) {
model.add( provider );
}
model.setSelectedItem( model.getModelObjects().get( 0 ) );
}
private class SelectedToItemConvertor extends BindingConvertor<NamedModelObject<NamedProvider>, Object> {
private SelectedToItemConvertor() {
}
public Object sourceToTarget( NamedModelObject<NamedProvider> value ) {
if ( value == null ) {
return null;
}
return value.getItem();
}
public NamedModelObject<NamedProvider> targetToSource( Object value ) {
if ( model.getSelectedItem() != null ) {
AuthProvider provider = (AuthProvider) value;
AuthProvider selectedProvider = (AuthProvider) model.getSelectedItem().getItem();
AuthProvider providerToUse = null;
if ( selectedProvider.getOverlay().equals( provider.getOverlay() ) ) {
providerToUse = selectedProvider;
} else {
// Clone the provider... the one passed in is the provider used in the method
// combobox... we don't want that instance in the main list.
try {
providerToUse = provider.clone();
providerToUse.bind();
} catch ( Exception e ) {
log.logError( resourceBundle.getString( "error.new_provider" ), e );
}
}
model.setItem( model.getSelectedItem(), providerToUse );
}
return model.getSelectedItem();
}
}
private class SelectedToStringConvertor extends BindingConvertor<NamedModelObject<NamedProvider>, String> {
private SelectedToStringConvertor() {
}
public String sourceToTarget( NamedModelObject<NamedProvider> value ) {
if ( value == null ) {
return "";
}
return value.getName();
}
public NamedModelObject<NamedProvider> targetToSource( String value ) {
if ( model.getSelectedItem() != null ) {
model.setName( value );
}
return model.getSelectedItem();
}
}
private class RowCountToBooleanConvertor<T> extends BindingConvertor<Collection<T>, Boolean> {
@Override
public Boolean sourceToTarget( Collection<T> value ) {
return ( value == null ) || ( value.isEmpty() );
}
@Override
public Collection<T> targetToSource( Boolean value ) {
return null;
}
}
/**
* Exposed only for junit tests
*
* @return ObjectListModel
*/
ObjectListModel getModel() {
return model;
}
}