package com.intellij.javascript.flex.maven;
import com.intellij.lang.javascript.flex.FlexBundle;
import com.intellij.lang.javascript.flex.FlexModuleType;
import com.intellij.lang.javascript.flex.projectStructure.FlexBuildConfigurationsExtension;
import com.intellij.lang.javascript.flex.projectStructure.model.BuildConfigurationEntry;
import com.intellij.lang.javascript.flex.projectStructure.model.impl.FlexProjectConfigurationEditor;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.notification.NotificationType;
import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.PairConsumer;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.importing.MavenExtraArtifactType;
import org.jetbrains.idea.maven.importing.MavenImporter;
import org.jetbrains.idea.maven.importing.MavenRootModelAdapter;
import org.jetbrains.idea.maven.model.MavenArtifact;
import org.jetbrains.idea.maven.model.MavenPlugin;
import org.jetbrains.idea.maven.project.*;
import org.jetbrains.idea.maven.server.MavenEmbedderWrapper;
import org.jetbrains.idea.maven.server.NativeMavenProjectHolder;
import org.jetbrains.idea.maven.utils.MavenLog;
import org.jetbrains.idea.maven.utils.MavenProcessCanceledException;
import org.jetbrains.jps.model.java.JavaSourceRootType;
import org.jetbrains.jps.model.module.JpsModuleSourceRootType;
import javax.swing.event.HyperlinkEvent;
import java.util.*;
public class FlexmojosImporter extends MavenImporter implements FlexConfigInformer {
static final String[] SUPPORTED_PACKAGINGS = {"swf", "swc", "air"};
static final String FLEXMOJOS_GROUP_ID = "org.sonatype.flexmojos";
static final String FLEXMOJOS_ARTIFACT_ID = "flexmojos-maven-plugin";
private static final List<String> DEPENDENCY_TYPES_FOR_IMPORT = Arrays.asList("swf", "swc", "ane", "resource-bundle", "rb.swc");
private static final List<String> DEPENDENCY_TYPES_FOR_COMPLETION = Arrays.asList("swf", "swc", "ane", "resource-bundle", "rb.swc");
private Notification myFlexConfigNotification;
// instantiated as an extension
public FlexmojosImporter() {
super(FLEXMOJOS_GROUP_ID, FLEXMOJOS_ARTIFACT_ID);
}
protected FlexmojosImporter(final String pluginGroupID, final String pluginArtifactID) {
super(pluginGroupID, pluginArtifactID);
}
public boolean isApplicable(MavenProject mavenProject) {
return ArrayUtil.contains(mavenProject.getPackaging(), SUPPORTED_PACKAGINGS) && super.isApplicable(mavenProject);
}
@NotNull
public ModuleType getModuleType() {
return FlexModuleType.getInstance();
}
public void getSupportedPackagings(Collection<String> result) {
Collections.addAll(result, SUPPORTED_PACKAGINGS);
}
public void getSupportedDependencyTypes(Collection<String> result, SupportedRequestType type) {
result.addAll(type == SupportedRequestType.FOR_COMPLETION ? DEPENDENCY_TYPES_FOR_COMPLETION : DEPENDENCY_TYPES_FOR_IMPORT);
}
public void getSupportedDependencyScopes(Collection<String> result) {
Collections.addAll(result, "merged", "internal", "external", "caching", "rsl");
}
public void resolve(Project project, MavenProject mavenProject, NativeMavenProjectHolder nativeMavenProject,
MavenEmbedderWrapper embedder, ResolveContext context) throws MavenProcessCanceledException {
final MavenPlugin plugin = getFlexmojosPlugin(mavenProject);
final String version = plugin.getVersion();
if (version != null && StringUtil.compareVersionNumbers(version, "4") < 0) {
embedder.resolvePlugin(plugin, mavenProject.getRemoteRepositories(), nativeMavenProject, true);
}
}
@NotNull
private MavenPlugin getFlexmojosPlugin(final MavenProject mavenProject) {
final MavenPlugin plugin = mavenProject.findPlugin(myPluginGroupID, myPluginArtifactID);
assert plugin != null;
return plugin;
}
static boolean isFlexmojos3(final MavenPlugin plugin) {
final String version = plugin.getVersion();
return version != null && version.startsWith("3.");
}
@Nullable
public Pair<String, String> getExtraArtifactClassifierAndExtension(MavenArtifact artifact, MavenExtraArtifactType type) {
if (!DEPENDENCY_TYPES_FOR_IMPORT.contains(artifact.getType())) return null;
if (type == MavenExtraArtifactType.DOCS) return Pair.create("asdoc", "zip");
return null;
}
static boolean isFlexApp(MavenProject project) {
return "swf".equals(project.getPackaging()) || "air".equals(project.getPackaging());
}
public void preProcess(Module module, MavenProject mavenProject, MavenProjectChanges changes,
IdeModifiableModelsProvider modifiableModelsProvider) {
}
public void process(final IdeModifiableModelsProvider modelsProvider,
final Module module,
final MavenRootModelAdapter modelAdapter,
final MavenProjectsTree mavenTree,
final MavenProject mavenProject,
final MavenProjectChanges changes,
final Map<MavenProject, String> mavenProjectToModuleName,
final List<MavenProjectsProcessorTask> postTasks) {
expireNotification();
final FlexProjectConfigurationEditor currentEditor = FlexBuildConfigurationsExtension.getInstance().getConfigurator().getConfigEditor();
final boolean needToCommit = currentEditor == null;
final LibraryTable.ModifiableModel projectLibrariesModel = modelsProvider.getModifiableProjectLibrariesModel();
final Map<Module, ModifiableRootModel> moduleToModifiableModel = Collections.singletonMap(module, modelAdapter.getRootModel());
final FlexProjectConfigurationEditor flexEditor =
currentEditor != null
? currentEditor
: new FlexProjectConfigurationEditor(module.getProject(),
FlexProjectConfigurationEditor
.createModelProvider(moduleToModifiableModel, projectLibrariesModel, null)) {
@Nullable
protected Module findModuleWithBC(final BuildConfigurationEntry bcEntry) {
// don't check BC presence here because corresponding BC may appear later in next import cycle
return modelAdapter.findModuleByName(bcEntry.getModuleName());
}
};
final MavenPlugin flexmojosPlugin = getFlexmojosPlugin(mavenProject);
final Flexmojos3Configurator configurator =
StringUtil.compareVersionNumbers(flexmojosPlugin.getVersion(), "5") >= 0
? new Flexmojos5Configurator(module, modelsProvider, flexEditor, mavenTree, mavenProjectToModuleName, mavenProject, flexmojosPlugin,
getCompiledLocales(mavenProject), getRuntimeLocales(mavenProject), this)
: StringUtil.compareVersionNumbers(flexmojosPlugin.getVersion(), "4") >= 0
? new Flexmojos4Configurator(module, modelsProvider, flexEditor, mavenTree, mavenProjectToModuleName, mavenProject, flexmojosPlugin,
getCompiledLocales(mavenProject), getRuntimeLocales(mavenProject), this)
: new Flexmojos3Configurator(module, modelsProvider, flexEditor, mavenTree, mavenProjectToModuleName, mavenProject, flexmojosPlugin,
getCompiledLocales(mavenProject), getRuntimeLocales(mavenProject), this);
configurator.configureAndAppendTasks(postTasks);
if (needToCommit) {
try {
flexEditor.commit();
}
catch (ConfigurationException e) {
MavenLog.LOG.error(e); // can't happen
}
}
}
@Override
public void collectSourceRoots(MavenProject mavenProject, PairConsumer<String, JpsModuleSourceRootType<?>> result) {
final String localesDir = findConfigValue(mavenProject, "resourceBundlePath", "src/main/locales/{locale}");
assert localesDir != null;
for (String locale : getCompiledLocales(mavenProject)) {
result.consume(localesDir.replace("{locale}", locale), JavaSourceRootType.SOURCE);
}
for (String locale : getRuntimeLocales(mavenProject)) {
result.consume(localesDir.replace("{locale}", locale), JavaSourceRootType.SOURCE);
}
}
private List<String> getRuntimeLocales(final MavenProject mavenProject) {
final String elementName = isFlexmojos3(getFlexmojosPlugin(mavenProject)) ? "runtimeLocales" : "localesRuntime";
final Element localesElement = getConfig(mavenProject, elementName);
return localesElement == null ? Collections.emptyList() : getChildrenValues(localesElement);
}
private List<String> getCompiledLocales(final MavenProject mavenProject) {
final boolean flexmojos3 = isFlexmojos3(getFlexmojosPlugin(mavenProject));
final String elementName = flexmojos3 ? "compiledLocales" : "localesCompiled";
Element localesElement = getConfig(mavenProject, elementName);
if (flexmojos3 && localesElement == null) localesElement = getConfig(mavenProject, "locales");
if (localesElement != null) {
return getChildrenValues(localesElement);
}
if (isFlexApp(mavenProject)) {
final String defaultLocale = getDefaultLocale(mavenProject);
if (defaultLocale != null) {
return Collections.singletonList(defaultLocale);
}
}
return Collections.emptyList();
}
private static List<String> getChildrenValues(final Element element) {
final List<String> result = new ArrayList<>();
//noinspection unchecked
for (Element child : (Iterable<Element>)element.getChildren()) {
final String childValue = child.getTextNormalize();
if (!StringUtil.isEmptyOrSpaces(childValue)) {
result.add(childValue);
}
}
return result;
}
@Nullable
private String getDefaultLocale(final MavenProject mavenProject) {
return "true".equals(findConfigValue(mavenProject, "useDefaultLocale", "true"))
? findConfigValue(mavenProject, "defaultLocale", "en_US")
: null;
}
public synchronized void showFlexConfigWarningIfNeeded(final Project project) {
if (myFlexConfigNotification != null) return; // already shown
doShowFlexConfigWarning(project);
}
private synchronized void doShowFlexConfigWarning(final Project project) {
final NotificationListener listener = new NotificationListener() {
public void hyperlinkUpdate(@NotNull final Notification notification, @NotNull final HyperlinkEvent event) {
Messages
.showWarningDialog(project, FlexBundle.message("flexmojos.warning.detailed"), FlexBundle.message("flexmojos.project.import"));
notification.expire();
}
};
myFlexConfigNotification =
new Notification("Maven", FlexBundle.message("flexmojos.project.import"), FlexBundle.message("flexmojos.warning.short"),
NotificationType.WARNING, listener);
myFlexConfigNotification.notify(project);
}
protected synchronized void expireNotification() {
if (myFlexConfigNotification != null && !myFlexConfigNotification.isExpired()) {
myFlexConfigNotification.expire();
}
myFlexConfigNotification = null;
}
public static String getOutputFilePath(final MavenProject mavenProject) {
MavenPlugin flexmojosPlugin = mavenProject.findPlugin(FLEXMOJOS_GROUP_ID, FLEXMOJOS_ARTIFACT_ID);
if (flexmojosPlugin == null) flexmojosPlugin = mavenProject.findPlugin(Flexmojos5Importer.FLEXMOJOS_5_GROUP_ID, FLEXMOJOS_ARTIFACT_ID);
final Element configurationElement = flexmojosPlugin == null ? null : flexmojosPlugin.getConfigurationElement();
final String overriddenTargetFilePath =
configurationElement == null || StringUtil.compareVersionNumbers(flexmojosPlugin.getVersion(), "4") >= 0
? null
: configurationElement.getChildTextNormalize("output", configurationElement.getNamespace());
if (overriddenTargetFilePath != null && !overriddenTargetFilePath.isEmpty()) {
return FileUtil.isAbsolute(overriddenTargetFilePath)
? FileUtil.toSystemIndependentName(overriddenTargetFilePath)
: FileUtil.toSystemIndependentName(mavenProject.getDirectory() + "/" + overriddenTargetFilePath);
}
final String classifier =
configurationElement == null ? null : configurationElement.getChildTextNormalize("classifier", configurationElement.getNamespace());
final String suffix = classifier == null ? "" : "-" + classifier;
final String fileExtension = "swc".equals(mavenProject.getPackaging()) ? "swc" : "swf";
return FileUtil.toSystemIndependentName(mavenProject.getBuildDirectory())
+ "/" + mavenProject.getFinalName() + suffix + "." + fileExtension;
}
}