/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * 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 *******************************************************************************/ package org.ebayopensource.turmeric.eclipse.typelibrary.ui.wst; import java.io.IOException; import java.net.MalformedURLException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; import javax.xml.namespace.QName; import org.apache.commons.lang.StringUtils; import org.ebayopensource.turmeric.common.config.LibraryType; import org.ebayopensource.turmeric.common.config.TypeDependencyType; import org.ebayopensource.turmeric.common.config.TypeLibraryDependencyType; import org.ebayopensource.turmeric.eclipse.buildsystem.SynchronizeWsdlAndDepXML; import org.ebayopensource.turmeric.eclipse.buildsystem.TypeDepMarshaller; import org.ebayopensource.turmeric.eclipse.buildsystem.TypeLibSynhcronizer; import org.ebayopensource.turmeric.eclipse.core.TurmericCoreActivator; import org.ebayopensource.turmeric.eclipse.core.compare.LibraryTypeComparator; import org.ebayopensource.turmeric.eclipse.core.logging.SOALogger; import org.ebayopensource.turmeric.eclipse.repositorysystem.core.GlobalRepositorySystem; import org.ebayopensource.turmeric.eclipse.repositorysystem.core.SOAGlobalRegistryAdapter; import org.ebayopensource.turmeric.eclipse.resources.model.ISOAProject; import org.ebayopensource.turmeric.eclipse.resources.model.SOAIntfProject; import org.ebayopensource.turmeric.eclipse.resources.util.SOAServiceUtil; import org.ebayopensource.turmeric.eclipse.typelibrary.resources.SOAMessages; import org.ebayopensource.turmeric.eclipse.typelibrary.ui.TypeLibraryUtil; import org.ebayopensource.turmeric.eclipse.typelibrary.ui.actions.ActionUtil; import org.ebayopensource.turmeric.eclipse.typelibrary.utils.XSDSchemaValidationUtil; import org.ebayopensource.turmeric.eclipse.ui.views.registry.TypeSelector; import org.ebayopensource.turmeric.eclipse.utils.lang.StringUtil; import org.ebayopensource.turmeric.eclipse.utils.plugin.EclipseMessageUtils; import org.ebayopensource.turmeric.eclipse.utils.plugin.ProgressUtil; import org.ebayopensource.turmeric.eclipse.utils.plugin.WorkspaceUtil; import org.ebayopensource.turmeric.eclipse.utils.ui.UIUtil; import org.ebayopensource.turmeric.tools.library.SOATypeRegistry; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IStatusLineManager; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.text.ITextOperationTarget; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.jface.window.Window; import org.eclipse.ui.progress.UIJob; import org.eclipse.wst.wsdl.Definition; import org.eclipse.xsd.XSDSchema; /** * Represents the import functionality of SOA type library. Contributes the * context menu to WTP editor context and import types to both WSDL and XSD. * Validates the type for duplicates and equality before importing into XSD or * WSDL. In XSDs it uses the custom SOA type library protocol and in WSDLs it * in-lines the XSD fully. Also validates the editor before importing the types. * This class is also responsible for formatting the final document, but due to * some WTP issues this might not be a successful operation always and in case * of failures this will show up a warning and tells the user how to format the * document. * * @author smathew * */ public class ImportTypeFromTypeLibrary extends AbastractTypeLibraryAtion { private static final SOALogger logger = SOALogger.getLogger(); /** * Instantiates a new import type from type library. */ public ImportTypeFromTypeLibrary() { } /** * The import action on the WTP Editor. This is for both XSD and WSDL * editors. Call back from eclipse. * * @param action the action * @see org.eclipse.ui.actions.ActionDelegate#run(org.eclipse.jface.action.IAction * ) */ @Override public void run(IAction action) { UIJob inlineType = new UIJob("Inline Type...") { @Override public IStatus runInUIThread(IProgressMonitor monitor) { monitor.beginTask("Inline Type...", ProgressUtil.PROGRESS_STEP * 10); if (WTPTypeLibUtil.validateEditorForContextMenus(editorPart) == false) { return Status.OK_STATUS; } ProgressUtil.progressOneStep(monitor); try { if (doValidation() == false) { return Status.OK_STATUS; } SOAGlobalRegistryAdapter registryAdapter = SOAGlobalRegistryAdapter .getInstance(); SOATypeRegistry typeRegistry = registryAdapter .getGlobalRegistry(); TypeSelector typeSelector = new TypeSelector( UIUtil.getActiveShell(), SOAMessages.SEL_TYPE, typeRegistry.getAllTypes().toArray( new LibraryType[0]), getSelectedFile().getProject().getName(), TypeLibraryUtil .getXsdTypeNameFromFileName(getSelectedFile() .getName())); typeSelector.setMultipleSelection(true); if (typeSelector.open() != Window.OK) { return Status.OK_STATUS; } ProgressUtil.progressOneStep(monitor); ArrayList<LibraryType> selectedTypes = typeSelector .getSelectedTypes(); // // selectedTypes.addAll(c) // for (LibraryType selectedObject : typeSelector // .getSelectedTypes()) { // selectedTypes.add((LibraryType) selectedObject); // } if (selectedTypes.isEmpty() == true) { return Status.OK_STATUS; } Object adaptedObject = TypeLibraryUtil .getAdapterClassFromWTPEditors(editorPart); LibraryType[] selectedtypeArr = selectedTypes .toArray(new LibraryType[0]); if (adaptedObject == null || validateSelectedTypeForImport(selectedtypeArr, getSelectedFile()) == false || validateDuplicateImports(selectedtypeArr, getSelectedFile(), adaptedObject) == false) { return Status.OK_STATUS; } ProgressUtil.progressOneStep(monitor); if (adaptedObject instanceof XSDSchema) { if (ActionUtil .validateEditor(editorPart, adaptedObject)) { performImportTasksForXSDEditor( (XSDSchema) adaptedObject, selectedtypeArr, getSelectedFile()); ITextOperationTarget formatter = TypeLibraryUtil .getFormatter(editorPart); ProgressUtil.progressOneStep(monitor); if (formatter != null) { // should not use // StructuredTextViewer.FORMAT_DOCUMENT, // it will set Definition.getTypes() to null formatter .doOperation(ISourceViewer.FORMAT); ProgressUtil.progressOneStep(monitor); } } } else if (adaptedObject instanceof Definition) { if (ActionUtil .validateEditor(editorPart, adaptedObject)) { ProgressUtil.progressOneStep(monitor); // This could be done on the WSDL Editor performInlineOperationsForWSDLEditor( (Definition) adaptedObject, selectedtypeArr, getSelectedFile()); ProgressUtil.progressOneStep(monitor); ITextOperationTarget formatter = TypeLibraryUtil .getFormatter(editorPart); if (formatter != null) { // should not use // StructuredTextViewer.FORMAT_DOCUMENT, // it will set Definition.getTypes() to null formatter .doOperation(ISourceViewer.FORMAT); } ProgressUtil.progressOneStep(monitor); } } else { showCommonErrorDialog(null); } } catch (Exception e) { logger.error(e); UIUtil.showErrorDialog(e); } finally{ monitor.done(); } return Status.OK_STATUS; } }; inlineType.schedule(); } /** * Shows the common Error dialog in case of import failures. Most of these * failures are due to stale registry or invalid XSD opened up outside the * work space etc. Thats why we show this common error in most cases. * * @param t the t */ public static void showCommonErrorDialog(Throwable t) { String msg = SOAMessages.OP_ERR_DETAILS; if (t != null) { msg += "\r\rRoot Cause:" + t.toString(); } UIUtil.openChoiceDialog(SOAMessages.OP_ERR, msg, MessageDialog.INFORMATION); } /** * Perform import tasks for xsd editor. * * @param parentXSDSchema the parent xsd schema * @param selectedTypes the selected types * @param selectedFile the selected file * @throws Exception the exception */ public static void performImportTasksForXSDEditor( XSDSchema parentXSDSchema, LibraryType selectedTypes[], IFile selectedFile) throws Exception { WorkspaceUtil.refresh(selectedFile); IProject project = selectedFile.getProject(); // Add Import to XSD for (LibraryType selectedType : selectedTypes) { runImportCommandInXSDEditor(parentXSDSchema, selectedType); } // Modify TypeDep.xml SynchronizeWsdlAndDepXML synch = new SynchronizeWsdlAndDepXML(project); synch.syncronizeXSDandDepXml(parentXSDSchema, TypeLibraryUtil.toQName(selectedFile)); // Modify project xml/pom synch.synchronizeTypeDepandProjectDep(ProgressUtil.getDefaultMonitor(null)); TypeLibSynhcronizer.updateVersionEntryTypeDep(TypeLibraryUtil .getXsdTypeNameFromFileName(selectedFile.getName()), Arrays .asList(selectedTypes), project); SOAGlobalRegistryAdapter registryAdapter = SOAGlobalRegistryAdapter.getInstance(); registryAdapter.populateRegistry(project.getName()); WorkspaceUtil.refresh(project); IStatusLineManager lineManager = UIUtil.getStatusLineManager(); if (lineManager != null) { lineManager.setMessage(SOAMessages.OP_SUCCESS); } } /** * In-line the selected types to the target definition object. Updates the * type dependency XML file, then modifies the project dependency. If it is * single name space WSDL then the information about the type library and * name space are added to the WSDL as annotation. In addition to this we * add it to the type dependency file also. If it is a multiple name space * we only add it to the type dependency file. When in-lining types in the * WSDL the dependent types are also found out and in-lined to form a stand * alone WSDL. * * @param definition the definition * @param selectedTypes the selected types * @param selectedFile the selected file * @throws Exception the exception */ public static void performInlineOperationsForWSDLEditor( Definition definition, LibraryType selectedTypes[], IFile selectedFile) throws Exception { WorkspaceUtil.refresh(selectedFile); IProject project = selectedFile.getProject(); if (definition == null || (definition instanceof Definition) == false) { showCommonErrorDialog(null); return; } TreeSet<LibraryType> librarySet = new TreeSet<LibraryType>( new LibraryTypeComparator()); // TreeSet<LibraryType> selectedTypesSet = new TreeSet<LibraryType>( // new LibraryTypeComparator()); // finding out all the dependent types for in-lining. SOATypeRegistry typeRegistry = SOAGlobalRegistryAdapter.getInstance().getGlobalRegistry(); for (LibraryType selectedType : selectedTypes) { librarySet.add(selectedType); // selectedTypesSet.add(selectedType); for (LibraryType libraryType : typeRegistry.getDependentParentTypeFiles( selectedType)) { librarySet.add(libraryType); } } XSDSchemaValidationUtil.validateType(project, librarySet.toArray(new LibraryType[0])); boolean typeFolding = SOAServiceUtil.getSOAIntfMetadata( SOAServiceUtil.getSOAEclipseMetadata(project)).getTypeFolding(); final List<IStatus> statuses = new ArrayList<IStatus>(); for (LibraryType selectedType : librarySet) { IStatus result = WTPTypeLibUtil.inlineType(selectedType, definition, true, typeFolding); if (result.getSeverity() == IStatus.ERROR) { statuses.add(result); }else if(result.isOK() == false){ SOALogger.getLogger().debug(result.getMessage()); } } // Modify TypeDep.xml SynchronizeWsdlAndDepXML synch = new SynchronizeWsdlAndDepXML(project); synch.syncronizeWSDLandDepXml(definition); synch.synchronizeTypeDepandProjectDep(ProgressUtil.getDefaultMonitor(null)); TypeLibSynhcronizer.updateVersionEntryTypeDep( GlobalRepositorySystem.instanceOf().getActiveRepositorySystem() .getTypeRegistryBridge().getTypeDependencyWsdlTypeName(), librarySet, project); WorkspaceUtil.refresh(project); if (statuses.size() > 0) { IStatus results = EclipseMessageUtils .createErrorMultiStatusBasedOnChildrenSeverity(statuses, "Inline Type operation results"); UIUtil.showErrorDialog(UIUtil.getActiveShell(), "Inline Type Results", results); } else { IStatusLineManager lineManager = UIUtil.getStatusLineManager(); if (lineManager != null) { lineManager.setMessage(SOAMessages.OP_SUCCESS); } } } /** * Validate selected type for import. * * @param selectedTypes the selected types * @param parentFile the parent file * @return true, if successful */ public static boolean validateSelectedTypeForImport( LibraryType[] selectedTypes, IFile parentFile) { for (LibraryType selectedType : selectedTypes) { try { if (StringUtils.equals(selectedType.getName(), TypeLibraryUtil .getXsdTypeNameFromFileName(parentFile.getName()))) { UIUtil .showErrorDialog(null, SOAMessages.IMPORT_FAILED, SOAMessages.IMPORT_XSD_ERR, StringUtil.formatString( SOAMessages.XSD_ERR_DETAILS, selectedType, parentFile.getName())); return false; } } catch (Exception exception) { SOALogger.getLogger().error(exception); UIUtil .showErrorDialog(null, SOAMessages.IMPORT_ERR, SOAMessages.IMPORT_FAILED, StringUtil .formatString(SOAMessages.BUILD_PROJ, exception.getMessage())); return false; } } return true; } /** * Validate duplicate imports. * * @param selectedTypes the selected types * @param selectedFile the selected file * @param schema the schema * @return true, if successful * @throws Exception the exception */ public static boolean validateDuplicateImports(LibraryType[] selectedTypes, IFile selectedFile, Object schema) throws Exception { IProject intfProject = selectedFile.getProject(); boolean isNamespaceFoldingEnabled = false; ISOAProject soaProject = GlobalRepositorySystem.instanceOf() .getActiveRepositorySystem().getAssetRegistry().getSOAProject( intfProject); if (soaProject instanceof SOAIntfProject) { SOAIntfProject soaIntfProject = (SOAIntfProject) soaProject; isNamespaceFoldingEnabled = soaIntfProject.getMetadata() .getTypeFolding(); } Set<QName> duplicatedType = new HashSet<QName>(); Set<QName> duplicatedName = new HashSet<QName>(); fillDuplicateImports(selectedTypes, selectedFile, schema, duplicatedType, duplicatedName, isNamespaceFoldingEnabled); StringBuffer errMsg = new StringBuffer(); if (duplicatedType.isEmpty() == false) { errMsg.append(SOAMessages.TYPEDEP_ERR + StringUtil.join(duplicatedType, ",")); } if (duplicatedName.isEmpty() == false) { errMsg.append("\r\n" + SOAMessages.TYPEDEP_ERR_ENF + StringUtil.join(duplicatedName, ",")); } if (errMsg.length() == 0) { return true; } else { MessageDialog.openWarning(UIUtil.getActiveShell(), SOAMessages.DUP_TYPES, errMsg + ".\r\n\r\n" + SOAMessages.TYPE_LINE_FAIL); return false; } } private void showFormatErrorDialog() { MessageDialog.openInformation(UIUtil.getActiveShell(), SOAMessages.FORMAT_ERR, SOAMessages.FORMAT_ERR_DETAILS); } private static void runImportCommandInXSDEditor(XSDSchema parentXSDSchema, LibraryType selectedType) throws MalformedURLException, IOException, Exception { XSDSchema xsdSchema = TypeLibraryUtil.parseSchema(TypeLibraryUtil .getXSD(selectedType)); AddImportCommand addImportCommand = new AddImportCommand( parentXSDSchema, TypeLibraryUtil .getProtocolString(selectedType), xsdSchema); addImportCommand.run(); } private static void fillDuplicateImports(LibraryType[] selectedTypes, IFile selectedFile, Object schema, Set<QName> duplicatedType, Set<QName> duplicatedName, boolean isNamespaceFoldingEnabled) throws Exception { // Is it already imported ie duplicate?. String typeName = GlobalRepositorySystem.instanceOf().getActiveRepositorySystem() .getTypeRegistryBridge().getTypeDependencyWsdlTypeName(); if (schema instanceof XSDSchema) { typeName = TypeLibraryUtil .getTypeNameFromXSDSchemaLocation(((XSDSchema) schema) .getSchemaLocation()); } IFile typeDepFile = TurmericCoreActivator.getDependencyFile(selectedFile .getProject()); if (typeDepFile.exists() == false) { return; } TypeLibraryDependencyType typeLibraryDependencyType = TypeDepMarshaller .unmarshallIt(typeDepFile); TypeDependencyType typeDependencyType = TypeDepMarshaller.getTypeEntry( typeLibraryDependencyType, typeName); if (typeDependencyType == null) { return; } // if isNamespaceFoldingEnabled == true, then type name duplication is // not allowed. Otherwise, type duplication is not allowed. Set<QName> importedTypes = TypeDepMarshaller .getAllReferredtypes(typeDependencyType); Set<String> importedTypeNamesStr = new HashSet<String>(); if (isNamespaceFoldingEnabled == true) { for (QName importedType : importedTypes) { String name = importedType.getLocalPart(); importedTypeNamesStr.add(name); } } for (LibraryType selectedLibraryType : selectedTypes) { QName name = TypeLibraryUtil.toQName(selectedLibraryType); if (importedTypes.contains(name)) { duplicatedType.add(name); continue; } if (isNamespaceFoldingEnabled == true) { if (importedTypeNamesStr.contains(name.getLocalPart())) { duplicatedName.add(name); } } } } }