blob: 14c4e27ebf6f6288347459c57b18206ab53b9a75 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.project.ui;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.netbeans.api.project.Project;
import org.netbeans.api.project.ui.OpenProjects;
import org.netbeans.api.project.ui.ProjectGroup;
import org.netbeans.api.project.ui.ProjectGroupChangeListener;
import org.netbeans.insane.live.CancelException;
import org.netbeans.modules.project.uiapi.OpenProjectsTrampoline;
import org.netbeans.modules.project.uiapi.ProjectOpenedTrampoline;
import org.netbeans.spi.project.ui.ProjectOpenedHook;
import org.openide.util.lookup.ServiceProvider;
/**
*
* @author Tomas Zezula
*/
@ServiceProvider(service = OpenProjectsTrampoline.class)
public final class TestTrampoline implements OpenProjectsTrampoline {
private final PropertyChangeSupport support = new PropertyChangeSupport(this);
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Set<Project> opened = new HashSet<>();
private volatile Project mainProject;
@Override
public Project[] getOpenProjectsAPI() {
rwLock.readLock().lock();
try {
return opened.toArray(new Project[opened.size()]);
} finally {
rwLock.readLock().unlock();
}
}
@Override
public void openAPI(Project[] projects, boolean openRequiredProjects, boolean showProgress) {
final Set<Project> justOpened = new HashSet<>();
rwLock.writeLock().lock();
try {
for (Project p : projects) {
if (opened.add(p)) {
justOpened.add(p);
}
}
} finally {
rwLock.writeLock().unlock();
}
for (Project p : justOpened) {
for (ProjectOpenedHook hook : p.getLookup().lookupAll(ProjectOpenedHook.class)) {
ProjectOpenedTrampoline.DEFAULT.projectOpened(hook);
}
}
if (!justOpened.isEmpty()) {
support.firePropertyChange(OpenProjects.PROPERTY_OPEN_PROJECTS, null, null);
}
}
@Override
public void closeAPI(Project[] projects) {
final Set<Project> justClosed = new HashSet<>();
rwLock.writeLock().lock();
try {
for (Project p : projects) {
if (opened.remove(p)) {
justClosed.add(p);
}
}
} finally {
rwLock.writeLock().unlock();
}
for (Project p : justClosed) {
for (ProjectOpenedHook hook : p.getLookup().lookupAll(ProjectOpenedHook.class)) {
ProjectOpenedTrampoline.DEFAULT.projectClosed(hook);
}
}
if (!justClosed.isEmpty()) {
support.firePropertyChange(OpenProjects.PROPERTY_OPEN_PROJECTS, null, null);
}
}
@Override
public void addPropertyChangeListenerAPI(PropertyChangeListener listener, Object source) {
this.support.addPropertyChangeListener(listener);
}
@Override
public void removePropertyChangeListenerAPI(PropertyChangeListener listener) {
this.support.removePropertyChangeListener(listener);
}
@Override
public Future<Project[]> openProjectsAPI() {
return new F();
}
@Override
public Project getMainProject() {
return mainProject;
}
@Override
public void setMainProject(Project project) {
mainProject = project;
support.firePropertyChange(OpenProjects.PROPERTY_MAIN_PROJECT, null, null);
}
@Override
public ProjectGroup getActiveProjectGroupAPI() {
return null;
}
@Override
public void addProjectGroupChangeListenerAPI(ProjectGroupChangeListener listener) {
}
@Override
public void removeProjectGroupChangeListenerAPI(ProjectGroupChangeListener listener) {
}
private final class F implements Future<Project[]> {
private volatile Project[] res;
private volatile boolean canceled;
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return canceled = true;
}
@Override
public boolean isCancelled() {
return canceled;
}
@Override
public boolean isDone() {
return canceled || res != null;
}
@Override
public Project[] get() throws InterruptedException, ExecutionException {
if (canceled) {
throw new CancelException();
}
if (res != null) {
return res;
}
return res = getOpenProjectsAPI();
}
@Override
public Project[] get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
if (canceled) {
throw new CancelException();
}
if (res != null) {
return res;
}
if (rwLock.readLock().tryLock(timeout, unit)) {
try {
return res = getOpenProjectsAPI();
}finally {
rwLock.readLock().unlock();
}
}
throw new TimeoutException();
}
}
}