blob: 50bf5645b5ba98fa764681c5967e5f22ce15a7a0 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2010, 2019 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.rhelp.core;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.eclipse.statet.jcommons.collections.ImList;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.jcommons.status.ErrorStatus;
import org.eclipse.statet.jcommons.status.ProgressMonitor;
import org.eclipse.statet.jcommons.status.StatusException;
import org.eclipse.statet.internal.rhelp.core.index.REnvIndexReader;
import org.eclipse.statet.internal.rhelp.core.server.ServerClientSupport;
import org.eclipse.statet.rhelp.core.DocResource;
import org.eclipse.statet.rhelp.core.REnvHelp;
import org.eclipse.statet.rhelp.core.REnvHelpConfiguration;
import org.eclipse.statet.rhelp.core.RHelpCore;
import org.eclipse.statet.rhelp.core.RHelpKeywordGroup;
import org.eclipse.statet.rhelp.core.RHelpPage;
import org.eclipse.statet.rhelp.core.RHelpSearchQuery;
import org.eclipse.statet.rhelp.core.RHelpSearchRequestor;
import org.eclipse.statet.rhelp.core.RPkgHelp;
import org.eclipse.statet.rj.renv.core.REnv;
import org.eclipse.statet.rj.renv.core.REnvConfiguration;
@NonNullByDefault
public final class REnvHelpImpl implements REnvHelp {
public static final long NOT_AVAILABLE_STAMP= 0;
public static long createStamp() {
long stamp= System.currentTimeMillis();
if (stamp == NOT_AVAILABLE_STAMP) {
stamp++;
}
return stamp;
}
private final REnv rEnv;
private final long stamp;
private final @Nullable String docDir;
private final ImList<DocResource> manuals;
private final ImList<DocResource> miscRes;
private final ImList<RHelpKeywordGroup> keywords;
private final ImList<RPkgHelp> packages;
private @Nullable volatile Map<String, RPkgHelp> packageMap;
private @Nullable volatile REnvHelpIndex index;
private boolean disposed;
private final ReentrantReadWriteLock lock= new ReentrantReadWriteLock();
public REnvHelpImpl(final REnv rEnv, final long stamp,
final @Nullable String docDir, final ImList<DocResource> manuals, final ImList<DocResource> miscRes,
final ImList<RHelpKeywordGroup> keywords, final ImList<RPkgHelp> packages) {
this.rEnv= rEnv;
this.stamp= stamp;
this.docDir= docDir;
this.manuals= manuals;
this.miscRes= miscRes;
this.keywords= keywords;
this.packages= packages;
}
public void dispose() {
this.lock.writeLock().lock();
try {
this.disposed= true;
this.packageMap= null;
if (this.index != null) {
this.index.dispose();
this.index= null;
}
}
finally {
this.lock.writeLock().unlock();
}
}
@Override
public REnv getREnv() {
return this.rEnv;
}
public long getStamp() {
return this.stamp;
}
public @Nullable String getDocDir() {
return this.docDir;
}
public void lock() {
this.lock.readLock().lock();
}
@Override
public void unlock() {
this.lock.readLock().unlock();
}
@Override
public ImList<DocResource> getManuals() {
return this.manuals;
}
@Override
public ImList<DocResource> getMiscResources() {
return this.miscRes;
}
@Override
public ImList<RHelpKeywordGroup> getKeywords() {
return this.keywords;
}
@Override
public ImList<RPkgHelp> getPkgs() {
return this.packages;
}
@Override
public @Nullable RPkgHelp getPkgHelp(final String pkgName) {
return getPackageMap().get(pkgName);
}
private Map<String, RPkgHelp> getPackageMap() {
Map<String, RPkgHelp> map= this.packageMap;
if (map == null) {
synchronized (this) {
if (this.disposed) {
throw new IllegalStateException("This help index is no longer valid.");
}
map= this.packageMap;
if (map == null) {
map= new HashMap<>(this.packages.size());
for (final RPkgHelp pkgHelp : this.packages) {
map.put(pkgHelp.getName(), pkgHelp);
}
this.packageMap= map;
}
}
}
return map;
}
synchronized void setIndex(final REnvHelpIndex index) {
if (!this.disposed && this.index == null) {
this.index= index;
}
}
private REnvHelpIndex getIndex() {
REnvHelpIndex index= this.index;
if (index == null) {
synchronized (this) {
if (this.disposed) {
throw new IllegalStateException("This help index is no longer valid.");
}
index= this.index;
if (index == null) {
final REnvHelpConfiguration rEnvConfig= this.rEnv.get(REnvHelpConfiguration.class);
if (rEnvConfig == null) {
throw new IllegalStateException("This R environment is no longer valid.");
}
try {
switch (rEnvConfig.getStateSharedType()) {
case REnvConfiguration.SHARED_DIRECTORY:
index= new REnvIndexReader(rEnvConfig);
break;
case REnvConfiguration.SHARED_SERVER:
index= ServerClientSupport.getInstance().getREnvHelpAccess(rEnvConfig);
break;
default:
throw new UnsupportedOperationException(rEnvConfig.getStateSharedType());
}
}
catch (final Exception e) {
RHelpCoreInternals.log(new ErrorStatus(RHelpCore.BUNDLE_ID,
"An error occurred when initializing searcher for the R help index.",
e ));
throw new RuntimeException("An error occurred when reading R help index.");
}
this.index= index;
}
}
}
return index;
}
@Override
public @Nullable RHelpPage getPage(final String pkgName, final String name) {
final RPkgHelp pkgHelp= getPackageMap().get(pkgName);
if (pkgHelp != null) {
return pkgHelp.getPage(name);
}
return null;
}
@Override
public List<RHelpPage> getPagesForTopic(final String topic,
final @Nullable ProgressMonitor m) throws StatusException {
return getIndex().getPagesForTopic(topic, getPackageMap(),
10, m );
}
public @Nullable String getHtmlPage(final RPkgHelp pkgHelp, final String pageName,
final @Nullable String queryString) throws StatusException {
return getIndex().getHtmlPage(pkgHelp, pageName, queryString,
-1, null );
}
public void search(final RHelpSearchQuery query,
final RHelpSearchRequestor requestor) throws StatusException {
getIndex().search(query, this.packages, getPackageMap(), requestor);
}
}