/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.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.jnode.driver;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.List;
import javax.naming.NamingException;
import org.jnode.bootlog.BootLogInstance;
import org.jnode.naming.InitialNaming;
import org.jnode.plugin.ConfigurationElement;
import org.jnode.plugin.Extension;
import org.jnode.plugin.ExtensionPoint;
import org.jnode.plugin.ExtensionPointListener;
import org.jnode.plugin.PluginException;
import org.jnode.work.Work;
import org.jnode.work.WorkUtils;
/**
* Default device manager.
*
* @author epr
*/
public final class DefaultDeviceManager extends AbstractDeviceManager implements ExtensionPointListener {
/**
* finder extension-point
*/
private final ExtensionPoint findersEP;
/**
* mappers extension-point
*/
private final ExtensionPoint mappersEP;
/**
* Create a new instance
*
* @param findersEP
* @param mappersEP
*/
public DefaultDeviceManager(ExtensionPoint findersEP,
ExtensionPoint mappersEP) {
super();
if (findersEP == null) {
throw new IllegalArgumentException("finders extension-point cannot be null");
}
if (mappersEP == null) {
throw new IllegalArgumentException("mappers extension-point cannot be null");
}
this.findersEP = findersEP;
this.mappersEP = mappersEP;
findersEP.addListener(this);
mappersEP.addListener(this);
}
/**
* Start this manager
*
* @throws PluginException
*/
public void start() throws PluginException {
try {
InitialNaming.bind(NAME, this);
WorkUtils.add(new Work("Start device manager") {
public void execute() {
loadExtensions();
}
});
} catch (NamingException ex) {
throw new PluginException(ex);
}
}
/**
* @param point
* @param extension
*/
public final void extensionAdded(ExtensionPoint point, Extension extension) {
loadExtensions();
findDeviceDrivers();
}
/**
* @param point
* @param extension
*/
public final void extensionRemoved(ExtensionPoint point, Extension extension) {
loadExtensions();
}
/**
* Refresh the list of finders, based on the mappers extension-point.
*
* @param finders
*/
protected final void refreshFinders(List<DeviceFinder> finders) {
finders.clear();
final Extension[] extensions = findersEP.getExtensions();
BootLogInstance.get().debug("Found " + extensions.length + " device finders");
for (int i = 0; i < extensions.length; i++) {
final Extension ext = extensions[i];
final ConfigurationElement[] elements = ext
.getConfigurationElements();
for (int j = 0; j < elements.length; j++) {
configureFinder(finders, elements[j]);
}
}
}
/**
* Refresh the list of mappers, based on the mappers extension-point.
*
* @param mappers
*/
protected final void refreshMappers(List<DeviceToDriverMapper> mappers) {
mappers.clear();
final Extension[] extensions = mappersEP.getExtensions();
BootLogInstance.get().debug("Found " + extensions.length + " mapper extensions");
// First load all mappers
for (int i = 0; i < extensions.length; i++) {
final Extension ext = extensions[i];
final ConfigurationElement[] elements = ext
.getConfigurationElements();
for (int j = 0; j < elements.length; j++) {
configureMapper(mappers, elements[j]);
}
}
// Now sort them
Collections.sort(mappers, MapperComparator.INSTANCE);
}
/**
* Configure a finder for a single finder configuration element and add the
* new finder to the given list.
*
* @param finders
* @param element
*/
private void configureFinder(List<DeviceFinder> finders, ConfigurationElement element) {
final String elementName = element.getName();
if (!elementName.equals("finder")) {
BootLogInstance.get().warn("Ignoring unrecognised descriptor element: " + elementName);
return;
}
final String className = element.getAttribute("class");
if (className != null) {
try {
BootLogInstance.get().debug("Configuring finder: " + className);
final Class cls = Thread.currentThread().getContextClassLoader().loadClass(className);
final DeviceFinder finder = (DeviceFinder) cls.newInstance();
finders.add(finder);
} catch (ClassNotFoundException ex) {
BootLogInstance.get().error("Cannot find finder class " + className);
} catch (IllegalAccessException ex) {
BootLogInstance.get().error("Cannot access finder class " + className);
} catch (InstantiationException ex) {
BootLogInstance.get().error("Cannot instantiate finder class " + className);
} catch (ClassCastException ex) {
BootLogInstance.get()
.error("Finder class " + className + " does not implement the DeviceFinder interface");
}
}
}
/**
* Configure a mapper for a single mapper configuration element and add the
* new mapper to the given list.
*
* @param mappers
* @param element
*/
private void configureMapper(List<DeviceToDriverMapper> mappers, ConfigurationElement element) {
final String elementName = element.getName();
if (!elementName.equals("mapper")) {
BootLogInstance.get().warn("Ignoring unrecognised descriptor element: " + elementName);
return;
}
final String className = element.getAttribute("class");
if (className != null) {
try {
BootLogInstance.get().debug("Configuring mapper: " + className);
final Class cls = Thread.currentThread().getContextClassLoader().loadClass(className);
final DeviceToDriverMapper mapper = newMapperInstance(cls, element);
mappers.add(mapper);
} catch (ClassNotFoundException ex) {
BootLogInstance.get().error("Cannot find mapper class " + className, ex);
} catch (IllegalAccessException ex) {
BootLogInstance.get().error("Cannot access mapper class " + className, ex);
} catch (InstantiationException ex) {
BootLogInstance.get().error("Cannot instantiate mapper class " + className, ex);
} catch (ClassCastException ex) {
BootLogInstance.get()
.error("Mapper class " + className + " does not implement the DeviceToDriverMapper interface");
}
} else {
BootLogInstance.get().error("class attribute required in mapper");
}
}
/**
* Instantiate the device to driver mapper.
* First look for a constructor with a ConfigurationElement parameter,
* if not found, use the default constructor.
*
* @param cls
* @param element
* @return
* @throws InstantiationException
* @throws IllegalAccessException
*/
private DeviceToDriverMapper newMapperInstance(Class cls, ConfigurationElement element)
throws InstantiationException, IllegalAccessException {
try {
final Constructor c = cls.getConstructor(new Class[]{ConfigurationElement.class});
try {
return (DeviceToDriverMapper) c.newInstance(new Object[]{element});
} catch (InvocationTargetException ex1) {
final InstantiationException ie = new InstantiationException();
ie.initCause(ex1.getTargetException());
throw ie;
}
} catch (NoSuchMethodException ex) {
return (DeviceToDriverMapper) cls.newInstance();
}
}
}