| /*=============================================================================# |
| # Copyright (c) 2010, 2017 Stephan Wahlbrink and others. |
| # |
| # This program and the accompanying materials are made available under the |
| # terms of the Eclipse Public License 2.0 which is available at |
| # https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 |
| # which is available at https://www.apache.org/licenses/LICENSE-2.0. |
| # |
| # SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 |
| # |
| # Contributors: |
| # Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation |
| #=============================================================================*/ |
| |
| package org.eclipse.statet.internal.r.core.rhelp; |
| |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.locks.ReentrantReadWriteLock; |
| |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| |
| import org.eclipse.statet.jcommons.collections.ImList; |
| |
| import org.eclipse.statet.internal.r.core.RCorePlugin; |
| import org.eclipse.statet.internal.r.core.rhelp.index.REnvIndexReader; |
| import org.eclipse.statet.r.core.RCore; |
| import org.eclipse.statet.r.core.renv.IREnv; |
| import org.eclipse.statet.r.core.renv.IREnvConfiguration; |
| import org.eclipse.statet.r.core.rhelp.IREnvHelp; |
| import org.eclipse.statet.r.core.rhelp.IRHelpKeyword; |
| import org.eclipse.statet.r.core.rhelp.IRHelpKeyword.Group; |
| import org.eclipse.statet.r.core.rhelp.IRHelpPage; |
| import org.eclipse.statet.r.core.rhelp.IRHelpSearchRequestor; |
| import org.eclipse.statet.r.core.rhelp.IRPkgHelp; |
| import org.eclipse.statet.r.core.rhelp.RHelpSearchQuery; |
| import org.eclipse.statet.rj.renv.core.RPkgDescription; |
| |
| |
| public final class REnvHelp implements IREnvHelp { |
| |
| |
| private final IREnv rEnv; |
| |
| private final String docDir; |
| |
| private final ImList<IRHelpKeyword.Group> keywords; |
| |
| private final ImList<IRPkgHelp> packages; |
| private volatile Map<String, IRPkgHelp> packageMap; |
| private volatile REnvIndexReader indexReader; |
| |
| private boolean disposed; |
| |
| private final ReentrantReadWriteLock lock= new ReentrantReadWriteLock(); |
| |
| |
| public REnvHelp(final IREnv rEnv, final String docDir, |
| final ImList<Group> keywords, final ImList<IRPkgHelp> packages) { |
| this.rEnv= rEnv; |
| this.docDir= docDir; |
| this.keywords= keywords; |
| this.packages= packages; |
| } |
| |
| |
| public void dispose() { |
| this.lock.writeLock().lock(); |
| try { |
| this.disposed= true; |
| this.packageMap= null; |
| if (this.indexReader != null) { |
| this.indexReader.dispose(); |
| this.indexReader= null; |
| } |
| } |
| finally { |
| this.lock.writeLock().unlock(); |
| } |
| } |
| |
| @Override |
| public IREnv getREnv() { |
| return this.rEnv; |
| } |
| |
| |
| public String getDocDir() { |
| return this.docDir; |
| } |
| |
| |
| public void lock() { |
| this.lock.readLock().lock(); |
| } |
| |
| @Override |
| public void unlock() { |
| this.lock.readLock().unlock(); |
| } |
| |
| |
| @Override |
| public ImList<IRHelpKeyword.Group> getKeywords() { |
| return this.keywords; |
| } |
| |
| @Override |
| public ImList<IRPkgHelp> getPkgs() { |
| return this.packages; |
| } |
| |
| @Override |
| public IRPkgHelp getPkgHelp(final String packageName) { |
| return getPackageMap().get(packageName); |
| } |
| |
| private Map<String, IRPkgHelp> getPackageMap() { |
| Map<String, IRPkgHelp> map= this.packageMap; |
| if (map == null) { |
| if (this.disposed) { |
| throw new IllegalStateException("This help index is no longer valid."); |
| } |
| synchronized (this) { |
| map= this.packageMap; |
| if (map == null) { |
| map= new HashMap<>(this.packages.size()); |
| for (final IRPkgHelp pkgHelp : this.packages) { |
| map.put(pkgHelp.getName(), pkgHelp); |
| } |
| this.packageMap= map; |
| } |
| } |
| } |
| return map; |
| } |
| |
| private REnvIndexReader getIndex() { |
| REnvIndexReader reader= this.indexReader; |
| if (reader == null) { |
| if (this.disposed) { |
| throw new IllegalStateException("This help index is no longer valid."); |
| } |
| synchronized (this) { |
| reader= this.indexReader; |
| if (reader == null) { |
| final IREnvConfiguration config= this.rEnv.getConfig(); |
| if (config == null) { |
| throw new IllegalStateException("This R environment is no longer valid."); |
| } |
| try { |
| reader= new REnvIndexReader(config); |
| } |
| catch (final Exception e) { |
| RCorePlugin.log(new Status(IStatus.ERROR, RCore.BUNDLE_ID, -1, |
| "An error occurred when initializing searcher for the R help index.", e)); |
| throw new RuntimeException("An error occurred when reading R help index."); |
| } |
| this.indexReader= reader; |
| } |
| } |
| } |
| return reader; |
| } |
| |
| @Override |
| public IRHelpPage getPage(final String packageName, final String name) { |
| final IRPkgHelp pkgHelp= getPackageMap().get(packageName); |
| if (pkgHelp != null) { |
| return pkgHelp.getHelpPage(name); |
| } |
| return null; |
| } |
| |
| @Override |
| public IRHelpPage getPageForTopic(final String packageName, final String topic) { |
| final IRPkgHelp pkgHelp= getPackageMap().get(packageName); |
| if (pkgHelp != null) { |
| return getIndex().getPageForTopic(pkgHelp, topic); |
| } |
| return null; |
| } |
| |
| @Override |
| public String getHtmlPage(final IRHelpPage page) { |
| return getHtmlPage(page.getPackage().getName(), page.getName(), null, null, null); |
| } |
| |
| @Override |
| public String getHtmlPage(final String packageName, final String pageName) { |
| return getHtmlPage(packageName, pageName, null, null, null); |
| } |
| |
| @Override |
| public String getHtmlPage(final String packageName, final String pageName, |
| final String queryString, final String[] preTags, final String[] postTags) { |
| return getIndex().getHtmlPage(packageName, pageName, queryString, preTags, postTags); |
| } |
| |
| @Override |
| public List<IRHelpPage> getPagesForTopic(final String topic) { |
| return getIndex().getPagesForTopic(topic, getPackageMap()); |
| } |
| |
| |
| public boolean search(final RHelpSearchQuery.Compiled query, final IRHelpSearchRequestor requestor) { |
| return getIndex().search(query, this.packages, getPackageMap(), requestor); |
| } |
| |
| |
| public List<RHelpTopicEntry> getPkgTopics(final IRPkgHelp pkgHelp) { |
| return getIndex().getPackageTopics(pkgHelp); |
| } |
| |
| @Override |
| public RPkgDescription getPkgDescription(final String pkgName) { |
| final IRPkgHelp pkgHelp= getPackageMap().get(pkgName); |
| if (pkgHelp != null) { |
| return getIndex().getPkgDescription(pkgHelp); |
| } |
| return null; |
| } |
| |
| @Override |
| public boolean searchTopics(final String prefix, final String topicType, |
| final List<String> packages, final ITopicSearchRequestor requestor) { |
| if (requestor == null) { |
| throw new NullPointerException("requestor"); //$NON-NLS-1$ |
| } |
| return getIndex().searchTopics(prefix, topicType, packages, requestor); |
| } |
| |
| } |