use of org.eclipse.scout.rt.client.context.ClientRunContext in project scout.rt by eclipse.
the class ClientJobCancelTest method doPingRequestAsync.
/**
* Runs a 'ping-request' which gets blocked in the service implementation.
*/
protected RequestData doPingRequestAsync(final String pingRequest) throws Exception {
final BlockingCountDownLatch serviceCallSetupLatch = new BlockingCountDownLatch(1);
final BlockingCountDownLatch serviceCallCompletedLatch = new BlockingCountDownLatch(1);
final AtomicBoolean serviceCallInterrupted = new AtomicBoolean(false);
// Mock the PingService.
class PingService implements IPingService {
@Override
public String ping(String s) {
try {
assertTrue(serviceCallSetupLatch.countDownAndBlock());
} catch (java.lang.InterruptedException e) {
serviceCallInterrupted.set(true);
} finally {
serviceCallCompletedLatch.countDown();
}
return s.toUpperCase();
}
}
// Create a separate RunContext with a separate RunMonitor, so we can wait for the service result in case of cancellation.
final ClientRunContext runContext = ClientRunContexts.copyCurrent();
final RunMonitor runMonitor = BEANS.get(RunMonitor.class);
runContext.withRunMonitor(runMonitor);
IFuture<String> pingFuture = Jobs.schedule(new Callable<String>() {
@Override
public String call() throws Exception {
return runContext.call(new Callable<String>() {
@Override
public String call() throws Exception {
IBean<?> bean = TestingUtility.registerBean(new BeanMetaData(PingService.class).withInitialInstance(new PingService()).withApplicationScoped(true));
try {
return ServiceTunnelUtility.createProxy(IPingService.class).ping(pingRequest);
} finally {
TestingUtility.unregisterBeans(Arrays.asList(bean));
}
}
});
}
}, Jobs.newInput().withExceptionHandling(null, false));
// Wait for the ping request to enter service implementation.
assertTrue(serviceCallSetupLatch.await());
return new RequestData(pingFuture, runMonitor, serviceCallSetupLatch, serviceCallCompletedLatch, serviceCallInterrupted);
}
use of org.eclipse.scout.rt.client.context.ClientRunContext in project scout.rt by eclipse.
the class AbstractSmartField2 method fetchLookupRows.
/**
* Loads lookup rows according to the specified {@link ILookupRowProvider}, and notifies the specified callback upon
* fetching completed.
*
* @return {@link IFuture} if data is fetched asynchronously, or <code>null</code> for synchronous fetching, or if
* using {@link LocalLookupCall}.
*/
private IFuture<Void> fetchLookupRows(final ILookupRowProvider<VALUE> dataProvider, final ILookupRowFetchedCallback<VALUE> callback, final boolean asynchronousFetching, final int maxRowCount) {
cancelPotentialLookup();
if (getLookupCall() == null) {
callback.onSuccess(Collections.<ILookupRow<VALUE>>emptyList());
return null;
}
// Prepare the lookup call.
final ILookupCall<VALUE> lookupCall = cloneLookupCall();
lookupCall.setMaxRowCount(maxRowCount > 0 ? maxRowCount : getBrowseMaxRowCount());
// Prepare processing of the fetched rows.
final ILookupRowFetchedCallback<VALUE> internalCallback = new ILookupRowFetchedCallback<VALUE>() {
@Override
public void onSuccess(final List<? extends ILookupRow<VALUE>> rows) {
joinModelThreadAndUpdateField(rows, null);
}
@Override
public void onFailure(final RuntimeException e) {
joinModelThreadAndUpdateField(null, e);
}
private void joinModelThreadAndUpdateField(final List<? extends ILookupRow<VALUE>> rows, final RuntimeException exception) {
if (ModelJobs.isModelThread()) {
updateField(rows, exception);
} else {
// Note: The model job will not commence execution if the current ClientRunContext is or gets cancelled.
try {
ClientRunContext callerRunContext = ClientRunContexts.copyCurrent();
if (callerRunContext.getRunMonitor().isCancelled()) {
return;
}
ModelJobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
updateField(rows, exception);
}
}, ModelJobs.newInput(callerRunContext).withName("Updating {}", AbstractSmartField2.this.getClass().getName())).awaitDone();
} catch (ThreadInterruptedError e) {
/*
This state can be reached by a race condition when the job's RunMonitor is in canceled state and later the ModelJob is run.
This yields to a Thread.interrupt in the RunContext.ThreadInterrupter...
at RunContext$ThreadInterrupter.cancel(boolean) line: 563
at RunMonitor.cancel(ICancellable, boolean) line: 160
at RunMonitor.registerCancellable(ICancellable) line: 104 <---------------------
at RunContext$ThreadInterrupter.<init>(Thread, RunMonitor) line: 545
at ClientRunContext(RunContext).call(Callable<RESULT>, Class<IExceptionTranslator<EXCEPTION>>) line: 154
at RunContextRunner<RESULT>.intercept(Chain<RESULT>) line: 38
which itself causes the running job to be interrupted with a InterruptedException
at org.eclipse.scout.rt.platform.job.internal.JobExceptionTranslator.translateInterruptedException(JobExceptionTranslator.java:49)
at org.eclipse.scout.rt.platform.job.internal.JobFutureTask.awaitDone(JobFutureTask.java:339)
at org.eclipse.scout.rt.client.ui.form.fields.smartfield2.AbstractSmartField2$7.joinModelThreadAndUpdateField(AbstractSmartField2.java:1598)
at org.eclipse.scout.rt.client.ui.form.fields.smartfield2.AbstractSmartField2$7.onSuccess(AbstractSmartField2.java:1575)
at org.eclipse.scout.rt.shared.services.lookup.LookupCall.loadData(LookupCall.java:437)
at org.eclipse.scout.rt.shared.services.lookup.LookupCall$5.run(LookupCall.java:417)
*/
return;
}
}
}
private void updateField(final List<? extends ILookupRow<VALUE>> rows, final RuntimeException exception) {
try {
if (exception != null) {
// throw to handle exception at the end.
throw exception;
}
final List<ILookupRow<VALUE>> result = new ArrayList<>(rows);
dataProvider.afterProvide(lookupCall, result);
callback.onSuccess(result);
} catch (FutureCancelledError | ThreadInterruptedError e) {
// NOSONAR
callback.onSuccess(Collections.<ILookupRow<VALUE>>emptyList());
} catch (final RuntimeException e) {
callback.onFailure(e);
}
}
};
// Start fetching lookup rows.
IFuture<Void> asyncLookupFuture = null;
try {
dataProvider.beforeProvide(lookupCall);
if (asynchronousFetching) {
asyncLookupFuture = dataProvider.provideAsync(lookupCall, internalCallback, ClientRunContexts.copyCurrent());
} else {
dataProvider.provideSync(lookupCall, internalCallback);
asyncLookupFuture = null;
}
} catch (final RuntimeException e) {
internalCallback.onFailure(e);
asyncLookupFuture = null;
}
m_lookupFuture = asyncLookupFuture;
return asyncLookupFuture;
}
use of org.eclipse.scout.rt.client.context.ClientRunContext in project scout.rt by eclipse.
the class AbstractSmartField2 method newByRecLookupRowProvider.
/**
* @see LookupCall#getDataByRec()
*/
protected ILookupRowProvider<VALUE> newByRecLookupRowProvider(final VALUE parentKey, final TriState activeState) {
return new ILookupRowProvider<VALUE>() {
@SuppressWarnings("unchecked")
@Override
public List<ILookupRow<VALUE>> provide(ILookupCall<VALUE> lookupCall) {
return (List<ILookupRow<VALUE>>) lookupCall.getDataByRec();
}
@Override
public void beforeProvide(ILookupCall<VALUE> lookupCall) {
prepareRecLookup(lookupCall, parentKey, activeState);
}
@Override
public void afterProvide(ILookupCall<VALUE> lookupCall, List<ILookupRow<VALUE>> result) {
interceptFilterLookupResult(lookupCall, result);
interceptFilterRecLookupResult(lookupCall, result);
cleanupResultList(result);
}
@Override
public void provideSync(ILookupCall<VALUE> lookupCall, ILookupRowFetchedCallback<VALUE> callback) {
throw new UnsupportedOperationException("Legacy calls not supported");
}
@Override
public IFuture<Void> provideAsync(ILookupCall<VALUE> lookupCall, ILookupRowFetchedCallback<VALUE> callback, ClientRunContext clientRunContext) {
throw new UnsupportedOperationException("Legacy calls not supported");
}
@Override
public String toString() {
ToStringBuilder sb = new ToStringBuilder(this).attr("Rec Lookup").attr("parentKey", parentKey).attr("activeState", activeState);
return sb.toString();
}
};
}
use of org.eclipse.scout.rt.client.context.ClientRunContext in project scout.rt by eclipse.
the class DisplayParentResolver method findClosestDisplayParent.
/**
* Resolves to the closest {@link IDisplayParent} from the current calling context.
*/
protected IDisplayParent findClosestDisplayParent() {
final ClientRunContext currentRunContext = ClientRunContexts.copyCurrent();
// Check whether a Form is currently the 'displayParent'. If being a wrapped Form, return its outer Form.
IForm currentForm = currentRunContext.getForm();
if (currentForm != null) {
while (currentForm.getOuterForm() != null) {
currentForm = currentForm.getOuterForm();
}
// added to the desktop (e.g. forms managed by form tool buttons).
if (currentForm.isFormStarted()) {
return currentForm;
}
}
// Check whether an Outline is currently the 'displayParent'.
final IOutline currentOutline = currentRunContext.getOutline();
if (currentOutline != null) {
return currentOutline;
}
// Use the desktop as 'displayParent'.
return currentRunContext.getDesktop();
}
use of org.eclipse.scout.rt.client.context.ClientRunContext in project scout.rt by eclipse.
the class BlockingTestUtility method runBlockingAction.
/**
* Helper method to test code which will enter a blocking condition.
* <p>
* If <code>runnableOnceBlocked</code> throws an exception, it is given to {@link JUnitExceptionHandler} to make the
* JUnit test fail.
*
* @param runnableGettingBlocked
* {@code IRunnable} that will enter a blocking condition.
* @param runnableOnceBlocked
* {@code IRunnable} to be executed once the 'runnableGettingBlocked' enters a blocking condition.
* @param awaitBackgroundJobs
* true waits for background jobs running in the same session to complete before runnableOnceBlocked is
* called
*/
public static void runBlockingAction(final IRunnable runnableGettingBlocked, final IRunnable runnableOnceBlocked, final boolean awaitBackgroundJobs) {
final ClientRunContext runContext = ClientRunContexts.copyCurrent();
final IBlockingCondition onceBlockedDoneCondition = Jobs.newBlockingCondition(true);
// remember the list of client jobs before blocking
final Set<IFuture<?>> jobsBefore = new HashSet<>();
jobsBefore.addAll(BEANS.get(IJobManager.class).getFutures(new IFilter<IFuture<?>>() {
@Override
public boolean accept(IFuture<?> cand) {
final RunContext candContext = cand.getJobInput().getRunContext();
return candContext instanceof ClientRunContext && ((ClientRunContext) candContext).getSession() == runContext.getSession();
}
}));
final IRegistrationHandle listenerRegistration = IFuture.CURRENT.get().addListener(Jobs.newEventFilterBuilder().andMatchEventType(JobEventType.JOB_STATE_CHANGED).andMatchState(JobState.WAITING_FOR_BLOCKING_CONDITION).andMatchExecutionHint(ModelJobs.EXECUTION_HINT_UI_INTERACTION_REQUIRED).toFilter(), new IJobListener() {
@Override
public void changed(final JobEvent event) {
// waitFor was entered
final IRunnable callRunnableOnceBlocked = new IRunnable() {
@Override
public void run() throws Exception {
try {
runnableOnceBlocked.run();
} finally {
event.getData().getBlockingCondition().setBlocking(false);
onceBlockedDoneCondition.setBlocking(false);
}
}
};
final JobInput jobInputForRunnableOnceBlocked = ModelJobs.newInput(runContext).withExceptionHandling(BEANS.get(JUnitExceptionHandler.class), true).withName("JUnit: Handling blocked thread because waiting for a blocking condition");
if (awaitBackgroundJobs) {
// wait until all background jobs finished
Jobs.schedule(new IRunnable() {
@Override
public void run() throws Exception {
jobsBefore.add(IFuture.CURRENT.get());
BEANS.get(IJobManager.class).awaitFinished(new IFilter<IFuture<?>>() {
@Override
public boolean accept(IFuture<?> f) {
RunContext candContext = f.getJobInput().getRunContext();
return candContext instanceof ClientRunContext && ((ClientRunContext) candContext).getSession() == runContext.getSession() && !jobsBefore.contains(f);
}
}, 5, TimeUnit.MINUTES);
// call runnableOnceBlocked
ModelJobs.schedule(callRunnableOnceBlocked, jobInputForRunnableOnceBlocked);
}
}, Jobs.newInput().withName("wait until background jobs finished"));
} else {
// call runnableOnceBlocked directly
ModelJobs.schedule(callRunnableOnceBlocked, jobInputForRunnableOnceBlocked);
}
}
});
try {
// this action will enter a blocking condition which causes the 'runnableOnceBlocked' to be executed.
runnableGettingBlocked.run();
} catch (final Exception e) {
throw BEANS.get(DefaultRuntimeExceptionTranslator.class).translate(e);
} finally {
listenerRegistration.dispose();
}
// we need to wait until the runnableOnceBlocked is completed.
// runnableOnceBlocked may, during its execution, set the original blocking condition to non-blocking but still execute
// important code afterwards. Therefore, the original blocking condition that starts runnableOnceBlocked is only used
// to indicate the start of the runnableOnceBlocked, but this method returns only AFTER runnableOnceBlocked completes execution.
onceBlockedDoneCondition.waitForUninterruptibly(120, TimeUnit.SECONDS);
}
Aggregations