Java - SWT - New runnable upon clicking submit button - java

I'm getting the dreaded...
Exception in thread "Controller Thread" org.eclipse.swt.SWTException: Invalid thread access
Quick overview of what I am trying to accomplish:
I have a listener on the Submit button, I would like to start a new thread due to the amount of processing the app will do with various url's.
This is part of my code in the Submit button listener...
submitButton.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent arg0) {
try {
// Check to see if http field is valid
httpValid = checkHttp(http);
if (httpValid) {
Thread t = new Thread(new UIMain(), "Controller Thread");
t.start();
} else {
System.out.println("Not a Valid http");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
Here is my run method...
public void run() {
options = new Options();
setOptions(options);
Controller run = new Controller(options);
}
The error points to line "setOptions(options)"
options is a object, holding some data from the SWF fields that the user will input. setOptions is fairly straight forward, in that function, I gather the data from the SWF fields, and set them in the object.
Let me know if I need to post any more code...
Example of some code I'm doing in setOptions(options)...
String url = http.getText();
options.addUrl(url);
Thanks,

You can not access the SWT UI straightly from a separate thread. What you should rather do is perform an async invocation from that separate thread using the Display API.
Example:
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
// access the SWT UI
}
});

Related

Displaying Progress Monitor for opening a Wizard in Eclipse Java SWT

I was trying to add a Progress Monitor for a Wizard Dialog in Eclipse in Java using SWT, but I'm getting an unusual error with no message at all. Here is my code:
This is the class I made for displaying the progress monitor:
public class OpenWizardsAction implements IRunnableWithProgress{
private WizardDialog dialog;
private String monitorMessage;
public OpenWizardsAction(WizardDialog dialog,String monitorMessage)
{
this.dialog=dialog;
this.monitorMessage=monitorMessage;
}
#Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException
{
// Tell the user what you are doing
monitor.beginTask(monitorMessage, IProgressMonitor.UNKNOWN);
// Do your work
if(Window.OK==dialog.open()) {}
// You are done
monitor.done();
}
}
And this is where I call this class:
WizardDialog dialog;
dialog = new WizardDialog(Display.getDefault().getActiveShell(), new RunWizard(runSum,runTable));
try {
IRunnableWithProgress op = new OpenWizardsAction(dialog,"Opening Run Wizard");
new ProgressMonitorDialog(Display.getDefault().getActiveShell()).run(true, true, op);
} catch (Exception e) {
MessageDialog.openError(Display.getDefault().getActiveShell(), "Unable to open Run Wizard", e.getMessage());
}
The MessageDialog.openError call shows empty message i.e. e.getMessage() is empty.
Is it because I'm using the same Display and Shell for both Wizard and ProgressMonitorDialog?
I also tried adding the below line in place of line 5 in the second code segment:
new ProgressMonitorDialog(new Shell(Display.getDefault(),SWT.NONE)).run(true, true, op);
Still there was error with an empty message.

hide and show a javafx stage from an other class with keeping all the information

I have this JavaFx app when I press one of the buttons, an other javafx class lauch!
so all what i need to know is : when I press the back button of the seconde class I need to find the first window with the same values entred in the bigging !
here what I can do for now:
Platform.runLater(new Runnable() {
#Override
public void run() {
try {
new MainApp().start(stage);
} catch (Exception e) {
StringWriter errors = new StringWriter();
e.printStackTrace(new PrintWriter(errors));
log.error(errors.toString());
}
}
});
I had the same problem and here is the solution:
let's suppose you have those 2 TextField one of them called apiurl and other called mainUrl ! all what you have to do is to to create String url = ""; and go to your button action and add this line : url=apiurl.getText(); in the initialize method in your controller add this : apiurl.setText(url); and this worked well for me !

Opening PDF file stored in resources folder raises Exception

I wrote a program in which a pdf file should be opened on an Action Event (you can have a look at my code below).
menuElementHilfe.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
File hilfe = new File ("src\\resources\\Hilfe.pdf");
try {
java.awt.Desktop.getDesktop().open(hilfe);
} catch (IOException e) {
e.printStackTrace();
}
}
});
If I execute the program via Eclipse everything works, but after exporting as a runnable jar I get following Exception:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: The file: src\resources\Hilfe.pdf doesn't exist.
Any Feedback is appreciated
The way you're retrieving resources may be the problem. try this :
menuElementHilfe.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
File hilfe = new File(getClass().getResource("/resources/Hilfe.pdf").getFile());
try {
java.awt.Desktop.getDesktop().open(hilfe);
} catch (IOException e) {
e.printStackTrace();
}
}
});
When running in Eclipse, you are targeting a file in your build path.
When running from JAR/WAR, the URL is different and look like "jar:file:/your-path/your-jar.jar!/Hilfe.pdf" which is not what you set when calling new File(...) So to get the right URL for internal resources, you have to use methods like getResource or getResourceAsStream depending on your needs.
Check out following explanations for more information :)
https://docs.oracle.com/javase/8/docs/technotes/guides/lang/resources.html
[EDIT]
I assume you're working on some Swing app, but I dont know if you're aware that doing some task like that in your AWT-EventQueue thread will freeze your UI.
To prevent that you have to run UI-unrelated stuff in another thread.
This is made using SwingUtilities.invokeLater (Java 5 and prior) method and/or the SwingWorker class (since Java 6).
as mentionned in this answer
You should put the previous solution in something like that :
SwingUtilities.invokeLater(new Runnable() {
public void run() {
// Your UI unrelated code here
}
});
The resource can be packed in the application jar, hence File (physical disk file)
is not possible. Copy it to a temporary file, so that the desktop can open it.
menuElementHilfe.addActionListener(evt -> {
Path tmp = Files.createTempFile("hilfe-", ".pdf");
Files.copy(getClass().getResourceAsStream("/Hilfe.pdf"), tmp);
try {
Desktop.getDesktop().open(tmp.toFile());
tmp.toFile().deleteOnExit();
} catch (IOException e) {
e.printStackTrace();
}
});
An other difference is the forward slash, and that the path is case-sensitive, opposed to Windows File.
After problems
menuElementHilfe.addActionListener(evt ->
SwingUtilities.invokeLater(() -> {
Path tmp = Files.createTempFile("hilfe-", ".pdf");
Logger.getLogger(getClass().getName()).log(Level.INFO, "actionPerformed "
+ tmp + "; event: " + evt);
Files.copy(getClass().getResourceAsStream("/resources/Hilfe.pdf"), tmp);
try {
Desktop.getDesktop().open(tmp.toFile());
//tmp.toFile().deleteOnExit();
} catch (IOException e) {
Logger.getLogger(getClass().getName()).log(Level.WARN, "Error with " + tmp,
e);
}
}));
I did not delete, so the Desktop access can live longer than the java app.
I did an invokeLater in order to have no frozen GUI on the actionPerformed.
I added logging to see every call to actionPerformed

multi-threaded website parser and out of memory problems

Hi.
I'm coding a website parser that is aimed to be fast and thus multi-threaded.
The external libraries I'm using are: apache HTTP client, Jsoup (for HTML parsing) and GPars (for message-driven threads).
Now I'll show some concept that I'm trying to implement
static StaticDispatchActor<String> httpActor;
public static void main(String[] args) throws ClientProtocolException, IOException {
int numThreads = 25;
try{
numThreads = Integer.parseInt(args[0]);
} catch (Exception e){
System.out.println("Number of threads defaulted to "+numThreads);
}
final int numberOfThreads = numThreads;
final ExecutorService threadpool = Executors.newCachedThreadPool();
final Async async = Async.newInstance().use(threadpool);
AtomicInteger jobCount = new AtomicInteger(0);
//.....
// This is a parser itself which parses usernames out of every page.
Actor jsoupUser = new StaticDispatchActor<String>(){ // actor to parse users
HashSet<String> users = new HashSet<>(); // found users
public void onMessage(String html){ // takes html -> adds parsed users 2 set
users.addAll(Jsoup.parse(html)
.select("a[href*=/profile/]").stream() // select links
.map(e -> e.text()) // extract usernames
.filter(s -> s.length() > 0) // empty lines -> out
.collect(Collectors.toSet()));
System.out.print("Users: "+users.size()+", Jobs: "+jobCount.get()+"\r");
}
}.start();
// This actor shall extract new links to parse out of every page
Actor jsoupLinker = new StaticDispatchActor<String>(){ // link extractor
HashSet<String> usedLinks = new HashSet<>(); // already found links
public synchronized void removeBack(String url){
#Override
public void onMessage(String html) {
Set<String> links = Jsoup.parse(html).select("a[href]").stream().parallel()
.map(e -> e.attr("href").replace("#comments", "")// here also some replacements...
)
.filter(s -> (!usedLinks.contains(s) && /* other filters */ )
.collect(Collectors.toSet());
links.forEach(url -> httpActor.send(url)); // send to process new URLs
}
}.start(); // start actor
// this actor is the processor of new links and where the error comes in:
httpActor = new StaticDispatchActor<String>(){ // process responses async
public void onMessage(String url) {
try{
while(jobCount.get()>numberOfThreads); // wait for running threads to be less than wanted value; without this number of running jobs goes out of any control
async.execute(Request.Get(defaultWebSiteUrl+url), new FutureCallback<Content>(){ #Override // do request and process async
public void completed(Content c) {
jobCount.decrementAndGet();
try{
String s = c.asString();
jsoupUser.send(s);
jsoupLinker.send(s);
} catch (OutOfMemoryError e1){
System.out.println("out of my memory, "); // This is the thrown error the question is about - [1]
}
}
#Override public void failed(Exception e) {
jobCount.decrementAndGet();
try {
throw e;
} catch (ConnectException e4){ // if the request is timed out resend it
httpActor.send(url);
System.out.println("resent\r\n");
} catch (HttpResponseException e0){
} catch (Exception e1) { // for all other exceptions
e1.printStackTrace();
}
}
#Override public void cancelled() {
jobCount.decrementAndGet(); // never done actually
}
});
jobCount.incrementAndGet();
} catch (IllegalArgumentException e3){
System.out.println("some illigal shit");
}
}
};
httpActor.start();
Now the problem is, although I limited a number of running jobs, my code somehow goes out of memory (search for [1] in the code to see where).
Maybe you have any idea on how to resolve it. Or there is some showcase for similar task, because I fill very wrong about the whole application design and maybe I should change it at all?
Thank you.
So, using BiziClop's tip, I was able to figure out the mistake.
If some is interested, I, as you can see above, was sending HTML code received from server as a string to 2 different actors and than, inside these actors, parsing them. That was the cause for all out-of-memory errors, since these HTML pages are pretty big especially given how many of them are waiting to be processed in the message queue.
The solution I used is just parse the document and select needed elements and transfer their list to matching actors for further processing.
Document doc = Jsoup.parse(c.asString());
jsoupUser.send(doc.select("a[href*=/profile/]"));
jsoupLinker.send(doc.select("a[href]"));
Still, if any one has anything to say about how to improve the algorithm I'll really appreciate it.

Execute multiple threads each one for a certain amount of time in java

I'm sending files to my local server that creates a file back. My problem occurs when the user perform multiple actions one after another and I need to show an error message if one of the requests don't get a feedback file in 5 min.
How can I handle all these requests? I used newSingleThreadScheduledExecutor to check if the feedback file is there every minute but I don't know how to handle multiple ones and keep the countdown to each request for the 5 min case.
My try:
ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(listPrinter.size()));
for(int i=0;i<list.size();i++){
try {
final File retrievedFile = new File("/home/"+list.get(i)+".csv");
ListenableFuture<File> future = executor.submit(new Callable<File>() {
public File call() {
// Actually send the file to your local server
// and retrieve a file back
if(retrievedFile.exists())
{
new Notification("file exits").show(Page.getCurrent());
}
else{
new Notification("file no exits").show(Page.getCurrent());
}
return retrievedFile;
}
});
future.get(5, TimeUnit.MINUTES);
} catch (InterruptedException ex) {
Exceptions.printStackTrace(ex);
} catch (ExecutionException ex) {
Exceptions.printStackTrace(ex);
} catch (TimeoutException ex) {
Exceptions.printStackTrace(ex);
new Notification("Time out").show(Page.getCurrent());
}
}
But it just get executed at the beginning and that's it but when the file is added nothing happens.
Is it possible to do this with watchService? It works pretty well for me but I didn't know about the 5 min case
Take a look to the Future interface:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html
should fit perfectly to your problem.
When you run a thread, the result could be a Future, it is the result of a asyncronous task, and you can have one Future per asyncronous task that you are launching.
Future<File> sendReceiveFile(File inputFile) {
final Future<File> future = new YourFuture<File>(...);
new Thread() {
#Override
public void run() {
File outputFile = null;
try {
outputFile = SendFileToServer(inputFile);
} catch (final Exception e) {
// do something
} finally {
future.setValue(fileOutput);
}
}
}.start();
return future;
}
And in your main:
Future<File> future = sendReceiveFile(myFile);
File outputFile = null;
try {
outputFile = future.get(1, TimeUnit.MINUTE);
} catch(TimeOutException e) {
// do something
}
You could do this manually, but using Guava ListenableFuture would be much better:
// Here we create a fixed thread pool with 10 threads and an inifinite-capacity queue
ListeningExecutorService executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
final File fileToSend = ...; //
ListenableFuture<File> future = executor.submit(new Callable<File>() {
public File call() {
// Actually send the file to your local server
// and retrieve a file back
File retrievedFile = YourLocalServer.sendAndRetrieve(fileToSend);
return retrievedFile;
}
});
Futures.addCallback(future, new FutureCallback<File>() {
public void onSuccess(File retrievedFile) {
// Handle the successfully retrieved file when it returns
}
public void onFailure(Throwable thrown) {
// Handle the error
}
});
By sending the file asynchronously, you can send and retrieve many files at any given time. Then, when the server responds (either with a retrieved file or with an error), you can handle the response (retrieved file or exception) just when it comes back, without needing to wait for it. This means that the onSuccess() or onFailure() methods will be automatically executed when there's a response available from your local server.
I solved the problem by using a Timer that is executed every 5 minutes getting all the db transactions that happened for the last 5 minutes and didn't get any response and show my error code. It works pretty good. Thanks everyone for the help

Categories