/*******************************************************************************
* 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
*******************************************************************************/
// BEGIN GENERATED CODE
package gov.redhawk.ide.codegen;
import gov.redhawk.ide.codegen.builders.TopLevelBuildScript;
import gov.redhawk.ide.codegen.builders.TopLevelRPMSpec;
import gov.redhawk.ide.natures.ScaComponentProjectNature;
import gov.redhawk.sca.util.Debug;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import mil.jpeojtrs.sca.spd.Implementation;
import mil.jpeojtrs.sca.spd.SoftPkg;
import mil.jpeojtrs.sca.util.ScaResourceFactoryUtil;
import org.eclipse.core.resources.ICommand;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.util.BasicEMap;
import org.eclipse.emf.common.util.BasicEMap.Entry;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.impl.EObjectImpl;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.edit.command.AddCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
public class CodegenUtil {
private static final Debug DEBUG = new Debug(RedhawkCodegenActivator.PLUGIN_ID, "codgenUtil");
/**
* @since 9.0
*/
public static final String JAVA_PACKAGE = "java_package";
/**
* @since 7.0
*/
public static final String CPP = "C++";
/**
* @since 7.0
*/
public static final String JAVA = "Java";
/**
* @since 7.0
*/
public static final String PYTHON = "Python";
private CodegenUtil() {
}
/**
* Gets the wave dev settings.
*
* @param waveDevResource the wave dev resource
*
* @return the wave dev settings
*/
public static WaveDevSettings getWaveDevSettings(final Resource waveDevResource) {
if (waveDevResource == null) {
return null;
}
return (WaveDevSettings) waveDevResource.getEObject("/");
}
/**
* Gets the wavedev uri. There is a 1-1 relationship for SPD file to wavedev
* settings
*
* @param spdResourceUri the SPD resource URI
*
* @return the wavedev settings uri
*/
public static URI getWaveDevSettingsURI(final URI spdResourceUri) {
String name = spdResourceUri.lastSegment();
name = name.substring(0, name.length() - 7);
URI uri = spdResourceUri.trimSegments(1).appendSegment("." + name + "wavedev");
return uri;
}
/**
* @since 9.0
*/
public static Command createAddImplementationSettingsCommand(final EditingDomain domain, final String implId, final ImplementationSettings settings,
final WaveDevSettings waveDevSettings) {
// XXX Is this right?!?
@SuppressWarnings("unchecked")
final BasicEMap.Entry<String, ImplementationSettings> entry = (Entry<String, ImplementationSettings>) EcoreUtil
.create(CodegenPackage.Literals.IMPL_ID_TO_SETTINGS_MAP);
entry.setKey(implId);
entry.setValue(settings);
return AddCommand.create(domain, waveDevSettings, CodegenPackage.Literals.WAVE_DEV_SETTINGS__IMPL_SETTINGS, Collections.singleton(entry));
}
/**
* Gets the settings URI
*
* @param softpkg the SPD resource
*
* @return the wavedev settings uri
* @since 9.0
* @deprecated Use {@link #getWaveDevSettingsURI(URI)} and append the fragment
*/
@Deprecated
public static URI getSettingsURI(final SoftPkg softpkg) {
if ((softpkg == null) || (softpkg.eResource() == null)) {
return null;
}
URI uri = softpkg.eResource().getURI();
return getWaveDevSettingsURI(uri).appendFragment("/");
}
/**
* Gets {@link ImplementationSettings} associated with an {@link Implementation}. A new .wavedev file is created if
* it doesn't already exist and this is a workspace project.
* @param impl The implementation for which to get {@link ImplementationSettings}
* @return implSettings The settings, or null if none could be found
*/
public static ImplementationSettings getImplementationSettings(final Implementation impl) {
final WaveDevSettings waveSettings = CodegenUtil.getWaveDevSettings(impl);
if (waveSettings != null) {
return waveSettings.getImplSettings().get(impl.getId());
}
return null;
}
/**
* Gets {@link WaveDevSettings} associated with an {@link Implementation}. A new .wavedev file is created if it
* doesn't already exist and this is a workspace project.
* @param impl The implementation to use when finding the {@link WaveDevSettings}
* @return waveDevSettings Return the Wave Dev Settings associated with the Implementation that was passed in
* @since 9.0
*/
public static WaveDevSettings getWaveDevSettings(final Implementation impl) {
if (impl == null || impl.eResource() == null) {
return null;
}
final ResourceSet resourceSet = impl.eResource().getResourceSet();
if (resourceSet == null) {
return null;
}
final URI uri = CodegenUtil.getWaveDevSettingsURI(impl.eResource().getURI());
Resource waveDevResource = null;
if (uri.isPlatform()) {
// Create the wavedev file if it doesn't already exist
final IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(uri.toPlatformString(true)));
if (!file.exists()) {
final ResourceSet set = ScaResourceFactoryUtil.createResourceSet();
waveDevResource = set.createResource(uri, CodegenPackage.eCONTENT_TYPE);
WaveDevSettings settings = CodegenFactory.eINSTANCE.createWaveDevSettings();
waveDevResource.getContents().add(settings);
try {
waveDevResource.save(null);
} catch (final IOException e1) {
if (DEBUG.enabled) {
DEBUG.catching("Unable to save resource: " + file, e1);
}
return null;
}
// If the wavedev is in the resource set unload it (it needs to be re-loaded from disk)
waveDevResource = resourceSet.getResource(uri, false);
if (waveDevResource != null && waveDevResource.isLoaded()) {
waveDevResource.unload();
}
}
// Load the wavedev into the resource set
waveDevResource = resourceSet.getResource(uri, true);
} else {
try {
waveDevResource = resourceSet.getResource(uri, true);
} catch (Exception e) {
if (DEBUG.enabled) {
DEBUG.catching("Unable to load wave dev settings: " + uri, e);
}
return null;
}
}
if (waveDevResource != null) {
try {
if (!waveDevResource.isLoaded()) {
waveDevResource.load(null);
}
} catch (final Exception e) {
if (DEBUG.enabled) {
DEBUG.catching("Unable to load wave dev settings: " + uri, e);
}
return null;
}
final Object obj = waveDevResource.getEObject("/");
if (obj instanceof WaveDevSettings) {
final WaveDevSettings settings = (WaveDevSettings) obj;
return settings;
}
}
return null;
}
public static WaveDevSettings loadWaveDevSettings(final SoftPkg softpkg) {
if (softpkg == null || softpkg.eResource() == null) {
return null;
}
final URI settingsUri = CodegenUtil.getWaveDevSettingsURI(softpkg.eResource().getURI());
if ((settingsUri == null) || !settingsUri.isPlatform()) {
return null;
}
final EObjectImpl proxy = (EObjectImpl) EcoreFactory.eINSTANCE.createEObject();
proxy.eSetProxyURI(settingsUri.appendFragment("/"));
final EObject obj = EcoreUtil.resolve(proxy, softpkg);
if (obj instanceof WaveDevSettings) {
return (WaveDevSettings) obj;
}
return null;
}
/**
* @since 5.0
*/
public static WaveDevSettings getWaveDevSettings(final URI fileURI) {
final ResourceSet resourceSet = ScaResourceFactoryUtil.createResourceSet();
final Resource resource = resourceSet.getResource(fileURI, true);
return CodegenUtil.getWaveDevSettings(resource);
}
/**
* @since 6.0
*/
public static String getValidName(final String input) {
if (input == null) return null;
final String name = input.replaceAll("[^A-Za-z0-9_]", "_");
return name;
}
/**
* @since 7.0
*/
public static ITemplateDesc getTemplate(final String templateName, final String codeGenId) {
ITemplateDesc temp = null;
// First, check if the template with the name exists
if (templateName != null) {
temp = RedhawkCodegenActivator.getCodeGeneratorTemplatesRegistry().findTemplate(templateName);
}
// Otherwise, check if the template with the generators name exists
if ((temp == null) && (codeGenId != null)) {
temp = RedhawkCodegenActivator.getCodeGeneratorTemplatesRegistry().findTemplate(codeGenId);
}
return temp;
}
/**
* @since 7.0
*/
public static IPortTemplateDesc getPortTemplate(final String templateId, final String codeGenId) {
IPortTemplateDesc temp = null;
// First, check if the template with the name exists
if (templateId != null) {
temp = RedhawkCodegenActivator.getCodeGeneratorPortTemplatesRegistry().findTemplate(templateId);
}
// Otherwise, check if the template specified by the code generator exists (not required to be specified)
if ((temp == null) && (codeGenId != null)) {
temp = RedhawkCodegenActivator.getCodeGeneratorPortTemplatesRegistry().findTemplate(codeGenId);
}
return temp;
}
/**
* Adds the top level build script generator to a REDHAWK project, if applicable for the project type.
* @param project The project to add the top level build script generator to
* @param progress the progress monitor to use for reporting progress to the user. It is the caller's responsibility
* to call done() on the given monitor. Accepts null, indicating that no progress should be reported and that the
* operation cannot be canceled.
* @throws CoreException A problem occurs adjusting the project description
* @since 7.0
* @deprecated Preserved for 1.8 codegen projects only. Does not apply to 1.9 and future.
*/
@Deprecated
public static void addTopLevelBuildScriptBuilder(final IProject project, final IProgressMonitor progress) throws CoreException {
if (project.hasNature(ScaComponentProjectNature.ID)) {
final IProjectDescription desc = project.getDescription();
final ICommand[] commands = desc.getBuildSpec();
// If the builder is already added, we're done
for (int i = 0; i < commands.length; ++i) {
if (commands[i].getBuilderName().equals(TopLevelBuildScript.ID)) {
return;
}
}
// Add builder to project
final ICommand command = desc.newCommand();
command.setBuilderName(TopLevelBuildScript.ID);
final ICommand[] newCommands = new ICommand[commands.length + 1];
// Add it before other builders.
System.arraycopy(commands, 0, newCommands, 1, commands.length);
newCommands[0] = command;
desc.setBuildSpec(newCommands);
project.setDescription(desc, progress);
}
}
/**
* Removes the builders for the top-level build.sh and spec file.
* @param project The project to modify
* @param progress the progress monitor to use for reporting progress to the user. It is the caller's responsibility
* to call done() on the given monitor. Accepts null, indicating that no progress should be reported and that the
* operation cannot be canceled.
* @throws CoreException
* @since 11.0
*/
public static void removeDeprecatedBuilders(final IProject project, final IProgressMonitor progress) throws CoreException {
if (project.hasNature(ScaComponentProjectNature.ID)) {
final IProjectDescription desc = project.getDescription();
final ICommand[] oldCommands = desc.getBuildSpec();
final List<ICommand> newCommands = new ArrayList<ICommand>();
// Keep everything except the two we don't want
for (ICommand command : oldCommands) {
String builderName = command.getBuilderName();
if (TopLevelBuildScript.ID.equals(builderName) || TopLevelRPMSpec.ID.equals(builderName)) {
continue;
}
newCommands.add(command);
}
// Only set the project description if we've modified it
if (oldCommands.length != newCommands.size()) {
desc.setBuildSpec(newCommands.toArray(new ICommand[newCommands.size()]));
project.setDescription(desc, progress);
}
}
}
/**
* Adds the top level RPM spec file generator to a project.
*
* @param project The project to add the top level RPM spec file generator to
* @param progress the progress monitor to use for reporting progress to the user. It is the caller's responsibility
* to call done() on the given monitor. Accepts null, indicating that no progress should be reported and that the
* operation cannot be canceled.
* @throws CoreException A problem occurs adjusting the project description
* @since 7.0
*/
public static void addTopLevelRPMSpecBuilder(final IProject project, final IProgressMonitor progress) throws CoreException {
final IProjectDescription desc = project.getDescription();
final ICommand[] commands = desc.getBuildSpec();
// If the builder is already added, we're done
for (int i = 0; i < commands.length; ++i) {
if (commands[i].getBuilderName().equals(TopLevelRPMSpec.ID)) {
return;
}
}
// Add builder to project
final ICommand command = desc.newCommand();
command.setBuilderName(TopLevelRPMSpec.ID);
final ICommand[] newCommands = new ICommand[commands.length + 1];
// Add it before other builders.
System.arraycopy(commands, 0, newCommands, 1, commands.length);
newCommands[0] = command;
desc.setBuildSpec(newCommands);
project.setDescription(desc, progress);
}
/**
* This method returns true if the given programming language name can be
* set to a primary implementation. This is currently only valid for C++.
* @param progLangName the name of the programming language to check
* @return true if the programming language can be set to a primary implementation
* @since 9.0
*/
public static boolean canPrimary(final String progLangName) {
return CodegenUtil.CPP.equals(progLangName);
}
/**
* @since 9.0
*/
public static void recreateImplSettings(final SoftPkg softPkg, final WaveDevSettings waveSettings) {
// Recreate the basic settings for each implementation
// This makes assumptions that the defaults are selected for everything
for (final Implementation impl : softPkg.getImplementation()) {
ImplementationSettings settings = waveSettings.getImplSettings().get(impl.getId());
if (settings == null) {
settings = CodegenFactory.eINSTANCE.createImplementationSettings();
}
// Find the code generator if specified, otherwise pick the first one returned by the registry
ICodeGeneratorDescriptor codeGenDesc = null;
final String lang = impl.getProgrammingLanguage().getName();
final ICodeGeneratorDescriptor[] codeGens = RedhawkCodegenActivator.getCodeGeneratorsRegistry().findCodegenByLanguage(lang);
for (final ICodeGeneratorDescriptor codegen : codeGens) {
if (!codegen.notDefaultableGenerator()) {
codeGenDesc = codegen;
}
}
// Proceed if we found one
IScaComponentCodegen generator = null;
if (codeGenDesc != null) {
try {
generator = codeGenDesc.getGenerator();
} catch (final CoreException e) {
// PASS We'll make the user choose a generator
}
}
if (generator != null) {
// Assume that there is <output dir>[/]<name> format for the entrypoint
String name = null;
final String ep = impl.getCode().getEntryPoint();
final int idx = ep.lastIndexOf('/');
if (idx > 0) {
name = ep.substring(idx + 1);
} else if (idx == 0) {
name = softPkg.getName();
}
if (name == null) {
name = "";
}
String outputDir = ep.substring(0, idx);
if (CodegenUtil.PYTHON.equals(lang)) {
final int dotIdx = name.indexOf('.');
name = name.substring(0, (dotIdx > 0) ? dotIdx : name.length()); // SUPPRESS CHECKSTYLE AvoidInline
outputDir = impl.getCode().getLocalFile().getName();
} else if (CodegenUtil.JAVA.equals(lang)) {
final int slhIdx = ep.indexOf('/');
name = ep.substring(0, (slhIdx > 0) ? slhIdx : name.length()); // SUPPRESS CHECKSTYLE AvoidInline
outputDir = impl.getCode().getLocalFile().getName();
}
// Set the generator, name and output directory
if (isEmpty(settings.getGeneratorId())) {
settings.setGeneratorId(generator.getClass().getCanonicalName());
}
// TODO: Determine if there is a way to set the name of the new settings without causing issues
// if (isEmpty(settings.getName())) {
// settings.setName(name);
// }
if (isEmpty(settings.getOutputDir())) {
settings.setOutputDir(outputDir);
}
if (isEmpty(settings.getTemplate())) {
// Find the template if specified, otherwise pick the first selectable and defaultable one returned by the registry
ITemplateDesc templateDesc = null;
final String componentType = softPkg.getDescriptor().getComponent().getComponentType();
final ITemplateDesc[] templates = RedhawkCodegenActivator.getCodeGeneratorTemplatesRegistry().findTemplatesByCodegen(settings.getGeneratorId(), componentType);
for (final ITemplateDesc itd : templates) {
if (itd.isSelectable() && !itd.notDefaultableGenerator()) {
templateDesc = itd;
break;
}
}
// If we found the template, use it
if (templateDesc != null) {
// Set the properties to their default values
for (final IPropertyDescriptor prop : templateDesc.getPropertyDescriptors()) {
final Property p = CodegenFactory.eINSTANCE.createProperty();
p.setId(prop.getKey());
if (CodegenUtil.JAVA.equals(lang) && CodegenUtil.JAVA_PACKAGE.equals(prop.getKey())) {
p.setValue(name);
} else {
p.setValue(prop.getDefaultValue());
}
settings.getProperties().add(p);
}
// Set the template
settings.setTemplate(templateDesc.getId());
}
}
}
// Save the created settings
waveSettings.getImplSettings().put(impl.getId(), settings);
}
}
private static boolean isEmpty(String str) {
return (str == null) || "".equals(str.trim());
}
}