package org.netbeans.gradle.project.properties; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.jtrim.concurrent.Tasks; import org.jtrim.event.ListenerRef; import org.jtrim.event.ListenerRegistries; import org.jtrim.utils.ExceptionHelper; import org.netbeans.gradle.project.util.NbConsumer; import org.netbeans.gradle.project.util.TestDetectUtils; public final class ProfileSettingsContainer { private static final AtomicReference<ProfileSettingsContainer> DEFAULT_REF = new AtomicReference<>(null); private final Lock mainLock; private final WeakValueHashMap<ProfileSettingsKey, LoadableSingleProfileSettingsEx> loaded; private ProfileSettingsContainer() { this.mainLock = new ReentrantLock(); this.loaded = new WeakValueHashMap<>(); } public static ProfileSettingsContainer getDefault() { ProfileSettingsContainer result = DEFAULT_REF.get(); if (result == null) { result = new ProfileSettingsContainer(); if (DEFAULT_REF.compareAndSet(null, result)) { if (!TestDetectUtils.isRunningTests()) { // We must not add this shutdown hook when running tests because // it would cause a dead-lock in NetBeans. final ProfileSettingsContainer toPersistBeforeTerminate = result; Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { @Override public void run() { toPersistBeforeTerminate.saveAllProfilesNow(); } })); } } else { result = DEFAULT_REF.get(); } } return result; } private void saveAllProfilesNow() { List<LoadableSingleProfileSettingsEx> toSave; mainLock.lock(); try { toSave = new ArrayList<>(loaded.values()); } finally { mainLock.unlock(); } for (LoadableSingleProfileSettingsEx settings: toSave) { settings.saveAndWait(); } } private LoadableSingleProfileSettingsEx getUnloadedProfileSettings(ProfileSettingsKey key) { ExceptionHelper.checkNotNullArgument(key, "key"); LoadableSingleProfileSettingsEx result; mainLock.lock(); try { result = loaded.get(key); if (result == null) { result = key.openUnloadedProfileSettings(); loaded.put(key, result); } } finally { mainLock.unlock(); } return result; } public SingleProfileSettingsEx loadProfileSettings(ProfileSettingsKey key) { LoadableSingleProfileSettingsEx result = getUnloadedProfileSettings(key); result.ensureLoadedAndWait(); return result; } public ListenerRef loadProfileSettings( ProfileSettingsKey key, final NbConsumer<? super SingleProfileSettingsEx> listener) { ExceptionHelper.checkNotNullArgument(listener, "listener"); final LoadableSingleProfileSettingsEx result = getUnloadedProfileSettings(key); result.ensureLoaded(); return result.notifyWhenLoaded(new Runnable() { @Override public void run() { listener.accept(result); } }); } public ListenerRef loadAllProfileSettings( Collection<ProfileSettingsKey> keys, final NbConsumer<? super List<SingleProfileSettingsEx>> listener) { ExceptionHelper.checkNotNullElements(keys, "keys"); ExceptionHelper.checkNotNullArgument(listener, "listener"); final List<LoadableSingleProfileSettingsEx> result = new ArrayList<>(keys.size()); for (ProfileSettingsKey key: keys) { result.add(getUnloadedProfileSettings(key)); } List<ListenerRef> resultRefs = new ArrayList<>(result.size()); final AtomicInteger loadCount = new AtomicInteger(result.size()); for (LoadableSingleProfileSettingsEx settings: result) { settings.ensureLoaded(); ListenerRef notifyRef = settings.notifyWhenLoaded(Tasks.runOnceTask(new Runnable() { @Override public void run() { if (loadCount.decrementAndGet() == 0) { listener.accept(new ArrayList<SingleProfileSettingsEx>(result)); } } }, false)); resultRefs.add(notifyRef); } return ListenerRegistries.combineListenerRefs(resultRefs); } public List<SingleProfileSettingsEx> loadAllProfileSettings(Collection<ProfileSettingsKey> keys) { ExceptionHelper.checkNotNullElements(keys, "keys"); List<SingleProfileSettingsEx> result = new ArrayList<>(keys.size()); for (ProfileSettingsKey key: keys) { result.add(loadProfileSettings(key)); } return result; } }