/*
* Copyright 2014 Lukas Krejci
*
* Licensed 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.revapi.java.model;
import java.util.List;
import java.util.SortedSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.revapi.API;
import org.revapi.Element;
import org.revapi.java.Timing;
import org.revapi.query.Filter;
import org.revapi.simple.SimpleElementForest;
/**
* @author Lukas Krejci
* @since 0.1
*/
public final class JavaElementForest extends SimpleElementForest {
private Future<?> compilation;
private static final ThreadLocal<Boolean> UNSAFE_MODE = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return false;
}
};
public JavaElementForest(API api) {
super(api);
}
public void setCompilationFuture(Future<?> compilation) {
this.compilation = compilation;
}
@Nonnull
@Override
@SuppressWarnings("unchecked")
public SortedSet<TypeElement> getRoots() {
waitForCompilation();
return (SortedSet<TypeElement>) super.getRoots();
}
@SuppressWarnings("unchecked")
public SortedSet<TypeElement> getRootsUnsafe() {
boolean wasUnsafe = UNSAFE_MODE.get();
try {
UNSAFE_MODE.set(true);
return (SortedSet<TypeElement>) super.getRoots();
} finally {
UNSAFE_MODE.set(wasUnsafe);
}
}
@Override
public <T extends Element> void search(@Nonnull List<T> results, @Nonnull Class<T> resultType,
@Nonnull SortedSet<? extends Element> currentLevel, boolean recurse, @Nullable Filter<? super T> filter) {
waitForCompilation();
super.search(results, resultType, currentLevel, recurse, filter);
}
@Nonnull
@Override
public <T extends Element> List<T> search(@Nonnull Class<T> resultType, boolean recurse,
@Nullable Filter<? super T> filter,
@Nullable Element root) {
waitForCompilation();
return super.search(resultType, recurse, filter, root);
}
public <T extends Element> List<T> searchUnsafe(Class<T> resultType, boolean recurse, Filter<? super T> filter,
Element root) {
boolean wasUnsafe = UNSAFE_MODE.get();
try {
UNSAFE_MODE.set(true);
return super.search(resultType, recurse, filter, root);
} finally {
UNSAFE_MODE.set(wasUnsafe);
}
}
@Override
public String toString() {
boolean unsafe = UNSAFE_MODE.get();
try {
UNSAFE_MODE.set(true);
return super.toString();
} finally {
UNSAFE_MODE.set(unsafe);
}
}
private void waitForCompilation() {
try {
if (compilation != null && !UNSAFE_MODE.get()) {
compilation.get();
compilation = null;
if (Timing.LOG.isDebugEnabled()) {
Timing.LOG.debug("Compilation completed for " + getApi());
}
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IllegalStateException("Interrupted while waiting for compilation to finish.");
} catch (ExecutionException e) {
throw new IllegalStateException("Failed to obtain class tree due to compilation failure.", e.getCause());
}
}
}