| 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 |
| } |
| } |
| } |
| } |