Q:

Cancel button in ProgressMonitorDialog and InvocationTargetException

In my application, I generate a report. Time of the operation is from a few seconds to up to several hours. To inform the user I use ProgressMonitorDialog. 
Always after about 70 minutes InvocationTargetException is thrown. I have no idea why this is happening.   
  try {
    new ProgressMonitorDialog(shell).run(true, true, new IRunnableWithProgress() {
        @Override
        public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
            monitor.beginTask("Something...", IProgressMonitor.UNKNOWN);
            controller.generate(model);
            monitor.done();
        }
    });
} catch (InvocationTargetException | InterruptedException e) {
    logger.error(e);
}

Stack Trace:
java.lang.reflect.InvocationTargetException
    at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:421)
    at org.eclipse.jface.dialogs.ProgressMonitorDialog.run(ProgressMonitorDialog.java:507)
    at pl.edu.prz.allegroapi.gui.report.ProductReport$4.widgetSelected(ProductReport.java:323)
    at org.eclipse.swt.widgets.TypedListener.handleEvent(Unknown Source)
    at org.eclipse.swt.widgets.EventTable.sendEvent(Unknown Source)
    at org.eclipse.swt.widgets.Widget.sendEvent(Unknown Source)
    at org.eclipse.swt.widgets.Display.runDeferredEvents(Unknown Source)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Unknown Source)
    at pl.edu.prz.allegroapi.gui.report.ProductReport.open(ProductReport.java:91)
    at pl.edu.prz.allegroapi.gui.MainWindow$2.widgetSelected(MainWindow.java:126)
    at org.eclipse.swt.widgets.TypedListener.handleEvent(Unknown Source)
    at org.eclipse.swt.widgets.EventTable.sendEvent(Unknown Source)
    at org.eclipse.swt.widgets.Widget.sendEvent(Unknown Source)
    at org.eclipse.swt.widgets.Display.runDeferredEvents(Unknown Source)
    at org.eclipse.swt.widgets.Display.readAndDispatch(Unknown Source)
    at pl.edu.prz.allegroapi.gui.MainWindow.open(MainWindow.java:75)
    at pl.edu.prz.allegroapi.tasks.CreateGuiTask.doStartup(CreateGuiTask.java:46)
    at pl.edu.prz.allegroapi.tasks.CreateGuiTask.access$0(CreateGuiTask.java:42)
    at pl.edu.prz.allegroapi.tasks.CreateGuiTask$1.run(CreateGuiTask.java:31)
    at java.lang.Thread.run(Unknown Source)
Caused by: org.eclipse.swt.SWTException: Invalid thread access
    at org.eclipse.swt.SWT.error(Unknown Source)
    at org.eclipse.swt.SWT.error(Unknown Source)
    at org.eclipse.swt.SWT.error(Unknown Source)
    at org.eclipse.swt.widgets.Widget.error(Unknown Source)
    at org.eclipse.swt.widgets.Widget.checkWidget(Unknown Source)
    at org.eclipse.swt.widgets.Dialog.checkParent(Unknown Source)
    at org.eclipse.swt.widgets.Dialog.<init>(Unknown Source)
    at org.eclipse.swt.widgets.MessageBox.<init>(Unknown Source)
    at pl.edu.prz.allegroapi.gui.report.ProductReportController.generate(ProductReportController.java:59)
    at pl.edu.prz.allegroapi.gui.report.ProductReport$4$1.run(ProductReport.java:335)
    at org.eclipse.jface.operation.ModalContext$ModalContextThread.run(ModalContext.java:121)

The second problem is the cancellation of the window with the progress of work. I know that pressing the "cancel" button, the method isCanceled() returns true. I tried the following solution, but it can not work because the variable exit would be final.
Boolean exit = false;
display.asyncExec(new Runnable() {
    public void run() {
        controller.generate(model);
        exit=true;
    }
});
try {
    new ProgressMonitorDialog(shell).run(true, true, new IRunnableWithProgress() {
        @Override
        public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
            try {
                monitor.beginTask("Something...", IProgressMonitor.UNKNOWN);
                while(!monitor.isCanceled() && !exit) {
                    Thread.sleep(1000);
                }
            } finally {
                monitor.done();
            }
        }
    });
} catch (InvocationTargetException | InterruptedException e) {
    e.printStackTrace();
}

A:

You came across the most common SWT exception which is "Invalid thread access".
It basically means that you are trying to update the UI from a thread that is not the UI-thread. This isn't allowed in SWT, unless you use a specific technique to do it.
You can read more about it in the official wiki.

The code you posted seems to be ok, you're problem is probably somewhere else in controller.generate(model);. I can't help you further without seeing the relevant code.
In the meantime, this is how you should interact with the UI from a non-UI-thread:
Display.getDefault().asyncExec(new Runnable() {
    public void run() {
        ... do any work that updates the screen ...
    }
});

UPDATE
Ok, here is an update that should show you how the ProgressMonitorDialog should be used in combination with Display#asyncExec():
public static void main(String[] args)
{
    final Display display = new Display();
    final Shell shell = new Shell(display);
    shell.setText("StackOverflow");
    shell.setLayout(new GridLayout(1, false));

    final Label label = new Label(shell, SWT.NONE);

    Button button = new Button(shell, SWT.PUSH);
    button.setText("Start");
    button.addListener(SWT.Selection, new Listener()
    {
        @Override
        public void handleEvent(Event arg0)
        {
            try
            {
                new ProgressMonitorDialog(shell).run(true, true, new IRunnableWithProgress()
                {
                    @Override
                    public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException
                    {
                        try
                        {
                            monitor.beginTask("Something...", IProgressMonitor.UNKNOWN);

                            for (int i = 0; i < 100; i++)
                            {
                                /* Check if the monitor has been canceled */
                                if (monitor.isCanceled())
                                    return;

                                try
                                {/* Only wrap the UI interaction in the asyncExec */
                                    doFancyUIStuff(label, i);
                                    Thread.sleep(100);
                                }
                                catch (InterruptedException e)
                                {
                                    e.printStackTrace();
                                }
                            }
                        }
                        finally
                        {
                            monitor.done();
                        }
                    }
                });
            }
            catch (InvocationTargetException e)
            {
                e.printStackTrace();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    });

    shell.pack();
    shell.open();

    while (!shell.isDisposed())
    {
        while (!display.readAndDispatch())
        {
            display.sleep();
        }
    }
}

private static void doFancyUIStuff(final Label label, final int index)
{
    Display.getDefault().asyncExec(new Runnable()
    {
        @Override
        public void run()
        {
            label.setText(index + "");
            label.getParent().layout();
        }
    });
}

Note that only the actual UI interaction is wrapped in Display.asyncExec(). This way, you can still check monitor.isCanceled() in each iteration.

