/******************************************************************************* * This file is protected by Copyright. * Please refer to the COPYRIGHT file distributed with this source distribution. * * This file is part of REDHAWK IDE. * * 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 *******************************************************************************/ package gov.redhawk.ide.codegen.ui.internal.upgrade; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.ListIterator; import java.util.Set; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.ecore.util.FeatureMap; import org.eclipse.emf.transaction.RunnableWithResult; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.ide.ResourceUtil; import org.osgi.framework.Version; import gov.redhawk.ide.codegen.IScaComponentCodegen; import gov.redhawk.ide.codegen.ImplementationSettings; import gov.redhawk.ide.codegen.ui.RedhawkCodegenUiActivator; import gov.redhawk.ide.codegen.ui.internal.GeneratorUtil; import gov.redhawk.ide.codegen.ui.internal.WaveDevUtil; import gov.redhawk.model.sca.commands.ScaModelCommand; import gov.redhawk.model.sca.commands.ScaModelCommandWithResult; import mil.jpeojtrs.sca.prf.AbstractProperty; import mil.jpeojtrs.sca.prf.AccessType; import mil.jpeojtrs.sca.prf.ConfigurationKind; import mil.jpeojtrs.sca.prf.Kind; import mil.jpeojtrs.sca.prf.PrfFactory; import mil.jpeojtrs.sca.prf.PrfPackage; import mil.jpeojtrs.sca.prf.Properties; import mil.jpeojtrs.sca.prf.PropertyConfigurationType; import mil.jpeojtrs.sca.prf.Simple; import mil.jpeojtrs.sca.prf.SimpleSequence; import mil.jpeojtrs.sca.prf.Struct; import mil.jpeojtrs.sca.prf.StructPropertyConfigurationType; import mil.jpeojtrs.sca.prf.StructSequence; import mil.jpeojtrs.sca.spd.Implementation; import mil.jpeojtrs.sca.spd.SoftPkg; import mil.jpeojtrs.sca.util.collections.FeatureMapList; public class PropertyKindUtil { private PropertyKindUtil() { } /** * Check if the properties associated with the implementation(s) need upgrading. The user will be prompted to * upgrade the properties if necessary, or codegen will be aborted. * @param shell * @param parentProject * @param impls * @throws CoreException * @throws OperationCanceledException */ public static void checkProperties(Shell shell, IProject parentProject, List<Implementation> impls) throws CoreException, OperationCanceledException { if (impls == null || impls.size() == 0) { return; } // Nothing to do if there isn't an associated PRF final SoftPkg spd = (SoftPkg) impls.get(0).eContainer(); if (spd.getPropertyFile() == null) { return; } final Properties prf = spd.getPropertyFile().getProperties(); // Get code generator version(s) List<Version> codegenVersions = new ArrayList<Version>(); for (Implementation impl : impls) { ImplementationSettings implSettings = WaveDevUtil.getImplSettings(impl); if (implSettings == null) { continue; } IScaComponentCodegen generator = GeneratorUtil.getGenerator(implSettings); if (generator == null) { continue; } codegenVersions.add(generator.getCodegenVersion()); } // Find if there are configure, execparam and property kinds in the properties file final Set<PropertyConfigurationType> kindTypes = new HashSet<PropertyConfigurationType>(); try { ScaModelCommandWithResult.runExclusive(prf, new RunnableWithResult.Impl<Object>() { @Override public void run() { FeatureMap props = prf.getProperties(); for (FeatureMap.Entry propEntry : props) { Object propObj = propEntry.getValue(); if (propObj instanceof Simple) { Simple prop = (Simple) propObj; findKinds(prop.getKind(), kindTypes); } else if (propObj instanceof SimpleSequence) { SimpleSequence prop = (SimpleSequence) propObj; findKinds(prop.getKind(), kindTypes); } else if (propObj instanceof Struct) { Struct prop = (Struct) propObj; findConfigurationKinds(prop.getConfigurationKind(), kindTypes); } else if (propObj instanceof StructSequence) { StructSequence prop = (StructSequence) propObj; findConfigurationKinds(prop.getConfigurationKind(), kindTypes); } } } }); } catch (InterruptedException e) { throw new OperationCanceledException(); } // Don't allow the user to proceed if they're using an old codegen with the new 'property' kind for (Version codegenVersion : codegenVersions) { if (codegenVersion.compareTo(new Version(2, 0, 0)) < 0 && kindTypes.contains(PropertyConfigurationType.PROPERTY)) { MessageDialog.openError(shell, Messages.OldCodeGen_Title, Messages.OldCodeGen_Message); throw new OperationCanceledException(); } } // Offer upgrade if using deprecated property kinds with a newer codegen for (Version codegenVersion : codegenVersions) { if (codegenVersion.compareTo(new Version(2, 0, 0)) >= 0 && (kindTypes.contains(PropertyConfigurationType.CONFIGURE) || kindTypes.contains(PropertyConfigurationType.EXECPARAM) || kindTypes.contains(PropertyConfigurationType.EVENT))) { String[] buttons = new String[] { IDialogConstants.CANCEL_LABEL, IDialogConstants.NO_LABEL, IDialogConstants.YES_LABEL }; MessageDialog dialog = new MessageDialog(shell, Messages.DeprecatedProps_Title, null, Messages.DeprecatedProps_Message, MessageDialog.QUESTION, buttons, 2); int result = dialog.open(); if (result == 2) { upgradeProperties(prf); save(parentProject, spd, prf); break; } else if (result == 1) { break; } else { throw new OperationCanceledException(); } } } } /** * Finds all unique kind types explicitly specified and adds them to the Set * @param kinds The list of kinds to look through * @param kindTypes Any property kind types present are added to the Set */ private static void findKinds(EList<Kind> kinds, Set<PropertyConfigurationType> kindTypes) { if (kinds == null) { return; } for (Kind kind : kinds) { kindTypes.add(kind.getType()); } } /** * Finds all unique configuration kind types explicitly specified and adds their kind type equivalent to the Set * @param kinds The list of kinds to look through * @param kindTypes Any property kind types present are added to the Set */ private static void findConfigurationKinds(EList<ConfigurationKind> kinds, Set<PropertyConfigurationType> kindTypes) { if (kinds == null) { return; } for (ConfigurationKind kind : kinds) { kindTypes.add(kind.getType().getPropertyConfigurationType()); } } /** * Upgrade 'configure' and 'execparam' properties to 'property' properties, or remove if superfluous. * @param prf The PRF model object to upgrade * @throws CoreException */ private static void upgradeProperties(final Properties prf) { // Upgrade each property ScaModelCommand.execute(prf, new ScaModelCommand() { @Override public void execute() { FeatureMapList<AbstractProperty> props = new FeatureMapList<AbstractProperty>(prf.getProperties(), AbstractProperty.class); for (AbstractProperty absProp : props) { switch (absProp.eClass().getClassifierID()) { case PrfPackage.SIMPLE: case PrfPackage.SIMPLE_SEQUENCE: upgradeKindProperties(absProp); break; case PrfPackage.STRUCT: case PrfPackage.STRUCT_SEQUENCE: upgradeConfigurationKindProperties(absProp); break; default: throw new IllegalArgumentException(); } } } }); } /** * Upgrade properties with the "kind" XML type (simple / simple sequence) * @param prop */ private static void upgradeKindProperties(AbstractProperty prop) { List<Kind> kinds; switch (prop.eClass().getClassifierID()) { case PrfPackage.SIMPLE: kinds = ((Simple) prop).getKind(); break; case PrfPackage.SIMPLE_SEQUENCE: kinds = ((SimpleSequence) prop).getKind(); break; default: throw new IllegalArgumentException(); } boolean hasProperty = false; boolean hadConfigure = false; boolean hadExecParam = false; ListIterator<Kind> iterator = kinds.listIterator(); while (iterator.hasNext()) { Kind kind = iterator.next(); switch (kind.getType()) { case PROPERTY: hasProperty = true; break; case CONFIGURE: iterator.remove(); hadConfigure = true; break; case EXECPARAM: iterator.remove(); hadExecParam = true; break; case EVENT: iterator.remove(); break; default: break; } } if (hadExecParam && prop.eClass().getClassifierID() == PrfPackage.SIMPLE) { // read-write execparms that aren't configurable -> read-only command line property if (!hadConfigure && !hasProperty && prop.getMode() == AccessType.READWRITE) { prop.setMode(AccessType.READONLY); } if (!hasProperty) { Kind newKind = PrfFactory.eINSTANCE.createKind(); newKind.setType(PropertyConfigurationType.PROPERTY); kinds.add(newKind); } ((Simple) prop).setCommandline(true); } else if (hadConfigure && !hasProperty) { Kind newKind = PrfFactory.eINSTANCE.createKind(); newKind.setType(PropertyConfigurationType.PROPERTY); kinds.add(newKind); } } /** * Upgrade properties with the "configurationkind" XML type (struct / struct sequence) * @param prop */ private static void upgradeConfigurationKindProperties(AbstractProperty prop) { List<ConfigurationKind> kinds; switch (prop.eClass().getClassifierID()) { case PrfPackage.STRUCT: kinds = ((Struct) prop).getConfigurationKind(); break; case PrfPackage.STRUCT_SEQUENCE: kinds = ((StructSequence) prop).getConfigurationKind(); break; default: throw new IllegalArgumentException(); } boolean hasProperty = false; boolean hadConfigure = false; ListIterator<ConfigurationKind> iterator = kinds.listIterator(); while (iterator.hasNext()) { ConfigurationKind kind = iterator.next(); switch (kind.getType()) { case PROPERTY: hasProperty = true; break; case CONFIGURE: iterator.remove(); hadConfigure = true; break; case EVENT: iterator.remove(); break; default: break; } } if (hadConfigure && !hasProperty) { ConfigurationKind newKind = PrfFactory.eINSTANCE.createConfigurationKind(); newKind.setType(StructPropertyConfigurationType.PROPERTY); kinds.add(newKind); } // Drop nested kinds switch (prop.eClass().getClassifierID()) { case PrfPackage.STRUCT: Struct struct = (Struct) prop; for (Simple simple : struct.getSimple()) { simple.getKind().clear(); } for (SimpleSequence simpleSequence : struct.getSimpleSequence()) { simpleSequence.getKind().clear(); } break; case PrfPackage.STRUCT_SEQUENCE: StructSequence structSequence = (StructSequence) prop; for (Simple simple : structSequence.getStruct().getSimple()) { simple.getKind().clear(); } for (SimpleSequence simpleSequence : structSequence.getStruct().getSimpleSequence()) { simpleSequence.getKind().clear(); } break; default: throw new IllegalArgumentException(); } } /** * Saves the properties file to disk. This will be done via an open SPD / PRF editor if possible, otherwise the * file will be saved directly and a change notification generated. * @param project The parent project * @param spd The SPD using the PRF * @param prf The PRF file to be saved * @throws CoreException */ private static void save(final IProject project, final SoftPkg spd, final Properties prf) throws CoreException { // Our model object may / most likely belongs to an editor RunnableWithResult<Boolean> saveViaEditor = new RunnableWithResult.Impl<Boolean>() { @Override public void run() { // Look for a PRF editor IEditorPart editorPart = ResourceUtil.findEditor(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), project.getFile(prf.eResource().getURI().lastSegment())); // If no PRF editor, look for SPD editor if (editorPart == null) { editorPart = ResourceUtil.findEditor(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(), project.getFile(spd.eResource().getURI().lastSegment())); } // If the editor is found and is dirty (i.e. it has our changes), save if (editorPart != null && editorPart.isDirty()) { editorPart.doSave(new NullProgressMonitor()); setResult(true); } } }; Display.getDefault().syncExec(saveViaEditor); // If we were unable to save via editor, save the resource directly if (saveViaEditor.getResult() == null) { try { prf.eResource().save(null); } catch (IOException e) { throw new CoreException(new Status(IStatus.ERROR, RedhawkCodegenUiActivator.PLUGIN_ID, Messages.Error_CantSavePrf, e)); } } } }