diff --git a/data-weave-plugin/src/main/gen/org/mule/tooling/lang/dw/parser/psi/WeaveDocument.java b/data-weave-plugin/src/main/gen/org/mule/tooling/lang/dw/parser/psi/WeaveDocument.java index c6fcfe33..23b49771 100644 --- a/data-weave-plugin/src/main/gen/org/mule/tooling/lang/dw/parser/psi/WeaveDocument.java +++ b/data-weave-plugin/src/main/gen/org/mule/tooling/lang/dw/parser/psi/WeaveDocument.java @@ -31,4 +31,6 @@ public interface WeaveDocument extends NavigatablePsiElement, PsiQualifiedNamedE Icon getElementIcon(int flags); + @Nullable WeaveOutputDirective getOutput(); + } diff --git a/data-weave-plugin/src/main/gen/org/mule/tooling/lang/dw/parser/psi/impl/WeaveDocumentImpl.java b/data-weave-plugin/src/main/gen/org/mule/tooling/lang/dw/parser/psi/impl/WeaveDocumentImpl.java index 3f9d74a8..1c53fb0f 100644 --- a/data-weave-plugin/src/main/gen/org/mule/tooling/lang/dw/parser/psi/impl/WeaveDocumentImpl.java +++ b/data-weave-plugin/src/main/gen/org/mule/tooling/lang/dw/parser/psi/impl/WeaveDocumentImpl.java @@ -76,4 +76,9 @@ public Icon getElementIcon(int flags) { return WeavePsiImplUtils.getElementIcon(this, flags); } + @Override + public @Nullable WeaveOutputDirective getOutput() { + return WeavePsiImplUtils.getOutput(this); + } + } diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/WeaveConstants.java b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/WeaveConstants.java index 40c3c237..d869c0dd 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/WeaveConstants.java +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/WeaveConstants.java @@ -1,11 +1,11 @@ package org.mule.tooling.lang.dw; public class WeaveConstants { - public static final int MODIFICATIONS_DELAY = 500; + public static final int MODIFICATIONS_DELAY = 1000; public static final int SERVER_TIMEOUT = 1000; public static final int LONG_TIMEOUT = 60 * 1000; //two seconds - public static final String INTEGRATION_TEST_FOLDER_NAME = "resources"; - public static final String MODULE_INTEGRATION_TEST_FOLDER_NAME = "dw"; + public static final String RESOURCES_FOLDER = "resources"; + public static final String TEST_FOLDER = "dw"; public static final String TEST_BASE_FOLDER_NAME = "test"; public static final String NO_SCENARIO = "No scenario"; public static final String DEFAULT_SCENARIO_NAME = "default_scenario"; diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/develop_view/DevelopToolingWindowFactory.java b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/develop_view/DevelopToolingWindowFactory.java index 9d16a4e6..2f60bf4e 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/develop_view/DevelopToolingWindowFactory.java +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/develop_view/DevelopToolingWindowFactory.java @@ -9,10 +9,10 @@ public class DevelopToolingWindowFactory implements ToolWindowFactory { @Override public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) { - toolWindow.getContentManager().addContent(ContentFactory.SERVICE.getInstance().createContent(new AstGraphToolingWindowPanel(project), "AST", false)); - toolWindow.getContentManager().addContent(ContentFactory.SERVICE.getInstance().createContent(new VariableGraphToolingWindowPanel(project), "Scope Graph", false)); - toolWindow.getContentManager().addContent(ContentFactory.SERVICE.getInstance().createContent(new TypeGraphToolingWindowPanel(project), "Type Graph", false)); - toolWindow.getContentManager().addContent(ContentFactory.SERVICE.getInstance().createContent(new DependencyGraphToolingWindowPanel(project), "Dependency Graph", false)); + toolWindow.getContentManager().addContent(ContentFactory.getInstance().createContent(new AstGraphToolingWindowPanel(project), "AST", false)); + toolWindow.getContentManager().addContent(ContentFactory.getInstance().createContent(new VariableGraphToolingWindowPanel(project), "Scope Graph", false)); + toolWindow.getContentManager().addContent(ContentFactory.getInstance().createContent(new TypeGraphToolingWindowPanel(project), "Type Graph", false)); + toolWindow.getContentManager().addContent(ContentFactory.getInstance().createContent(new DependencyGraphToolingWindowPanel(project), "Dependency Graph", false)); } @Override diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/launcher/configuration/ui/test/WeaveIntegrationTestConfiguration.java b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/launcher/configuration/ui/test/WeaveIntegrationTestConfiguration.java index 89526a71..712a125a 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/launcher/configuration/ui/test/WeaveIntegrationTestConfiguration.java +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/launcher/configuration/ui/test/WeaveIntegrationTestConfiguration.java @@ -100,11 +100,11 @@ public void checkConfiguration() throws RuntimeConfigurationException { @Override public List getTests() { final ArrayList tests = new ArrayList<>(); - if (WeaveUtils.getDWITFolder(getModule()) != null && kind.shouldRunDWIT()) { + if (WeaveUtils.getDWTestResourceFolder(getModule()) != null && kind.shouldRunDWIT()) { tests.add("dw::test::DWITTestRunner"); } - if (WeaveUtils.getDWMITFolder(getModule()) != null && kind.shouldRunDWMIT()) { + if (WeaveUtils.getDWTestFolder(getModule()) != null && kind.shouldRunDWMIT()) { tests.add("dw::test::DWMITTestRunner"); } @@ -122,12 +122,12 @@ public boolean isUpdateResult() { @Override public void addAdditionalVMParameters(JavaParameters javaParams) { - final VirtualFile dwitFolder = WeaveUtils.getDWITFolder(getModule()); + final VirtualFile dwitFolder = WeaveUtils.getDWTestResourceFolder(getModule()); if (dwitFolder != null && dwitFolder.getCanonicalPath() != null) { javaParams.getVMParametersList().addProperty("dwitDir", dwitFolder.getCanonicalPath()); } - VirtualFile dwmitFolder = WeaveUtils.getDWMITFolder(getModule()); + VirtualFile dwmitFolder = WeaveUtils.getDWTestFolder(getModule()); if (dwmitFolder != null && dwmitFolder.getCanonicalPath() != null) { javaParams.getVMParametersList().addProperty("dwmitDir", dwmitFolder.getCanonicalPath()); } diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/Weave.bnf b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/Weave.bnf index c77cbc2f..ea49de2c 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/Weave.bnf +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/Weave.bnf @@ -115,7 +115,7 @@ root ::= Document Document ::= Header ('---' Body) ? | Body { implements=["com.intellij.psi.NavigatablePsiElement" "com.intellij.psi.PsiQualifiedNamedElement"] - methods=[getPresentation getQualifiedName getName setName isMappingDocument isModuleDocument getElementIcon] + methods=[getPresentation getQualifiedName getName setName isMappingDocument isModuleDocument getElementIcon getOutput] } Header::= (Directive)+ diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/psi/WeaveElementFactory.java b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/psi/WeaveElementFactory.java index 07f279fd..cddbec1d 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/psi/WeaveElementFactory.java +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/psi/WeaveElementFactory.java @@ -4,8 +4,10 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileFactory; import com.intellij.psi.PsiParserFacade; +import com.intellij.psi.util.PsiTreeUtil; import org.jetbrains.annotations.NotNull; import org.mule.tooling.lang.dw.WeaveFileType; import org.mule.tooling.lang.dw.refactor.utils.RefactorUtils; @@ -51,8 +53,9 @@ public static WeaveHeader createHeader(Project project) { public static WeaveDocument createFile(Project project, String text) { String name = "dummy.dwl"; - return (WeaveDocument) PsiFileFactory.getInstance(project). - createFileFromText(name, WeaveFileType.getInstance(), text).getChildren()[0]; + PsiFile fileFromText = PsiFileFactory.getInstance(project). + createFileFromText(name, WeaveFileType.getInstance(), text); + return PsiTreeUtil.findChildOfType(fileFromText, WeaveDocument.class); } public static WeaveDoExpression createDoBlock(Project project, PsiElement value) { @@ -67,10 +70,16 @@ public static PsiElement createBlockSeparator(Project project) { @NotNull public static PsiElement createNewLine(Project project) { - PsiParserFacade helper = PsiParserFacade.SERVICE.getInstance(project); + PsiParserFacade helper = PsiParserFacade.getInstance(project); return helper.createWhiteSpaceFromText("\n"); } + @NotNull + public static WeaveExpression createExpression(Project project, String text) { + WeaveDocument file = createFile(project, text); + return file.getBody().getExpression(); + } + @NotNull public static WeaveFunctionCallExpression createFunctionCall(Project project, String functionName, List argNames) { WeaveDocument file = createFile(project, functionName + "(" + StringUtil.join(argNames, ",") + ")"); diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/psi/WeavePsiImplUtils.java b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/psi/WeavePsiImplUtils.java index e4d93edc..f56fcfa8 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/psi/WeavePsiImplUtils.java +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/psi/WeavePsiImplUtils.java @@ -49,6 +49,11 @@ public static Icon getElementIcon(WeaveDocument document, final int flags) { return document.isMappingDocument() ? WeaveIcons.DataWeaveMappingIcon : WeaveIcons.DataWeaveModuleIcon; } + public static @Nullable WeaveOutputDirective getOutput(WeaveDocument weaveDocument) { + return PsiTreeUtil.findChildOfType(weaveDocument.getHeader(), WeaveOutputDirective.class); + } + + public static Icon getElementIcon(WeaveFunctionDefinition functionDefinition, final int flags) { return PlatformIcons.FUNCTION_ICON; } diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/psi/WeavePsiUtils.java b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/psi/WeavePsiUtils.java index c06b5fb2..328af325 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/psi/WeavePsiUtils.java +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/parser/psi/WeavePsiUtils.java @@ -209,17 +209,16 @@ public static Collection getInputTypes(WeaveDocument weaveD return PsiTreeUtil.findChildrenOfAnyType(weaveDocument.getHeader(), WeaveInputDirective.class); } + @Nullable public static WeaveDocument getWeaveDocument(PsiFile psiFile) { if (psiFile == null) { return null; } PsiElement[] children = psiFile.getChildren(); - if (children.length > 0) { - for (PsiElement child : children) { - if (child instanceof WeaveDocument) { - return (WeaveDocument) child; - } + for (PsiElement child : children) { + if (child instanceof WeaveDocument) { + return (WeaveDocument) child; } } return null; diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/OutputComponent.java b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/OutputComponent.java index 53dad30d..aefdcb2c 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/OutputComponent.java +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/OutputComponent.java @@ -90,6 +90,7 @@ private JComponent createOutputPanel() { public DefaultActionGroup createActions() { DefaultActionGroup group = new DefaultActionGroup(); group.add(new SaveOutputAction()); + group.add(new CreateTestAction()); group.add(showDiffAction); return group; } @@ -139,6 +140,7 @@ public void onPreviewResult(PreviewExecutedSuccessfulEvent result, VirtualFile e } } else if (extension != null) { setDocumentContent(content); + show(EDITOR_PANEL); } else { changePanel(new MessagePanel("Unable to render the output for extension " + extension), messagePanel, MESSAGE_PANEL); } @@ -189,6 +191,37 @@ public void close() { this.currentFile = null; } + private class CreateTestAction extends AnAction { + + + public CreateTestAction() { + super("Create Mapping Test", "Create mapping test", AllIcons.Nodes.Test); + } + + @Override + public @NotNull ActionUpdateThread getActionUpdateThread() { + return ActionUpdateThread.BGT; + } + + @Override + public void update(@NotNull AnActionEvent e) { + super.update(e); + e.getPresentation().setEnabled(outputEditor != null); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + WeaveDocument document = WeavePsiUtils.getWeaveDocument(currentFile); + WeaveRuntimeService manager = WeaveRuntimeService.getInstance(myProject); + Scenario currentScenario = manager.getCurrentScenarioFor(document); + if (currentScenario != null) { + manager.createTest(currentFile, currentScenario); + } + } + + + } + private class SaveOutputAction extends AnAction { @@ -198,7 +231,7 @@ public SaveOutputAction() { @Override public @NotNull ActionUpdateThread getActionUpdateThread() { - return ActionUpdateThread.EDT; + return ActionUpdateThread.BGT; } @Override @@ -211,7 +244,7 @@ public void update(@NotNull AnActionEvent e) { public void actionPerformed(@NotNull AnActionEvent e) { Scenario scenario = getOrCreateScenario(); String ext = outputType.getDefaultExtension(); - scenario.addOutput("out." + ext, outputDocument.getText(), myProject); + scenario.addOutput(Scenario.OUTPUT_FILE_NAME + "." + ext, outputDocument.getText(), myProject); } private Scenario getOrCreateScenario() { diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/PreviewToolWindowPanel.java b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/PreviewToolWindowPanel.java index 6f706ce8..ee73aa9f 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/PreviewToolWindowPanel.java +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/PreviewToolWindowPanel.java @@ -1,6 +1,5 @@ package org.mule.tooling.lang.dw.preview; -import com.intellij.ProjectTopics; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ReadAction; @@ -122,9 +121,9 @@ public void selectionChanged(@NotNull FileEditorManagerEvent e) { } connection[0] = myProject.getMessageBus().connect(PreviewToolWindowPanel.this); - connection[0].subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootListener() { + connection[0].subscribe(ModuleRootListener.TOPIC, new ModuleRootListener() { @Override - public void rootsChanged(ModuleRootEvent event) { + public void rootsChanged(@NotNull ModuleRootEvent event) { dependenciesChanges.submit(() -> { if (agentRuntimeManager.isWeaveRuntimeInstalled()) { showFile(e); diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/WeavePreviewComponent.java b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/WeavePreviewComponent.java index 9366520b..cf7fdc80 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/WeavePreviewComponent.java +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/WeavePreviewComponent.java @@ -53,7 +53,7 @@ public class WeavePreviewComponent implements Disposable { private final Project myProject; private PsiFile currentFile; - private boolean runOnChange = true; + private boolean runOnChange = false; private final Alarm myDocumentAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, this); private PreviewToolWindowFactory.NameChanger nameChanger; @@ -156,7 +156,7 @@ public void setSelected(@NotNull AnActionEvent e, boolean state) { group.add(new AnAction("Run", "Execute", AllIcons.RunConfigurations.TestState.Run) { @Override public @NotNull ActionUpdateThread getActionUpdateThread() { - return ActionUpdateThread.EDT; + return ActionUpdateThread.BGT; } @Override @@ -169,6 +169,24 @@ public void update(@NotNull AnActionEvent e) { e.getPresentation().setEnabled(runAvailable()); } }); + + group.add(new AnAction("Restart Agent", "Restart agent", AllIcons.Actions.Refresh) { + @Override + public @NotNull ActionUpdateThread getActionUpdateThread() { + return ActionUpdateThread.BGT; + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + final WeaveAgentService agentComponent = WeaveAgentService.getInstance(myProject); + agentComponent.scheduleRestart(); + } + + @Override + public void update(@NotNull AnActionEvent e) { + e.getPresentation().setEnabled(runAvailable()); + } + }); group.add(new ToggleAction("Run on Editor Changes", "Run on editor changes", AllIcons.Ide.IncomingChangesOn) { @Override public @NotNull ActionUpdateThread getActionUpdateThread() { diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/ui/AddScenarioDialog.java b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/ui/AddScenarioDialog.java index 4510d7d0..7bd34213 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/ui/AddScenarioDialog.java +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/preview/ui/AddScenarioDialog.java @@ -39,7 +39,7 @@ public void keyReleased(KeyEvent e) { private void validateInputName() { String inputName = getInputName(); - VirtualFile dwitFolder = manager.findOrCreateMappingTestFolder(currentFile); + VirtualFile dwitFolder = manager.findOrCreateMappingResourceFolder(currentFile); if (dwitFolder != null) { VirtualFile child = dwitFolder.findChild(inputName); if (child != null) { diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/refactor/IntroduceFunctionHandler.java b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/refactor/IntroduceFunctionHandler.java index 9be6c3a2..3b220959 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/refactor/IntroduceFunctionHandler.java +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/refactor/IntroduceFunctionHandler.java @@ -159,7 +159,7 @@ public void doIntroduceFunction(@NotNull Project project, PsiFile psiFile, PsiEl WeaveFqnIdentifier elementOfClassAtRange = PsiTreeUtil.findElementOfClassAtRange(psiFile, startOffset, endOffset, WeaveFqnIdentifier.class); return new RenameVariable(elementOfClassAtRange, arg.getParamName()); })); - }).collect(Collectors.toList()); + }).toList(); WeaveRefactorFunctionData finalWeaveRefactorFunctionData = weaveRefactorFunctionData; simpleRefactor(() -> { diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/service/Scenario.java b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/service/Scenario.java index 682ade7b..c801a996 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/service/Scenario.java +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/service/Scenario.java @@ -3,6 +3,7 @@ import com.intellij.navigation.ItemPresentation; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.WriteAction; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; @@ -22,190 +23,189 @@ public class Scenario implements ItemPresentation { - public static final String INPUTS_FOLDER = "inputs"; - public static final String OUTPUT_FILE_NAME = "out"; - private VirtualFile scenario; - - public Scenario(@NotNull VirtualFile scenario) { - this.scenario = scenario; - } - - @NotNull - public String getPath() { - return this.scenario.getPath(); - } - - @Nullable - public VirtualFile getInputs() { - if (!isValid(scenario)) { - return null; - } - return scenario.findChild(INPUTS_FOLDER); - } - - public Optional getOutput() { - return getChildByName(scenario, OUTPUT_FILE_NAME); - } - - private Optional getChildByName(VirtualFile parent, String nameWithoutExt) { - if (!isValid(parent)) return Optional.empty(); - VirtualFile[] children = parent.getChildren(); - return Arrays.stream(children).filter(x -> x.getNameWithoutExtension().equals(nameWithoutExt)).findAny(); - } - - public boolean containsInput(String inputName) { - VirtualFile inputs = getInputs(); - if (inputs == null) { - return false; - } - return inputs.findChild(inputName) != null; - } - - @Nullable - public VirtualFile addInput(String fileName) { - try { - VirtualFile inputs = getOrCreateInputs(); - String baseName = FilenameUtils.getBaseName(fileName); - String extension = FilenameUtils.getExtension(fileName); - if (baseName.contains(".")) { - String[] split = baseName.split("\\."); - List folders = Arrays.asList(split).subList(0, split.length - 1); - VirtualFile childDirectory = inputs; - for (String folder : folders) { - VirtualFile child = childDirectory.findChild(folder); - if (child == null) { - childDirectory = childDirectory.createChildDirectory(this, folder); - } else { - childDirectory = child; - } + private static final Logger LOG = Logger.getInstance(Scenario.class); + + public static final String INPUTS_FOLDER = "inputs"; + public static final String OUTPUT_FILE_NAME = "out"; + private VirtualFile scenario; + + public Scenario(@NotNull VirtualFile scenario) { + this.scenario = scenario; + } + + @NotNull + public String getPath() { + return this.scenario.getPath(); + } + + @Nullable + public VirtualFile getInputs() { + if (!isValid(scenario)) { + return null; + } + return scenario.findChild(INPUTS_FOLDER); + } + + public Optional getOutput() { + return getChildByName(scenario, OUTPUT_FILE_NAME); + } + + private Optional getChildByName(VirtualFile parent, String nameWithoutExt) { + if (!isValid(parent)) return Optional.empty(); + final VirtualFile[] children = parent.getChildren(); + return Arrays.stream(children).filter(x -> x.getNameWithoutExtension().equals(nameWithoutExt)).findAny(); + } + + public boolean containsInput(String inputName) { + VirtualFile inputs = getInputs(); + if (inputs == null) { + return false; } - return childDirectory.createChildData(this, split[split.length - 1] + "." + extension); - } else { - return inputs.createChildData(this, fileName); - } - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } - - @NotNull - private VirtualFile getOrCreateInputs() throws IOException { - VirtualFile inputs = getInputs(); - if (!isValid(inputs)) { - inputs = scenario.createChildDirectory(this, INPUTS_FOLDER); - } - return inputs; - } - - @Nullable - public VirtualFile addOutput(String fileName, String content, Project project) { - if (!isValid(scenario)) { - return null; - } - VirtualFile file = scenario.findChild(fileName); - if (file == null) { - return createFile(fileName, content); - } - - //TODO: maybe instead of yes/no show a preview of before/after - if (promptOverwrite(project)) { - setFileContent(file, content); - } - return file; - } - - private Boolean promptOverwrite(Project project) { - Ref overwriteRef = Ref.create(); - ApplicationManager.getApplication().invokeAndWait(() -> { - YesNoDialog dialog = new YesNoDialog("Overwrite file", "Do you want to overwrite the existing expected output?", null, project); - overwriteRef.set(dialog.showAndGet()); - }); - return overwriteRef.get(); - } - - private VirtualFile createFile(String fileName, String content) { - try { - return WriteAction.compute(() -> { - VirtualFile newFile = scenario.createChildData(this, fileName); - setFileContent(newFile, content); - return newFile; - }); - } catch (IOException e) { - e.printStackTrace(); - return null; - } - } - - private void setFileContent(VirtualFile file, String content) { - WriteAction.run(() -> { - if (file == null) { - return; - } - if (!file.isValid()) { - System.out.println("Input file is invalid. " + file.toString()); - return; - } - - try { - file.setBinaryContent(content.getBytes()); - } catch (Exception ex) { - ex.printStackTrace(); - } - }); - } - - @Nullable - public VirtualFile getExpected() { - if (!isValid(scenario)) { - return null; - } - VirtualFile[] children = scenario.getChildren(); - return Arrays.stream(children).filter((vf) -> vf.getNameWithoutExtension().equals("out")).findFirst().orElse(null); - } - - - public String getName() { - return scenario.getName(); - } - - @Nullable - @Override - public String getPresentableText() { - return StringUtil.capitalizeWords(scenario.getName(), "_", false, false); - } - - @Nullable - @Override - public String getLocationString() { - return scenario.getPresentableUrl(); - } - - @Nullable - @Override - public Icon getIcon(boolean unused) { - return null; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Scenario scenario1 = (Scenario) o; - return Objects.equals(scenario, scenario1.scenario); - } - - private boolean isValid(VirtualFile file) { - return file != null && file.isValid(); - } - - @Override - public int hashCode() { - - return Objects.hash(scenario); - } - - public boolean isValid() { - return scenario.isValid(); - } + return inputs.findChild(inputName) != null; + } + + @Nullable + public VirtualFile addInput(String fileName) { + try { + VirtualFile inputs = getOrCreateInputs(); + String baseName = FilenameUtils.getBaseName(fileName); + String extension = FilenameUtils.getExtension(fileName); + if (baseName.contains(".")) { + String[] split = baseName.split("\\."); + List folders = Arrays.asList(split).subList(0, split.length - 1); + VirtualFile childDirectory = inputs; + for (String folder : folders) { + VirtualFile child = childDirectory.findChild(folder); + if (child == null) { + childDirectory = childDirectory.createChildDirectory(this, folder); + } else { + childDirectory = child; + } + } + return childDirectory.createChildData(this, split[split.length - 1] + "." + extension); + } else { + return inputs.createChildData(this, fileName); + } + } catch (IOException e) { + LOG.error(e); + return null; + } + } + + @NotNull + private VirtualFile getOrCreateInputs() throws IOException { + VirtualFile inputs = getInputs(); + if (!isValid(inputs)) { + inputs = scenario.createChildDirectory(this, INPUTS_FOLDER); + } + return inputs; + } + + @Nullable + public VirtualFile addOutput(String fileName, String content, Project project) { + if (!isValid(scenario)) { + return null; + } + VirtualFile file = scenario.findChild(fileName); + if (file == null) { + return createFile(fileName, content); + } + if (promptOverwrite(project)) { + setFileContent(file, content); + } + return file; + } + + private Boolean promptOverwrite(Project project) { + Ref overwriteRef = Ref.create(); + ApplicationManager.getApplication().invokeAndWait(() -> { + YesNoDialog dialog = new YesNoDialog("Overwrite file", "Do you want to overwrite the existing expected output?", null, project); + overwriteRef.set(dialog.showAndGet()); + }); + return overwriteRef.get(); + } + + private VirtualFile createFile(String fileName, String content) { + try { + return WriteAction.compute(() -> { + VirtualFile newFile = scenario.createChildData(this, fileName); + setFileContent(newFile, content); + return newFile; + }); + } catch (IOException e) { + LOG.error(e); + return null; + } + } + + private void setFileContent(VirtualFile file, String content) { + WriteAction.run(() -> { + if (file == null) { + return; + } + if (!file.isValid()) { + LOG.error("Input file is invalid. " + file.toString()); + return; + } + try { + file.setBinaryContent(content.getBytes()); + } catch (Exception ex) { + LOG.error(ex); + } + }); + } + + @Nullable + public VirtualFile getExpected() { + if (!isValid(scenario)) { + return null; + } + VirtualFile[] children = scenario.getChildren(); + return Arrays.stream(children).filter((vf) -> vf.getNameWithoutExtension().equals("out")).findFirst().orElse(null); + } + + + public String getName() { + return scenario.getName(); + } + + @Nullable + @Override + public String getPresentableText() { + return StringUtil.capitalizeWords(scenario.getName(), "_", false, false); + } + + @Nullable + @Override + public String getLocationString() { + return scenario.getPresentableUrl(); + } + + @Nullable + @Override + public Icon getIcon(boolean unused) { + return null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Scenario scenario1 = (Scenario) o; + return Objects.equals(scenario, scenario1.scenario); + } + + private boolean isValid(VirtualFile file) { + return file != null && file.isValid(); + } + + @Override + public int hashCode() { + + return Objects.hash(scenario); + } + + public boolean isValid() { + return scenario.isValid(); + } } diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/service/WeaveRuntimeService.java b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/service/WeaveRuntimeService.java index 8b741122..0024d2a1 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/service/WeaveRuntimeService.java +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/service/WeaveRuntimeService.java @@ -1,5 +1,8 @@ package org.mule.tooling.lang.dw.service; +import com.intellij.notification.Notification; +import com.intellij.notification.NotificationType; +import com.intellij.notification.Notifications; import com.intellij.openapi.Disposable; import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; @@ -27,8 +30,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.mule.tooling.lang.dw.WeaveConstants; -import org.mule.tooling.lang.dw.parser.psi.WeaveDocument; -import org.mule.tooling.lang.dw.parser.psi.WeavePsiUtils; +import org.mule.tooling.lang.dw.parser.psi.*; import org.mule.tooling.lang.dw.service.agent.WeaveAgentService; import org.mule.tooling.lang.dw.util.ModuleUtils; import org.mule.tooling.lang.dw.util.WeaveUtils; @@ -40,14 +42,16 @@ import scala.Tuple2; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; -import java.util.stream.Collectors; +import static com.intellij.openapi.command.WriteCommandAction.runWriteCommandAction; +import static java.util.Optional.ofNullable; import static org.mule.tooling.lang.dw.parser.psi.WeavePsiUtils.getWeaveDocument; @Service(Service.Level.PROJECT) @@ -56,7 +60,7 @@ public final class WeaveRuntimeService implements Disposable { private static final Logger LOG = Logger.getInstance(WeaveRuntimeService.class); private Map selectedScenariosByMapping = new HashMap<>(); - private Map implicitInputTypes = new ConcurrentHashMap<>(); + private Map implicitInputTypes = new ConcurrentHashMap<>(); private Map expectedOutputType = new HashMap<>(); private Map dwitFolders = new HashMap<>(); @@ -127,18 +131,14 @@ private void onFileChanged(VirtualFile modifiedFile) { return; } final Application app = ApplicationManager.getApplication(); - ReadAction.nonBlocking(() -> { - if (myProject.isDisposed()) { - return null; //sometime - } return ModuleUtil.findModuleForFile(modifiedFile, myProject); }) .submit(AppExecutorUtil.getAppExecutorService()) .onSuccess((moduleForFile) -> { app.invokeLater(() -> { WriteAction.run(() -> { - final VirtualFile dwitFolder = getScenariosRootFolder(moduleForFile); + final VirtualFile dwitFolder = WeaveUtils.getDWTestResourceFolder(moduleForFile); if (dwitFolder != null && VfsUtil.isAncestor(dwitFolder, modifiedFile, true)) { VirtualFile scenario = findScenario(modifiedFile, dwitFolder); onModified(new Scenario(scenario)); @@ -190,8 +190,10 @@ private VirtualFile findScenario(VirtualFile modifiedFile, VirtualFile dwitFolde } private void onModified(Scenario scenario) { - implicitInputTypes.remove(scenario); - expectedOutputType.remove(scenario); + ImplicitInputStatus implicitInputStatus = implicitInputTypes.get(scenario); + if (implicitInputStatus != null) { + implicitInputTypes.put(scenario, new ImplicitInputStatus(implicitInputStatus.implicitInput(), false, false)); + } } public void setCurrentScenario(WeaveDocument weaveDocument, Scenario scenario) { @@ -201,7 +203,7 @@ public void setCurrentScenario(WeaveDocument weaveDocument, Scenario scenario) { @NotNull private String getTestFolderName(WeaveDocument weaveDocument) { // Replace directory separator with a "-". Support Mac, Unix and Windows directory separators - return weaveDocument.getQualifiedName().replaceAll("::|/|\\\\", "-"); + return weaveDocument.getQualifiedName().replaceAll("::", "/"); } @Nullable @@ -238,11 +240,14 @@ public ImplicitInput getImplicitInputTypes(WeaveDocument weaveDocument) { if (weaveDocument == null || currentScenario == null) { return null; } - if (implicitInputTypes.containsKey(currentScenario)) { - return implicitInputTypes.get(currentScenario); + if (implicitInputTypes.containsKey(currentScenario) + && (implicitInputTypes.get(currentScenario).active() || implicitInputTypes.get(currentScenario).resolving())) { + return implicitInputTypes.get(currentScenario).implicitInput(); } else { final FutureResult futureResult = new FutureResult<>(); if (WeaveAgentService.getInstance(myProject).isWeaveRuntimeInstalled()) { + //We create Dummy inputs + createDummyInputs(currentScenario, false); VirtualFile inputs = currentScenario.getInputs(); if (inputs != null) { AppExecutorUtil.getAppExecutorService().submit(() -> { @@ -259,7 +264,7 @@ public ImplicitInput getImplicitInputTypes(WeaveDocument weaveDocument) { } implicitInput.addInput(weaveTypeEntry.name(), weaveType); } - implicitInputTypes.put(currentScenario, implicitInput); + implicitInputTypes.put(currentScenario, new ImplicitInputStatus(implicitInput, true, false)); futureResult.set(implicitInput); }); } @@ -268,19 +273,11 @@ public ImplicitInput getImplicitInputTypes(WeaveDocument weaveDocument) { return futureResult.get(WeaveConstants.SERVER_TIMEOUT, TimeUnit.MILLISECONDS); } catch (InterruptedException | ExecutionException | TimeoutException e) { LOG.warn("Unable Infer Input Types. Reason: \n" + e.getMessage(), e); - final VirtualFile scenarioInputs = currentScenario.getInputs(); - if (scenarioInputs != null) { - final VirtualFile[] children = scenarioInputs.getChildren(); - final HashMap inputTypes = new HashMap<>(); - for (VirtualFile child : children) { - inputTypes.put(child.getNameWithoutExtension(), AnyType.apply()); - } - implicitInputTypes.put(currentScenario, ImplicitInput.apply(toScalaImmutableMap(inputTypes))); - + if (implicitInputTypes.containsKey(currentScenario)) { + return implicitInputTypes.get(currentScenario).implicitInput(); } else { - implicitInputTypes.put(currentScenario, ImplicitInput.apply()); + return createDummyInputs(currentScenario, false); } - return implicitInputTypes.get(currentScenario); } } } @@ -288,6 +285,21 @@ public ImplicitInput getImplicitInputTypes(WeaveDocument weaveDocument) { } } + private @Nullable ImplicitInput createDummyInputs(Scenario currentScenario, boolean resolving) { + final VirtualFile scenarioInputs = currentScenario.getInputs(); + if (scenarioInputs != null) { + final VirtualFile[] children = scenarioInputs.getChildren(); + final HashMap inputTypes = new HashMap<>(); + for (VirtualFile child : children) { + inputTypes.put(child.getNameWithoutExtension(), AnyType.apply()); + } + implicitInputTypes.put(currentScenario, new ImplicitInputStatus(ImplicitInput.apply(toScalaImmutableMap(inputTypes)), false, resolving)); + } else { + implicitInputTypes.put(currentScenario, new ImplicitInputStatus(null, false, resolving)); + } + return implicitInputTypes.get(currentScenario).implicitInput(); + } + @SuppressWarnings("unchecked") private static scala.collection.immutable.Map toScalaImmutableMap(java.util.Map javaMap) { final java.util.List> list = new java.util.ArrayList<>(javaMap.size()); @@ -357,13 +369,13 @@ public List getScenariosFor(WeaveDocument weaveDocument) { final Module moduleForFile = ModuleUtils.findModule(weaveFile); if (moduleForFile != null) { List scenarios = findScenarios(weaveFile); - result.addAll(scenarios.stream().map(Scenario::new).collect(Collectors.toList())); + result.addAll(scenarios.stream().map(Scenario::new).toList()); } return result; } private List findScenarios(PsiFile psiFile) { - VirtualFile mappingTestFolder = findMappingTestFolder(psiFile); + VirtualFile mappingTestFolder = findMappingTestResourcesFolder(psiFile); if (mappingTestFolder != null) { return Arrays.asList(mappingTestFolder.getChildren()); } @@ -371,23 +383,55 @@ private List findScenarios(PsiFile psiFile) { } @Nullable - public VirtualFile findMappingTestFolder(PsiFile psiFile) { - WeaveDocument document = getWeaveDocument(psiFile); + public VirtualFile findMappingTestResourcesFolder(PsiFile psiFile) { + final WeaveDocument document = getWeaveDocument(psiFile); if (document != null) { - String qualifiedName = ReadAction.compute(() -> getTestFolderName(document)); - VirtualFile scenariosRootFolder = getScenariosRootFolder(psiFile); + final String qualifiedName = ReadAction.compute(() -> getTestFolderName(document)); + final VirtualFile scenariosRootFolder = getScenariosResourceFolder(psiFile); if (scenariosRootFolder != null && scenariosRootFolder.isValid()) { - return scenariosRootFolder.findChild(qualifiedName); + return scenariosRootFolder.findFileByRelativePath(qualifiedName); } } return null; } + @Nullable - public VirtualFile findOrCreateMappingTestFolder(PsiFile psiFile) { - VirtualFile testFolder = findMappingTestFolder(psiFile); + public VirtualFile findTestFolder(PsiFile dwFile) { + final WeaveDocument document = getWeaveDocument(dwFile); + if (document != null) { + final String qualifiedName = ReadAction.compute(() -> getTestFolderName(document)); + final VirtualFile scenariosRootFolder = getScenariosTestFolder(dwFile); + if (scenariosRootFolder != null && scenariosRootFolder.isValid()) { + try { + return createDirectories(qualifiedName, scenariosRootFolder); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + return null; + } + + private VirtualFile createDirectories(String qualifiedName, VirtualFile scenariosRootFolder) throws IOException { + final String[] directories = qualifiedName.split("/"); + VirtualFile childDirectory = scenariosRootFolder; + for (String directory : directories) { + VirtualFile child = childDirectory.findChild(directory); + if (child != null) { + childDirectory = child; + } else { + childDirectory = childDirectory.createChildDirectory(this, directory); + } + } + return childDirectory; + } + + @Nullable + public VirtualFile findOrCreateMappingResourceFolder(PsiFile psiFile) { + VirtualFile testFolder = findMappingTestResourcesFolder(psiFile); if (testFolder == null) { - testFolder = createMappingTestFolder(psiFile); + testFolder = createMappingResourceFolder(psiFile); } return testFolder; } @@ -395,12 +439,12 @@ public VirtualFile findOrCreateMappingTestFolder(PsiFile psiFile) { @Nullable public Scenario createScenario(PsiFile psiFile, String scenarioName) { - VirtualFile testFolder = findOrCreateMappingTestFolder(psiFile); + final VirtualFile testFolder = findOrCreateMappingResourceFolder(psiFile); if (testFolder == null) { return null; } try { - VirtualFile scenarioFolder = WriteAction.compute(() -> testFolder.createChildDirectory(this, scenarioName)); + final VirtualFile scenarioFolder = WriteAction.compute(() -> testFolder.createChildDirectory(this, scenarioName)); Scenario scenario = new Scenario(scenarioFolder); WeaveDocument weaveDocument = WeavePsiUtils.getWeaveDocument(psiFile); if (weaveDocument != null) { @@ -416,12 +460,12 @@ public Scenario createScenario(PsiFile psiFile, String scenarioName) { } @Nullable - public VirtualFile createMappingTestFolder(PsiFile weaveFile) { + public VirtualFile createMappingResourceFolder(PsiFile weaveFile) { return WriteAction.compute(() -> { try { - VirtualFile dwitFolder = getScenariosRootFolder(weaveFile); - if (dwitFolder == null) { - //See if "src/test/dwit exists, if not, create it + VirtualFile testResourceFolder = getScenariosResourceFolder(weaveFile); + if (testResourceFolder == null) { + //See if "src/test/resources exists, if not, create it final Module module = ModuleUtils.findModule(weaveFile); if (module == null) { return null; @@ -438,26 +482,26 @@ public VirtualFile createMappingTestFolder(PsiFile weaveFile) { } else if (!testFolder.isDirectory()) { return null; } - dwitFolder = testFolder.findChild(WeaveConstants.INTEGRATION_TEST_FOLDER_NAME); - if (dwitFolder == null) { - dwitFolder = testFolder.createChildDirectory(this, WeaveConstants.INTEGRATION_TEST_FOLDER_NAME); - } else if (!dwitFolder.isDirectory()) { + testResourceFolder = testFolder.findChild(WeaveConstants.RESOURCES_FOLDER); + if (testResourceFolder == null) { + testResourceFolder = testFolder.createChildDirectory(this, WeaveConstants.RESOURCES_FOLDER); + } else if (!testResourceFolder.isDirectory()) { return null; } ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel(); ContentEntry[] entries = model.getContentEntries(); for (ContentEntry entry : entries) { if (Objects.equals(entry.getFile(), moduleRoot)) - entry.addSourceFolder(dwitFolder, true); + entry.addSourceFolder(testResourceFolder, true); } model.commit(); } final WeaveDocument document = WeavePsiUtils.getWeaveDocument(weaveFile); if (document != null) { String qName = getTestFolderName(document); - VirtualFile child = dwitFolder.findChild(qName); + VirtualFile child = testResourceFolder.findChild(qName); if (child == null) { - return dwitFolder.createChildDirectory(this, qName); + return createDirectories(qName, testResourceFolder); } else { if (child.isDirectory()) { return child; @@ -476,20 +520,103 @@ public VirtualFile createMappingTestFolder(PsiFile weaveFile) { } @Nullable - public VirtualFile getScenariosRootFolder(PsiFile weaveFile) { + public VirtualFile getScenariosResourceFolder(PsiFile weaveFile) { final Module module = ModuleUtils.findModule(weaveFile); if (module != null) { - return getScenariosRootFolder(module); + return WeaveUtils.getDWTestResourceFolder(module); } return null; } @Nullable - private VirtualFile getScenariosRootFolder(@Nullable Module module) { - return WeaveUtils.getDWITFolder(module); + public VirtualFile getScenariosTestFolder(PsiFile weaveFile) { + final Module module = ModuleUtils.findModule(weaveFile); + if (module != null) { + return WeaveUtils.getDWTestFolder(module); + } + return null; } + @Override public void dispose() { } + + public void createTest(PsiFile mappingFile, Scenario scenario) { + try { + WriteAction.run(() -> { + VirtualFile testFolder = findTestFolder(mappingFile); + if (testFolder == null) { + return; + } + WeaveDocument weaveDocument = getWeaveDocument(mappingFile); + if (weaveDocument != null) { + final String testFolderName = getTestFolderName(weaveDocument); + final String testModule = weaveDocument.getName() + "Test.dwl"; + final VirtualFile childData = testFolder.createChildData(this, testModule); + final String scenarioPath = testFolderName + "/" + scenario.getName(); + final String mimeType = ofNullable(weaveDocument.getOutput()) + .flatMap((out) -> + ofNullable(out.getDataFormat()) + .map((o) -> o.getText()) + .or(() -> + ofNullable(out.getIdentifier()) + .map((i) -> i.getText()))) + .orElse("json"); + + final String testCase = "\t\"Assert " + scenario.getName() + "\" in do {\n" + + "\t\t\tevalPath(\"" + testFolderName + ".dwl\", inputsFrom(\"" + scenarioPath + "\"), '" + mimeType + "') \n\t\t\t\tmust equalTo(outputFrom(\"" + scenarioPath + "\")) \n " + + "\t\t}\n"; + VirtualFile testFile = testFolder.findChild(testModule); + if (testFile == null) { + final String testSuite = "import * from dw::test::Tests\n" + + "import * from dw::test::Asserts\n" + + "---\n" + + "\"Test " + weaveDocument.getName() + "\" describedBy [\n" + + testCase + + "]"; + childData.setBinaryContent(testSuite.getBytes(StandardCharsets.UTF_8)); + + Notifications.Bus.notify(new Notification(WeaveAgentService.WEAVE_NOTIFICATION, "New Test " + childData.getPath() + " was created", NotificationType.INFORMATION)); + } else { + PsiFile testPsiFile = PsiManager.getInstance(myProject).findFile(testFile); + WeaveDocument testWeaveDocument = getWeaveDocument(testPsiFile); + WeaveBody body = testWeaveDocument.getBody(); + if (body != null) { + WeaveExpression expression = body.getExpression(); + if (expression instanceof WeaveBinaryExpression) { + List expressionList = ((WeaveBinaryExpression) expression).getExpressionList(); + if (expressionList.size() == 2) { + WeaveExpression weaveExpression = expressionList.get(1); + if (weaveExpression instanceof WeaveArrayExpression) { + + runWriteCommandAction(myProject, () -> { + String text = weaveExpression.getText(); + int i = text.lastIndexOf("]"); + String s = text.substring(0, i).trim() + ",\n\t" + testCase + "]"; + WeaveExpression textCaseExpression = WeaveElementFactory.createExpression(myProject, s); + weaveExpression.replace(textCaseExpression); + }); + Notifications.Bus.notify(new Notification(WeaveAgentService.WEAVE_NOTIFICATION, "New Test case was added to " + childData.getPath() + ".", NotificationType.INFORMATION)); + } + } + } + } + + } + + + } + }); + } catch (IOException e) { + throw new RuntimeException(e); + } + + } + + } + +record ImplicitInputStatus(ImplicitInput implicitInput, boolean active, boolean resolving) { +} + diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/service/agent/WeaveAgentService.java b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/service/agent/WeaveAgentService.java index b290babb..ba563f0f 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/service/agent/WeaveAgentService.java +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/service/agent/WeaveAgentService.java @@ -1,6 +1,5 @@ package org.mule.tooling.lang.dw.service.agent; -import com.intellij.ProjectTopics; import com.intellij.compiler.server.BuildManagerListener; import com.intellij.execution.DefaultExecutionResult; import com.intellij.execution.ExecutionException; @@ -31,6 +30,8 @@ import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.progress.EmptyProgressIndicator; import com.intellij.openapi.progress.ProgressIndicator; +import com.intellij.openapi.progress.ProgressManager; +import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootEvent; @@ -62,506 +63,523 @@ @Service(Service.Level.PROJECT) public final class WeaveAgentService implements Disposable { - private static final String AGENT_SERVER_LAUNCHER_MAIN_CLASS = "org.mule.weave.v2.agent.server.AgentServerLauncher"; - public static final int MAX_RETRIES = 10; - public static final long MAX_ALLOWED_WAIT = 10; + private static final String AGENT_SERVER_LAUNCHER_MAIN_CLASS = "org.mule.weave.v2.agent.server.AgentServerLauncher"; + public static final int MAX_RETRIES = 10; + public static final long MAX_ALLOWED_WAIT = 10; + public static final String WEAVE_NOTIFICATION = "WeaveNotification"; - private final Alarm myRestartAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, this); + private final Alarm myRestartAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, this); - @Nullable - private WeaveAgentClient client; - private ProcessHandler processHandler; - private boolean disabled = false; - private List listeners; + @Nullable + private WeaveAgentClient client; + private ProcessHandler processHandler; + private boolean disabled = false; + private List listeners; - private Alarm idleAgentAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, this); + private Alarm idleAgentAlarm = new Alarm(Alarm.ThreadToUse.POOLED_THREAD, this); - private static final Logger LOG = Logger.getInstance(WeaveAgentService.class); - private Project myProject; + private static final Logger LOG = Logger.getInstance(WeaveAgentService.class); + private Project myProject; - private final AgentClasspathResolver agentClasspathResolver = new ResourceBasedAgentClasspathResolver(); + private final AgentClasspathResolver agentClasspathResolver = new ResourceBasedAgentClasspathResolver(); - private WeaveAgentService(Project project) { - this.myProject = project; - this.listeners = new ArrayList<>(); - initialize(); - } + private WeaveAgentService(Project project) { + this.myProject = project; + this.listeners = new ArrayList<>(); + initialize(); + } - public void addStatusListener(WeaveAgentStatusListener listener) { - if (client != null && client.isConnected()) { - listener.agentStarted(); + public void addStatusListener(WeaveAgentStatusListener listener) { + if (client != null && client.isConnected()) { + listener.agentStarted(); + } + this.listeners.add(listener); } - this.listeners.add(listener); - } - - - public void initialize() { - myProject.getMessageBus() - .connect(myProject) - .subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootListener() { - @Override - public void rootsChanged(@NotNull ModuleRootEvent event) { - //We stop the server as classpath has changed - //But only if the process was started - if (processHandler != null) { - scheduleRestart(); + + + public void initialize() { + myProject.getMessageBus() + .connect(this) + .subscribe(ModuleRootListener.TOPIC, new ModuleRootListener() { + @Override + public void rootsChanged(@NotNull ModuleRootEvent event) { + //We stop the server as classpath has changed + //But only if the process was started + if (processHandler != null) { + scheduleRestart(); + } + } + }); + + final MessageBus messageBus = ApplicationManager.getApplication().getMessageBus(); + final MessageBusConnection connection = messageBus.connect(this); + + connection.subscribe(BuildManagerListener.TOPIC, new BuildManagerListener() { + @Override + public void buildFinished(@NotNull Project project, @NotNull UUID sessionId, boolean isAutomake) { + if (project == myProject) { + scheduleRestart(); } - } - }); + } + }); - final MessageBus messageBus = ApplicationManager.getApplication().getMessageBus(); - final MessageBusConnection connection = messageBus.connect(this); + connection.subscribe(CompilerTopics.COMPILATION_STATUS, new CompilationStatusListener() { + @Override + public void compilationFinished(boolean aborted, int errors, int warnings, @NotNull CompileContext compileContext) { + compilationFinished(compileContext); + } - connection.subscribe(BuildManagerListener.TOPIC, new BuildManagerListener() { - @Override - public void buildFinished(@NotNull Project project, @NotNull UUID sessionId, boolean isAutomake) { - if (project == myProject) { - scheduleRestart(); - } - } - }); - - connection.subscribe(CompilerTopics.COMPILATION_STATUS, new CompilationStatusListener() { - @Override - public void compilationFinished(boolean aborted, int errors, int warnings, @NotNull CompileContext compileContext) { - compilationFinished(compileContext); - } - - @Override - public void automakeCompilationFinished(int errors, int warnings, @NotNull CompileContext compileContext) { - compilationFinished(compileContext); - } - - private void compilationFinished(@NotNull CompileContext context) { - if (!(context instanceof DummyCompileContext) && context.getProject() == myProject) { - scheduleRestart(); + @Override + public void automakeCompilationFinished(int errors, int warnings, @NotNull CompileContext compileContext) { + compilationFinished(compileContext); + } + + private void compilationFinished(@NotNull CompileContext context) { + if (!(context instanceof DummyCompileContext) && context.getProject() == myProject) { + scheduleRestart(); + } + } + }); + + Runtime.getRuntime().addShutdownHook(new Thread(this::tearDown)); + } + + public void scheduleRestart() { + if (client != null) { + myRestartAlarm.cancelAllRequests(); + myRestartAlarm.addRequest(() -> { + //We only restart if there is an active connection + tearDown(); + ProgressManager.getInstance().run( + new Task.Backgroundable(myProject, "Starting agent") { + @Override + public void run(@NotNull ProgressIndicator indicator) { + init(indicator); + } + }); + + }, TimeUnit.SECONDS.toMillis(1)); } - } - }); + } - Runtime.getRuntime().addShutdownHook(new Thread(this::tearDown)); - } - private void scheduleRestart() { - if (client != null) { - myRestartAlarm.cancelAllRequests(); - myRestartAlarm.addRequest(() -> { - //We only restart if there is an active connection - tearDown(); - init(new EmptyProgressIndicator()); - }, TimeUnit.SECONDS.toMillis(1)); + public void disable() { + this.disabled = true; + } + public void enable() { + this.disabled = false; } - } - public void disable() { - this.disabled = true; - } + public synchronized void init(ProgressIndicator indicator) { + if (isEnabled() && (client == null || !client.isConnected())) { - public void enable() { - this.disabled = false; - } + if (processHandler != null) { + tearDown(); + } + int freePort; + try { + freePort = NetUtils.findAvailableSocketPort(); + } catch (IOException e) { + freePort = 2333; + } + LOG.info("DataWeave agent is starting on port " + freePort); - public synchronized void init(ProgressIndicator indicator) { - if (isEnabled() && (client == null || !client.isConnected())) { + final ProgramRunner runner = new DefaultProgramRunner() { + @Override + @NotNull + public String getRunnerId() { + return "Weave Agent Runner"; + } - if (processHandler != null) { - tearDown(); - } - int freePort; - try { - freePort = NetUtils.findAvailableSocketPort(); - } catch (IOException e) { - freePort = 2333; - } - - LOG.info("DataWeave agent is starting on port " + freePort); - - final ProgramRunner runner = new DefaultProgramRunner() { - @Override - @NotNull - public String getRunnerId() { - return "Weave Agent Runner"; - } + @Override + public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) { + return true; + } - @Override - public boolean canRun(@NotNull String executorId, @NotNull RunProfile profile) { - return true; - } + }; + final Executor executor = DefaultRunExecutor.getRunExecutorInstance(); + try { + final ProjectRootManager manager = ProjectRootManager.getInstance(myProject); + if (manager.getProjectSdk() == null) { + return; + } + final RunProfileState state = createRunProfileState(freePort); + final ExecutionResult result = state.execute(executor, runner); + + //noinspection ConstantConditions + processHandler = result.getProcessHandler(); + processHandler.addProcessListener(new ProcessAdapter() { + + @Override + public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) { + LOG.info("[Agent Process] " + event.getText()); + } + }); + int i = 0; + //Wait for two seconds + while (!processHandler.waitFor(MAX_ALLOWED_WAIT) && i < 200) { + i = i + 1; + } + } catch (Throwable e) { + Notifications.Bus.notify(new Notification(WEAVE_NOTIFICATION, "Unable to start agent", "Unable to start agent. Reason: \n" + e.getMessage(), NotificationType.ERROR)); + LOG.warn("\"Unable to start agent. Reason: \\n\" + e.getMessage()", e); + disable(); + return; + } + processHandler.startNotify(); + TcpClientProtocol clientProtocol = new TcpClientProtocol("localhost", freePort); + client = new WeaveAgentClient(clientProtocol); + + final int finalFreePort = freePort; + client.connect(MAX_RETRIES, 1000L, new ConnectionRetriesListener() { + @Override + public void failToConnect(String reason) { + indicator.setText2("Fail to connect to the agent client at port " + finalFreePort + " reason " + reason); + LOG.warn("Fail to connect to the agent client at port " + finalFreePort + " reason " + reason + " ; will retry in 1 second"); + } - }; - final Executor executor = DefaultRunExecutor.getRunExecutorInstance(); - try { - final ProjectRootManager manager = ProjectRootManager.getInstance(myProject); - if (manager.getProjectSdk() == null) { - return; - } - final RunProfileState state = createRunProfileState(freePort); - final ExecutionResult result = state.execute(executor, runner); + @Override + public void connectedSuccessfully() { + indicator.setText2("Agent connected successfully"); + Notifications.Bus.notify(new Notification(WEAVE_NOTIFICATION, "Server started", "Weave Server started and is reachable at port " + finalFreePort, NotificationType.INFORMATION)); + LOG.info("Weave Server started and is reachable at port " + finalFreePort); + } - //noinspection ConstantConditions - processHandler = result.getProcessHandler(); - processHandler.addProcessListener(new ProcessAdapter() { + @Override + public void startConnecting() { + indicator.setText2("Trying to connect to the agent client at port " + finalFreePort); + LOG.info("Trying to connect to the agent client at port " + finalFreePort); + } - @Override - public void onTextAvailable(@NotNull ProcessEvent event, @NotNull Key outputType) { - LOG.info("[Agent Process] " + event.getText()); - } - }); - int i = 0; - //Wait for two seconds - while (!processHandler.waitFor(MAX_ALLOWED_WAIT) && i < 200) { - i = i + 1; - } - } catch (Throwable e) { - Notifications.Bus.notify(new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "Unable to start agent", "Unable to start agent. Reason: \n" + e.getMessage(), NotificationType.ERROR)); - LOG.warn("\"Unable to start agent. Reason: \\n\" + e.getMessage()", e); - e.printStackTrace(); - disable(); - return; - } - processHandler.startNotify(); - TcpClientProtocol clientProtocol = new TcpClientProtocol("localhost", freePort); - client = new WeaveAgentClient(clientProtocol); - - final int finalFreePort = freePort; - client.connect(MAX_RETRIES, 1000L, new ConnectionRetriesListener() { - @Override - public void failToConnect(String reason) { - indicator.setText2("Fail to connect to the agent client at port " + finalFreePort + " reason " + reason); - LOG.warn("Fail to connect to the agent client at port " + finalFreePort + " reason " + reason + " ; will retry in 1 second"); - } + @Override + public boolean onRetry(int count, int total) { + return !indicator.isCanceled(); + } + }); + if (client != null && client.isConnected()) { + LOG.info("Weave agent connected to server. Port: " + finalFreePort); + for (WeaveAgentStatusListener listener : listeners) { + listener.agentStarted(); + } + } else { + LOG.warn("WeaveAgentRuntimeManager cannot be started, disabling..."); + //disable the service as for some weird reason it can not be started + disable(); + } - @Override - public void connectedSuccessfully() { - indicator.setText2("Agent connected successfully"); - Notifications.Bus.notify(new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "Server started", "Weave Server started and is reachable at port " + finalFreePort, NotificationType.INFORMATION)); - LOG.info("Weave Server started and is reachable at port " + finalFreePort); } - @Override - public void startConnecting() { - indicator.setText2("Trying to connect to the agent client at port " + finalFreePort); - LOG.info("Trying to connect to the agent client at port " + finalFreePort); + if (client != null) { + actionOcurred(); } - @Override - public boolean onRetry(int count, int total) { - return !indicator.isCanceled(); - } - }); - if (client != null && client.isConnected()) { - LOG.info("Weave agent connected to server. Port: " + finalFreePort); - for (WeaveAgentStatusListener listener : listeners) { - listener.agentStarted(); - } - } else { - LOG.warn("WeaveAgentRuntimeManager cannot be started, disabling..."); - //disable the service as for some weird reason it can not be started - disable(); - } + } + void actionOcurred() { + idleAgentAlarm.cancelAllRequests(); + idleAgentAlarm.addRequest(() -> { + if (idleAgentAlarm.isDisposed()) { + return; + } + tearDown(); + }, DataWeaveSettingsState.getInstance().getMaxTimePreview() * 100); + //If after 5 minute the agent is not used it is going to be teardown to avoid too many running servers } - if (client != null) { - actionOccured(); + public void runPreview(String inputsPath, String script, String identifier, String url, Long maxTime, Module module, RunPreviewCallback callback) { + boolean connected = checkClientConnected(() -> { + //Make sure all files are persisted before running preview + ApplicationManager.getApplication().invokeLater(() -> { + //Save all files + FileDocumentManager.getInstance().saveAllDocuments(); + ProgressManager.getInstance().run( + new Task.Backgroundable(myProject, "Running preview") { + @Override + public void run(@NotNull ProgressIndicator indicator) { + doRunPreview(module, inputsPath, script, identifier, url, maxTime, callback); + } + }); + + }); + }); + if (!connected) { + + Notifications.Bus.notify(new Notification(WEAVE_NOTIFICATION, "Client not connected", "Unable to connect to client", NotificationType.INFORMATION)); + } } - } - - void actionOccured() { - idleAgentAlarm.cancelAllRequests(); - idleAgentAlarm.addRequest(() -> { - if (idleAgentAlarm.isDisposed()) { - return; - } - tearDown(); - }, DataWeaveSettingsState.getInstance().getMaxTimePreview() * 100); - //If after 5 minute the agent is not used it is going to be teardown to avoid too many running servers - } - - public void runPreview(String inputsPath, String script, String identifier, String url, Long maxTime, Module module, RunPreviewCallback callback) { - checkClientConnected(() -> { - //Make sure all files are persisted before running preview - ApplicationManager.getApplication().invokeLater(() -> { - //Save all files - FileDocumentManager.getInstance().saveAllDocuments(); - ApplicationManager.getApplication().executeOnPooledThread(() -> { - final String[] paths = getClasspath(module); - if (client != null) { + private void doRunPreview(Module module, String inputsPath, String script, String identifier, String url, Long maxTime, RunPreviewCallback callback) { + final String[] paths = getClasspath(module); + if (client != null) { long startTime = System.currentTimeMillis(); client.runPreview(inputsPath, script, identifier, url, maxTime, paths, new PreviewExecutedListener() { - @Override - public void onPreviewExecuted(PreviewExecutedEvent result) { - long duration = System.currentTimeMillis() - startTime; - if (result instanceof PreviewExecutedSuccessfulEvent successfulEvent) { - callback.onPreviewSuccessful(successfulEvent, duration); - } else if (result instanceof PreviewExecutedFailedEvent) { - callback.onPreviewFailed((PreviewExecutedFailedEvent) result); + @Override + public void onPreviewExecuted(PreviewExecutedEvent result) { + long duration = System.currentTimeMillis() - startTime; + if (result instanceof PreviewExecutedSuccessfulEvent successfulEvent) { + callback.onPreviewSuccessful(successfulEvent, duration); + } else if (result instanceof PreviewExecutedFailedEvent) { + callback.onPreviewFailed((PreviewExecutedFailedEvent) result); + } } - } - @Override - public void onUnexpectedError(UnexpectedServerErrorEvent unexpectedServerErrorEvent) { - Notifications.Bus.notify(new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "[data-weave-agent] Unexpected error at 'runPreview'", - "Unexpected error at 'runPreview' caused by: \n" + unexpectedServerErrorEvent.stacktrace(), NotificationType.ERROR)); - } + @Override + public void onUnexpectedError(UnexpectedServerErrorEvent unexpectedServerErrorEvent) { + Notifications.Bus.notify(new Notification(WEAVE_NOTIFICATION, "[data-weave-agent] Unexpected error at 'runPreview'", + "Unexpected error at 'runPreview' caused by: \n" + unexpectedServerErrorEvent.stacktrace(), NotificationType.ERROR)); + } }); - } - }); - }); - }); - } - - @NotNull - public String[] getClasspath(Module module) { - final PathsList pathsList = new PathsList(); - loadClasspathInto(module, pathsList); - return pathsList.getPathList().toArray(new String[0]); - } - - public String[] getClasspath(Project project) { - final PathsList pathsList = new PathsList(); - // All modules to use the same things - final Module[] modules = ModuleManager.getInstance(project).getModules(); - for (Module module : modules) { - loadClasspathInto(module, pathsList); + } } - return pathsList.getPathList().toArray(new String[0]); - } - - public void loadClasspathInto(Module module, PathsList pathsList) { - final OrderEnumerator orderEnumerator = OrderEnumerator.orderEntries(module).withoutSdk(); - //We add sources too as we don't compile the we want to have the weave files up to date - pathsList.addVirtualFiles(orderEnumerator.getSourceRoots()); - pathsList.addVirtualFiles(orderEnumerator.getClassesRoots()); - pathsList.addVirtualFiles(orderEnumerator.getAllLibrariesAndSdkClassesRoots()); - } - - public void checkClientConnected(Runnable onConnected) { - if (isEnabled()) { - if (client == null || !client.isConnected()) { - if (isWeaveRuntimeInstalled()) { - init(new EmptyProgressIndicator()); + + @NotNull + public String[] getClasspath(Module module) { + final PathsList pathsList = new PathsList(); + loadClasspathInto(module, pathsList); + return pathsList.getPathList().toArray(new String[0]); + } + + public String[] getClasspath(Project project) { + final PathsList pathsList = new PathsList(); + // All modules to use the same things + final Module[] modules = ModuleManager.getInstance(project).getModules(); + for (Module module : modules) { + loadClasspathInto(module, pathsList); } - } - if (client != null && client.isConnected()) { - onConnected.run(); - } else { - Notifications.Bus.notify(new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "Unable to connect", "Client is not able to connect to runtime", NotificationType.WARNING)); - LOG.warn("Unable to connect; Client is " + client); - } + return pathsList.getPathList().toArray(new String[0]); } - } - - private boolean isEnabled() { - return !disabled; - } - - public boolean isWeaveRuntimeInstalled() { - try { - GlobalSearchScope scope = GlobalSearchScope.allScope(myProject); - JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(myProject); - PsiClass c = ReadAction.compute(() -> psiFacade.findClass(getMarkerClassFQName(), scope)); - LOG.info("Checking for Weave Runtime installation, found PsiClass " + c); - return c != null; - } catch (IndexNotReadyException e) { - //If index is not yes available just try it out - return true; + + public void loadClasspathInto(Module module, PathsList pathsList) { + final OrderEnumerator orderEnumerator = OrderEnumerator.orderEntries(module).withoutSdk(); + //We add sources too as we don't compile the we want to have the weave files up to date + pathsList.addVirtualFiles(orderEnumerator.getSourceRoots()); + pathsList.addVirtualFiles(orderEnumerator.getClassesRoots()); + pathsList.addVirtualFiles(orderEnumerator.getAllLibrariesAndSdkClassesRoots()); } - } - - private String getMarkerClassFQName() { - //The class from the agent runtime - return "org.mule.weave.v2.runtime.DataWeaveScriptingEngine"; - } - - public void calculateImplicitInputTypes(String inputsPath, ImplicitInputTypesCallback callback) { - checkClientConnected(() -> { - //Make sure all files are persisted before running preview - ApplicationManager.getApplication().invokeLater(() -> { - FileDocumentManager.getInstance().saveAllDocuments(); - ApplicationManager.getApplication().executeOnPooledThread(() -> { - if (client == null) return; - - client.inferInputsWeaveType(inputsPath, new ImplicitWeaveTypesListener() { - @Override - public void onImplicitWeaveTypesCalculated(ImplicitInputTypesEvent result) { - ApplicationManager.getApplication().invokeLater(() -> { - callback.onInputsTypesCalculated(result); - }); - } - @Override - public void onUnexpectedError(UnexpectedServerErrorEvent unexpectedServerErrorEvent) { - Notifications.Bus.notify(new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "[data-weave-agent] Unexpected error at 'inferInputsWeaveType'", - "Unexpected error at 'inferInputsWeaveType' caused by: \n" + unexpectedServerErrorEvent.stacktrace(), NotificationType.ERROR)); + public boolean checkClientConnected(Runnable onConnected) { + if (isEnabled()) { + if (client == null || !client.isConnected()) { + if (isWeaveRuntimeInstalled()) { + init(new EmptyProgressIndicator()); + } } - }); - }); - }); - }); - } - - public void calculateWeaveType(String path, InferTypeResultCallback callback) { - checkClientConnected(() -> { - //Make sure all files are persisted before running preview - ApplicationManager.getApplication().invokeLater(() -> { - if (client != null) { - client.inferWeaveType(path, new WeaveTypeInferListener() { - @Override - public void onWeaveTypeInfer(InferWeaveTypeEvent result) { - ApplicationManager.getApplication().invokeLater(() -> { - callback.onType(result); - }); + if (client != null && client.isConnected()) { + onConnected.run(); + } else { + Notifications.Bus.notify(new Notification(WEAVE_NOTIFICATION, "Unable to connect", "Client is not able to connect to runtime", NotificationType.WARNING)); + LOG.warn("Unable to connect; Client is " + client); } + return true; + } else { + return false; + } + } - @Override - public void onUnexpectedError(UnexpectedServerErrorEvent unexpectedServerErrorEvent) { - Notifications.Bus.notify(new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "[data-weave-agent] Unexpected error at 'inferWeaveType'", - "Unexpected error at 'inferWeaveType' caused by: \n" + unexpectedServerErrorEvent.stacktrace(), NotificationType.ERROR)); - } - }); + private boolean isEnabled() { + return !disabled; + } + + public boolean isWeaveRuntimeInstalled() { + try { + GlobalSearchScope scope = GlobalSearchScope.allScope(myProject); + JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(myProject); + PsiClass c = ReadAction.compute(() -> psiFacade.findClass(getMarkerClassFQName(), scope)); + LOG.info("Checking for Weave Runtime installation, found PsiClass " + c); + return c != null; + } catch (IndexNotReadyException e) { + //If index is not yes available just try it out + return true; } - }); - }); - } - - public void dataFormats(DataFormatsDefinitionCallback callback) { - checkClientConnected(() -> { - if (client != null) { - client.definedDataFormats(new DataFormatDefinitionListener() { - @Override - public void onDataFormatDefinitionCalculated(DataFormatsDefinitionsEvent dfde) { + } + + private String getMarkerClassFQName() { + //The class from the agent runtime + return "org.mule.weave.v2.runtime.DataWeaveScriptingEngine"; + } + + public void calculateImplicitInputTypes(String inputsPath, ImplicitInputTypesCallback callback) { + checkClientConnected(() -> { + //Make sure all files are persisted before running preview ApplicationManager.getApplication().invokeLater(() -> { - callback.onDataFormatsLoaded(dfde); + FileDocumentManager.getInstance().saveAllDocuments(); + ApplicationManager.getApplication().executeOnPooledThread(() -> { + if (client == null) return; + + client.inferInputsWeaveType(inputsPath, new ImplicitWeaveTypesListener() { + @Override + public void onImplicitWeaveTypesCalculated(ImplicitInputTypesEvent result) { + ApplicationManager.getApplication().invokeLater(() -> { + callback.onInputsTypesCalculated(result); + }); + } + + @Override + public void onUnexpectedError(UnexpectedServerErrorEvent unexpectedServerErrorEvent) { + LOG.info(unexpectedServerErrorEvent.toString()); + } + }); + }); }); - } + }); + } - @Override - public void onUnexpectedError(UnexpectedServerErrorEvent unexpectedServerErrorEvent) { - Notifications.Bus.notify(new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "[data-weave-agent] Unexpected error at 'definedDataFormats'", - "Unexpected error at 'definedDataFormats' caused by: \n" + unexpectedServerErrorEvent.stacktrace(), NotificationType.ERROR)); - } + public void calculateWeaveType(String path, InferTypeResultCallback callback) { + checkClientConnected(() -> { + //Make sure all files are persisted before running preview + if (client != null) { + client.inferWeaveType(path, new WeaveTypeInferListener() { + @Override + public void onWeaveTypeInfer(InferWeaveTypeEvent result) { + ApplicationManager.getApplication().invokeLater(() -> { + callback.onType(result); + }); + } + + @Override + public void onUnexpectedError(UnexpectedServerErrorEvent unexpectedServerErrorEvent) { + LOG.info(unexpectedServerErrorEvent.toString()); + } + }); + } }); - } - }); - } - - public void availableModules(AvailableModulesCallback callback) { - if (client != null) { - client.availableModules(new AvailableModulesListener() { - @Override - public void onAvailableModules(AvailableModulesEvent am) { - ApplicationManager.getApplication().invokeLater(() -> { - callback.onAvailableModules(am); - }); - } + } - @Override - public void onUnexpectedError(UnexpectedServerErrorEvent unexpectedServerErrorEvent) { - Notifications.Bus.notify(new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "[data-weave-agent] Unexpected error at 'availableModules'", - "Unexpected error at 'availableModules' caused by: \n" + unexpectedServerErrorEvent.stacktrace(), NotificationType.ERROR)); - } - }); + public void dataFormats(DataFormatsDefinitionCallback callback) { + checkClientConnected(() -> { + if (client != null) { + client.definedDataFormats(new DataFormatDefinitionListener() { + @Override + public void onDataFormatDefinitionCalculated(DataFormatsDefinitionsEvent dfde) { + ApplicationManager.getApplication().invokeLater(() -> { + callback.onDataFormatsLoaded(dfde); + }); + } + + @Override + public void onUnexpectedError(UnexpectedServerErrorEvent unexpectedServerErrorEvent) { + LOG.info("[data-weave-agent] Unexpected error at 'definedDataFormats' : \n" + + "Unexpected error at 'definedDataFormats' caused by: \n" + unexpectedServerErrorEvent.stacktrace()); + } + }); + } + }); } - } - - public void resolveModule(String identifier, String loader, Project module, ModuleLoadedCallback callback) { - final String[] paths = getClasspath(module); - checkClientConnected(() -> { - if (client != null) { - client.resolveModule(identifier, loader, paths, new ModuleLoadedListener() { - @Override - public void onModuleLoaded(ModuleResolvedEvent result) { - ApplicationManager.getApplication().invokeLater(() -> { - callback.onModuleResolved(result); + + public void availableModules(AvailableModulesCallback callback) { + if (client != null) { + client.availableModules(new AvailableModulesListener() { + @Override + public void onAvailableModules(AvailableModulesEvent am) { + ApplicationManager.getApplication().invokeLater(() -> { + callback.onAvailableModules(am); + }); + } + + @Override + public void onUnexpectedError(UnexpectedServerErrorEvent unexpectedServerErrorEvent) { + LOG.info("[data-weave-agent] Unexpected error at 'AvailableModules' : \n" + + "Unexpected error at 'AvailableModules' caused by: \n" + unexpectedServerErrorEvent.stacktrace()); + } }); - } + } + } - @Override - public void onUnexpectedError(UnexpectedServerErrorEvent unexpectedServerErrorEvent) { - Notifications.Bus.notify(new Notification(Notifications.SYSTEM_MESSAGES_GROUP_ID, "[data-weave-agent] Unexpected error at 'resolveModule'", - "Unexpected error at 'resolveModule' caused by: \n" + unexpectedServerErrorEvent.stacktrace(), NotificationType.ERROR)); - } + public void resolveModule(String identifier, String loader, Project module, ModuleLoadedCallback callback) { + final String[] paths = getClasspath(module); + checkClientConnected(() -> { + if (client != null) { + client.resolveModule(identifier, loader, paths, new ModuleLoadedListener() { + @Override + public void onModuleLoaded(ModuleResolvedEvent result) { + ApplicationManager.getApplication().invokeLater(() -> { + callback.onModuleResolved(result); + }); + } + + @Override + public void onUnexpectedError(UnexpectedServerErrorEvent unexpectedServerErrorEvent) { + LOG.info("[data-weave-agent] Unexpected error at 'resolveModule' : \n" + + "Unexpected error at 'resolveModule' caused by: \n" + unexpectedServerErrorEvent.stacktrace()); + } + }); + } }); - } - }); - } - - public synchronized void tearDown() { - LOG.info("Tearing down WeaveAgent"); - //Kill the process - if (processHandler != null) { - processHandler.destroyProcess(); - processHandler = null; } - if (client != null) { - client.disconnect(); - client = null; + public synchronized void tearDown() { + LOG.info("Tearing down WeaveAgent"); + //Kill the process + if (processHandler != null) { + processHandler.destroyProcess(); + processHandler = null; + } + + if (client != null) { + client.disconnect(); + client = null; + } + this.enable(); } - this.enable(); - } - private RunProfileState createRunProfileState(int freePort) { - return new CommandLineState(null) { - private SimpleJavaParameters createJavaParameters() { - final SimpleJavaParameters params = WeaveRunnerHelper.createJavaParameters(myProject, AGENT_SERVER_LAUNCHER_MAIN_CLASS); + private RunProfileState createRunProfileState(int freePort) { + return new CommandLineState(null) { + private SimpleJavaParameters createJavaParameters() { + final SimpleJavaParameters params = WeaveRunnerHelper.createJavaParameters(myProject, AGENT_SERVER_LAUNCHER_MAIN_CLASS); // if (Boolean.getBoolean("debugWeaveAgent")) { // params.getVMParametersList().add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5678"); // - for (String jar : agentClasspathResolver.resolveClasspathJars()) { - params.getClassPath().add(jar); - } - ParametersList parametersList = params.getProgramParametersList(); - // parametersList.add("--agent"); - parametersList.add("-p"); - parametersList.add(String.valueOf(freePort)); - - // Force use of dynamic classpath. In Windows, a large project will cause the agent fail to start due - // to a very large classpath line in the command line. - //noinspection MissingRecentApi - params.useDynamicClasspathDefinedByJdkLevel(); - - return params; - } - - @NotNull - @Override - public ExecutionResult execute(@NotNull Executor executor, @NotNull ProgramRunner runner) throws ExecutionException { - ProcessHandler processHandler = startProcess(); - return new DefaultExecutionResult(null, processHandler); - } - - @Override - @NotNull - protected OSProcessHandler startProcess() throws ExecutionException { - SimpleJavaParameters params = createJavaParameters(); - - GeneralCommandLine commandLine = params.toCommandLine(); - OSProcessHandler processHandler = new OSProcessHandler(commandLine); - processHandler.setShouldDestroyProcessRecursively(false); - return processHandler; - } - }; - } - - public static WeaveAgentService getInstance(@NotNull Project project) { - return project.getService(WeaveAgentService.class); - } - - @Override - public void dispose() { - tearDown(); - } - - public interface WeaveAgentStatusListener { - void agentStarted(); - } + for (String jar : agentClasspathResolver.resolveClasspathJars()) { + params.getClassPath().add(jar); + } + ParametersList parametersList = params.getProgramParametersList(); + // parametersList.add("--agent"); + parametersList.add("-p"); + parametersList.add(String.valueOf(freePort)); + + // Force use of dynamic classpath. In Windows, a large project will cause the agent fail to start due + // to a very large classpath line in the command line. + params.useDynamicClasspathDefinedByJdkLevel(); + + return params; + } + + @NotNull + @Override + public ExecutionResult execute(@NotNull Executor executor, @NotNull ProgramRunner runner) throws ExecutionException { + ProcessHandler processHandler = startProcess(); + return new DefaultExecutionResult(null, processHandler); + } + + @Override + @NotNull + protected OSProcessHandler startProcess() throws ExecutionException { + SimpleJavaParameters params = createJavaParameters(); + + GeneralCommandLine commandLine = params.toCommandLine(); + OSProcessHandler processHandler = new OSProcessHandler(commandLine); + processHandler.setShouldDestroyProcessRecursively(false); + return processHandler; + } + }; + } + + public static WeaveAgentService getInstance(@NotNull Project project) { + return project.getService(WeaveAgentService.class); + } + + @Override + public void dispose() { + tearDown(); + } + + public interface WeaveAgentStatusListener { + void agentStarted(); + } } diff --git a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/util/WeaveUtils.java b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/util/WeaveUtils.java index 0b6c23d3..69224e00 100644 --- a/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/util/WeaveUtils.java +++ b/data-weave-plugin/src/main/java/org/mule/tooling/lang/dw/util/WeaveUtils.java @@ -72,7 +72,7 @@ public static boolean isTestFile(@Nullable WeaveDocument document) { } @Nullable - public static VirtualFile getDWITFolder(@Nullable Module module) { + public static VirtualFile getDWTestResourceFolder(@Nullable Module module) { if (module == null) { return null; } @@ -83,11 +83,11 @@ public static VirtualFile getDWITFolder(@Nullable Module module) { return null; } //Create it here - return moduleRoot.findFileByRelativePath(WeaveConstants.TEST_BASE_FOLDER_NAME + "/" + WeaveConstants.INTEGRATION_TEST_FOLDER_NAME); + return moduleRoot.findFileByRelativePath(WeaveConstants.TEST_BASE_FOLDER_NAME + "/" + WeaveConstants.RESOURCES_FOLDER); } @Nullable - public static VirtualFile getDWMITFolder(@Nullable Module module) { + public static VirtualFile getDWTestFolder(@Nullable Module module) { if (module == null) { return null; } @@ -98,7 +98,7 @@ public static VirtualFile getDWMITFolder(@Nullable Module module) { return null; } //Create it here - return moduleRoot.findFileByRelativePath(WeaveConstants.TEST_BASE_FOLDER_NAME + "/" + WeaveConstants.MODULE_INTEGRATION_TEST_FOLDER_NAME); + return moduleRoot.findFileByRelativePath(WeaveConstants.TEST_BASE_FOLDER_NAME + "/" + WeaveConstants.TEST_FOLDER); } } diff --git a/data-weave-plugin/src/main/resources/META-INF/plugin.xml b/data-weave-plugin/src/main/resources/META-INF/plugin.xml index 6f45e99d..59af4afa 100644 --- a/data-weave-plugin/src/main/resources/META-INF/plugin.xml +++ b/data-weave-plugin/src/main/resources/META-INF/plugin.xml @@ -486,6 +486,8 @@ + +