GroovyScriptEngine can't reload the dependent file - groovy

https://groovy-lang.org/integrating.html#_groovyscriptengine
. I test the GroovyScriptEngine features according the upon url,everything is ok except the last step:
"And as a last test, you can update the Dependency.groovy file without touching the ReloadingTest file:"
this is my code
1、GroovyScriptEngine_WAY.groovy
package com.zjc.groovy.class_
class GroovyScriptEngine_WAY {
static void main(String[] args){
loadByScriptEngine()
}
static void loadByScriptEngine() throws IOException, ResourceException, ScriptException {
String[] urls = ["springbootOrigin/src/main/java/com/zjc/groovy/script/"]
def engine = new GroovyScriptEngine(urls);
def binding = new Binding();
binding.setVariable("name","test GroovyScriptEngine");
while (true){
def greeter = engine.run('ReloadingTest.groovy',binding)
println greeter.sayHello()
Thread.sleep(1000)
}
}
}
2、ReloadingTest.groovy
package com.zjc.groovy.script
class Greeter {
String sayHello(){
Dependency dependency = new Dependency()
def greet = dependency.message
greet
}
}
new Greeter()
3、Dependency_1.groovy
package com.zjc.groovy.script
class Dependency {
String message = "Hello, dependency 11"
}
print("this is dependency")
I have check the code, make sure is the same with the official website。however can't not reload the dependent file when change。

Related

CliBuilder not getting entire list of arguments for an option

Problem
I need to parse command like:
groovy App.groovy --sourceFiles a.xlsx b.xlsx --destinationFolder ../legacy-data-migration
What I have tried
I write a CommandLineUtils, defined to be:
package com.signaturemd.sposZohoMergeScript.utils
import org.apache.commons.cli.Option
import org.apache.commons.cli.Options
import groovy.cli.commons.CliBuilder
import groovy.cli.commons.OptionAccessor
public final class CommandLineUtils {
private static CliBuilder cli;
public static CliBuilder GetCliBuilder() {
if (this.cli == null)
this.cli = new CliBuilder();
return this.cli;
}
public static OptionAccessor HandleAppCliInput(String[] args) {
return this.HandleCommandLineInput(args,
{ CliBuilder builder ->
builder.usage = "groovy App.groovy [OPTIONS]"
builder.header = "Merge multiple Excel files into a single file."
builder.footer = "Source files must be in XLSX format and destination folder must exist."
// Define options
builder << Option.builder()
.option("h")
.longOpt("help")
.desc("Print this help message.")
.build();
builder << Option.builder()
.option("s")
.longOpt("sourceFiles")
.desc("The source XLSX files to merge.")
.hasArgs()
.required()
.build();
builder << Option.builder()
.option("d")
.longOpt("destinationFolder")
.desc("The destination folder for the merged file.")
.numberOfArgs(1)
.required()
.build();
},
{ OptionAccessor options ->
// return (options.sourceFiles != null) && (!((List<String>)options.sourceFiles).isEmpty()) &&
return (options.sourceFiles) &&
(options.destinationFolder);
})
}
public static OptionAccessor HandleCommandLineInput(String[] args, Closure onGetSetup, Closure<Boolean> onValidateOptions) {
this.GetCliBuilder().with(onGetSetup);
OptionAccessor options = this.GetCliBuilder().parse(args);
if (!onValidateOptions(options)) {
printUsage();
System.exit(1);
}
return options;
}
public static void printUsage() {
println cli.usage();
}
}
Test
I write a JUnit test against the CommandLineUtils.HandleAppCliInput(), defined to be :
#Test
void testHandleAppCliInput() {
final String destinationFolder = "../legacy-data-migration";
final List<String> excelFiles = ["a.xlsx", "b.xlsx"];
final String[] commandTokens = "groovy App.groovy --sourceFiles ${excelFiles.join(' ')} --destinationFolder ${destinationFolder}"
.split(' ');
final String[] args = commandTokens.takeRight(commandTokens.length - 2);
assertTrue(args[0].equals("--sourceFiles"))
final OptionAccessor options = CommandLineUtils.HandleAppCliInput(args);
assertIterableEquals(excelFiles, options.sourceFiles);
assertEquals(destinationFolder, options.destinationFolder);
}
and it fails!
At run time, options.sourceFiles.equals("a.xlsx"), instead of the ['a.xlsx', 'b.xlsx'] that we're expecting...
What am I doing wrong here?
DISCLAIMER: I am using implementation 'org.apache.groovy:groovy-cli-commons:4.0.9'

how to create NexmoClient object?

I tried to get NexmoClient object without success.
I Fill in API_KEY and API_SECRET with the values I copied from the Nexmo Dashboard.
import com.nexmo.client.NexmoClient;
import com.nexmo.client.auth.AuthMethod;
import com.nexmo.client.auth.TokenAuthMethod;
import com.nexmo.client.sms.SmsSubmissionResult;
import com.nexmo.client.sms.messages.TextMessage;
public class SendSMS {
public static void main(String[] args) throws Exception {
AuthMethod auth = new TokenAuthMethod(1111,22222);
NexmoClient client = new NexmoClient(auth);
}
}
"
After the Gradle run, I was expected to NexmoClient object as they wrote in the docs https://www.nexmo.com/blog/2017/05/03/send-sms-messages-with-java-dr/
for continue to the next step, but I didn't know where to insert the following info
TextMessage message = new TextMessage(FROM_NUMBER, TO_NUMBER, "Hello from
Nexmo!");
SmsSubmissionResult[] responses =
client.getSmsClient().submitMessage(message);
for (SmsSubmissionResult response : responses) {
System.out.println(response);
}
You can put that code below where you initialize the client. Your whole class will then look like this:
import com.nexmo.client.NexmoClient;
import com.nexmo.client.auth.AuthMethod;
import com.nexmo.client.auth.TokenAuthMethod;
import com.nexmo.client.sms.messages.TextMessage;
public class SendSMS {
private static final String FROM_NUMBER = "";
private static final String TO_NUMBER = "";
public static void main(String[] args) throws Exception {
AuthMethod auth = new TokenAuthMethod(1111, 22222);
NexmoClient client = new NexmoClient(auth);
TextMessage message = new TextMessage(FROM_NUMBER, TO_NUMBER, "Hello from Nexmo !");
SmsSubmissionResult[] responses = client.getSmsClient().submitMessage(message);
for (SmsSubmissionResult response : responses) {
System.out.println(response);
}
}
}
This blog post is actually a bit old and suggests using an older version of the server SDK. There's an updated example on the developer portal as some things have changed in the newer versions of the SDK: https://developer.nexmo.com/messaging/sms/code-snippets/send-an-sms

TextArea is not updating while zip extraction

I am working on a JavaFx application, there i have a script that extract a zip followed by some other operation like updating files etc.
I want to have a textArea that displays whats going on in background, like "Zip extracting...", "Updating xyz file" etc.
Till now i have tried following way:
MyTask<String> task;
task = new MyTask<String>() {
#Override
protected String call() throws Exception {
File path = new File(exportTo.getAbsolutePath());
updateMessage("Extracting modular app to target directory...");
patcher.unZip(appPath.getAbsolutePath(), path.getAbsolutePath());
if (path.exists()) {
AppInfo info = getAppInfo();
patcher.patchAndroid(info, resourceZip, new File(path.getAbsolutePath() + "/" + appPath.getName().substring(0, appPath.getName().lastIndexOf("."))), this);
showOkAlert("Build completed!");
} else {
showOkAlert("Modular app folder not found");
}
return "";
}
#Override
protected void updateProgress(double workDone, double max) {
patcher.reportLogs(message);
}
private String message;
#Override
public void updateMessage(final String message) {
Platform.runLater(() -> patcher.reportLogs(message));
this.message = message;
//updateProgress(0, 0);
}
};
task.run();
MyTask class
abstract class MyTask<T> extends Task<T> {
abstract public void updateMessage(String message);
}
I have tried using updateProgress method, Platform.runLater() but nothing is working.
All the message i printed in textArea are printed after all operation is done.
Please help.
As javadoc for Task states you need to manually create a Thread to execute your Task:
Thread th = new Thread(task);
th.start();
Currently your task is being run on Application UI thread and blocks UI updates.

Mockito : Mock groovy rest client call

I am using Mockito with Groovy to unit test some rest calls using the Groovy rest client.
How can I mock the bpmApiRestClient.get call in the updatePhase method below?
#Service
public class PhasesBPMServiceImpl implements PhasesBPMService {
Logger logger = Logger.getLogger(PhasesBPMServiceImpl.class)
#Autowired
ObjectMapper objectMapper
#Autowired
BPMConfig bpmConfig
#Autowired
JsonSlurper jsonSlurper
#Autowired
GetMaintenanceActivitiesPhasesCurrentResponseTransformer getMaintenanceActivitiesPhasesCurrentResponseTransformer
#Autowired
PutMaintenanceActivityPhaseRequestTransformer putMaintenanceActivityPhaseRequestTransformer
public void updatePhase(
String loggedInUsernameEncoded,
String phaseDefinitionKey,
String activityId,
Reader reader) {
def bpmApiRestClient = new BpmRestClient(bpmConfig)
try {
def processInstancePhases = bpmApiRestClient.get path: 'task', query: [ processInstanceId: activityId ]
} catch (Exception e) {
e.printStackTrace()
logger.error "Error occurred while updating phase details. Error Message [${e?.message}]. Error Cause [${e?.cause}]"
throw e
}
finally {
bpmApiRestClient.shutdown()
}
}
At one stage I had things working as per the unit test below but once I refactored bpmApiRestClient to be instantiated inside the method rather than at the class level the mocking stopped working.
class PhasesBPMServiceImplPutMaintenanceActivitiesByActivityIdPhasesNameTest {
def restClient, responseTransformer, objectMapper, jsonSlurper, bpmConfig
void init() {
restClient = Mockito.mock(RESTClient)
when(restClient.get(anyObject())).thenReturn([data: [
[ // get current task for process id
id: "2",
name: "Waiting to be allocated",
assignee: "Cosmo Kramer",
created: "2016-11-16T15:10:29"
]
]])
responseTransformer = new PutMaintenanceActivityPhaseRequestTransformer(responseBaseUrl: '/maintenance/activities')
objectMapper = new ObjectMapperConfig().getObjectMapper()
jsonSlurper = new JsonSlurper()
bpmConfig = new BPMConfig(maintenanceProcessName:'Maintenance_Activity_Process',
baseUrl:'http://localhost:12378/v1/camunda/rest/')
}
#Test
void testUpdatePhaseSuccess() {
// setup
init()
PhasesBPMServiceImpl service =
new PhasesBPMServiceImpl(bpmConfig: bpmConfig,
putMaintenanceActivityPhaseRequestTransformer: responseTransformer,
objectMapper: objectMapper,
jsonSlurper: new JsonSlurper())
// invoke
try {
def request = getClass().getResourceAsStream('/in/putPhaseRequest.json').text
def response = service.updatePhase('rriviere', 'Unallocated', '7', new StringReader(request))
} catch (Exception e) {
e.printStackTrace()
fail()
}
}
}
thanks
You refactored your code to be untestable as the bpmApiRestClient cannot be mocked. Make it a dependency of this class (instead of bpmConfig) or refactor retrieving the results into a separate class.

Debugging Package Manager Console Update-Database Seed Method

I wanted to debug the Seed() method in my Entity Framework database configuration class when I run Update-Database from the Package Manager Console but didn't know how to do it. I wanted to share the solution with others in case they have the same issue.
Here is similar question with a solution that works really well.
It does NOT require Thread.Sleep.
Just Launches the debugger using this code.
Clipped from the answer
if (!System.Diagnostics.Debugger.IsAttached)
System.Diagnostics.Debugger.Launch();
The way I solved this was to open a new instance of Visual Studio and then open the same solution in this new instance of Visual Studio. I then attached the debugger in this new instance to the old instance (devenv.exe) while running the update-database command. This allowed me to debug the Seed method.
Just to make sure I didn't miss the breakpoint by not attaching in time I added a Thread.Sleep before the breakpoint.
I hope this helps someone.
If you need to get a specific variable's value, a quick hack is to throw an exception:
throw new Exception(variable);
A cleaner solution (I guess this requires EF 6) would IMHO be to call update-database from code:
var configuration = new DbMigrationsConfiguration<TContext>();
var databaseMigrator = new DbMigrator(configuration);
databaseMigrator.Update();
This allows you to debug the Seed method.
You may take this one step further and construct a unit test (or, more precisely, an integration test) that creates an empty test database, applies all EF migrations, runs the Seed method, and drops the test database again:
var configuration = new DbMigrationsConfiguration<TContext>();
Database.Delete("TestDatabaseNameOrConnectionString");
var databaseMigrator = new DbMigrator(configuration);
databaseMigrator.Update();
Database.Delete("TestDatabaseNameOrConnectionString");
But be careful not to run this against your development database!
I know this is an old question, but if all you want is messages, and you don't care to include references to WinForms in your project, I made some simple debug window where I can send Trace events.
For more serious and step-by-step debugging, I'll open another Visual Studio instance, but it's not necessary for simple stuff.
This is the whole code:
SeedApplicationContext.cs
using System;
using System.Data.Entity;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
namespace Data.Persistence.Migrations.SeedDebug
{
public class SeedApplicationContext<T> : ApplicationContext
where T : DbContext
{
private class SeedTraceListener : TraceListener
{
private readonly SeedApplicationContext<T> _appContext;
public SeedTraceListener(SeedApplicationContext<T> appContext)
{
_appContext = appContext;
}
public override void Write(string message)
{
_appContext.WriteDebugText(message);
}
public override void WriteLine(string message)
{
_appContext.WriteDebugLine(message);
}
}
private Form _debugForm;
private TextBox _debugTextBox;
private TraceListener _traceListener;
private readonly Action<T> _seedAction;
private readonly T _dbcontext;
public Exception Exception { get; private set; }
public bool WaitBeforeExit { get; private set; }
public SeedApplicationContext(Action<T> seedAction, T dbcontext, bool waitBeforeExit = false)
{
_dbcontext = dbcontext;
_seedAction = seedAction;
WaitBeforeExit = waitBeforeExit;
_traceListener = new SeedTraceListener(this);
CreateDebugForm();
MainForm = _debugForm;
Trace.Listeners.Add(_traceListener);
}
private void CreateDebugForm()
{
var textbox = new TextBox {Multiline = true, Dock = DockStyle.Fill, ScrollBars = ScrollBars.Both, WordWrap = false};
var form = new Form {Font = new Font(#"Lucida Console", 8), Text = "Seed Trace"};
form.Controls.Add(tb);
form.Shown += OnFormShown;
_debugForm = form;
_debugTextBox = textbox;
}
private void OnFormShown(object sender, EventArgs eventArgs)
{
WriteDebugLine("Initializing seed...");
try
{
_seedAction(_dbcontext);
if(!WaitBeforeExit)
_debugForm.Close();
else
WriteDebugLine("Finished seed. Close this window to continue");
}
catch (Exception e)
{
Exception = e;
var einner = e;
while (einner != null)
{
WriteDebugLine(string.Format("[Exception {0}] {1}", einner.GetType(), einner.Message));
WriteDebugLine(einner.StackTrace);
einner = einner.InnerException;
if (einner != null)
WriteDebugLine("------- Inner Exception -------");
}
}
}
protected override void Dispose(bool disposing)
{
if (disposing && _traceListener != null)
{
Trace.Listeners.Remove(_traceListener);
_traceListener.Dispose();
_traceListener = null;
}
base.Dispose(disposing);
}
private void WriteDebugText(string message)
{
_debugTextBox.Text += message;
Application.DoEvents();
}
private void WriteDebugLine(string message)
{
WriteDebugText(message + Environment.NewLine);
}
}
}
And on your standard Configuration.cs
// ...
using System.Windows.Forms;
using Data.Persistence.Migrations.SeedDebug;
// ...
namespace Data.Persistence.Migrations
{
internal sealed class Configuration : DbMigrationsConfiguration<MyContext>
{
public Configuration()
{
// Migrations configuration here
}
protected override void Seed(MyContext context)
{
// Create our application context which will host our debug window and message loop
var appContext = new SeedApplicationContext<MyContext>(SeedInternal, context, false);
Application.Run(appContext);
var e = appContext.Exception;
Application.Exit();
// Rethrow the exception to the package manager console
if (e != null)
throw e;
}
// Our original Seed method, now with Trace support!
private void SeedInternal(MyContext context)
{
// ...
Trace.WriteLine("I'm seeding!")
// ...
}
}
}
Uh Debugging is one thing but don't forget to call:
context.Update()
Also don't wrap in try catch without a good inner exceptions spill to the console.
https://coderwall.com/p/fbcyaw/debug-into-entity-framework-code-first
with catch (DbEntityValidationException ex)
I have 2 workarounds (without Debugger.Launch() since it doesn't work for me):
To print message in Package Manager Console use exception:
throw new Exception("Your message");
Another way is to print message in file by creating a cmd process:
// Logs to file {solution folder}\seed.log data from Seed method (for DEBUG only)
private void Log(string msg)
{
string echoCmd = $"/C echo {DateTime.Now} - {msg} >> seed.log";
System.Diagnostics.Process.Start("cmd.exe", echoCmd);
}

Resources