/****************************************************************************** * Copyright (c) 2008-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.services.su.wizards; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.xml.parsers.ParserConfigurationException; import org.eclipse.bpel.common.wsdl.importhelpers.WsdlImportHelper; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExecutableExtension; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.jface.wizard.Wizard; import org.eclipse.ui.actions.WorkspaceModifyOperation; import org.xml.sax.SAXException; import com.ebmwebsourcing.petals.common.internal.provisional.maven.MavenBean; import com.ebmwebsourcing.petals.common.internal.provisional.utils.IoUtils; import com.ebmwebsourcing.petals.common.internal.provisional.utils.PetalsConstants; import com.ebmwebsourcing.petals.common.internal.provisional.utils.ResourceUtils; import com.ebmwebsourcing.petals.common.internal.provisional.utils.StringUtils; import com.ebmwebsourcing.petals.common.internal.provisional.utils.WsdlUtils; import com.ebmwebsourcing.petals.services.Messages; import com.ebmwebsourcing.petals.services.PetalsServicesPlugin; import com.ebmwebsourcing.petals.services.su.extensions.ComponentVersionDescription; import com.ebmwebsourcing.petals.services.su.extensions.SuWizardSettings; import com.ebmwebsourcing.petals.services.su.wizards.pages.AbstractSuWizardPage; import com.ebmwebsourcing.petals.services.su.wizards.pages.JbiConsumePage; import com.ebmwebsourcing.petals.services.su.wizards.pages.JbiProvidePage; import com.ebmwebsourcing.petals.services.su.wizards.pages.ProjectPage; import com.sun.java.xml.ns.jbi.AbstractEndpoint; import com.sun.java.xml.ns.jbi.JbiFactory; /** * The specialized wizard for the Petals service units. * @author Vincent Zurczak - EBM WebSourcing */ public abstract class AbstractServiceUnitWizard extends Wizard implements IExecutableExtension { /** * The Petals mode associated with this instance of the wizard. */ protected PetalsMode petalsMode; /** * The instance of the JBI object model. */ protected AbstractEndpoint endpoint; protected ProjectPage projectPage; protected JbiProvidePage jbiProvidePage; protected FinishServiceCreationStrategy finishStrategy; protected SuWizardSettings settings; protected Set<IResource> resourcesToSelect; protected String finalWsdlFileLocation; /** * Constructor. */ public AbstractServiceUnitWizard() { setNeedsProgressMonitor( true ); setForcePreviousAndNextButtons( true ); setDefaultPageImageDescriptor( PetalsServicesPlugin.getImageDescriptor( "icons/wizban/wiz_service_unit.png" )); this.settings = new SuWizardSettings (); this.resourcesToSelect = new HashSet<IResource> (); } /** * Sets the strategy. * @param strategy */ public void setStrategy( FinishServiceCreationStrategy strategy ) { this.finishStrategy = strategy; } /* * (non-Javadoc) * @see org.eclipse.core.runtime.IExecutableExtension * #setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object) */ @Override public void setInitializationData( IConfigurationElement config, String propertyName, Object data ) throws CoreException { if (propertyName.toLowerCase().contains("provide")) { this.petalsMode = PetalsMode.provides; this.endpoint = JbiFactory.eINSTANCE.createProvides(); setWindowTitle(Messages.provideTitle); } else { this.petalsMode = PetalsMode.consumes; this.endpoint = JbiFactory.eINSTANCE.createConsumes(); setWindowTitle(Messages.consumeTitle); } presetServiceValues(this.endpoint); this.finishStrategy = new CreateJBIStrategy(); } /** * @return the resourcesToSelect */ public Set<IResource> getResourcesToSelect() { return this.resourcesToSelect; } /* * (non-Javadoc) * @see org.eclipse.jface.wizard.Wizard * #addPage(org.eclipse.jface.wizard.IWizardPage) */ @Override public void addPage( IWizardPage page ) { super.addPage(page); page.setWizard(this); String title = this.petalsMode == PetalsMode.provides ? "Petals Service Provider" : "Petals Service Consumer"; title += " (" + getComponentVersionDescription().getComponentAlias() + ")"; page.setTitle( title ); if( page.getDescription() == null ) { if (this.petalsMode == PetalsMode.consumes) page.setDescription(getComponentVersionDescription().getConsumeDescription()); else if (this.petalsMode == PetalsMode.provides) page.setDescription(getComponentVersionDescription().getProvideDescription()); } } /* * (non-Javadoc) * @see org.eclipse.jface.wizard.Wizard * #addPages() */ @Override public void addPages() { // If people go back to the selection wizard, // some pages can be added twice in a wizard. // Normally, a SU wizard starts with no page. if( super.getPageCount() != 0 ) return; // Add the pages AbstractSuWizardPage[] pages = this.getCustomWizardPagesBeforeJbi(); if (pages != null) { for (IWizardPage page : pages) addPage( page ); } if( this.settings.showJbiPage) { if (this.petalsMode == PetalsMode.consumes) addPage( new JbiConsumePage()); else if (this.petalsMode == PetalsMode.provides) { this.jbiProvidePage = new JbiProvidePage(); addPage(this.jbiProvidePage); } } if( this.finishStrategy instanceof CreateJBIStrategy ) { this.projectPage = new ProjectPage(); addPage( this.projectPage ); } pages = getLastCustomWizardPages(); if( pages != null ) { for (IWizardPage page : this.getLastCustomWizardPages()) addPage(page); } } /** * Creates the Petals project and selects and open the required elements. */ @Override public boolean performFinish() { // Define the wizard completion process WorkspaceModifyOperation op = new WorkspaceModifyOperation() { IProject project; @Override protected void execute( IProgressMonitor monitor ) throws CoreException, InterruptedException { try { this.project = AbstractServiceUnitWizard.this.finishStrategy.getSUProject(AbstractServiceUnitWizard.this, monitor); doFinish(monitor ); } catch( Exception e ) { PetalsServicesPlugin.log( e, IStatus.ERROR ); } finally { this.project.refreshLocal( IResource.DEPTH_INFINITE, null ); monitor.done(); } } }; // Run it and perform the UI actions try { // Run the operation. getContainer().run( true, false, op ); } catch( InterruptedException e ) { // nothing } catch( Exception e ) { PetalsServicesPlugin.log( e, IStatus.ERROR ); MessageDialog.openError( getShell(), "Error", "An error occurred during the wizard completion. Check the logs for more details." ); } // Show resources in the project explorer (not in the workspace modify operation!) if( ! this.resourcesToSelect.isEmpty()) ResourceUtils.selectResourceInPetalsExplorer( true, this.resourcesToSelect ); return true; } /** * Creates the project. * @param elementsToSelect the elements to select (not null) * @param monitor the progress monitor * @throws CoreException * @throws IOException */ private void doFinish( IProgressMonitor monitor ) throws Exception { // Common stuff IProject project = this.finishStrategy.getSUProject(this, monitor); IFile jbiFile = project.getFile( PetalsConstants.LOC_JBI_FILE ); // Import the WSDL and update the jbi.xml file in consequence final IFolder resourceDirectory = project.getFolder( PetalsConstants.LOC_RES_FOLDER ); if( this.petalsMode == PetalsMode.provides && this.settings.showWsdl && this.settings.showJbiPage) importWSDLFileInProvideSUProject(monitor, jbiFile, resourceDirectory); monitor.subTask( "Importing additional files..." ); importAdditionalFiles( resourceDirectory, monitor ); monitor.worked( 1 ); monitor.subTask( "Performing extra-actions..." ); resourceDirectory.refreshLocal( IResource.DEPTH_INFINITE, monitor ); performLastActions(resourceDirectory, this.endpoint, monitor); // Last action so that previous ones can keep on modifying JBI this.finishStrategy.finishWizard( this, this.endpoint, monitor ); } /** * Imports a WSDL file in the created project. * @param monitor * @param jbiFile * @param resourceDirectory */ public void importWSDLFileInProvideSUProject(IProgressMonitor monitor, IFile jbiFile, IFolder resourceDirectory) { File wsdlFile = null; monitor.subTask( "Importing the WSDL..." ); this.finalWsdlFileLocation = getSelectedWSDLForProvide(); if( this.finalWsdlFileLocation != null && this.jbiProvidePage.isImportWsdl()) { try { WsdlImportHelper helper = new WsdlImportHelper(); Map<String,File> fileToUrl = helper.importWsdlOrXsdAndDependencies( resourceDirectory.getLocation().toFile(), getSelectedWSDLForProvide()); wsdlFile = fileToUrl.get( getSelectedWSDLForProvide()); this.finalWsdlFileLocation = IoUtils.getRelativeLocationToFile( jbiFile.getLocation().toFile(), wsdlFile ); monitor.subTask( "Updating the WSDL..." ); WsdlUtils.INSTANCE.updateEndpointNameInWsdl( wsdlFile, this.endpoint.getServiceName(), this.settings.soapOriginalPort, this.endpoint.getEndpointName()); } catch( ParserConfigurationException e ) { PetalsServicesPlugin.log( e, IStatus.ERROR ); } catch( IOException e ) { PetalsServicesPlugin.log( e, IStatus.ERROR ); } catch( URISyntaxException e ) { PetalsServicesPlugin.log( e, IStatus.ERROR ); } catch( SAXException e ) { PetalsServicesPlugin.log( e, IStatus.ERROR ); } monitor.worked( 1 ); } } /** * @return the WSDL URL or null if it was not provided */ public String getSelectedWSDLForProvide() { return this.settings.wsdlUri; } /** * Creates the file and write its content. * @param targetFile the target file * @param content the content to write in the file * @param monitor a progress monitor */ protected void createFile( IFile targetFile, String content, IProgressMonitor monitor ) { try { if( content == null ) content = "Result was null. Make your code correct."; ByteArrayInputStream inputStream = new ByteArrayInputStream( content.getBytes()); if( ! targetFile.exists()) targetFile.create( inputStream, true, monitor ); else targetFile.setContents( inputStream, true, true, monitor ); } catch( Exception e ) { PetalsServicesPlugin.log( e, IStatus.ERROR ); } } /** * @return the Petals mode */ public PetalsMode getPetalsMode() { return this.petalsMode; } /** * @return the newly created end-point (provides or consumes) */ public AbstractEndpoint getNewlyCreatedEndpoint() { return this.endpoint; } /** * @return the wizard settings */ public SuWizardSettings getSettings() { return this.settings; } /** * @return a non-null list of Maven dependencies. */ public List<MavenBean> getAdditionalMavenDependencies() { return Collections.emptyList(); } /** * @return the last pages, located after the PROJECT page (can be null) */ protected AbstractSuWizardPage[] getLastCustomWizardPages() { return null; } /** * @return the pages located before the JBI page (can be null) */ protected AbstractSuWizardPage[] getCustomWizardPagesBeforeJbi() { return null; } /** * @return true if the project to create must have the Java nature, false otherwise (false by default) */ protected boolean isJavaProject() { return false; } /** * Presets some values in the jbi.xml * @param endpoint the end-point to configure */ protected void presetServiceValues( AbstractEndpoint endpoint ) { // nothing } /** * Imports additional files in the created project. * @param resourceDirectory the resource directory of the project * @param monitor the progress monitor * @return a status indicating the success or failure of the import(s) */ protected IStatus importAdditionalFiles( IFolder resourceDirectory, IProgressMonitor monitor ) { return Status.OK_STATUS; } /** * Allows to remove unset features from the model. * <p> * To guarantee insertion order in the wizard, one can preset all the values * in {@link #presetServiceValues(AbstractEndpoint)}. The insertion order must respect the one * in XML schema. * </p> * <p> * This method allows to remove the values that were not set or that should not be written. * </p> * * @param ae * @param features */ protected void hackEmfModel( AbstractEndpoint ae, EStructuralFeature... features ) { if( features == null ) return; for( EStructuralFeature feature : features ) { if( feature.isUnsettable()) continue; Object value = ae.eGet( feature ); if( value == null || value instanceof String && StringUtils.isEmpty((String) value)) ae.eSet( feature, null ); } } /** * Performs the last actions. * <p> * It can be create a new file, open an editor... * Resources to select in the Petals project explorer should be added * to {@link #resourcesToSelect} directly. The super class is in charge of displaying them. * </p> * * @param resourceDirectory the resource directory * @param newlyCreatedEndpoint the newly created end-point * @param monitor the progress monitor * @return a status indicating how things worked */ protected abstract IStatus performLastActions( IFolder resourceDirectory, AbstractEndpoint newlyCreatedEndpoint, IProgressMonitor monitor ); /** * @return the description of the component version */ public abstract ComponentVersionDescription getComponentVersionDescription(); }