/******************************************************************************
* Copyright (c) 2011-2013, Linagora
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Linagora - initial API and implementation
*******************************************************************************/
package com.ebmwebsourcing.petals.components.drivers;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.eclipse.bpel.common.wsdl.helpers.UriAndUrlHelper;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.jface.wizard.IWizardPage;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import com.ebmwebsourcing.petals.common.internal.provisional.emf.InvalidJbiXmlException;
import com.ebmwebsourcing.petals.common.internal.provisional.preferences.PreferencesManager;
import com.ebmwebsourcing.petals.common.internal.provisional.utils.StringUtils;
import com.ebmwebsourcing.petals.components.PetalsComponentsPlugin;
import com.ebmwebsourcing.petals.components.utils.ArtifactArchiveUtils;
/**
* A wizard page to specify one or several SL to add to a component.
* @author Vincent Zurczak - EBM WebSourcing
*/
public class ComponentConfigurationWizardPage extends WizardPage implements IWizardPage {
private final static String NAME = "Name";
private final static String VERSION = "Version";
private boolean overwrite;
private String componentUrl, updatedFileLocation;
private final Map<String,String> slNameToVersion = new HashMap<String,String> ();
/**
* Constructor.
*/
protected ComponentConfigurationWizardPage() {
super( "Component Configuration Page" );
}
/* (non-Jsdoc)
* @see org.eclipse.jface.dialogs.IDialogPage
* #createControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createControl( Composite parent ) {
setTitle( "Configured Component" );
setMessage( "Update a Petals component to use one or several shared libraries." );
Composite container = new Composite( parent, SWT.NONE );
container.setLayout( new GridLayout());
container.setLayoutData( new GridData( GridData.FILL_BOTH ));
setControl( container );
// Select the component's archive
Composite subC = new Composite( container, SWT.NONE );
GridLayout layout = new GridLayout( 3, false );
layout.marginWidth = 0;
layout.marginHeight = 0;
subC.setLayout( layout );
subC.setLayoutData( new GridData( GridData.FILL_HORIZONTAL ));
Label l = new Label( subC, SWT.NONE );
l.setText( "Component's URL:" );
l.setToolTipText( "The URL of the component's ZIP" );
final Text componentUrlText = new Text( subC, SWT.SINGLE | SWT.BORDER );
componentUrlText.setLayoutData( new GridData( GridData.FILL_HORIZONTAL ));
componentUrlText.addModifyListener( new ModifyListener() {
@Override
public void modifyText( ModifyEvent e ) {
ComponentConfigurationWizardPage.this.componentUrl = ((Text) e.widget).getText().trim();
validate();
}
});
Button browseButton = new Button( subC, SWT.PUSH );
browseButton.setText( "Browse..." );
browseButton.addSelectionListener( new SelectionListener() {
@Override
public void widgetSelected( SelectionEvent e ) {
widgetDefaultSelected( e );
}
@Override
public void widgetDefaultSelected( SelectionEvent e ) {
FileDialog dlg = new FileDialog( getShell(), SWT.SINGLE );
dlg.setText( "Select a zipped component file" );
dlg.setFilterNames( new String[] { "ZIP (*.zip)" });
dlg.setFilterExtensions( new String[] { "*.zip" });
String path = PreferencesManager.getSavedLocation();
if( ! StringUtils.isEmpty( path )) {
try {
File f = new File( path );
dlg.setFilterPath( f.getParentFile().getAbsolutePath());
dlg.setFileName( f.getName());
} catch( Exception e1 ) {
// nothing
}
}
String fn = dlg.open();
if( fn != null ) {
PreferencesManager.setSavedLocation( fn );
fn = convertFilePathToUrl( fn );
componentUrlText.setText( fn );
}
}
});
// Choose the output location
l = new Label( subC, SWT.NONE );
l.setText( "Output Location:" );
l.setToolTipText( "The location of the component after configuration" );
final Text outputLocationText = new Text( subC, SWT.SINGLE | SWT.BORDER );
outputLocationText.setLayoutData( new GridData( GridData.FILL_HORIZONTAL ));
outputLocationText.addModifyListener( new ModifyListener() {
@Override
public void modifyText( ModifyEvent e ) {
ComponentConfigurationWizardPage.this.updatedFileLocation = ((Text) e.widget).getText().trim();
validate();
}
});
browseButton = new Button( subC, SWT.PUSH );
browseButton.setText( "Browse..." );
browseButton.addSelectionListener( new SelectionListener() {
@Override
public void widgetSelected( SelectionEvent e ) {
widgetDefaultSelected( e );
}
@Override
public void widgetDefaultSelected( SelectionEvent e ) {
FileDialog dlg = new FileDialog( getShell(), SWT.SINGLE | SWT.SAVE );
dlg.setText( "Select a zipped component file" );
dlg.setFilterNames( new String[] { "ZIP (*.zip)" });
dlg.setFilterExtensions( new String[] { "*.zip" });
// File name
String name = null;
if( ComponentConfigurationWizardPage.this.componentUrl != null ) {
int index = Math.max(
ComponentConfigurationWizardPage.this.componentUrl.lastIndexOf( '/' ),
ComponentConfigurationWizardPage.this.componentUrl.lastIndexOf( '\\' ));
if( index > 0 && index < ComponentConfigurationWizardPage.this.componentUrl.length() - 1 ) {
name = ComponentConfigurationWizardPage.this.componentUrl.substring( index + 1 );
name = StringUtils.insertSuffixBeforeFileExtension( name, "--patched" );
}
}
// Save location
String path = PreferencesManager.getSavedLocation();
if( ! StringUtils.isEmpty( path )) {
try {
File f = new File( path );
dlg.setFilterPath( f.getParentFile().getAbsolutePath());
dlg.setFileName( name == null ? f.getName() : name );
} catch( Exception e1 ) {
// nothing
}
} else if( name != null ) {
dlg.setFileName( name );
}
String fn = dlg.open();
if( fn != null )
outputLocationText.setText( fn );
}
});
new Label( subC, SWT.NO_FOCUS );
final Button overwriteButton = new Button( subC, SWT.CHECK );
overwriteButton.setText( "Overwrite" );
overwriteButton.addSelectionListener( new SelectionListener() {
@Override
public void widgetSelected( SelectionEvent e ) {
widgetDefaultSelected( e );
}
@Override
public void widgetDefaultSelected( SelectionEvent e ) {
ComponentConfigurationWizardPage.this.overwrite = overwriteButton.getSelection();
validate();
}
});
// Add a table to display the shared libraries to add
subC = new Composite( container, SWT.NONE );
layout = new GridLayout( 2, false );
layout.marginWidth = 0;
layout.marginHeight = 0;
layout.marginTop = 18;
subC.setLayout( layout );
subC.setLayoutData( new GridData( GridData.FILL_BOTH ));
l = new Label( subC, SWT.NONE );
l.setText( "Select or define the shared libraries this component must use." );
GridData layoutData = new GridData();
layoutData.horizontalSpan = 2;
l.setLayoutData( layoutData );
final TableViewer slViewer = new TableViewer( subC, SWT.BORDER | SWT.HIDE_SELECTION | SWT.FULL_SELECTION | SWT.SINGLE );
slViewer.setContentProvider( new ArrayContentProvider());
slViewer.setLabelProvider( new ITableLabelProvider() {
@Override
public void removeListener( ILabelProviderListener listener ) {
// nothing
}
@Override
public boolean isLabelProperty( Object element, String property ) {
return false;
}
@Override
public void dispose() {
// nothing
}
@Override
public void addListener( ILabelProviderListener listener ) {
// nothing
}
@Override
public String getColumnText( Object element, int columnIndex ) {
Object key = ((Map.Entry<?,?>) element).getKey();
Object value = ((Map.Entry<?,?>) element).getValue();
String result = "";;
if( columnIndex == 0 )
result = (String) key;
else if( columnIndex == 1 )
result = (String) value;
return result;
}
@Override
public Image getColumnImage( Object element, int columnIndex ) {
return null;
}
});
slViewer.getTable().setLayoutData( new GridData( GridData.FILL_BOTH ));
slViewer.getTable().setHeaderVisible( true );
slViewer.getTable().setLinesVisible( true );
TableLayout tlayout = new TableLayout();
tlayout.addColumnData( new ColumnWeightData( 85, 300, true ));
tlayout.addColumnData( new ColumnWeightData( 15, 50, true ));
slViewer.getTable().setLayout( tlayout );
TableColumn column = new TableColumn( slViewer.getTable(), SWT.LEFT );
column.setText( NAME );
column = new TableColumn( slViewer.getTable(), SWT.CENTER );
column.setText( VERSION );
slViewer.setColumnProperties( new String[] { NAME, VERSION });
// Add some buttons
Composite buttonsComposite = new Composite( subC, SWT.NONE );
layout = new GridLayout();
layout.marginWidth = 0;
layout.marginHeight = 0;
buttonsComposite.setLayout( layout );
buttonsComposite.setLayoutData( new GridData( SWT.FILL, SWT.TOP, false, true ));
Button addSlFileButton = new Button( buttonsComposite, SWT.PUSH );
addSlFileButton.setText( "Add a File..." );
addSlFileButton.setToolTipText( "Select a Shared Library file" );
addSlFileButton.setLayoutData( new GridData( SWT.FILL, SWT.TOP, false, false ));
Button addSlUrlButton = new Button( buttonsComposite, SWT.PUSH );
addSlUrlButton.setText( "Add an URL..." );
addSlUrlButton.setToolTipText( "Add an URL pointing to a Shared Library" );
addSlUrlButton.setLayoutData( new GridData( SWT.FILL, SWT.TOP, false, false ));
Button specifySlButton = new Button( buttonsComposite, SWT.PUSH );
specifySlButton.setText( "Specify Manually..." );
specifySlButton.setToolTipText( "Enter a shared library name and a shared library version manually" );
specifySlButton.setLayoutData( new GridData( SWT.FILL, SWT.TOP, false, false ));
final Button editButton = new Button( buttonsComposite, SWT.PUSH );
editButton.setText( "Edit..." );
editButton.setLayoutData( new GridData( SWT.FILL, SWT.TOP, false, false ));
final Button deleteButton = new Button( buttonsComposite, SWT.PUSH );
deleteButton.setText( "Delete" );
deleteButton.setLayoutData( new GridData( SWT.FILL, SWT.TOP, false, false ));
// Button listeners
addSlFileButton.addSelectionListener( new SelectionListener() {
@Override
public void widgetSelected( SelectionEvent e ) {
openSlFileDialog( slViewer, null );
}
@Override
public void widgetDefaultSelected( SelectionEvent e ) {
openSlFileDialog( slViewer, null );
}
});
addSlUrlButton.addSelectionListener( new SelectionListener() {
@Override
public void widgetSelected( SelectionEvent e ) {
openSlUrlDialog( slViewer, null );
}
@Override
public void widgetDefaultSelected( SelectionEvent e ) {
openSlUrlDialog( slViewer, null );
}
});
specifySlButton.addSelectionListener( new SelectionListener() {
@Override
public void widgetSelected( SelectionEvent e ) {
openSlDialog( slViewer, null );
}
@Override
public void widgetDefaultSelected( SelectionEvent e ) {
openSlDialog( slViewer, null );
}
});
editButton.addSelectionListener( new SelectionListener() {
@Override
public void widgetSelected( SelectionEvent e ) {
widgetDefaultSelected( e );
}
@Override
public void widgetDefaultSelected( SelectionEvent e ) {
if( ! slViewer.getSelection().isEmpty()) {
Object o = ((IStructuredSelection) slViewer.getSelection()).getFirstElement();
if( o instanceof Map.Entry<?,?> ) {
o = ((Map.Entry<?,?>) o).getKey();
if( o instanceof String )
openSlDialog( slViewer, (String) o);
}
}
}
});
deleteButton.addSelectionListener( new SelectionListener() {
@Override
public void widgetSelected( SelectionEvent e ) {
widgetDefaultSelected( e );
}
@Override
public void widgetDefaultSelected( SelectionEvent e ) {
if( ! slViewer.getSelection().isEmpty()) {
Object o = ((IStructuredSelection) slViewer.getSelection()).getFirstElement();
ComponentConfigurationWizardPage.this.slNameToVersion.remove( o );
slViewer.setInput( ComponentConfigurationWizardPage.this.slNameToVersion.entrySet());
slViewer.refresh();
}
}
});
// Other listeners
slViewer.addSelectionChangedListener( new ISelectionChangedListener() {
@Override
public void selectionChanged( SelectionChangedEvent event ) {
deleteButton.setEnabled( true );
Object o = ((IStructuredSelection) slViewer.getSelection()).getFirstElement();
if( o instanceof Map.Entry<?,?> ) {
o = ((Map.Entry<?,?>) o).getKey();
boolean disabled = o instanceof File;
editButton.setEnabled( ! disabled );
}
}
});
setPageComplete( false );
}
/**
* @param slViewer the shared libraries viewer
* @param name
*/
private void openSlDialog( final TableViewer slViewer, String name ) {
DuoInputDialog dlg = new DuoInputDialog( getShell());
dlg.setName( name );
dlg.setVersion( this.slNameToVersion.get( name ));
if( dlg.open() == Window.OK ) {
ComponentConfigurationWizardPage.this.slNameToVersion.put( dlg.getName(), dlg.getVersion());
slViewer.setInput( ComponentConfigurationWizardPage.this.slNameToVersion.entrySet());
slViewer.refresh();
validate();
}
}
/**
* @param slViewer the shared libraries viewer
* @param file
*/
private void openSlFileDialog( final TableViewer slViewer, File file ) {
FileDialog dlg = new FileDialog( getShell(), SWT.SINGLE );
dlg.setText( "Select a shared library file" );
dlg.setFilterNames( new String[] { "ZIP (*.zip)" });
dlg.setFilterExtensions( new String[] { "*.zip" });
if( file != null )
dlg.setFilterPath( file.getParentFile().getAbsolutePath());
String path = PreferencesManager.getSavedLocation();
if( ! StringUtils.isEmpty( path )) {
try {
File f = new File( path );
dlg.setFilterPath( f.getParentFile().getAbsolutePath());
dlg.setFileName( f.getName());
} catch( Exception e1 ) {
// nothing
}
}
String fn = dlg.open();
if( fn != null ) {
PreferencesManager.setSavedLocation( fn );
File f = new File( fn );
String version = null;
String name = null;
try {
Properties prop = ArtifactArchiveUtils.getSharedLibraryVersion( f );
version = prop.getProperty( ArtifactArchiveUtils.SL_VERSION );
name = prop.getProperty( ArtifactArchiveUtils.SL_NAME );
} catch( InvalidJbiXmlException e ) {
PetalsComponentsPlugin.log( e, IStatus.ERROR );
}
if( ! StringUtils.isEmpty( name )) {
ComponentConfigurationWizardPage.this.slNameToVersion.put( name, version );
slViewer.setInput( ComponentConfigurationWizardPage.this.slNameToVersion.entrySet());
slViewer.refresh();
validate();
}
}
}
/**
* @param slViewer the shared libraries viewer
* @param url
*/
private void openSlUrlDialog( final TableViewer slViewer, URL url ) {
ZipUrlInputDialog dlg = new ZipUrlInputDialog( getShell(), url );
if( dlg.open() == Window.OK
&& ! dlg.isCancelled()
&& ! StringUtils.isEmpty( dlg.getName())) {
ComponentConfigurationWizardPage.this.slNameToVersion.put( dlg.getName(), dlg.getVersion());
slViewer.setInput( ComponentConfigurationWizardPage.this.slNameToVersion.entrySet());
slViewer.refresh();
validate();
}
}
/**
* Validates all the inputs.
*/
private void validate() {
String msg = null;
if( StringUtils.isEmpty( this.componentUrl ))
msg = "You must indicate the location of a component archive.";
else if(( msg = validateUrl( this.componentUrl )) == null ) {
if( StringUtils.isEmpty( this.updatedFileLocation ))
msg = "You must indicate the location of the output archive.";
else if( new File( this.updatedFileLocation ).exists() && ! this.overwrite )
msg = "The output file already exists.";
else if( this.componentUrl.equals( convertFilePathToUrl( this.updatedFileLocation )))
msg = "The output component cannot overwrite the input component.";
else if( this.slNameToVersion.isEmpty())
msg = "You must specify at least one shared library to use.";
}
setErrorMessage( msg );
setPageComplete( msg == null );
}
/**
* @return the componentUrl
*/
public String getComponentUrl() {
return this.componentUrl;
}
/**
* @return the updatedFileLocation
*/
public String getOutputLocation() {
return this.updatedFileLocation;
}
/**
* @return the slNameToVersion
*/
public Map<String,String> getSlNameToVersion() {
return this.slNameToVersion;
}
/**
* Builds an URL from a string and escapes illegal characters.
* @param path the file path or file URL
* @return an URL
*/
private static String convertFilePathToUrl( String path ) {
URL url;
try {
url = new URL( path );
} catch( MalformedURLException e1 ) {
try {
URI uri = new File( path ).toURI();
uri.normalize();
url = uri.toURL();
} catch( Exception e ) {
throw new IllegalArgumentException( "Broken URL: " + path );
}
}
return url.toString();
}
/**
* Checks that an URL points to an existing resource.
* @param url an URL (not null)
* @return null if everything is fine, an error message otherwise
*/
private static String validateUrl( String url ) {
String msg = null;
InputStream is = null;
try {
is = UriAndUrlHelper.urlToUri( url ).toURL().openStream();
} catch( MalformedURLException e ) {
msg = e.getMessage();
} catch( IOException e ) {
msg = e.getMessage();
} finally {
if( is != null ) {
try {
is.close();
} catch( IOException e ) {
PetalsComponentsPlugin.log( e, IStatus.WARNING );
}
}
}
return msg;
}
}