package org.netbeans.gradle.project.extensions;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jtrim.utils.ExceptionHelper;
import org.netbeans.gradle.project.api.entry.GradleProjectExtension2;
import org.netbeans.gradle.project.api.entry.GradleProjectExtensionDef;
import org.netbeans.gradle.project.api.entry.ModelLoadResult;
import org.netbeans.gradle.project.api.entry.ParsedModel;
import org.netbeans.gradle.project.lookups.DynamicLookup;
import org.openide.util.Lookup;
public final class NbGradleExtensionRef {
private static final Logger LOGGER = Logger.getLogger(NbGradleExtensionRef.class.getName());
private final String name;
private final String displayName;
private final DefWithExtension<?> defWithExtension;
private final ModelNeeds modelNeed;
private final AtomicBoolean lastActive;
private final DeducedExtensionServicesProvider deducedServicesProvider;
private final DynamicLookup extensionLookup;
private final DynamicLookup projectLookup;
private final AtomicReference<Lookup> deducedServicesRef;
public <ModelType> NbGradleExtensionRef(
GradleProjectExtensionDef<ModelType> extensionDef,
GradleProjectExtension2<ModelType> extension,
DeducedExtensionServicesProvider deducedServicesProvider) {
ExceptionHelper.checkNotNullArgument(extensionDef, "extensionDef");
ExceptionHelper.checkNotNullArgument(extension, "extension");
ExceptionHelper.checkNotNullArgument(deducedServicesProvider, "deducedServicesProvider");
this.name = extensionDef.getName();
checkExtensionName(name, extensionDef);
this.deducedServicesProvider = deducedServicesProvider;
this.displayName = useNameIfNoDisplayName(extensionDef.getDisplayName(), name);
this.defWithExtension = new DefWithExtension<>(extensionDef, extension);
this.modelNeed = new ModelNeeds(extensionDef);
this.projectLookup = new DynamicLookup(extension.getPermanentProjectLookup());
this.extensionLookup = new DynamicLookup();
this.lastActive = new AtomicBoolean(false);
this.deducedServicesRef = new AtomicReference<>(null);
}
private static void checkExtensionName(String name, GradleProjectExtensionDef<?> def) {
if (name == null) {
throw new NullPointerException("Extension name cannot be null for " + def.getClass().getName());
}
if (name.trim().isEmpty()) {
throw new IllegalArgumentException("Extension name cannot be empty for " + def.getClass().getName());
}
}
private static String useNameIfNoDisplayName(String displayName, String name) {
if (displayName == null) {
LOGGER.log(Level.WARNING,
"GradleProjectExtensionDef.getDisplayName returned null for extension {0}",
name);
return name;
}
return displayName;
}
public ModelNeeds getModelNeeds() {
return modelNeed;
}
public GradleProjectExtensionDef<?> getExtensionDef() {
return defWithExtension.extensionDef;
}
public GradleProjectExtension2<?> getExtension() {
return defWithExtension.extension;
}
public String getDisplayName() {
return displayName;
}
public String getName() {
return name;
}
public Lookup getExtensionLookup() {
return extensionLookup.getUnmodifiableView();
}
public Lookup getProjectLookup() {
return projectLookup.getUnmodifiableView();
}
private ParsedModel<?> safelyReturn(ParsedModel<?> result) {
if (result == null) {
LOGGER.log(Level.WARNING,
"GradleProjectExtensionDef.parseModel returned null for extension {0}",
getName());
return ParsedModel.noModels();
}
else {
return result;
}
}
public ParsedModel<?> parseModel(ModelLoadResult retrievedModels) {
ExceptionHelper.checkNotNullArgument(retrievedModels, "retrievedModels");
try {
return safelyReturn(getExtensionDef().parseModel(retrievedModels));
} catch (Throwable ex) {
LOGGER.log(Level.SEVERE, "Extension failed to parse models: " + getName(), ex);
return ParsedModel.noModels();
}
}
private Lookup createDeducedLookup() {
GradleProjectExtension2<?> extension = getExtension();
return deducedServicesProvider.getDeducedLookup(this,
extension.getExtensionLookup(),
extension.getPermanentProjectLookup(),
extension.getProjectLookup());
}
private Lookup getDeducedLookup() {
Lookup result = deducedServicesRef.get();
if (result == null) {
result = createDeducedLookup();
if (!deducedServicesRef.compareAndSet(null, result)) {
result = deducedServicesRef.get();
}
}
return result;
}
public boolean setModelForExtension(Object model) {
boolean active = model != null;
boolean prevActive = lastActive.getAndSet(active);
GradleProjectExtension2<?> extension = getExtension();
if (active) {
projectLookup.replaceLookups(
extension.getPermanentProjectLookup(),
extension.getProjectLookup());
extensionLookup.replaceLookups(
getDeducedLookup(),
extension.getExtensionLookup(),
extension.getPermanentProjectLookup(),
extension.getProjectLookup());
defWithExtension.activate(model);
}
else {
projectLookup.replaceLookups(extension.getPermanentProjectLookup());
extensionLookup.replaceLookups(Lookup.EMPTY);
defWithExtension.deactivate();
}
return prevActive != active;
}
private static final class DefWithExtension<ModelType> {
public final GradleProjectExtensionDef<ModelType> extensionDef;
public final GradleProjectExtension2<ModelType> extension;
private final Class<ModelType> modelType;
public DefWithExtension(
GradleProjectExtensionDef<ModelType> extensionDef,
GradleProjectExtension2<ModelType> extension) {
ExceptionHelper.checkNotNullArgument(extensionDef, "extensionDef");
ExceptionHelper.checkNotNullArgument(extension, "extension");
this.extensionDef = extensionDef;
this.extension = extension;
this.modelType = extensionDef.getModelType();
if (this.modelType == null) {
throw new NullPointerException(
"GradleProjectExtensionDef[" + extensionDef.getName() + "].getModelType");
}
}
public void activate(Object model) {
ExceptionHelper.checkNotNullArgument(model, "model");
extension.activateExtension(modelType.cast(model));
}
public void deactivate() {
extension.deactivateExtension();
}
}
}