Cannot run a JUnit test case containing threads from Eclipse - eclipse

I am running JUnit test case from Eclipse 3.4.1 . This test case creates a class which starts a thread to do some stuff. When the test method ends it seems that Eclipse is forcibly shutting down the thread.
If I run the same test from the command line, then the thread runs properly.
Somehow I do not remember running into such problems with Eclipse before. Is this something that was always present in Eclipse or did they add it in 3.4.x ?
Here is an example:
When I run this test from Eclipse, I get a few printts of the cnt (till about 1800) and then the test case is terminated utomatically. However, if I run the main method, which starts JUnit's TestRunner, then the thread counts indefinetely.
import junit.framework.TestCase;
import junit.textui.TestRunner;
/**
* This class shows that Eclipses JUnit test case runner will forcibly
* terminate all running threads
*
* #author pshah
*
*/
public class ThreadTest extends TestCase {
static Runnable run = new Runnable() {
public void run() {
int cnt = 0;
while(true) System.out.println(cnt++);
}
};
public void testThread() {
Thread t = new Thread(run);
t.start();
}
public static void main(String args[]) {
TestRunner runner = new TestRunner();
runner.run(ThreadTest.class);
}
}

I adapted your code to JUnit NG and it's the same result: The thread is killed.
public class ThreadTest {
static Runnable run = new Runnable() {
public void run() {
int cnt = 0;
while (true)
System.out.println(cnt++);
}
};
#Test
public void threadRun() {
Thread t = new Thread(run);
t.start();
assertEquals("RUNNABLE", t.getState().toString());
}
}
If I use the JUnit jar (4.3.1 in my case) from the Eclipe plugin folder to execute the tests via the command line, it has the same behavior like executing it in Eclipse (It's logical :) ).
I tested JUnit 4.6 (just downloaded) in the commandline and it also stops after a short time! It's exactly the same behavior like in Eclipse
I found out, that it is killed if the last instruction is done. It's logical, if you consider how JUnit works:
For each test, a new object is created. If the test is over, it's killed. Everything belonging to this test is killed.
That means, that every thread must be stopped.
JUnit deals correctly with this situation. Unit test must be isolated and easy to execute. So it has to end all threads, if the end of the test is reached.
You may wait, till the test is finished and then execute your assertXXX instruction. This would be the right way to test threads.
But be carefull: It may kill your execution times!

I believe this modification will yield the desired result for unit testing various thread scenarios.
(sorry if the formatting is wonky)
public class ThreadTest {
static Runnable run = new Runnable() {
public void run() {
int cnt = 0;
while (true)
System.out.println(cnt++);
}
};
#Test
public void threadRun() {
Thread t = new Thread(run);
t.start();
//Run the thread, t, for 30 seconds total.
//Assert the thread's state is RUNNABLE, once per second
for(int i=0;i<30;i++){
assertEquals("RUNNABLE", t.getState().toString());
try {
Thread.sleep(1000);//1 second sleep
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Done with my thread unit test.");
}
}

This works but you have to name your thread or find another way to refer to it.
protected boolean monitorSecondaryThread(String threadName, StringBuilder errorMessage, boolean ignoreFailSafe) {
int NUM_THREADS_BESIDES_SECONDARY_THREAD = 2;
int MAX_WAIT_TIME = 10000;
MyUncaughtExceptionHandler meh = new MyUncaughtExceptionHandler();
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for (Thread t : threadSet) {
t.setUncaughtExceptionHandler(meh);
}
Date start = Calendar.getInstance().getTime();
boolean stillAlive = true;
while (stillAlive) {
for (Thread t : threadSet) {
if (t.getName().equalsIgnoreCase(threadName) && !t.isAlive()) {
stillAlive = false;
}
}
Date end = Calendar.getInstance().getTime();
if (!ignoreFailSafe && (end.getTime() - start.getTime() > MAX_WAIT_TIME || Thread.activeCount() <= NUM_THREADS_BESIDES_SECONDARY_THREAD)) {
System.out.println("Oops, flawed thread monitor.");
stillAlive = false;
}
}
if (meh.errorCount > 0) {
System.out.println(meh.error);
errorMessage.append(meh.error);
return false;
}
return true;
}
private class MyUncaughtExceptionHandler implements UncaughtExceptionHandler {
public int errorCount = 0;
public String error = "";
#Override
public void uncaughtException(Thread t, Throwable e) {
ByteArrayOutputStream bs = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(bs);
e.printStackTrace(ps);
error = bs.toString();
errorCount++;
}
}

Related

Reset scheduled job after completion

I have an scheduled job implemented with Spring batch. Right now when it finishes it doesn't start again because it is detected as completed, is it possible to reset its state after completion?
#Component
class JobScheduler {
#Autowired
private Job job1;
#Autowired
private JobLauncher jobLauncher;
#Scheduled(cron = "0 0/15 * * * ?")
public void launchJob1() throws Exception {
this.jobLauncher.run(this.job1, new JobParameters());
}
}
#Configuration
public class Job1Configuration{
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Bean
public Job job1() {
return this.jobBuilderFactory.get("job1")
.start(this.step1()).on(STEP1_STATUS.NOT_READY.get()).end()
.from(this.step1()).on(STEP1_STATUS.READY.get()).to(this.step2())
.next(this.step3())
.end()
.build();
}
}
I know I can set a job parameter with the time or the id, but this will launch a new execution every 15 minutes. I want to repeat the same execution until is completed without errors, and then, execute a new one.
You can't restart your job because you're setting the job status to COMPLETE by calling end() in .start(this.step1()).on(STEP1_STATUS.NOT_READY.get()).end().
You should instead either fail the job by calling .start(this.step1()).on(STEP1_STATUS.NOT_READY.get()).fail()
or stop the job by calling .start(this.step1()).on(STEP1_STATUS.NOT_READY.get()).stopAndRestart(step1())
Those options will mean the job status is either FAILED or STOPPED instead of COMPLETE which means that if you launch the job with the same JobParameters, it will restart the previous job execution.
See https://docs.spring.io/spring-batch/docs/current/reference/html/step.html#configuringForStop
To launch the job in a way that handles restarting previous instances or starting a new instance, you could look at how the SimpleJobService in spring-batch-admin does it and modify the launch method slightly for your purposes. This requires you to specify an incremental job parameter that is used to launch new instances of your job.
https://github.com/spring-attic/spring-batch-admin/blob/master/spring-batch-admin-manager/src/main/java/org/springframework/batch/admin/service/SimpleJobService.java#L250
#Override
public JobExecution launch(String jobName, JobParameters jobParameters) throws NoSuchJobException,
JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException,
JobParametersInvalidException {
JobExecution jobExecution = null;
if (jobLocator.getJobNames().contains(jobName)) {
Job job = jobLocator.getJob(jobName);
JobExecution lastJobExecution = jobRepository.getLastJobExecution(jobName, jobParameters);
boolean restart = false;
if (lastJobExecution != null) {
BatchStatus status = lastJobExecution.getStatus();
if (status.isUnsuccessful() && status != BatchStatus.ABANDONED) {
restart = true;
}
}
if (job.getJobParametersIncrementer() != null && !restart) {
jobParameters = job.getJobParametersIncrementer().getNext(jobParameters);
}
jobExecution = jobLauncher.run(job, jobParameters);
if (jobExecution.isRunning()) {
activeExecutions.add(jobExecution);
}
} else {
if (jsrJobOperator != null) {
// jobExecution = this.jobExecutionDao
// .getJobExecution(jsrJobOperator.start(jobName, jobParameters.toProperties()));
jobExecution = new JobExecution(jsrJobOperator.start(jobName, jobParameters.toProperties()));
} else {
throw new NoSuchJobException(String.format("Unable to find job %s to launch",
String.valueOf(jobName)));
}
}
return jobExecution;
}
I think the difficulty here comes from mixing scheduling with restartability. I would make each schedule execute a distinct job instance (for example by adding the run time as an identifying job parameter).
Now if a given schedule fails, it could be restarted separately until completion without affecting subsequent schedules. This can be done manually or programmtically in another scheduled method.
This is the solution I came up with after all the comments:
#Component
class JobScheduler extends JobSchedulerLauncher {
#Autowired
private Job job1;
#Scheduled(cron = "0 0/15 * * * ?")
public void launchJob1() throws Exception {
this.launch(this.job1);
}
}
public abstract class JobSchedulerLauncher {
#Autowired
private JobOperator jobOperator;
#Autowired
private JobExplorer jobExplorer;
public void launch(Job job) throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException,
JobParametersInvalidException, NoSuchJobException, NoSuchJobExecutionException, JobExecutionNotRunningException, JobParametersNotFoundException, UnexpectedJobExecutionException {
// Get the last instance
final List<JobInstance> jobInstances = this.jobExplorer.findJobInstancesByJobName(job.getName(), 0, 1);
if (CollectionUtils.isNotEmpty(jobInstances)) {
// Get the last executions
final List<JobExecution> jobExecutions = this.jobExplorer.getJobExecutions(jobInstances.get(0));
if (CollectionUtils.isNotEmpty(jobExecutions)) {
final JobExecution lastJobExecution = jobExecutions.get(0);
if (lastJobExecution.isRunning()) {
this.jobOperator.stop(lastJobExecution.getId().longValue());
this.jobOperator.abandon(lastJobExecution.getId().longValue());
} else if (lastJobExecution.getExitStatus().equals(ExitStatus.FAILED) || lastJobExecution.getExitStatus().equals(ExitStatus.STOPPED)) {
this.jobOperator.restart(lastJobExecution.getId().longValue());
return;
}
}
}
this.jobOperator.startNextInstance(job.getName());
}
}
My job now uses an incrementer, based on this one https://docs.spring.io/spring-batch/docs/current/reference/html/job.html#JobParametersIncrementer:
#Bean
public Job job1() {
return this.jobBuilderFactory.get("job1")
.incrementer(new CustomJobParameterIncrementor())
.start(this.step1()).on(STEP1_STATUS.NOT_READY.get()).end()
.from(this.step1()).on(STEP1_STATUS.READY.get()).to(this.step2())
.next(this.step3())
.end()
.build();
}
In my case my scheduler won't start 2 instances of the same job at the same time, so if I detect a running job in this code it means that the server restarted leaving the job with status STARTED, that's why I stop it and abandon it.

How to stop NUnit ITestRunner?

Using nunit.engine 3.10.0, I can't stop an asynchronously running ITestRunner. The TestPackage is set up to be executed locally, i.e. InProcess and in the current AppDomain. No more tests are started after the second test as expected, but the while loop never ends.
public static void Main(string[] args)
{
// 2 assemblies x 2 TestFixtures each x 2 Tests each = 8 test cases
string[] testAssemblyFileNames = { TestAssemblyFileName1, TestAssemblyFileName2 };
string assemblyDirectory = Path.GetDirectoryName(Uri.UnescapeDataString(
new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));
// Nunit 3.10.0
var minVersion = new Version("3.4");
ITestEngine testEngine = TestEngineActivator.CreateInstance(minVersion);
// configure a test package that executes
// in the current process and in the current domain
var testPackage = new TestPackage(testAssemblyFileNames);
testPackage.AddSetting(EnginePackageSettings.ProcessModel, "InProcess");
testPackage.AddSetting(EnginePackageSettings.DomainUsage, "None");
testPackage.AddSetting(EnginePackageSettings.DisposeRunners, "True");
testPackage.AddSetting(EnginePackageSettings.WorkDirectory, assemblyDirectory);
ITestRunner testRunner = testEngine.GetRunner(testPackage);
// prepare a listener that stops the test runner
// when the second test has been started
const bool StopAfterSecondTest = true;
int testStartedCount = 0;
var listener = new MyTestEventListener();
listener.TestStarted += (sender, eventArgs) =>
{
testStartedCount++;
if ( StopAfterSecondTest && testStartedCount == 2 )
{
testRunner.StopRun(force: true);
}
};
var testFilterBuilder = new TestFilterBuilder();
TestFilter testFilter = testFilterBuilder.GetFilter();
ITestRun testRun = testRunner.RunAsync(listener, testFilter);
bool keepRunning;
int loopCount = 0;
do
{
bool completed = testRun.Wait(500);
bool running = testRunner.IsTestRunning;
keepRunning = !completed && running;
loopCount++;
} while ( keepRunning );
Console.WriteLine($"Loop count: {loopCount}");
XmlNode resultNode = testRun.Result;
Console.WriteLine(resultNode.InnerText);
Console.ReadKey();
}
private class MyTestEventListener : ITestEventListener
{
private const string TestCaseStartPrefix = "<start-test";
private const string TestMethodTypeAttribute = " type=\"TestMethod\"";
public event EventHandler<EventArgs> TestStarted;
public void OnTestEvent(string report)
{
if ( report.StartsWith(TestCaseStartPrefix) &&
report.Contains(TestMethodTypeAttribute) )
{
TestStarted?.Invoke(this, new EventArgs());
}
}
}
If I skip waiting and try to get the test result, I get an InvalidOperationException: 'Cannot retrieve Result from an incomplete or cancelled TestRun.'
How can I stop the test runner and get the results of the tests that were completed before the stopping?
You can't do it from inside a test. Your listener is executed in the context of the test itself. For that reason, listeners are specifically forbidden from trying to change the outcome of a test. Additionally, the event is buffered and may not even be received in this case until after the test run is complete.
StopRun is intended to be called by the main runner itself, generally as triggered by some user input.
You should also take note of this issue: https://github.com/nunit/nunit/issues/3276 which prevents StopRun(true) from working under any circumstances. It was fixed in PR https://github.com/nunit/nunit/pull/3281 but is not yet in any release of the framework. You will have to either use a recent dev build of the framework or switch to StopRun(false).
Based on the answer by #Charlie, this is how to modify the code in order to stop all threads:
public static void Main(string[] args)
{
// 2 assemblies x 2 TestFixtures each x 2 Tests each = 8 test cases
// each test case includes a 200 ms delay
string[] testAssemblyFileNames = { TestAssemblyFileName1, TestAssemblyFileName2 };
string assemblyDirectory = Path.GetDirectoryName(Uri.UnescapeDataString(
new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));
// Nunit 3.10.0
var minVersion = new Version("3.4");
ITestEngine testEngine = TestEngineActivator.CreateInstance(minVersion);
// configure a test package that executes
// in the current process and in the current domain
var testPackage = new TestPackage(testAssemblyFileNames);
testPackage.AddSetting(EnginePackageSettings.ProcessModel, "InProcess");
testPackage.AddSetting(EnginePackageSettings.DomainUsage, "None");
testPackage.AddSetting(EnginePackageSettings.DisposeRunners, "True");
testPackage.AddSetting(EnginePackageSettings.WorkDirectory, assemblyDirectory);
ITestRunner testRunner = testEngine.GetRunner(testPackage);
var listener = new TestStartListener();
var testFilterBuilder = new TestFilterBuilder();
TestFilter testFilter = testFilterBuilder.GetFilter();
ITestRun testRun = testRunner.RunAsync(listener, testFilter);
// wait until the first test case has been started
while ( listener.Count < 1 )
{
Thread.Sleep(50);
}
bool keepRunning = true;
while ( keepRunning )
{
int testStartedCount = listener.Count;
testRunner.StopRun(force: false);
Writer.WriteLine($"{GetTimeStamp()}, Stop requested after {testStartedCount} test cases.");
// wait for less time than a single test needs to complete
bool completed = testRun.Wait(100);
bool running = testRunner.IsTestRunning;
Writer.WriteLine($"{GetTimeStamp()} Completed: {completed}, running: {running}");
keepRunning = !completed && running;
}
listener.WriteReportsTo(Writer);
XmlNode resultNode = testRun.Result;
Writer.WriteLine("Test result:");
resultNode.WriteContentTo(ResultWriter);
Console.ReadKey();
}
private class TestStartListener : List<string>, ITestEventListener
{
private const string TestCaseStartPrefix = "<start-test";
private const string TestMethodTypeAttribute = " type=\"TestMethod\"";
public event EventHandler<EventArgs> TestStarted;
public void OnTestEvent(string report)
{
if ( report.StartsWith(TestCaseStartPrefix) &&
report.Contains(TestMethodTypeAttribute) )
{
Add($"{GetTimeStamp()}, {report}");
TestStarted?.Invoke(this, new EventArgs());
}
}
public void WriteReportsTo(TextWriter writer)
{
Writer.WriteLine($"Listener was called {Count} times.");
foreach ( var report in this )
{
Writer.WriteLine(report);
}
}
}
The two test assemblies get executed in the runner's process, in a single domain and on two threads, one for each test assembly. In total, two test methods get executed and pass; one for each of the two test assemblies. Other test methods do not get executed and not reported. Other test fixtures (classes) do not get executed and get reported with result="Failed" label="Cancelled".
Note that testRunner.StopRun(force: false) is called repeatedly. If only called once, the other thread will run to completion.

rxjava: queue scheduler with default idle job

I have a client server application and I'm using rxjava to do server requests from the client. The client should only do one request at a time so I intent to use a thread queue scheduler similar to the trampoline scheduler.
Now I try to implement a mechanism to watch changes on the server. Therefore I send a long living request that blocks until the server has some changes and sends back the result (long pull).
This long pull request should only run when the job queue is idle. I'm looking for a way to automatically stop the watch request when a regular request is scheduled and start it again when the queue becomes empty. I thought about modifying the trampoline scheduler to get this behavior but I have the feeling that this is a common problem and there might be an easier solution?
You can hold onto the Subscription returned by scheduling the long poll task, unsubscribe it if the queue becomes non-empty and re-schedule if the queue becomes empty.
Edit: here is an example with the basic ExecutorScheduler:
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
public class IdleScheduling {
static final class TaskQueue {
final ExecutorService executor;
final AtomicReference<Future<?>> idleFuture;
final Runnable idleRunnable;
final AtomicInteger wip;
public TaskQueue(Runnable idleRunnable) {
this.executor = Executors.newFixedThreadPool(1);
this.idleRunnable = idleRunnable;
this.idleFuture = new AtomicReference<>();
this.wip = new AtomicInteger();
this.idleFuture.set(executor.submit(idleRunnable));
}
public void shutdownNow() {
executor.shutdownNow();
}
public Future<?> enqueue(Runnable task) {
if (wip.getAndIncrement() == 0) {
idleFuture.get().cancel(true);
}
return executor.submit(() -> {
task.run();
if (wip.decrementAndGet() == 0) {
startIdle();
}
});
}
void startIdle() {
idleFuture.set(executor.submit(idleRunnable));
}
}
public static void main(String[] args) throws Exception {
TaskQueue tq = new TaskQueue(() -> {
while (!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println("Idle interrupted...");
return;
}
System.out.println("Idle...");
}
});
try {
Thread.sleep(1500);
tq.enqueue(() -> System.out.println("Work 1"));
Thread.sleep(500);
tq.enqueue(() -> {
System.out.println("Work 2");
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
}
});
tq.enqueue(() -> System.out.println("Work 3"));
Thread.sleep(1500);
} finally {
tq.shutdownNow();
}
}
}

Deploy exploded bundle to Apache Felix using an Eclipse launch task

I am looking for a way to (re)deploy an exploded bundle (meaning not jarred but in a folder) to a running Apache Felix OSGi container from within Eclipse, preferably using a launch task.
I found this question, which has an answer that comes close but it depends on typing commands into a Gogo shell, which is not convenient for long-term development use. I'd like to use Eclipse's launch task mechanism for this, but if there are alternatives that are equally fast and convenient I am open to that as well.
Now I think that if I can fire Gogo shell commands from an Eclipse launch tasks, that would be a solution, but I also can't get my head around how to do that. I presume I need the Remote Shell bundle for that right?
I am starting to think about writing a telnet client in Java that can connect to the Remote Shell bundle and execute Gogo commands in an automated fashion. I have seen some example of that already which I can modify to suit my needs... However I am getting a 'reinventing the wheel' kind of feeling from that. Surely there is a better way?
Some background to help you understand what I am doing:
I have set up an Eclipse 'OSGiContainer' project which basically contains the Apache Felix jar and the third party bundles I want to deploy (like Gogo shell), similar to the project setup described here. Then I created a second 'MyBundle' project that contains my bundle. I want to start the OSGi container by launching the OSGiContainer project, and then just develop on my bundle and test my changes by launching the MyBundle project into the OSGiContainer that I just want to keep running the whole time during development.
Project layout:
OSGiContainer
bin (contains felix jar)
bundles (third party bundles)
conf (Felix' config.properties file)
MyBundle
src
target
classes
I am then able to deploy my bundle to the OSGi container by invoking these commands on the Gogo shell:
install reference:file:../MyBundle/target/classes
start <bundleId>
To re-deploy, I invoke these commands:
stop <bundleId>
uninstall <bundleId>
install reference:file:../MyBundle/target/classes
start <bundleId>
You can imagine having to invoke 4 commands on the shell each time is not that much fun... So even if you can give me a way to boil this down to less commands to type it would be a great improvement already.
UPDATE
I hacked around a bit and came up with the class below. It's an adaptation of the telnet example with some small changes and a main method with the necessary commands to uninstall a bundle and then re-install and start it. The path to the bundle should be given as an argument to the program and would look like:
reference:file:../MyBundle/target/classes
I still very much welcome answers to this question, as I don't really like this solution at all. I have however verified that this works:
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.net.SocketException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.commons.net.telnet.TelnetClient;
public class GogoDeployer {
static class Responder extends Thread {
private StringBuilder builder = new StringBuilder();
private final GogoDeployer checker;
private CountDownLatch latch;
private String waitFor = null;
private boolean isKeepRunning = true;
Responder(GogoDeployer checker) {
this.checker = checker;
}
boolean foundWaitFor(String waitFor) {
return builder.toString().contains(waitFor);
}
public synchronized String getAndClearBuffer() {
String result = builder.toString();
builder = new StringBuilder();
return result;
}
#Override
public void run() {
while (isKeepRunning) {
String s;
try {
s = checker.messageQueue.take();
} catch (InterruptedException e) {
break;
}
synchronized (Responder.class) {
builder.append(s);
}
if (waitFor != null && latch != null && foundWaitFor(waitFor)) {
latch.countDown();
}
}
System.out.println("Responder stopped.");
}
public String waitFor(String waitFor) {
synchronized (Responder.class) {
if (foundWaitFor(waitFor)) {
return getAndClearBuffer();
}
}
this.waitFor = waitFor;
latch = new CountDownLatch(1);
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
String result = null;
synchronized (Responder.class) {
result = builder.toString();
builder = new StringBuilder();
}
return result;
}
}
static class TelnetReader extends Thread {
private boolean isKeepRunning = true;
private final GogoDeployer checker;
private final TelnetClient tc;
TelnetReader(GogoDeployer checker, TelnetClient tc) {
this.checker = checker;
this.tc = tc;
}
#Override
public void run() {
InputStream instr = tc.getInputStream();
try {
byte[] buff = new byte[1024];
int ret_read = 0;
do {
if (instr.available() > 0) {
ret_read = instr.read(buff);
}
if (ret_read > 0) {
checker.sendForResponse(new String(buff, 0, ret_read));
ret_read = 0;
}
} while (isKeepRunning && (ret_read >= 0));
} catch (Exception e) {
System.err.println("Exception while reading socket:" + e.getMessage());
}
try {
tc.disconnect();
checker.stop();
System.out.println("Disconnected.");
} catch (Exception e) {
System.err.println("Exception while closing telnet:" + e.getMessage());
}
}
}
private static final String prompt = "g!";
private static GogoDeployer client;
private String host;
private BlockingQueue<String> messageQueue = new LinkedBlockingQueue<String>();
private int port;
private TelnetReader reader;
private Responder responder;
private TelnetClient tc;
public GogoDeployer(String host, int port) {
this.host = host;
this.port = port;
}
public void stop() {
responder.isKeepRunning = false;
reader.isKeepRunning = false;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
responder.interrupt();
reader.interrupt();
}
public void send(String command) {
PrintStream ps = new PrintStream(tc.getOutputStream());
ps.println(command);
ps.flush();
}
public void sendForResponse(String s) {
messageQueue.add(s);
}
public void connect() throws SocketException, IOException {
tc = new TelnetClient();
tc.connect(host, port);
reader = new TelnetReader(this, tc);
reader.start();
responder = new Responder(this);
responder.start();
}
public String waitFor(String s) {
return responder.waitFor(s);
}
private static String exec(String cmd) {
String result = "";
System.out.println(cmd);
client.send(cmd);
result = client.waitFor(prompt);
return result;
}
public static void main(String[] args) {
try {
String project = args[0];
client = new GogoDeployer("localhost", 6666);
client.connect();
System.out.println(client.waitFor(prompt));
System.out.println(exec("uninstall " + project));
String result = exec("install " + project);
System.out.println(result);
int start = result.indexOf(":");
int stop = result.indexOf(prompt);
String bundleId = result.substring(start + 1, stop).trim();
System.out.println(exec("start " + bundleId));
client.stop();
} catch (SocketException e) {
System.err.println("Unable to conect to Gogo remote shell: " + e.getMessage());
} catch (IOException e) {
System.err.println("Unable to conect to Gogo remote shell: " + e.getMessage());
}
}
}
When I met the same requirement (deploy bundle from target/classes as fast as I can) my first thought was also extending my container with some shell functionality. My second thought was, however, to write a simple bundle that opens up an always-on-top window and I can simply drag-and-drop any project(s) from Eclipse (or total commander or whatever) to that window. The code than checks if the folder(s) that was dropped has a target/classes folder and if it has it will be deployed.
The source code is available at https://github.com/everit-org/osgi-richconsole
The dependency is available from the maven-central.
The dependency is:
<dependency>
<groupId>org.everit.osgi.dev</groupId>
<artifactId>org.everit.osgi.dev.richconsole</artifactId>
<version>1.2.0</version>
</dependency>
You can use the bundle it while you develop and remove it when you set up your live server. However it is not necessary as if the container is running in a headless mode the pop-up window is not shown.
I called it richconsole as I would like to have more features in the future (not just deployment) :)

random types of errors occurring randomly in GTK# app using SOAP service async

I'm developing a GTK# application using a SOAP service to get the data. Errors are occurring on retrieving items and putting them in a Gtk.ComboBox.
Types of errors seen:
gmem.c:170: failed to allocate x bytes, followed by SIGTRAP/SIGSEV/whatever
glibc detected * /usr/bin/mono: double free or corruption (fasttop): 0x00007f27100e85a0 *
Gdk:ERROR:gdkregion-generic.c:1110:miUnionNonO: assertion failed: (y1 < y2)
followed by SIGIOT
*just a SIGSEGV with a long stracktrace
I do also see these quite often:
(KvkManager:11471): Pango-WARNING **: Invalid UTF-8 string passed to pango_layout_set_text()
(KvkManager:11506): Gtk-WARNING **: gtktreemodel.c:2114: bad row reference, proxy has no outstanding row references
This is the main part of my code:
using System;
using Gtk;
using KvkWsProxy;
public partial class MainWindow: Gtk.Window
{
private KvkSoapServerService kvkProxy;
private NodeStore productsStore;
protected Gdk.PixbufAnimation loadingTrobber;
public MainWindow (): base (Gtk.WindowType.Toplevel)
{
Build ();
this.tabs.CurrentPage = 0;
this.loadingTrobber = new Gdk.PixbufAnimation("ajax-loader.gif");
this.productsStore = new Gtk.NodeStore(typeof(KvkManager.SimpleProductTreeNode));
this.kvkProxy = new KvkSoapServerService();
this.kvkProxy.getSimpleProductsCompleted += this.putProducts;
this.kvkProxy.getCollectionsCompleted += this.putProductCollections;
this.kvkProxy.getTypesCompleted += this.putProductTypes;
this.productsList.NodeStore = productsStore;
this.productsList.AppendColumn("Nummer", new Gtk.CellRendererText(), "text", 0);
this.productsList.AppendColumn("Naam", new Gtk.CellRendererText(), "text", 1);
this.productsList.AppendColumn("Prijs", new Gtk.CellRendererText(), "text", 2);
this.productsList.ShowAll();
this.getProductCollections();
this.getProductTypes();
}
protected void OnDeleteEvent (object sender, DeleteEventArgs a)
{
Application.Quit ();
a.RetVal = true;
}
protected void putProductCollections(object sender, getCollectionsCompletedEventArgs args)
{
this.productCollectionsComboBox.Clear();
CellRendererText cell = new CellRendererText();
this.productCollectionsComboBox.PackStart(cell, false);
this.productCollectionsComboBox.AddAttribute(cell, "markup", 1);
ListStore store = new ListStore(typeof(int), typeof(string));
this.productCollectionsComboBox.Model = store;
store.AppendValues(-1, "<span font-style=\"italic\">alle collecties</span>");
foreach(Product_ProductCollection collection in args.Result)
{
store.AppendValues(collection.id, collection.name);
}
this.productCollectionsComboBox.Active = 0;
this.productCollectionsComboBox.Sensitive = true;
this.getCollectionsAnimation.Visible = false;
}
protected void putProductTypes(object sender, getTypesCompletedEventArgs args)
{
... like putProductCollections() ...
}
protected void OnSearchButtonClicked (object sender, System.EventArgs e)
{
this.productSearchButton.Sensitive = false;
this.searchAnimation.PixbufAnimation = this.loadingTrobber;
this.searchAnimation.Visible = true;
productsStore.Clear();
this.kvkProxy.getSimpleProductsAsync();
}
protected void putProducts(object sender, getSimpleProductsCompletedEventArgs args)
{
foreach(Product_SimpleProduct product in args.Result)
{
productsStore.AddNode(new KvkManager.SimpleProductTreeNode(product));
}
this.productSearchButton.Sensitive = true;
this.searchAnimation.Visible = false;
}
protected void getProductCollections()
{
this.productCollectionsComboBox.Sensitive = false;
this.getCollectionsAnimation.PixbufAnimation = this.loadingTrobber;
this.getCollectionsAnimation.Visible = true;
this.kvkProxy.getCollectionsAsync();
}
protected void getProductTypes()
{
... like putProductCollections() ...
}
protected void getProductSizegroups()
{
... like putProductCollections() ...
}
protected void getProductBrands()
{
... like putProductCollections() ...
}
}
You can download the whole project on http://home.vdslikke.net:8090/~johan/KvkManager.zip.
Versions of my software:
MonoDevelop 2.8.1
Mono 2.10.5 (tarball Mon Sep 5 19:35:47 UTC 2011) (64-bit)
GTK 2.24.8 (GTK# 2.12.0.0)
If there is any information you need to help me with this problem, please let me know.
I found out what I was doing wrong here
The thread that happens to run the event loop is said to "own" Gtk. This means that all Gtk operations should be perfomed from this thread and no other thread. Failure to restrict the use of Gtk to this thread will result in unpredictable behavior, and most often will lead to a crash.
After wrapping all GUI operations in Gtk.Application.Invoke() I get no errors anymore.
I solved the problem by not assigning the model before all the items were added, like this:
protected void putProductCollections(object sender, getCollectionsCompletedEventArgs args)
{
this.productCollectionsComboBox.Clear();
CellRendererText cell = new CellRendererText();
this.productCollectionsComboBox.PackStart(cell, false);
this.productCollectionsComboBox.AddAttribute(cell, "markup", 1);
ListStore store = new ListStore(typeof(int), typeof(string));
store.AppendValues(-1, "<span font-style=\"italic\">alle collecties</span>");
foreach(Product_ProductCollection collection in args.Result)
{
store.AppendValues(collection.id, collection.name);
}
this.productCollectionsComboBox.Model = store;
this.productCollectionsComboBox.Active = 0;
this.productCollectionsComboBox.Sensitive = true;
this.getCollectionsAnimation.Visible = false;
}
Now I only get GTK problems like wrong-drawn tabs and invisible animations once in a while. Then the following warning is printed in the console:
(KvkManager:13889): Gtk-CRITICAL **: IA__gtk_tree_row_reference_new: assertion `GTK_IS_TREE_MODEL (model)' failed
Any ideas on that?