/******************************************************************************* | |
* Copyright (c) 2011, 2015 IBM Corporation and others. | |
* All rights reserved. This program and the accompanying materials | |
* are made available under the terms of the Eclipse Public License v1.0 | |
* which accompanies this distribution, and is available at | |
* http://www.eclipse.org/legal/epl-v10.html | |
* | |
* Contributors: | |
* IBM Corporation - initial API and implementation | |
*******************************************************************************/ | |
package org.eclipse.help.internal.base; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.HashSet; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Set; | |
import java.util.StringTokenizer; | |
import org.eclipse.core.runtime.IConfigurationElement; | |
import org.eclipse.core.runtime.IExtensionRegistry; | |
import org.eclipse.core.runtime.Platform; | |
import org.eclipse.core.runtime.preferences.IEclipsePreferences; | |
import org.eclipse.core.runtime.preferences.IScopeContext; | |
import org.eclipse.core.runtime.preferences.InstanceScope; | |
import org.eclipse.help.internal.HelpPlugin; | |
import org.osgi.service.prefs.BackingStoreException; | |
/** | |
* Handles unresolved toc place holders as well as situations where remote help | |
* is unavailable | |
*/ | |
public class MissingContentManager { | |
private static final String HELP_PROTOCOL = "help:"; //$NON-NLS-1$ | |
private static final String EXTENSION_POINT_ID_TOC = HelpPlugin.PLUGIN_ID + ".toc"; //$NON-NLS-1$ | |
private static final String ELEMENT_NAME_PLACEHOLDER = "placeholder"; //$NON-NLS-1$ | |
private static final String ATTRIBUTE_NAME_PLUGIN = "plugin"; //$NON-NLS-1$ | |
private static final String ATTRIBUTE_NAME_PLACEHOLDER_PAGE = "placeholderPage"; //$NON-NLS-1$ | |
public static final String IGNORE_MISSING_PLACEHOLDER_PREFERENCE = "ignorePlaceholders"; //$NON-NLS-1$ | |
// Hrefs which are processed by org.eclipse.help.internal.webapp.StatusProducer | |
public static final String REMOTE_STATUS_HREF = "NetworkHelpStatus.html"; //$NON-NLS-1$ | |
public static final String REMOTE_STATUS_HELP_VIEW_HREF = "NetworkHelpStatusHV.html"; //$NON-NLS-1$ | |
public static final String MISSING_TOPIC_HREF = "MissingTopicStatus.html"; //$NON-NLS-1$ | |
public static final String MISSING_TOPIC_PATH = "missingTopic/"; //$NON-NLS-1$ | |
public static final String MISSING_BOOKS_HREF = "MissingBooks.html"; //$NON-NLS-1$ | |
public static final String MISSING_BOOKS_HELP_VIEW_HREF = "MissingBooksHV.html"; //$NON-NLS-1$ | |
/* | |
* A place holder defines a page to be shown when a documentation page | |
* which matches the specified path not installed | |
*/ | |
public static class Placeholder implements Comparable<Placeholder> { | |
public String path; | |
public String bundle; | |
public String placeholderPage; | |
public Placeholder(String path, String bundle, String placeholderPage) { | |
this.path = path; | |
this.bundle = bundle; | |
this.placeholderPage = placeholderPage; | |
} | |
@Override | |
public int compareTo(Placeholder o) { | |
return o.path.compareTo(path); | |
} | |
} | |
private static MissingContentManager instance; | |
private List<Placeholder> placeholders; | |
private Set<String> bundlesToIgnore; // A set of bundles the user does not want to see reference to | |
public static MissingContentManager getInstance() { | |
if ( instance == null ) { | |
instance = new MissingContentManager(); | |
} | |
return instance; | |
} | |
/* | |
* Read the extension registry | |
*/ | |
private MissingContentManager() { | |
IExtensionRegistry registry = Platform.getExtensionRegistry(); | |
placeholders = new ArrayList<>(); | |
bundlesToIgnore = new HashSet<>(); | |
if ( BaseHelpSystem.getMode() == BaseHelpSystem.MODE_INFOCENTER ) { | |
return; // Placeholders are not shown for infocenters | |
} | |
// Read the placeholders from the extension registry | |
IConfigurationElement[] elements = registry | |
.getConfigurationElementsFor(EXTENSION_POINT_ID_TOC); | |
for (int i = 0; i < elements.length; ++i) { | |
IConfigurationElement elem = elements[i]; | |
String pluginId = elem.getContributor().getName(); | |
if (elem.getName().equals(ELEMENT_NAME_PLACEHOLDER)) { | |
try { | |
String plugin = elem.getAttribute(ATTRIBUTE_NAME_PLUGIN); | |
String path = HELP_PROTOCOL + plugin + '/'; | |
String placeholder = elem | |
.getAttribute(ATTRIBUTE_NAME_PLACEHOLDER_PAGE); | |
placeholders.add(new Placeholder(path, plugin, placeholder)); | |
} catch (Exception e) { | |
// log and skip | |
String msg = "Exception reading " + ELEMENT_NAME_PLACEHOLDER + " extension in bundle" + pluginId; //$NON-NLS-1$ //$NON-NLS-2$ | |
HelpPlugin.logError(msg, e); | |
} | |
} | |
} | |
Collections.sort(placeholders); | |
// Read the preferences to find any ignored placeholders | |
String ignoredBundles = Platform.getPreferencesService().getString(HelpBasePlugin.PLUGIN_ID, IGNORE_MISSING_PLACEHOLDER_PREFERENCE, "", null); //$NON-NLS-1$ | |
if (ignoredBundles.length() > 0) { | |
StringTokenizer tokenizer = new StringTokenizer(ignoredBundles, " ,"); //$NON-NLS-1$ | |
while (tokenizer.hasMoreTokens()) { | |
bundlesToIgnore.add(tokenizer.nextToken()); | |
} | |
} | |
} | |
/** | |
* Called when a page cannot be found | |
* @param path the path of the page that could not be loaded | |
* @return a place holder page if defined, otherwise an error page | |
*/ | |
public String getPageNotFoundPage(String path, boolean showPlaceholderPage) { | |
for (Iterator<Placeholder> iter = placeholders.iterator(); iter.hasNext(); ) { | |
Placeholder placeholder = iter.next(); | |
if (path.startsWith(placeholder.path) && Platform.getBundle(placeholder.bundle) == null) { | |
if ( showPlaceholderPage) { | |
return placeholder.placeholderPage; | |
} else { | |
return "/org.eclipse.help.webapp/" + MISSING_TOPIC_PATH + path.substring(HELP_PROTOCOL.length()); //$NON-NLS-1$ | |
} | |
} | |
} | |
return Platform.getPreferencesService().getString(HelpBasePlugin.PLUGIN_ID, "page_not_found", null, null); //$NON-NLS-1$ | |
} | |
/** | |
* | |
* @return true if there is an unresolved place holder and this is not an infocenter | |
*/ | |
public boolean isUnresolvedPlaceholders() { | |
if (BaseHelpSystem.getMode()==BaseHelpSystem.MODE_INFOCENTER) { | |
return false; | |
} | |
Placeholder[] unresolvedPlaceHolders = getUnresolvedPlaceholders(); | |
return unresolvedPlaceHolders.length > 0; | |
} | |
/** | |
* If any help is missing returns an appropriate page | |
* @return null if no help is unavailable or an appropriate page if | |
* the plug-in that corresponds to a place holder is not available. | |
* The returned page will be in the format /plug-in/path. | |
*/ | |
public String getHelpMissingPage(boolean isHelpView) { | |
Placeholder[] unresolvedPlaceHolders = getUnresolvedPlaceholders(); | |
if (unresolvedPlaceHolders.length == 0) { | |
return null; | |
} else { | |
String suffix = isHelpView ? MISSING_BOOKS_HELP_VIEW_HREF : MISSING_BOOKS_HREF; | |
return "/org.eclipse.help.webapp" + '/'+ suffix; //$NON-NLS-1$ | |
} | |
} | |
/** | |
* Get the page to be shown when some remote help is known to be unavailable | |
*/ | |
public String getRemoteHelpUnavailablePage(boolean isHelpView) { | |
if ( BaseHelpSystem.getMode()!=BaseHelpSystem.MODE_INFOCENTER ) { | |
String suffix = isHelpView ? REMOTE_STATUS_HELP_VIEW_HREF : REMOTE_STATUS_HREF; | |
return "/org.eclipse.help.webapp/" + suffix; //$NON-NLS-1$ | |
} | |
return null; | |
} | |
public Placeholder[] getUnresolvedPlaceholders() { | |
List<Placeholder> unresolved; | |
unresolved = new ArrayList<>(); | |
for (Iterator<Placeholder> iter = placeholders.iterator(); iter.hasNext(); ) { | |
Placeholder ph = iter.next(); | |
String bundle = ph.bundle; | |
if (bundle != null && !bundlesToIgnore.contains(bundle) ) { | |
if (Platform.getBundle(bundle) == null ) { | |
unresolved.add(ph); | |
} | |
} | |
} | |
return unresolved.toArray(new Placeholder[unresolved.size()]); | |
} | |
// Modifies the preferences to ignore any bundles that are currently unresolved placeholders | |
public void ignoreAllMissingPlaceholders() { | |
Placeholder[] unresolved = getUnresolvedPlaceholders(); | |
String ignoredBundles = Platform.getPreferencesService().getString(HelpBasePlugin.PLUGIN_ID, IGNORE_MISSING_PLACEHOLDER_PREFERENCE, "", null); //$NON-NLS-1$ | |
for ( int i = 0; i < unresolved.length; i++) { | |
String bundle = unresolved[i].bundle; | |
bundlesToIgnore.add(bundle); | |
if (ignoredBundles.length() > 0) { | |
ignoredBundles = ignoredBundles + ','; | |
} | |
ignoredBundles = ignoredBundles + bundle; | |
} | |
IScopeContext instanceScope = InstanceScope.INSTANCE; | |
IEclipsePreferences prefs = instanceScope.getNode(HelpBasePlugin.PLUGIN_ID); | |
prefs.put(IGNORE_MISSING_PLACEHOLDER_PREFERENCE, ignoredBundles); | |
try { | |
prefs.flush(); | |
} catch (BackingStoreException e) { | |
HelpBasePlugin.logError("Cannot save preferences", e); //$NON-NLS-1$ | |
} | |
} | |
} |