/****************************************************************************** * 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; } }