/* * Copyright 2000-2013 JetBrains s.r.o. * Copyright 2014-2014 AS3Boyan * Copyright 2014-2014 Elias Ku * * 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 com.intellij.plugins.haxe.haxelib; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.projectRoots.Sdk; import org.apache.log4j.Level; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.Hashtable; /** * Manage a cache of SDKs. In actuality, this class is really just a * cache of library managers, keyed by SDK name. For most projects, there * will only be one in use. * * If we need more speed or compactness, we could track the library managers * by the actual haxelib executable path. SDKs specify a path which * multiple SDKs could use, but, in practice, probably don't. * * This is a pretty small class and putting this functionality directly into * HaxelibLibraryManager is an option. This implementation just allowed for * fewer changes to that api, which was becoming less useful/manageable as I * started adding SDK and/or Module parameters everywhere. */ public class HaxelibLibraryCacheManager { static final Logger LOG = Logger.getInstance("#com.intellij.plugins.haxe.haxelib.HaxeLibraryManager"); static { LOG.setLevel(Level.DEBUG); } final SdkCache mySdkCache; public HaxelibLibraryCacheManager() { mySdkCache = new SdkCache(); } /** * Get the library manager associated with the given module. This will * be either using the SDK specified on the module, or the one inherited * from the project, if applicable. * * @param module - module to look up libraries for. * @return a library manager for the given module. */ @NotNull public HaxelibLibraryCache getLibraryManager(@NotNull Module module) { Sdk sdk = HaxelibSdkUtils.lookupSdk(module); return getLibraryCache(sdk); } /** * Get the library manager associated with the given SDK. There is * only one per project with the given name (e.g. modules that specify * the same SDK will get the same library manager object). Therefore, * if all modules specify the same SDK it is functionally identical to * inheriting the project SDK. * * @param sdk - SDK to look up libraries for. * @return a library manager for the given SDK. */ @NotNull public HaxelibLibraryCache getLibraryCache(@NotNull Sdk sdk) { SdkEntry entry = mySdkCache.get(sdk.getName()); if (null == entry) { // Not in the cache? Put it there. entry = new SdkEntry(sdk); mySdkCache.add(entry); } return entry.getLibraryCache(); } /** * Cache entry for the SDK table. */ final class SdkEntry { final Sdk mySdk; final HaxelibLibraryCache myMgr; public SdkEntry(@NotNull Sdk sdk) { mySdk = sdk; myMgr = new HaxelibLibraryCache(sdk); } @NotNull public String getName() { return mySdk.getName(); } @NotNull public HaxelibLibraryCache getLibraryCache() { return myMgr; } public boolean nameEquals(@NotNull SdkEntry entry) { return getName().equals(entry.getName()); } public boolean nameEquals(@NotNull String name) { return getName().equals(name); } } /** * Cache of library managers per SDK. */ final class SdkCache { // Optimize the common case where we only have one... SdkEntry cacheOfOne = null; Hashtable<String, SdkEntry> myCache; public SdkCache() { } /** * Lazy initialization. */ private void initCache() { myCache = new Hashtable<String, SdkEntry>(); } /** * Add a library manager to the cache. If a library manager of the same * name already exists, the old one will be kept and the new ignored. * * @param entry An SdkEntry object */ public void add(@NotNull SdkEntry entry) { if (null == myCache) { if (null == cacheOfOne ) { cacheOfOne = entry; } else if (! cacheOfOne.nameEquals(entry)) { // Don't need to add another of the same name. initCache(); add(entry); add(cacheOfOne); cacheOfOne = null; } } else { if (! myCache.containsKey(entry.getName())) { // Don't replace a full cache with an empty one. SdkEntry oldEntry = myCache.put(entry.getName(), entry); if (null != oldEntry) { LOG.warn("Duplicating cached data for entry " + entry.getName()); } } } } public void clear() { cacheOfOne = null; if (null != myCache) { myCache.clear(); } } @Nullable public SdkEntry get(@NotNull String name) { if (null != cacheOfOne && cacheOfOne.nameEquals(name)) { return cacheOfOne; } if (null != myCache) { return myCache.get(name); } return null; } } }