| /* |
| * 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.spi.java.classpath.support; |
| |
| import java.beans.PropertyChangeEvent; |
| import java.beans.PropertyChangeListener; |
| import java.beans.PropertyChangeSupport; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.Set; |
| import org.netbeans.api.annotations.common.NonNull; |
| import org.netbeans.api.java.classpath.ClassPath; |
| import org.netbeans.spi.java.classpath.FlaggedClassPathImplementation; |
| import org.netbeans.spi.java.classpath.PathResourceImplementation; |
| import org.openide.util.Parameters; |
| import org.openide.util.WeakListeners; |
| |
| /** |
| * |
| * @author Tomas Zezula |
| */ |
| final class MuxClassPathImplementation implements FlaggedClassPathImplementation, PropertyChangeListener { |
| private final ClassPathSupport.Selector selector; |
| private final PropertyChangeSupport listeners; |
| //@GuardedBy("this") |
| private List<PathResourceImplementation> cache; |
| //@GuardedBy("this") |
| private Set<ClassPath.Flag> flagsCache; |
| //GuardedBy("this") |
| private boolean activeClassPathValid; |
| //GuardedBy("this") |
| private ClassPath activeClassPath; |
| //@GuardedBy("this") |
| private PropertyChangeListener activeListener; |
| |
| MuxClassPathImplementation(@NonNull final ClassPathSupport.Selector selector) { |
| Parameters.notNull("selector", selector); //NOI18N |
| this.listeners = new PropertyChangeSupport(this); |
| this.selector = selector; |
| this.selector.addPropertyChangeListener(WeakListeners.propertyChange(this, this.selector)); |
| } |
| |
| @Override |
| @NonNull |
| public Set<ClassPath.Flag> getFlags() { |
| Set<ClassPath.Flag> res; |
| synchronized (this) { |
| res = flagsCache; |
| } |
| if (res == null) { |
| res = getActiveClassPath().getFlags(); |
| assert res != null; |
| synchronized (this) { |
| if (flagsCache == null) { |
| flagsCache = res; |
| } else { |
| res = flagsCache; |
| } |
| } |
| } |
| return res; |
| } |
| |
| @Override |
| @NonNull |
| public List<? extends PathResourceImplementation> getResources() { |
| List<PathResourceImplementation> res; |
| synchronized (this) { |
| res = cache; |
| } |
| if (res == null) { |
| final ClassPath cp = getActiveClassPath(); |
| final List<ClassPath.Entry> entries = cp.entries(); |
| res = new ArrayList<>(entries.size()); |
| for (ClassPath.Entry entry : entries) { |
| res.add(org.netbeans.spi.java.classpath.support.ClassPathSupport.createResource(entry.getURL())); |
| } |
| synchronized (this) { |
| if (cache == null) { |
| cache = Collections.unmodifiableList(res); |
| } else { |
| res = cache; |
| } |
| } |
| } |
| return res; |
| } |
| |
| @Override |
| public void addPropertyChangeListener(@NonNull final PropertyChangeListener listener) { |
| Parameters.notNull("listener", listener); //NOI18N |
| this.listeners.addPropertyChangeListener(listener); |
| } |
| |
| @Override |
| public void removePropertyChangeListener(PropertyChangeListener listener) { |
| Parameters.notNull("listener", listener); //NOI18N |
| this.listeners.removePropertyChangeListener(listener); |
| } |
| |
| @Override |
| public void propertyChange(PropertyChangeEvent evt) { |
| final String propName = evt.getPropertyName(); |
| if (ClassPathSupport.Selector.PROP_ACTIVE_CLASS_PATH.equals(propName)) { |
| synchronized (this) { |
| cache = null; |
| flagsCache = null; |
| activeClassPathValid = false; |
| } |
| this.listeners.firePropertyChange(PROP_RESOURCES, null, null); |
| this.listeners.firePropertyChange(PROP_FLAGS, null, null); |
| } else if (ClassPath.PROP_ENTRIES.equals(propName)) { |
| synchronized (this) { |
| cache = null; |
| } |
| this.listeners.firePropertyChange(PROP_RESOURCES, null, null); |
| } else if (ClassPath.PROP_FLAGS.equals(propName)) { |
| synchronized (this) { |
| flagsCache = null; |
| } |
| this.listeners.firePropertyChange(PROP_FLAGS, null, null); |
| } |
| } |
| |
| @NonNull |
| private ClassPath getActiveClassPath() { |
| synchronized (this) { |
| if (activeClassPathValid) { |
| assert activeClassPath != null; |
| return activeClassPath; |
| } |
| if (activeClassPath != null) { |
| assert activeListener != null; |
| activeClassPath.removePropertyChangeListener(activeListener); |
| activeClassPath = null; |
| activeListener = null; |
| } |
| } |
| final ClassPath newCp = selector.getActiveClassPath(); |
| assert newCp != null : String.format( |
| "Selector: %s (%s) returned null ClassPath", //NOI18N |
| selector, |
| selector.getClass()); |
| synchronized (this) { |
| if (activeClassPath == null) { |
| assert activeListener == null; |
| activeClassPath = newCp; |
| activeListener = WeakListeners.propertyChange(this, activeClassPath); |
| activeClassPath.addPropertyChangeListener(activeListener); |
| activeClassPathValid = true; |
| } |
| return activeClassPath; |
| } |
| } |
| } |