blob: 0dc2875a547e9f10eec91d71fdb167354a68fb1a [file] [log] [blame]
package com.intellij.openapi.externalSystem.service;
import com.intellij.execution.rmi.RemoteServer;
import com.intellij.openapi.externalSystem.model.settings.ExternalSystemExecutionSettings;
import com.intellij.openapi.externalSystem.model.task.*;
import com.intellij.openapi.externalSystem.service.project.ExternalSystemProjectResolver;
import com.intellij.openapi.externalSystem.service.remote.*;
import com.intellij.openapi.externalSystem.task.ExternalSystemTaskManager;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.ContainerUtilRt;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.rmi.RemoteException;
import java.util.*;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;
/**
* @author Denis Zhdanov
* @since 8/8/11 12:51 PM
*/
public abstract class AbstractExternalSystemFacadeImpl<S extends ExternalSystemExecutionSettings> extends RemoteServer
implements RemoteExternalSystemFacade<S>
{
private final ConcurrentMap<Class<?>, RemoteExternalSystemService<S>> myRemotes = ContainerUtil.newConcurrentMap();
private final AtomicReference<S> mySettings = new AtomicReference<S>();
private final AtomicReference<ExternalSystemTaskNotificationListener> myNotificationListener =
new AtomicReference<ExternalSystemTaskNotificationListener>(new ExternalSystemTaskNotificationListenerAdapter() {});
@NotNull private final RemoteExternalSystemProjectResolverImpl<S> myProjectResolver;
@NotNull private final RemoteExternalSystemTaskManagerImpl<S> myTaskManager;
public AbstractExternalSystemFacadeImpl(@NotNull Class<ExternalSystemProjectResolver<S>> projectResolverClass,
@NotNull Class<ExternalSystemTaskManager<S>> buildManagerClass)
throws IllegalAccessException, InstantiationException
{
myProjectResolver = new RemoteExternalSystemProjectResolverImpl<S>(projectResolverClass.newInstance());
myTaskManager = new RemoteExternalSystemTaskManagerImpl<S>(buildManagerClass.newInstance());
}
protected void init() throws RemoteException {
applyProgressManager(RemoteExternalSystemProgressNotificationManager.NULL_OBJECT);
}
@Nullable
protected S getSettings() {
return mySettings.get();
}
@NotNull
protected ExternalSystemTaskNotificationListener getNotificationListener() {
return myNotificationListener.get();
}
@SuppressWarnings("unchecked")
@NotNull
@Override
public RemoteExternalSystemProjectResolver<S> getResolver() throws RemoteException, IllegalStateException {
try {
return getService(RemoteExternalSystemProjectResolver.class, myProjectResolver);
}
catch (Exception e) {
throw new IllegalStateException(String.format("Can't create '%s' service", RemoteExternalSystemProjectResolverImpl.class.getName()),
e);
}
}
@SuppressWarnings("unchecked")
@NotNull
@Override
public RemoteExternalSystemTaskManager<S> getTaskManager() throws RemoteException {
try {
return getService(RemoteExternalSystemTaskManager.class, myTaskManager);
}
catch (Exception e) {
throw new IllegalStateException(String.format("Can't create '%s' service", ExternalSystemTaskManager.class.getName()), e);
}
}
@SuppressWarnings({"unchecked", "IOResourceOpenedButNotSafelyClosed", "UseOfSystemOutOrSystemErr"})
private <I extends RemoteExternalSystemService<S>, C extends I> I getService(@NotNull Class<I> interfaceClass,
@NotNull final C impl)
throws ClassNotFoundException, IllegalAccessException, InstantiationException, RemoteException
{
Object cachedResult = myRemotes.get(interfaceClass);
if (cachedResult != null) {
return (I)cachedResult;
}
S settings = getSettings();
if (settings != null) {
impl.setNotificationListener(getNotificationListener());
impl.setSettings(settings);
}
impl.setNotificationListener(getNotificationListener());
try {
I created = createService(interfaceClass, impl);
I stored = (I)myRemotes.putIfAbsent(interfaceClass, created);
return stored == null ? created : stored;
}
catch (RemoteException e) {
Object raceResult = myRemotes.get(interfaceClass);
if (raceResult != null) {
// Race condition occurred
return (I)raceResult;
}
else {
throw new IllegalStateException(
String.format("Can't prepare remote service for interface '%s', implementation '%s'", interfaceClass, impl),
e
);
}
}
}
/**
* Generic method to retrieve exposed implementations of the target interface.
* <p/>
* Uses cached value if it's found; creates new and caches it otherwise.
*
* @param interfaceClass target service interface class
* @param impl service implementation
* @param <I> service interface class
* @param <C> service implementation
* @return implementation of the target service
* @throws IllegalAccessException in case of incorrect assumptions about server class interface
* @throws InstantiationException in case of incorrect assumptions about server class interface
* @throws ClassNotFoundException in case of incorrect assumptions about server class interface
* @throws RemoteException
*/
@SuppressWarnings({"unchecked", "IOResourceOpenedButNotSafelyClosed", "UseOfSystemOutOrSystemErr"})
protected abstract <I extends RemoteExternalSystemService<S>, C extends I> I createService(@NotNull Class<I> interfaceClass,
@NotNull final C impl)
throws ClassNotFoundException, IllegalAccessException, InstantiationException, RemoteException;
@Override
public boolean isTaskInProgress(@NotNull ExternalSystemTaskId id) throws RemoteException {
for (RemoteExternalSystemService service : myRemotes.values()) {
if (service.isTaskInProgress(id)) {
return true;
}
}
return false;
}
@NotNull
@Override
public Map<ExternalSystemTaskType, Set<ExternalSystemTaskId>> getTasksInProgress() throws RemoteException {
Map<ExternalSystemTaskType, Set<ExternalSystemTaskId>> result = null;
for (RemoteExternalSystemService service : myRemotes.values()) {
final Map<ExternalSystemTaskType, Set<ExternalSystemTaskId>> tasks = service.getTasksInProgress();
if (tasks.isEmpty()) {
continue;
}
if (result == null) {
result = new HashMap<ExternalSystemTaskType, Set<ExternalSystemTaskId>>();
}
for (Map.Entry<ExternalSystemTaskType, Set<ExternalSystemTaskId>> entry : tasks.entrySet()) {
Set<ExternalSystemTaskId> ids = result.get(entry.getKey());
if (ids == null) {
result.put(entry.getKey(), ids = new HashSet<ExternalSystemTaskId>());
}
ids.addAll(entry.getValue());
}
}
if (result == null) {
result = Collections.emptyMap();
}
return result;
}
@Override
public void applySettings(@NotNull S settings) throws RemoteException {
mySettings.set(settings);
List<RemoteExternalSystemService<S>> services = ContainerUtilRt.newArrayList(myRemotes.values());
for (RemoteExternalSystemService<S> service : services) {
service.setSettings(settings);
}
}
@Override
public void applyProgressManager(@NotNull RemoteExternalSystemProgressNotificationManager progressManager) throws RemoteException {
ExternalSystemTaskNotificationListener listener = new SwallowingNotificationListener(progressManager);
myNotificationListener.set(listener);
myProjectResolver.setNotificationListener(listener);
myTaskManager.setNotificationListener(listener);
}
@Override
public boolean cancelTask(@NotNull ExternalSystemTaskId id) throws RemoteException {
if(id.getType() == ExternalSystemTaskType.RESOLVE_PROJECT) {
return myProjectResolver.cancelTask(id);
} else{
return myTaskManager.cancelTask(id);
}
}
private static class SwallowingNotificationListener implements ExternalSystemTaskNotificationListener {
@NotNull private final RemoteExternalSystemProgressNotificationManager myManager;
SwallowingNotificationListener(@NotNull RemoteExternalSystemProgressNotificationManager manager) {
myManager = manager;
}
@Override
public void onQueued(@NotNull ExternalSystemTaskId id) {
}
@Override
public void onStart(@NotNull ExternalSystemTaskId id) {
try {
myManager.onStart(id);
}
catch (RemoteException e) {
// Ignore
}
}
@Override
public void onStatusChange(@NotNull ExternalSystemTaskNotificationEvent event) {
try {
myManager.onStatusChange(event);
}
catch (RemoteException e) {
// Ignore
}
}
@Override
public void onTaskOutput(@NotNull ExternalSystemTaskId id, @NotNull String text, boolean stdOut) {
try {
myManager.onTaskOutput(id, text, stdOut);
}
catch (RemoteException e) {
// Ignore
}
}
@Override
public void onEnd(@NotNull ExternalSystemTaskId id) {
try {
myManager.onEnd(id);
}
catch (RemoteException e) {
// Ignore
}
}
@Override
public void onSuccess(@NotNull ExternalSystemTaskId id) {
try {
myManager.onSuccess(id);
}
catch (RemoteException e) {
// Ignore
}
}
@Override
public void onFailure(@NotNull ExternalSystemTaskId id, @NotNull Exception ex) {
try {
myManager.onFailure(id, ex);
}
catch (RemoteException e) {
// Ignore
}
}
}
}