blob: de6c0ba17a7b53764c32b51d069393c61c79d5b4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.nutch.plugin;
import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.hadoop.conf.Configuration;
/**
* The <code>PluginDescriptor</code> provide access to all meta information of a
* nutch-plugin, as well to the internationalizable resources and the plugin own
* classloader. There are meta information about <code>Plugin</code>,
* <code>ExtensionPoint</code> and <code>Extension</code>. To provide access to
* the meta data of a plugin via a descriptor allow a lazy loading mechanism.
*/
public class PluginDescriptor {
private String fPluginPath;
private String fPluginClass = Plugin.class.getName();
private String fPluginId;
private String fVersion;
private String fName;
private String fProviderName;
private HashMap<String, ResourceBundle> fMessages = new HashMap<>();
private ArrayList<ExtensionPoint> fExtensionPoints = new ArrayList<>();
private ArrayList<String> fDependencies = new ArrayList<>();
private ArrayList<URL> fExportedLibs = new ArrayList<>();
private ArrayList<URL> fNotExportedLibs = new ArrayList<>();
private ArrayList<Extension> fExtensions = new ArrayList<>();
private PluginClassLoader fClassLoader;
private static final Logger LOG = LoggerFactory
.getLogger(MethodHandles.lookup().lookupClass());
private Configuration fConf;
/**
* Constructor
*
* @param pId
* @param pVersion
* @param pName
* @param pProviderName
* @param pPluginclazz
* @param pPath
*/
public PluginDescriptor(String pId, String pVersion, String pName,
String pProviderName, String pPluginclazz, String pPath,
Configuration conf) {
setPath(pPath);
setPluginId(pId);
setVersion(pVersion);
setName(pName);
setProvidername(pProviderName);
if (pPluginclazz != null)
setPluginClass(pPluginclazz);
this.fConf = conf;
}
/**
* @param pPath
*/
private void setPath(String pPath) {
fPluginPath = pPath;
}
/**
* Returns the name of the plugin.
*
* @return String
*/
public String getName() {
return fName;
}
/**
* @param providerName
*/
private void setProvidername(String providerName) {
fProviderName = providerName;
}
/**
* @param name
*/
private void setName(String name) {
fName = name;
}
/**
* @param version
*/
private void setVersion(String version) {
fVersion = version;
}
/**
* Returns the fully qualified name of the class which implements the abstarct
* <code>Plugin</code> class.
*
* @return the name of this plug-in's runtime class or <code>null</code>.
*/
public String getPluginClass() {
return fPluginClass;
}
/**
* Returns the unique identifier of the plug-in or <code>null</code>.
*
* @return String
*/
public String getPluginId() {
return fPluginId;
}
/**
* Returns an array of extensions.
*
* @return Exception[]
*/
public Extension[] getExtensions() {
return fExtensions.toArray(new Extension[fExtensions.size()]);
}
/**
* Adds a extension.
*
* @param pExtension
*/
public void addExtension(Extension pExtension) {
fExtensions.add(pExtension);
}
/**
* Sets the pluginClass.
*
* @param pluginClass
* The pluginClass to set
*/
private void setPluginClass(String pluginClass) {
fPluginClass = pluginClass;
}
/**
* Sets the plugin Id.
*
* @param pluginId
* The pluginId to set
*/
private void setPluginId(String pluginId) {
fPluginId = pluginId;
}
/**
* Adds a extension point.
*
* @param extensionPoint
*/
public void addExtensionPoint(ExtensionPoint extensionPoint) {
fExtensionPoints.add(extensionPoint);
}
/**
* Returns a array of extension points.
*
* @return ExtensionPoint[]
*/
public ExtensionPoint[] getExtenstionPoints() {
return fExtensionPoints
.toArray(new ExtensionPoint[fExtensionPoints.size()]);
}
/**
* Returns a array of plugin ids.
*
* @return String[]
*/
public String[] getDependencies() {
return fDependencies.toArray(new String[fDependencies.size()]);
}
/**
* Adds a dependency
*
* @param pId
* id of the dependent plugin
*/
public void addDependency(String pId) {
fDependencies.add(pId);
}
/**
* Adds a exported library with a relative path to the plugin directory. We
* automatically escape characters that are illegal in URLs. It is recommended
* that code converts an abstract pathname into a URL by first converting it
* into a URI, via the toURI method, and then converting the URI into a URL
* via the URI.toURL method.
*
* @param pLibPath
*/
public void addExportedLibRelative(String pLibPath)
throws MalformedURLException {
URI uri = new File(getPluginPath() + File.separator + pLibPath).toURI();
URL url = uri.toURL();
fExportedLibs.add(url);
}
/**
* Returns the directory path of the plugin.
*
* @return String
*/
public String getPluginPath() {
return fPluginPath;
}
/**
* Returns a array exported librareis as URLs
*
* @return URL[]
*/
public URL[] getExportedLibUrls() {
return fExportedLibs.toArray(new URL[0]);
}
/**
* Adds a exported library with a relative path to the plugin directory. We
* automatically escape characters that are illegal in URLs. It is recommended
* that code converts an abstract pathname into a URL by first converting it
* into a URI, via the toURI method, and then converting the URI into a URL
* via the URI.toURL method.
*
* @param pLibPath
*/
public void addNotExportedLibRelative(String pLibPath)
throws MalformedURLException {
URI uri = new File(getPluginPath() + File.separator + pLibPath).toURI();
URL url = uri.toURL();
fNotExportedLibs.add(url);
}
/**
* Returns a array of libraries as URLs that are not exported by the plugin.
*
* @return URL[]
*/
public URL[] getNotExportedLibUrls() {
return fNotExportedLibs.toArray(new URL[fNotExportedLibs.size()]);
}
/**
* Returns a cached classloader for a plugin. Until classloader creation all
* needed libraries are collected. A classloader use as first the plugins own
* libraries and add then all exported libraries of dependend plugins.
*
* @return PluginClassLoader the classloader for the plugin
*/
public PluginClassLoader getClassLoader() {
if (fClassLoader != null)
return fClassLoader;
ArrayList<URL> arrayList = new ArrayList<>();
arrayList.addAll(fExportedLibs);
arrayList.addAll(fNotExportedLibs);
arrayList.addAll(getDependencyLibs());
File file = new File(getPluginPath());
try {
for (File file2 : file.listFiles()) {
if (file2.getAbsolutePath().endsWith("properties"))
arrayList.add(file2.getParentFile().toURI().toURL());
}
} catch (MalformedURLException e) {
LOG.debug(getPluginId() + " " + e.toString());
}
URL[] urls = arrayList.toArray(new URL[arrayList.size()]);
fClassLoader = new PluginClassLoader(urls,
PluginDescriptor.class.getClassLoader());
return fClassLoader;
}
/**
* @return Collection
*/
private ArrayList<URL> getDependencyLibs() {
ArrayList<URL> list = new ArrayList<>();
collectLibs(list, this);
return list;
}
/**
* @param pLibs
* @param pDescriptor
*/
private void collectLibs(ArrayList<URL> pLibs, PluginDescriptor pDescriptor) {
for (String id : pDescriptor.getDependencies()) {
PluginDescriptor descriptor = PluginRepository.get(fConf)
.getPluginDescriptor(id);
for (URL url : descriptor.getExportedLibUrls()) {
pLibs.add(url);
}
collectLibs(pLibs, descriptor);
}
}
/**
* Returns a I18N'd resource string. The resource bundles could be stored in
* root directory of a plugin in the well know i18n file name conventions.
*
* @param pKey
* @param pLocale
* @return String
* @throws IOException
*/
public String getResourceString(String pKey, Locale pLocale)
throws IOException {
if (fMessages.containsKey(pLocale.toString())) {
ResourceBundle bundle = fMessages.get(pLocale.toString());
try {
return bundle.getString(pKey);
} catch (MissingResourceException e) {
return '!' + pKey + '!';
}
}
try {
ResourceBundle res = ResourceBundle.getBundle("messages", pLocale,
getClassLoader());
return res.getString(pKey);
} catch (MissingResourceException x) {
return '!' + pKey + '!';
}
}
public String getProviderName() {
return fProviderName;
}
public String getVersion() {
return fVersion;
}
}