/*
* This is a common dao with basic CRUD operations and is not limited to any
* persistent layer implementation
*
* Copyright (C) 2008 Imran M Yousuf (imyousuf@smartitengineering.com)
*
* 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 3 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 com.smartitengineering.exim;
import com.smartitengineering.util.simple.IOFactory;
import com.smartitengineering.util.simple.reflection.ClassInstanceVisitorImpl;
import com.smartitengineering.util.simple.reflection.ClassScanner;
import com.smartitengineering.util.simple.reflection.Config;
import com.smartitengineering.util.simple.reflection.VisitCallback;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
/**
* A central registrar for configuration scanners. It will register scanners
* according their priority first and then in lexical order by class name. And
* it will also iterate in the same order.
* @author imyousuf
* @since 0.4
*/
public final class ConfigRegistrar {
private static final Set<ConfigScannerRegistryItem<ClassConfigScanner>> CLASS_CONFIG_SCANNER =
Collections.synchronizedSortedSet(
new TreeSet<ConfigScannerRegistryItem<ClassConfigScanner>>());
private static final Set<ConfigScannerRegistryItem<PackageConfigScanner>> PACKAGE_CONFIG_SCANNER =
Collections.synchronizedSortedSet(
new TreeSet<ConfigScannerRegistryItem<PackageConfigScanner>>());
static Set<ConfigScannerRegistryItem<ClassConfigScanner>> getClassConfigScannerRegistryItems() {
return CLASS_CONFIG_SCANNER;
}
static Set<ConfigScannerRegistryItem<PackageConfigScanner>> getPackageConfigScannerRegistryItems() {
return PACKAGE_CONFIG_SCANNER;
}
/**
* The following static block loads the default config scanner impl classes,
* so that if they have any static initializers then they can invoked
*/
static {
String packageName =
ConfigRegistrar.class.getPackage().getName().concat(".impl");
ClassScanner scanner = IOFactory.getDefaultClassScanner();
scanner.scan(new String[] {packageName},
new ClassInstanceVisitorImpl(IOFactory.getClassNameForVisitor(
ClassConfigScanner.class), new VisitCallback<Config>() {
public void handle(Config config) {
try {
IOFactory.getClassFromVisitorName(config.getClassName());
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}));
scanner.scan(new String[] {packageName},
new ClassInstanceVisitorImpl(IOFactory.getClassNameForVisitor(
PackageConfigScanner.class), new VisitCallback<Config>() {
public void handle(Config config) {
try {
IOFactory.getClassFromVisitorName(config.getClassName());
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}));
}
private ConfigRegistrar() {
throw new AssertionError();
}
/**
* Register the class scanner with its priority
* @param classScannerClass Class scanner
* @param priority Priority of the scanner
* @throws IllegalArgumentException If class scanner is null
*/
public static void registerClassScanner(
final Class<? extends ClassConfigScanner> classScannerClass,
int priority) {
CLASS_CONFIG_SCANNER.add(new ConfigScannerRegistryItem<ClassConfigScanner>(
classScannerClass, priority));
}
/**
* Register the package scanner with its priority
* @param packageScannerClass Package scanner
* @param priority Priority of the scanner
* @throws IllegalArgumentException If class scanner is null
*/
public static void registerPackageScanner(
final Class<? extends PackageConfigScanner> packageScannerClass,
int priority) {
PACKAGE_CONFIG_SCANNER.add(new ConfigScannerRegistryItem<PackageConfigScanner>(
packageScannerClass, priority));
}
/**
* Scans (if required) and return the configuration for the resource class
* @param resourceClass Resource class
* @return config for the resource class, null if not config found for the
* class.
*/
public static EximResourceConfig getConfigForClass(final Class resourceClass) {
for (ConfigScannerRegistryItem<ClassConfigScanner> scanner :
CLASS_CONFIG_SCANNER) {
EximResourceConfig config = scanner.getInstance().
getResourceConfigForClass(resourceClass);
if (config != null) {
return config;
}
}
return null;
}
/**
* Simply scan a package to gather all its configurations. This would be
* helpful if an only if the scanner caches the config result.
* @param resourcePackage Package to scan for resources
*/
public static void scanPackage(final Package resourcePackage) {
for (ConfigScannerRegistryItem<PackageConfigScanner> scanner :
PACKAGE_CONFIG_SCANNER) {
scanner.getInstance().scanPackageForResourceConfigs(resourcePackage);
}
}
/**
* Return all configurations from a package and in process if requried also
* initiate a scan process
* @param resourcePackage Package to scan
* @return All configurations from the resource package
*/
public static Collection<EximResourceConfig> getConfigForPackage(
final Package resourcePackage) {
Set<EximResourceConfig> configs = new HashSet<EximResourceConfig>();
for (ConfigScannerRegistryItem<PackageConfigScanner> scanner :
PACKAGE_CONFIG_SCANNER) {
PackageConfigScanner configScanner = scanner.getInstance();
configScanner.scanPackageForResourceConfigs(resourcePackage);
Collection<Class> configClasses = configScanner.
getConfiguredResourceClasses();
for (Class configClass : configClasses) {
if (resourcePackage.equals(configClass.getPackage())) {
configs.add(configScanner.getConfigurations().get(
configClass));
}
}
}
return configs;
}
public static class ConfigScannerRegistryItem<T extends ConfigScanner>
implements Comparable<ConfigScannerRegistryItem<T>> {
private Class<? extends T> configClass;
private int priority;
public ConfigScannerRegistryItem(Class<? extends T> configClass,
int priority) {
if (configClass == null) {
throw new IllegalArgumentException();
}
this.configClass = configClass;
this.priority = priority;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final ConfigScannerRegistryItem<T> other =
(ConfigScannerRegistryItem<T>) obj;
if (this.configClass != other.configClass &&
(this.configClass == null ||
!this.configClass.equals(other.configClass))) {
return false;
}
if (this.priority != other.priority) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 7;
hash =
71 * hash +
(this.configClass != null ? this.configClass.hashCode() : 0);
hash = 71 * hash + this.priority;
return hash;
}
public int compareTo(ConfigScannerRegistryItem<T> obj) {
if (obj == null) {
return 1;
}
Integer myPriority = Integer.valueOf(priority);
Integer otherPriority = Integer.valueOf(obj.priority);
int myComp = myPriority.compareTo(otherPriority);
if (myComp == 0) {
int classComp = configClass.getName().compareTo(obj.configClass.
getName());
return classComp;
}
else {
return myComp;
}
}
/**
* Returns the instance of the scanner.
* @return If static getInstance() method is implemented then it will
* invoke that first else will try to use no-args constructor.
* Null if both fails.
*/
public T getInstance() {
T instance = null;
try {
Method getInstanceMethod = configClass.getMethod("getInstance",
new Class[0]);
if (getInstanceMethod != null &&
Modifier.isStatic(getInstanceMethod.getModifiers())) {
instance = (T) getInstanceMethod.invoke(null, new Object[0]);
}
}
catch (NoSuchMethodException exception) {
}
catch (InvocationTargetException exception) {
}
catch (IllegalAccessException exception) {
}
catch (IllegalArgumentException exception) {
}
if (instance == null) {
try {
instance = configClass.newInstance();
}
catch (InstantiationException ex) {
}
catch (IllegalAccessException ex) {
}
catch (RuntimeException ex) {
}
}
return instance;
}
}
}