blob: 654dedd100337a516bcf9a7cf4b85167299ff6ec [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.java.j2semodule;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.netbeans.api.queries.FileBuiltQuery.Status;
import org.netbeans.spi.queries.FileBuiltQueryImplementation;
import org.openide.filesystems.FileObject;
import org.openide.util.ChangeSupport;
/**
*
* @author Tomas Zezula
*/
final class CoSAwareFileBuiltQueryImpl implements FileBuiltQueryImplementation, PropertyChangeListener {
private final FileBuiltQueryImplementation delegate;
private final J2SEModularProject project;
private final AtomicBoolean cosEnabled = new AtomicBoolean();
private final Map<FileObject, Reference<StatusImpl>> file2Status = new WeakHashMap<FileObject, Reference<StatusImpl>>();
@SuppressWarnings("LeakingThisInConstructor")
public CoSAwareFileBuiltQueryImpl(FileBuiltQueryImplementation delegate, J2SEModularProject project) {
this.delegate = delegate;
this.project = project;
project.evaluator().addPropertyChangeListener(this);
setCoSEnabledAndXor();
}
private synchronized StatusImpl readFromCache(FileObject file) {
Reference<StatusImpl> r = file2Status.get(file);
return r != null ? r.get() : null;
}
@Override
public Status getStatus(FileObject file) {
StatusImpl result = readFromCache(file);
if (result != null) {
return result;
}
Status status = delegate.getStatus(file);
if (status == null) {
return null;
}
synchronized (this) {
StatusImpl foisted = readFromCache(file);
if (foisted != null) {
return foisted;
}
file2Status.put(file, new WeakReference<>(result = new StatusImpl(cosEnabled, status)));
}
return result;
}
boolean setCoSEnabledAndXor() {
boolean nue = J2SEModularProjectUtil.isCompileOnSaveEnabled(project);
boolean old = cosEnabled.getAndSet(nue);
return old != nue;
}
@Override
public void propertyChange(PropertyChangeEvent evt) {
if (!setCoSEnabledAndXor()) {
return;
}
Collection<Reference<StatusImpl>> toRefresh;
synchronized (this) {
toRefresh = new LinkedList<>(file2Status.values());
}
for (Reference<StatusImpl> r : toRefresh) {
StatusImpl s = r.get();
if (s != null) {
s.stateChanged(null);
}
}
}
private static final class StatusImpl implements Status, ChangeListener {
private final ChangeSupport cs = new ChangeSupport(this);
private final AtomicBoolean cosEnabled;
private final Status delegate;
@SuppressWarnings("LeakingThisInConstructor")
public StatusImpl(AtomicBoolean cosEnabled, Status delegate) {
this.cosEnabled = cosEnabled;
this.delegate = delegate;
this.delegate.addChangeListener(this);
}
@Override
public boolean isBuilt() {
return cosEnabled.get() || delegate.isBuilt();
}
@Override
public void addChangeListener(ChangeListener l) {
cs.addChangeListener(l);
}
@Override
public void removeChangeListener(ChangeListener l) {
cs.removeChangeListener(l);
}
@Override
public void stateChanged(ChangeEvent e) {
cs.fireChange();
}
}
}