org.exist.plugin.PluginsManagerImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of exist-core Show documentation
Show all versions of exist-core Show documentation
eXist-db NoSQL Database Core
/*
* eXist-db Open Source Native XML Database
* Copyright (C) 2001 The eXist-db Authors
*
* [email protected]
* http://www.exist-db.org
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.exist.plugin;
import java.io.*;
import java.lang.invoke.LambdaMetafactory;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Function;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.exist.Database;
import org.exist.EXistException;
import org.exist.LifeCycle;
import org.exist.backup.BackupHandler;
import org.exist.backup.RestoreHandler;
import org.exist.collections.Collection;
import org.exist.collections.triggers.TriggerException;
import org.exist.config.*;
import org.exist.config.Configuration;
import org.exist.config.annotation.*;
import org.exist.security.Permission;
import org.exist.security.PermissionDeniedException;
import org.exist.storage.BrokerPool;
import org.exist.storage.BrokerPoolService;
import org.exist.storage.BrokerPoolServiceException;
import org.exist.storage.DBBroker;
import org.exist.storage.txn.Txn;
import org.exist.util.LockException;
import org.exist.util.serializer.SAXSerializer;
import org.exist.xmldb.XmldbURI;
import org.w3c.dom.Document;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;
import static java.lang.invoke.MethodType.methodType;
/**
* Plugins manager.
* It control search procedure, activation and de-actication (including runtime).
*
* @author Dmitriy Shabanov
*
* @deprecated Should no longer be used.
*/
@ConfigurationClass("plugin-manager")
@Deprecated
public class PluginsManagerImpl implements Configurable, BrokerPoolService, PluginsManager, LifeCycle {
private static final Logger LOG = LogManager.getLogger(PluginsManagerImpl.class);
private static final XmldbURI COLLETION_URI = XmldbURI.SYSTEM.append("plugins");
private static final XmldbURI CONFIG_FILE_URI = XmldbURI.create("config.xml");
@ConfigurationFieldAsAttribute("version")
private String version = "1.0";
@ConfigurationFieldAsElement("plugin")
private List runPlugins = new ArrayList<>();
private Map jacks = new HashMap<>();
private Configuration configuration = null;
private Collection collection;
private Database db;
@Override
public void prepare(final BrokerPool brokerPool) {
this.db = brokerPool;
}
@Override
public void startSystem(final DBBroker systemBroker, final Txn transaction) throws BrokerPoolServiceException {
try {
start(systemBroker, transaction);
} catch(final EXistException e) {
throw new BrokerPoolServiceException(e);
}
}
@Override
public void start(final DBBroker broker, final Txn transaction) throws EXistException {
boolean interrupted = false;
try {
try {
collection = broker.getCollection(COLLETION_URI);
if (collection == null) {
collection = broker.getOrCreateCollection(transaction, COLLETION_URI);
if (collection == null) {
return;
}
//if db corrupted it can lead to unrunnable issue
//throw new ConfigurationException("Collection '/db/system/plugins' can't be created.");
collection.setPermissions(broker, Permission.DEFAULT_SYSTEM_SECURITY_COLLECTION_PERM);
broker.saveCollection(transaction, collection);
}
} catch (final TriggerException | PermissionDeniedException | IOException | LockException e) {
LOG.warn("Loading PluginsManager configuration failed: {}", e.getMessage());
}
final Configuration _config_ = Configurator.parse(this, broker, collection, CONFIG_FILE_URI);
configuration = Configurator.configure(this, _config_);
//load plugins by META-INF/services/
try {
final MethodHandles.Lookup lookup = MethodHandles.lookup();
for (final Class extends Plug> pluginClazz : listServices(Plug.class)) {
try {
final MethodHandle methodHandle = lookup.findConstructor(pluginClazz, methodType(void.class, PluginsManager.class));
final Function ctor = (Function)
LambdaMetafactory.metafactory(
lookup, "apply", methodType(Function.class),
methodHandle.type().erase(), methodHandle, methodHandle.type()).getTarget().invokeExact();
final Plug plgn = ctor.apply(this);
jacks.put(pluginClazz.getName(), plgn);
} catch (final Throwable e) {
if (e instanceof InterruptedException) {
// NOTE: must set interrupted flag
interrupted = true;
}
LOG.error(e);
}
}
} catch (final Throwable e) {
LOG.error(e);
}
//UNDERSTAND: call save?
// try {
// configuration.save(broker);
// } catch (PermissionDeniedException e) {
// //LOG?
// }
for (final Plug jack : jacks.values()) {
jack.start(broker, transaction);
}
} finally {
if (interrupted) {
// NOTE: must set interrupted flag
Thread.currentThread().interrupt();
}
}
}
@Override
public void sync(final DBBroker broker) {
for (final Plug plugin : jacks.values()) {
try {
plugin.sync(broker);
} catch (final Throwable e) {
LOG.error(e);
}
}
}
@Override
@Deprecated
public void stop(final DBBroker broker) {
stopSystem(broker);
}
@Override
public void stopSystem(final DBBroker broker) {
for (final Plug plugin : jacks.values()) {
try {
plugin.stop(broker);
} catch (final Throwable e) {
LOG.error(e);
}
}
}
public String version() {
return version;
}
@Override
public Database getDatabase() {
return db; //TODO(AR) get rid of this, maybe expand the BrokerPoolService arch to replace PluginsManagerImpl etc
}
@SuppressWarnings("unchecked")
@Override
public void addPlugin(final String className) {
//check if already run
if (jacks.containsKey(className))
{return;}
try {
final Class extends Plug> pluginClazz = (Class extends Plug>) Class.forName(className);
final MethodHandles.Lookup lookup = MethodHandles.lookup();
final MethodHandle methodHandle = lookup.findConstructor(pluginClazz, methodType(void.class, PluginsManager.class));
final Function ctor = (Function)
LambdaMetafactory.metafactory(
lookup, "apply", methodType(Function.class),
methodHandle.type().erase(), methodHandle, methodHandle.type()).getTarget().invokeExact();
final Plug plgn = ctor.apply(this);
jacks.put(pluginClazz.getName(), plgn);
runPlugins.add(className);
//TODO: if (jack instanceof Startable) { ((Startable) jack).startUp(broker); }
} catch (final Throwable e) {
if (e instanceof InterruptedException) {
// NOTE: must set interrupted flag
Thread.currentThread().interrupt();
}
LOG.error(e);
}
}
/*
* Generate list of service implementations
*/
private Iterable> listServices(final Class ifc) throws Exception {
final ClassLoader ldr = Thread.currentThread().getContextClassLoader();
final Enumeration e = ldr.getResources("META-INF/services/" + ifc.getName());
final Set> services = new HashSet<>();
while (e.hasMoreElements()) {
final URL url = e.nextElement();
try (final InputStream is = url.openStream();
final BufferedReader r = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
String line;
while ((line = r.readLine()) != null) {
final int comment = line.indexOf('#');
if (comment >= 0) {
line = line.substring(0, comment);
}
final String name = line.trim();
if (name.length() == 0) {
continue;
}
final Class> clz = Class.forName(name, true, ldr);
final Class extends S> impl = clz.asSubclass(ifc);
services.add(impl);
}
}
}
return services;
}
@Override
public boolean isConfigured() {
return configuration != null;
}
@Override
public Configuration getConfiguration() {
return configuration;
}
@Override
public BackupHandler getBackupHandler(final Logger logger) {
return new BH(logger);
}
class BH implements BackupHandler {
Logger LOG;
BH(final Logger logger) {
LOG = logger;
}
@Override
public void backup(final Collection colection, final AttributesImpl attrs) {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof BackupHandler) {
try {
((BackupHandler) plugin).backup(colection, attrs);
} catch (final Exception e) {
LOG.error(e.getMessage(), e);
}
}
}
}
@Override
public void backup(final Collection colection, final SAXSerializer serializer) {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof BackupHandler) {
try {
((BackupHandler) plugin).backup(colection, serializer);
} catch (final Exception e) {
LOG.error(e.getMessage(), e);
}
}
}
}
@Override
public void backup(final Document document, final AttributesImpl attrs) {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof BackupHandler) {
try {
((BackupHandler) plugin).backup(document, attrs);
} catch (final Exception e) {
LOG.error(e.getMessage(), e);
}
}
}
}
@Override
public void backup(final Document document, final SAXSerializer serializer) {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof BackupHandler) {
try {
((BackupHandler) plugin).backup(document, serializer);
} catch (final Exception e) {
LOG.error(e.getMessage(), e);
}
}
}
}
}
private RestoreHandler rh = new RH();
@Override
public RestoreHandler getRestoreHandler() {
return rh;
}
class RH implements RestoreHandler {
@Override
public void setDocumentLocator(final Locator locator) {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof RestoreHandler) {
((RestoreHandler) plugin).setDocumentLocator(locator);
}
}
}
@Override
public void startDocument() throws SAXException {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof RestoreHandler) {
((RestoreHandler) plugin).startDocument();
}
}
}
@Override
public void endDocument() throws SAXException {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof RestoreHandler) {
((RestoreHandler) plugin).endDocument();
}
}
}
@Override
public void startPrefixMapping(final String prefix, final String uri) throws SAXException {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof RestoreHandler) {
((RestoreHandler) plugin).startPrefixMapping(prefix, uri);
}
}
}
@Override
public void endPrefixMapping(final String prefix) throws SAXException {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof RestoreHandler) {
((RestoreHandler) plugin).endPrefixMapping(prefix);
}
}
}
@Override
public void startElement(final String uri, final String localName, final String qName, final Attributes atts) throws SAXException {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof RestoreHandler) {
((RestoreHandler) plugin).startElement(uri, localName, qName, atts);
}
}
}
@Override
public void endElement(final String uri, final String localName, final String qName) throws SAXException {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof RestoreHandler) {
((RestoreHandler) plugin).endElement(uri, localName, qName);
}
}
}
@Override
public void characters(final char[] ch, final int start, final int length) throws SAXException {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof RestoreHandler) {
((RestoreHandler) plugin).characters(ch, start, length);
}
}
}
@Override
public void ignorableWhitespace(final char[] ch, final int start, final int length) throws SAXException {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof RestoreHandler) {
((RestoreHandler) plugin).ignorableWhitespace(ch, start, length);
}
}
}
@Override
public void processingInstruction(final String target, final String data) throws SAXException {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof RestoreHandler) {
((RestoreHandler) plugin).processingInstruction(target, data);
}
}
}
@Override
public void skippedEntity(final String name) throws SAXException {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof RestoreHandler) {
((RestoreHandler) plugin).skippedEntity(name);
}
}
}
@Override
public void startCollectionRestore(final Collection colection, final Attributes atts) {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof RestoreHandler) {
((RestoreHandler) plugin).startCollectionRestore(colection, atts);
}
}
}
@Override
public void endCollectionRestore(final Collection colection) {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof RestoreHandler) {
((RestoreHandler) plugin).endCollectionRestore(colection);
}
}
}
@Override
public void startDocumentRestore(final Document document, final Attributes atts) {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof RestoreHandler) {
((RestoreHandler) plugin).startDocumentRestore(document, atts);
}
}
}
@Override
public void endDocumentRestore(final Document document) {
for (final Plug plugin : jacks.values()) {
if (plugin instanceof RestoreHandler) {
((RestoreHandler) plugin).endDocumentRestore(document);
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy