mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-15 08:18:55 +00:00
[eclipse/xtext#1629] Migrate server.concurrent from Xtend to Java (#1327)
Migrate server.concurrent from Xtend to Java see eclipse/xtext#1629
This commit is contained in:
parent
01c74550c4
commit
f45a3c4aaa
14 changed files with 325 additions and 526 deletions
|
@ -0,0 +1,51 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2019 TypeFox GmbH (http://www.typefox.io) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.server.concurrent;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* Abstract base type for read and write requests.
|
||||
*
|
||||
* @author kosyakov - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
public abstract class AbstractRequest<V> implements Runnable, Cancellable {
|
||||
/**
|
||||
* The underyling future.
|
||||
*/
|
||||
protected final CompletableFuture<V> result;
|
||||
|
||||
/**
|
||||
* The current cancel indicator.
|
||||
*/
|
||||
protected final RequestCancelIndicator cancelIndicator;
|
||||
|
||||
/**
|
||||
* The request manager that is handling this request.
|
||||
*/
|
||||
protected final RequestManager requestManager;
|
||||
|
||||
protected AbstractRequest(RequestManager requestManager) {
|
||||
this.requestManager = requestManager;
|
||||
this.result = new CompletableFuture<>();
|
||||
this.cancelIndicator = new RequestCancelIndicator(this.result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
cancelIndicator.cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the underlying future.
|
||||
*/
|
||||
public CompletableFuture<V> get() {
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -5,12 +5,17 @@
|
|||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.server.concurrent
|
||||
package org.eclipse.xtext.ide.server.concurrent;
|
||||
|
||||
/**
|
||||
* A functional interface that indicates something that can be cancelled.
|
||||
*
|
||||
* @author kosyakov - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
interface Cancellable {
|
||||
def void cancel()
|
||||
public interface Cancellable {
|
||||
/**
|
||||
* Attempt to cancel.
|
||||
*/
|
||||
void cancel();
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2019 TypeFox GmbH (http://www.typefox.io) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.server.concurrent;
|
||||
|
||||
import java.util.concurrent.ExecutorService;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function1;
|
||||
|
||||
/**
|
||||
* @author kosyakov - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
public class ReadRequest<V> extends AbstractRequest<V> {
|
||||
private static final Logger LOG = Logger.getLogger(ReadRequest.class);
|
||||
|
||||
private final Function1<? super CancelIndicator, ? extends V> cancellable;
|
||||
|
||||
private final ExecutorService executor;
|
||||
|
||||
public ReadRequest(RequestManager requestManager, Function1<? super CancelIndicator, ? extends V> cancellable,
|
||||
ExecutorService executor) {
|
||||
super(requestManager);
|
||||
this.cancellable = cancellable;
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (result.isCancelled()) {
|
||||
return;
|
||||
}
|
||||
this.executor.submit(() -> {
|
||||
try {
|
||||
cancelIndicator.checkCanceled();
|
||||
result.complete(cancellable.apply(cancelIndicator));
|
||||
} catch (Throwable t) {
|
||||
if (!requestManager.isCancelException(t)) {
|
||||
LOG.error("Error during request: ", t);
|
||||
}
|
||||
result.completeExceptionally(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2019 TypeFox GmbH (http://www.typefox.io) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.server.concurrent;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
|
||||
/**
|
||||
* @author kosyakov - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
public class RequestCancelIndicator implements CancelIndicator, CancelChecker, Cancellable {
|
||||
private final CompletableFuture<?> requestFuture;
|
||||
|
||||
public RequestCancelIndicator(CompletableFuture<?> requestFuture) {
|
||||
this.requestFuture = requestFuture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.requestFuture.cancel(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Not really boolean guard but will throw a {@link CancellationException} instead of returning
|
||||
* <code>true</code>. Otherwise returns <code>false</code>.
|
||||
*/
|
||||
@Override
|
||||
public boolean isCanceled() {
|
||||
this.checkCanceled();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCanceled() {
|
||||
if (this.requestFuture.isCancelled()) {
|
||||
throw new CancellationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.server.concurrent
|
||||
|
||||
import java.util.concurrent.CancellationException
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
|
||||
import org.eclipse.xtext.util.CancelIndicator
|
||||
|
||||
/**
|
||||
* @author kosyakov - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@FinalFieldsConstructor
|
||||
class RequestCancelIndicator implements CancelIndicator, CancelChecker, Cancellable {
|
||||
|
||||
val CompletableFuture<?> requestFuture
|
||||
|
||||
override cancel() {
|
||||
requestFuture.cancel(true)
|
||||
}
|
||||
|
||||
override isCanceled() {
|
||||
checkCanceled
|
||||
return false
|
||||
}
|
||||
|
||||
override void checkCanceled() {
|
||||
if (requestFuture.cancelled) {
|
||||
throw new CancellationException()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2019 TypeFox GmbH (http://www.typefox.io) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.server.concurrent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.eclipse.xtext.service.OperationCanceledManager;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function0;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function1;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function2;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
/**
|
||||
* @author kosyakov - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@Singleton
|
||||
public class RequestManager {
|
||||
|
||||
@Inject
|
||||
private ExecutorService parallel;
|
||||
|
||||
@Inject
|
||||
private OperationCanceledManager operationCanceledManager;
|
||||
|
||||
private final ExecutorService queue = Executors.newSingleThreadExecutor(
|
||||
new ThreadFactoryBuilder().setDaemon(true).setNameFormat("RequestManager-Queue-%d").build());
|
||||
|
||||
private List<AbstractRequest<?>> requests = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* An orderly shutdown of this request manager.
|
||||
*/
|
||||
public void shutdown() {
|
||||
queue.shutdown();
|
||||
parallel.shutdown();
|
||||
cancel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the given cancellable logic as a read request.
|
||||
*/
|
||||
public <V> CompletableFuture<V> runRead(Function1<? super CancelIndicator, ? extends V> cancellable) {
|
||||
return submit(new ReadRequest<>(this, cancellable, parallel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the given write and run the cancellable logic afterwards.
|
||||
*/
|
||||
public <U, V> CompletableFuture<V> runWrite(
|
||||
Function0<? extends U> nonCancellable,
|
||||
Function2<? super CancelIndicator, ? super U, ? extends V> cancellable) {
|
||||
return submit(new WriteRequest<>(this, nonCancellable, cancellable, cancel()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit the given request.
|
||||
*/
|
||||
protected <V> CompletableFuture<V> submit(AbstractRequest<V> request) {
|
||||
requests.add(request);
|
||||
queue.submit(request);
|
||||
return request.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel all requests in the queue.
|
||||
*/
|
||||
protected CompletableFuture<Void> cancel() {
|
||||
List<AbstractRequest<?>> localRequests = requests;
|
||||
requests = new ArrayList<>();
|
||||
CompletableFuture<?>[] cfs = new CompletableFuture<?>[localRequests.size()];
|
||||
for (int i = 0, max = localRequests.size(); i < max; i++) {
|
||||
AbstractRequest<?> request = localRequests.get(i);
|
||||
request.cancel();
|
||||
cfs[i] = request.get();
|
||||
}
|
||||
return CompletableFuture.allOf(cfs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given throwable is an indicator for a cancellation.
|
||||
*/
|
||||
protected boolean isCancelException(Throwable t) {
|
||||
if (t == null) {
|
||||
return false;
|
||||
}
|
||||
Throwable cause = t;
|
||||
if (t instanceof CompletionException) {
|
||||
cause = ((CompletionException) t).getCause();
|
||||
}
|
||||
return operationCanceledManager.isOperationCanceledException(cause);
|
||||
}
|
||||
}
|
|
@ -1,154 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2017, 2018 TypeFox GmbH (http://www.typefox.io) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.server.concurrent
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder
|
||||
import com.google.inject.Inject
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.concurrent.CompletionException
|
||||
import java.util.concurrent.ExecutorService
|
||||
import java.util.concurrent.Executors
|
||||
import org.apache.log4j.Logger
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor
|
||||
import org.eclipse.xtext.service.OperationCanceledManager
|
||||
import org.eclipse.xtext.util.CancelIndicator
|
||||
|
||||
/**
|
||||
*
|
||||
* @author kosyakov - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
class RequestManager {
|
||||
|
||||
@Inject ExecutorService parallel
|
||||
|
||||
@Inject
|
||||
OperationCanceledManager operationCanceledManager
|
||||
|
||||
val queue = Executors.newSingleThreadExecutor(
|
||||
new ThreadFactoryBuilder().setDaemon(true).setNameFormat("RequestManager-Queue-%d").build
|
||||
)
|
||||
var requests = <AbstractRequest<?>>newArrayList
|
||||
|
||||
def void shutdown() {
|
||||
queue.shutdown()
|
||||
parallel.shutdown()
|
||||
cancel()
|
||||
}
|
||||
|
||||
def <V> CompletableFuture<V> runRead((CancelIndicator)=>V cancellable) {
|
||||
return submit(
|
||||
new ReadRequest(this, cancellable, parallel)
|
||||
)
|
||||
}
|
||||
|
||||
def <U, V> CompletableFuture<V> runWrite(()=>U nonCancellable, (CancelIndicator, U)=>V cancellable) {
|
||||
val cancelFuture = cancel()
|
||||
return submit(
|
||||
new WriteRequest(this, nonCancellable, cancellable, cancelFuture)
|
||||
)
|
||||
}
|
||||
|
||||
protected def <V> CompletableFuture<V> submit(AbstractRequest<V> request) {
|
||||
requests += request
|
||||
queue.submit(request)
|
||||
return request.get
|
||||
}
|
||||
|
||||
protected def CompletableFuture<Void> cancel() {
|
||||
val localRequests = requests
|
||||
requests = newArrayList
|
||||
|
||||
val cfs = newArrayList
|
||||
for (request : localRequests) {
|
||||
request.cancel
|
||||
cfs += request.get
|
||||
}
|
||||
return CompletableFuture.allOf(cfs)
|
||||
}
|
||||
|
||||
protected def boolean isCancelException(Throwable t) {
|
||||
if(t === null) return false;
|
||||
val cause = if(t instanceof CompletionException) t.cause else t
|
||||
return operationCanceledManager.isOperationCanceledException(cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@FinalFieldsConstructor
|
||||
class ReadRequest<V> extends AbstractRequest<V> {
|
||||
static final Logger LOG = Logger.getLogger(ReadRequest);
|
||||
|
||||
val (CancelIndicator)=>V cancellable
|
||||
val ExecutorService executor
|
||||
|
||||
override void run() {
|
||||
if(result.cancelled) return;
|
||||
executor.submit [
|
||||
try {
|
||||
cancelIndicator.checkCanceled
|
||||
result.complete(cancellable.apply(cancelIndicator))
|
||||
} catch(Throwable e) {
|
||||
if (e !== null && !requestManager.isCancelException(e)) {
|
||||
LOG.error("Error during request: ", e);
|
||||
}
|
||||
result.completeExceptionally(e)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@FinalFieldsConstructor
|
||||
class WriteRequest<U, V> extends AbstractRequest<V> {
|
||||
static final Logger LOG = Logger.getLogger(WriteRequest);
|
||||
|
||||
val ()=>U nonCancellable
|
||||
val (CancelIndicator, U)=>V cancellable
|
||||
val CompletableFuture<Void> previous
|
||||
|
||||
override void run() {
|
||||
try {
|
||||
previous.join
|
||||
} catch(Throwable e) {
|
||||
// We are not interested in results, only to make sure that all previous requests are finished before running next write request.
|
||||
}
|
||||
try {
|
||||
val intermediateResult = nonCancellable.apply
|
||||
|
||||
cancelIndicator.checkCanceled
|
||||
result.complete(cancellable.apply(cancelIndicator, intermediateResult))
|
||||
} catch(Throwable e) {
|
||||
if (e !== null && !requestManager.isCancelException(e)) {
|
||||
LOG.error("Error during request: ", e);
|
||||
}
|
||||
result.completeExceptionally(e)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
abstract class AbstractRequest<V> implements Runnable, Cancellable {
|
||||
|
||||
protected val result = new CompletableFuture<V>()
|
||||
protected val cancelIndicator = new RequestCancelIndicator(result)
|
||||
protected val RequestManager requestManager;
|
||||
|
||||
new (RequestManager requestManager) {
|
||||
this.requestManager = requestManager;
|
||||
}
|
||||
|
||||
override cancel() {
|
||||
cancelIndicator.cancel
|
||||
}
|
||||
|
||||
def CompletableFuture<V> get() {
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016, 2019 TypeFox GmbH (http://www.typefox.io) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.server.concurrent;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function0;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function2;
|
||||
|
||||
/**
|
||||
* @author kosyakov - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
public class WriteRequest<U, V> extends AbstractRequest<V> {
|
||||
private static final Logger LOG = Logger.getLogger(WriteRequest.class);
|
||||
|
||||
private final Function0<? extends U> nonCancellable;
|
||||
|
||||
private final Function2<? super CancelIndicator, ? super U, ? extends V> cancellable;
|
||||
|
||||
private final CompletableFuture<Void> previous;
|
||||
|
||||
public WriteRequest(RequestManager requestManager, Function0<? extends U> nonCancellable,
|
||||
Function2<? super CancelIndicator, ? super U, ? extends V> cancellable,
|
||||
CompletableFuture<Void> previous) {
|
||||
super(requestManager);
|
||||
this.nonCancellable = nonCancellable;
|
||||
this.cancellable = cancellable;
|
||||
this.previous = previous;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
previous.join();
|
||||
} catch (Throwable t) {
|
||||
// We are not interested in results, only to make sure that all previous requests are finished before running next write request.
|
||||
}
|
||||
try {
|
||||
U intermediateResult = this.nonCancellable.apply();
|
||||
cancelIndicator.checkCanceled();
|
||||
result.complete(cancellable.apply(cancelIndicator, intermediateResult));
|
||||
} catch (Throwable t) {
|
||||
if (!requestManager.isCancelException(t)) {
|
||||
LOG.error("Error during request: ", t);
|
||||
}
|
||||
result.completeExceptionally(t);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2016, 2017, 2018 TypeFox GmbH (http://www.typefox.io) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.xtext.ide.server.concurrent;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import org.eclipse.xtext.ide.server.concurrent.Cancellable;
|
||||
import org.eclipse.xtext.ide.server.concurrent.RequestCancelIndicator;
|
||||
import org.eclipse.xtext.ide.server.concurrent.RequestManager;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public abstract class AbstractRequest<V extends Object> implements Runnable, Cancellable {
|
||||
protected final CompletableFuture<V> result = new CompletableFuture<V>();
|
||||
|
||||
protected final RequestCancelIndicator cancelIndicator = new RequestCancelIndicator(this.result);
|
||||
|
||||
protected final RequestManager requestManager;
|
||||
|
||||
public AbstractRequest(final RequestManager requestManager) {
|
||||
this.requestManager = requestManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.cancelIndicator.cancel();
|
||||
}
|
||||
|
||||
public CompletableFuture<V> get() {
|
||||
return this.result;
|
||||
}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.xtext.ide.server.concurrent;
|
||||
|
||||
/**
|
||||
* @author kosyakov - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public interface Cancellable {
|
||||
public abstract void cancel();
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2016, 2017, 2018 TypeFox GmbH (http://www.typefox.io) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.xtext.ide.server.concurrent;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor;
|
||||
import org.eclipse.xtext.ide.server.concurrent.AbstractRequest;
|
||||
import org.eclipse.xtext.ide.server.concurrent.RequestManager;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.xbase.lib.Exceptions;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function1;
|
||||
|
||||
@FinalFieldsConstructor
|
||||
@SuppressWarnings("all")
|
||||
public class ReadRequest<V extends Object> extends AbstractRequest<V> {
|
||||
private static final Logger LOG = Logger.getLogger(ReadRequest.class);
|
||||
|
||||
private final Function1<? super CancelIndicator, ? extends V> cancellable;
|
||||
|
||||
private final ExecutorService executor;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
boolean _isCancelled = this.result.isCancelled();
|
||||
if (_isCancelled) {
|
||||
return;
|
||||
}
|
||||
final Callable<Boolean> _function = () -> {
|
||||
boolean _xtrycatchfinallyexpression = false;
|
||||
try {
|
||||
boolean _xblockexpression = false;
|
||||
{
|
||||
this.cancelIndicator.checkCanceled();
|
||||
_xblockexpression = this.result.complete(this.cancellable.apply(this.cancelIndicator));
|
||||
}
|
||||
_xtrycatchfinallyexpression = _xblockexpression;
|
||||
} catch (final Throwable _t) {
|
||||
if (_t instanceof Throwable) {
|
||||
final Throwable e = (Throwable)_t;
|
||||
boolean _xblockexpression_1 = false;
|
||||
{
|
||||
if (((e != null) && (!this.requestManager.isCancelException(e)))) {
|
||||
ReadRequest.LOG.error("Error during request: ", e);
|
||||
}
|
||||
_xblockexpression_1 = this.result.completeExceptionally(e);
|
||||
}
|
||||
_xtrycatchfinallyexpression = _xblockexpression_1;
|
||||
} else {
|
||||
throw Exceptions.sneakyThrow(_t);
|
||||
}
|
||||
}
|
||||
return Boolean.valueOf(_xtrycatchfinallyexpression);
|
||||
};
|
||||
this.executor.<Boolean>submit(_function);
|
||||
}
|
||||
|
||||
public ReadRequest(final RequestManager requestManager, final Function1<? super CancelIndicator, ? extends V> cancellable, final ExecutorService executor) {
|
||||
super(requestManager);
|
||||
this.cancellable = cancellable;
|
||||
this.executor = executor;
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.xtext.ide.server.concurrent;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor;
|
||||
import org.eclipse.xtext.ide.server.concurrent.Cancellable;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
|
||||
/**
|
||||
* @author kosyakov - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@FinalFieldsConstructor
|
||||
@SuppressWarnings("all")
|
||||
public class RequestCancelIndicator implements CancelIndicator, CancelChecker, Cancellable {
|
||||
private final CompletableFuture<?> requestFuture;
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.requestFuture.cancel(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCanceled() {
|
||||
this.checkCanceled();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkCanceled() {
|
||||
boolean _isCancelled = this.requestFuture.isCancelled();
|
||||
if (_isCancelled) {
|
||||
throw new CancellationException();
|
||||
}
|
||||
}
|
||||
|
||||
public RequestCancelIndicator(final CompletableFuture<?> requestFuture) {
|
||||
super();
|
||||
this.requestFuture = requestFuture;
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2016, 2017, 2018 TypeFox GmbH (http://www.typefox.io) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.xtext.ide.server.concurrent;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import com.google.inject.Inject;
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CompletionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import org.eclipse.xtext.ide.server.concurrent.AbstractRequest;
|
||||
import org.eclipse.xtext.ide.server.concurrent.ReadRequest;
|
||||
import org.eclipse.xtext.ide.server.concurrent.WriteRequest;
|
||||
import org.eclipse.xtext.service.OperationCanceledManager;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
|
||||
import org.eclipse.xtext.xbase.lib.Conversions;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function0;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function1;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function2;
|
||||
|
||||
/**
|
||||
* @author kosyakov - Initial contribution and API
|
||||
* @since 2.11
|
||||
*/
|
||||
@SuppressWarnings("all")
|
||||
public class RequestManager {
|
||||
@Inject
|
||||
private ExecutorService parallel;
|
||||
|
||||
@Inject
|
||||
private OperationCanceledManager operationCanceledManager;
|
||||
|
||||
private final ExecutorService queue = Executors.newSingleThreadExecutor(
|
||||
new ThreadFactoryBuilder().setDaemon(true).setNameFormat("RequestManager-Queue-%d").build());
|
||||
|
||||
private ArrayList<AbstractRequest<?>> requests = CollectionLiterals.<AbstractRequest<?>>newArrayList();
|
||||
|
||||
public void shutdown() {
|
||||
this.queue.shutdown();
|
||||
this.parallel.shutdown();
|
||||
this.cancel();
|
||||
}
|
||||
|
||||
public <V extends Object> CompletableFuture<V> runRead(final Function1<? super CancelIndicator, ? extends V> cancellable) {
|
||||
ReadRequest<V> _readRequest = new ReadRequest<V>(this, cancellable, this.parallel);
|
||||
return this.<V>submit(_readRequest);
|
||||
}
|
||||
|
||||
public <U extends Object, V extends Object> CompletableFuture<V> runWrite(final Function0<? extends U> nonCancellable, final Function2<? super CancelIndicator, ? super U, ? extends V> cancellable) {
|
||||
final CompletableFuture<Void> cancelFuture = this.cancel();
|
||||
WriteRequest<U, V> _writeRequest = new WriteRequest<U, V>(this, nonCancellable, cancellable, cancelFuture);
|
||||
return this.<V>submit(_writeRequest);
|
||||
}
|
||||
|
||||
protected <V extends Object> CompletableFuture<V> submit(final AbstractRequest<V> request) {
|
||||
this.requests.add(request);
|
||||
this.queue.submit(request);
|
||||
return request.get();
|
||||
}
|
||||
|
||||
protected CompletableFuture<Void> cancel() {
|
||||
final ArrayList<AbstractRequest<?>> localRequests = this.requests;
|
||||
this.requests = CollectionLiterals.<AbstractRequest<?>>newArrayList();
|
||||
final ArrayList<CompletableFuture<?>> cfs = CollectionLiterals.<CompletableFuture<?>>newArrayList();
|
||||
for (final AbstractRequest<?> request : localRequests) {
|
||||
{
|
||||
request.cancel();
|
||||
CompletableFuture<?> _get = request.get();
|
||||
cfs.add(_get);
|
||||
}
|
||||
}
|
||||
return CompletableFuture.allOf(((CompletableFuture<?>[])Conversions.unwrapArray(cfs, CompletableFuture.class)));
|
||||
}
|
||||
|
||||
protected boolean isCancelException(final Throwable t) {
|
||||
if ((t == null)) {
|
||||
return false;
|
||||
}
|
||||
Throwable _xifexpression = null;
|
||||
if ((t instanceof CompletionException)) {
|
||||
_xifexpression = ((CompletionException)t).getCause();
|
||||
} else {
|
||||
_xifexpression = t;
|
||||
}
|
||||
final Throwable cause = _xifexpression;
|
||||
return this.operationCanceledManager.isOperationCanceledException(cause);
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2016, 2017, 2018 TypeFox GmbH (http://www.typefox.io) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*/
|
||||
package org.eclipse.xtext.ide.server.concurrent;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import org.apache.log4j.Logger;
|
||||
import org.eclipse.xtend.lib.annotations.FinalFieldsConstructor;
|
||||
import org.eclipse.xtext.ide.server.concurrent.AbstractRequest;
|
||||
import org.eclipse.xtext.ide.server.concurrent.RequestManager;
|
||||
import org.eclipse.xtext.util.CancelIndicator;
|
||||
import org.eclipse.xtext.xbase.lib.Exceptions;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function0;
|
||||
import org.eclipse.xtext.xbase.lib.Functions.Function2;
|
||||
|
||||
@FinalFieldsConstructor
|
||||
@SuppressWarnings("all")
|
||||
public class WriteRequest<U extends Object, V extends Object> extends AbstractRequest<V> {
|
||||
private static final Logger LOG = Logger.getLogger(WriteRequest.class);
|
||||
|
||||
private final Function0<? extends U> nonCancellable;
|
||||
|
||||
private final Function2<? super CancelIndicator, ? super U, ? extends V> cancellable;
|
||||
|
||||
private final CompletableFuture<Void> previous;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
this.previous.join();
|
||||
} catch (final Throwable _t) {
|
||||
if (_t instanceof Throwable) {
|
||||
} else {
|
||||
throw Exceptions.sneakyThrow(_t);
|
||||
}
|
||||
}
|
||||
try {
|
||||
final U intermediateResult = this.nonCancellable.apply();
|
||||
this.cancelIndicator.checkCanceled();
|
||||
this.result.complete(this.cancellable.apply(this.cancelIndicator, intermediateResult));
|
||||
} catch (final Throwable _t) {
|
||||
if (_t instanceof Throwable) {
|
||||
final Throwable e = (Throwable)_t;
|
||||
if (((e != null) && (!this.requestManager.isCancelException(e)))) {
|
||||
WriteRequest.LOG.error("Error during request: ", e);
|
||||
}
|
||||
this.result.completeExceptionally(e);
|
||||
} else {
|
||||
throw Exceptions.sneakyThrow(_t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public WriteRequest(final RequestManager requestManager, final Function0<? extends U> nonCancellable, final Function2<? super CancelIndicator, ? super U, ? extends V> cancellable, final CompletableFuture<Void> previous) {
|
||||
super(requestManager);
|
||||
this.nonCancellable = nonCancellable;
|
||||
this.cancellable = cancellable;
|
||||
this.previous = previous;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue