/******************************************************************************* * Copyright (c) 2005, 2016 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 * Sopot Cela - Bug 466829 *******************************************************************************/ package org.eclipse.help.internal.search; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.Properties; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.help.internal.base.HelpBasePlugin; import org.eclipse.help.internal.base.util.ProxyUtil; import org.eclipse.help.internal.util.ResourceLocator; import org.osgi.framework.Bundle; public class PluginIndex { private static final String COMPLETE_FILENAME = "indexed_complete"; //$NON-NLS-1$ private String pluginId; /** * index path as defined in plugin.xml, e.g. "index" */ private String path; private SearchIndex targetIndex; /** * path prefixes where index is found e.g. "", "nl/en/US", "ws/gtk" */ private List<String> indexIDs; /** * resolved directory paths (Strings) corresponding to indexes at given * prefixes, e.g. //d/eclipse/...../os/linux/index, */ private List<String> resolvedPaths; public PluginIndex(String pluginId, String path, SearchIndex targetIndex) { super(); this.pluginId = pluginId; this.path = path; this.targetIndex = targetIndex; } private void resolve() { if (indexIDs != null) { // resolved return; } indexIDs = new ArrayList<>(); resolvedPaths = new ArrayList<>(); Bundle bundle = Platform.getBundle(pluginId); if (bundle == null) { return; } boolean found = false; ArrayList<String> availablePrefixes = ResourceLocator.getPathPrefix(targetIndex .getLocale()); for (int i = 0; i < availablePrefixes.size(); i++) { String prefix = availablePrefixes.get(i); IPath prefixedPath = new Path(prefix + path); // find index at this directory in plugin or fragments URL url = FileLocator.find(bundle, prefixedPath, null); if (url == null) { continue; } found = true; if (!isCompatible(bundle, prefixedPath)) { continue; } URL resolved; try { resolved = FileLocator.resolve(url); } catch (IOException ioe) { HelpBasePlugin.logError("Help index directory at " //$NON-NLS-1$ + prefixedPath + " for plugin " //$NON-NLS-1$ + bundle.getSymbolicName() + " cannot be resolved.", //$NON-NLS-1$ ioe); continue; } if ("file".equals(resolved.getProtocol())) { //$NON-NLS-1$ indexIDs.add(getIndexId(prefix)); resolvedPaths.add(resolved.getFile()); if (isComplete(bundle, prefixedPath)) { // don't process default language index break; } } else { try { // extract index from jarred bundles URL localURL = FileLocator.toFileURL(url); if ("file".equals(localURL.getProtocol())) { //$NON-NLS-1$ indexIDs.add(getIndexId(prefix)); resolvedPaths.add(localURL.getFile()); if (isComplete(bundle, prefixedPath)) { // don't process default language index break; } } } catch (IOException ioe) { HelpBasePlugin.logError( "Help index directory at " + prefixedPath //$NON-NLS-1$ + " for plugin " + bundle.getSymbolicName() //$NON-NLS-1$ + " cannot be resolved.", ioe); //$NON-NLS-1$ continue; } } } if (!found) { HelpBasePlugin.logError( "Help index declared, but missing for plugin " //$NON-NLS-1$ + getPluginId() + ".", null); //$NON-NLS-1$ } } public boolean isCompatible(Bundle bundle, IPath prefixedPath) { URL url = FileLocator.find(bundle, prefixedPath.append(SearchIndex.DEPENDENCIES_VERSION_FILENAME), null); if (url == null) { HelpBasePlugin.logError( prefixedPath.append(SearchIndex.DEPENDENCIES_VERSION_FILENAME) + " file missing from help index \"" //$NON-NLS-1$ + path + "\" of plugin " + getPluginId(), //$NON-NLS-1$ null); return false; } try (InputStream in = ProxyUtil.getStream(url)) { Properties prop = new Properties(); prop.load(in); String lucene = prop .getProperty(SearchIndex.DEPENDENCIES_KEY_LUCENE); String analyzer = prop .getProperty(SearchIndex.DEPENDENCIES_KEY_ANALYZER); if (!targetIndex.isLuceneCompatible(lucene) || !targetIndex.isAnalyzerCompatible(analyzer)) { String message = "Unable to consume Lucene index from bundle '" + bundle.toString() //$NON-NLS-1$ + "'. The index should be rebuilt with Lucene 6.1."; //$NON-NLS-1$ Status warningStatus = new Status(IStatus.WARNING, HelpBasePlugin.PLUGIN_ID, IStatus.OK, message, null); HelpBasePlugin.logStatus(warningStatus); return false; } } catch (MalformedURLException mue) { return false; } catch (IOException ioe) { HelpBasePlugin.logError( "IOException accessing prebuilt index.", ioe); //$NON-NLS-1$ } return true; } private boolean isComplete(Bundle bundle, IPath prefixedPath) { URL url = FileLocator.find(bundle, prefixedPath.append(COMPLETE_FILENAME), null); return url != null; } /** * Creates id of prebuilt index * * @param prefix * index directory prefix, e.g. "", "ws/gtk" * @return indexId string, e.g. "/", "/ws/gtk" */ private String getIndexId(String prefix) { if (prefix.length() == 0) { // root return "/"; //$NON-NLS-1$ } return "/" + prefix.substring(0, prefix.length() - 1); //$NON-NLS-1$ } @Override public boolean equals(Object obj) { if ( !(obj instanceof PluginIndex) ) { return false; } PluginIndex index = (PluginIndex) obj; return pluginId.equals(index.pluginId) && path.equals(index.path); } @Override public int hashCode() { return pluginId.hashCode() + path.hashCode(); } @Override public String toString() { StringBuffer ret = new StringBuffer(pluginId); ret.append(":"); //$NON-NLS-1$ ret.append(path); ret.append("="); //$NON-NLS-1$ if (indexIDs == null) { ret.append("unresolved"); //$NON-NLS-1$ } else { for (int i = 0; i < indexIDs.size(); i++) { ret.append(indexIDs.get(i)); ret.append("@"); //$NON-NLS-1$ ret.append(resolvedPaths.get(i)); } } return ret.toString(); } public List<String> getIDs() { resolve(); return indexIDs; } /** * @return list of paths (string) to an index directory. Paths are ordered * from */ public List<String> getPaths() { resolve(); return resolvedPaths; } public String getPluginId() { return pluginId; } }