blob: 5aed76a3513c199bffab7ee1a5d371a495afcfbd [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.lang.ref.WeakReference;
import java.net.URL;
import java.net.URLStreamHandler;
import java.util.ArrayList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This URLStreamHandlerFactory knows about all the plugins
* in use and thus can create the correct URLStreamHandler
* even if it comes from a plugin classpath.
* As the JVM allows only one instance of URLStreamHandlerFactory
* to be registered, this class implements a singleton pattern.
* @author Hiran Chaudhuri
*
*/
public class URLStreamHandlerFactory
implements java.net.URLStreamHandlerFactory {
protected static final Logger LOG = LoggerFactory
.getLogger(URLStreamHandlerFactory.class);
/** The singleton instance. */
private static URLStreamHandlerFactory instance;
/** Here we register all PluginRepositories.
* In this class we do not know why several instances of PluginRepository
* are kept, nor do we know how long they will be used. To prevent
* a memory leak, this class must not keep references to PluginRepository
* but use WeakReference which allows PluginRepository to still be
* garbage collected. The prize is we need to clean the list for
* outdated references which is done in the {@link #removeInvalidRefs()} method.
*/
private ArrayList<WeakReference<PluginRepository>> prs;
static {
instance = new URLStreamHandlerFactory();
URL.setURLStreamHandlerFactory(instance);
LOG.debug("Registered URLStreamHandlerFactory with the JVM.");
}
private URLStreamHandlerFactory() {
this.prs = new ArrayList<>();
}
/**
* Get the singleton instance of this class.
* @return a {@link org.apache.nutch.plugin.URLStreamHandlerFactory} instance
*/
public static URLStreamHandlerFactory getInstance() {
return instance;
}
/** Use this method once a new PluginRepository was created to register it.
*
* @param pr The PluginRepository to be registered.
*/
public void registerPluginRepository(PluginRepository pr) {
this.prs.add(new WeakReference<PluginRepository>(pr));
removeInvalidRefs();
}
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
LOG.debug("Creating URLStreamHandler for protocol: {}", protocol);
removeInvalidRefs();
// find the 'correct' PluginRepository. For now we simply take the first.
// then ask it to return the URLStreamHandler
for(WeakReference<PluginRepository> ref: this.prs) {
PluginRepository pr = ref.get();
if(pr != null) {
// found PluginRepository. Let's get the URLStreamHandler...
return pr.createURLStreamHandler(protocol);
}
}
return null;
}
/** Maintains the list of PluginRepositories by
* removing the references whose referents have been
* garbage collected meanwhile.
*/
private void removeInvalidRefs() {
ArrayList<WeakReference<PluginRepository>> copy = new ArrayList<>(this.prs);
for(WeakReference<PluginRepository> ref: copy) {
if(ref.get() == null) {
this.prs.remove(ref);
}
}
LOG.debug("Removed '{}' invalid references. '{}' remaining.", copy.size()-this.prs.size(), this.prs.size());
}
}