/*
* Copyright (c) 2010 Red Hat, Inc.
*
* Licensed 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.ovirt.engine.api.common.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import org.ovirt.engine.api.common.resource.AbstractUpdatableResource;
import org.ovirt.engine.api.model.BaseResource;
public class ReflectionHelper {
private static final String GET_ROOT = "get";
private static final String SET_ROOT = "set";
private static final String IS_SET_ROOT = "isSet";
private ReflectionHelper() {}
public static <R extends BaseResource> R newModel(Class<R> clz) {
R ret = null;
try {
ret = clz.newInstance();
} catch (Exception e) {
}
return ret;
}
@SuppressWarnings("unchecked")
public static <R extends BaseResource> R newModel(AbstractUpdatableResource<R> resource) {
return newModel((Class<R>)((ParameterizedType)resource.getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
}
public static <R extends BaseResource> R assignChildModel(BaseResource parent, Class<R> childType) {
Method setter = getMethod(parent,
SET_ROOT + capitalize(childType.getSimpleName().toLowerCase()));
R child = newModel(childType);
try {
setter.invoke(parent, child);
} catch (Exception e) {
// InvocationTargetException etc. should never occur
// as this is a simple setter
}
return child;
}
public static String capitalize(String s) {
return Character.isLowerCase(s.charAt(0))
? s.substring(0, 1).toUpperCase() + s.substring(1)
: s;
}
public static boolean isSet(Object o, String name) {
if(o != null){
Method m = getMethod(o, IS_SET_ROOT + name);
Object ret = invoke(o, m);
return ret != null && ret instanceof Boolean && ((Boolean)ret).booleanValue();
}
return false;
}
public static boolean different(Object lhs, Object rhs, String name) {
Method lhsm = getMethod(lhs, GET_ROOT + name);
Method rhsm = getMethod(rhs, GET_ROOT + name);
Object lhsr = lhsm != null ? invoke(lhs, lhsm) : null;
Object rhsr = rhsm != null ? invoke(rhs, rhsm) : null;
return !(lhsr == null || lhsr.equals(rhsr));
}
public static Object invoke(Object o, Method m) {
Object ret = null;
try {
ret = m.invoke(o);
} catch (Exception e) {
// InvocationTargetException etc. should never occur
// as this is a simple getter
}
return ret;
}
public static boolean set(Object o, String field, String value) {
boolean success = false;
String name = SET_ROOT + capitalize(field);
for (Method m : o.getClass().getMethods()) {
if (m.getName().equals(name) && isPrimitive(m)) {
Object arg = isString(m)
? value
: isBoolean(m)
? Boolean.parseBoolean(value)
: isInteger(m)
? Integer.parseInt(value)
: null;
if (arg != null) {
try {
m.invoke(o, arg);
success = true;
} catch (Exception e) {
// InvocationTargetException etc. should never occur
// as this is a simple getter
}
}
break;
}
}
return success;
}
public static Object get(Object o, String field) {
Object ret = null;
String name = GET_ROOT + capitalize(field);
for (Method m : o.getClass().getMethods()) {
if (m.getName().equals(name)) {
try {
ret = m.invoke(o);
} catch (Exception e) {
// InvocationTargetException etc. should never occur
// as this is a simple getter
}
break;
}
}
return ret;
}
private static boolean isPrimitive(Method m) {
Class<?>[] params = m.getParameterTypes();
return params.length == 1
&& (String.class.equals(params[0])
|| Boolean.TYPE.equals(params[0])
|| Integer.TYPE.equals(params[0]));
}
private static boolean isString(Method m) {
return String.class.equals(m.getParameterTypes()[0]);
}
private static boolean isInteger(Method m) {
return Integer.TYPE.equals(m.getParameterTypes()[0]);
}
private static boolean isBoolean(Method m) {
return Boolean.TYPE.equals(m.getParameterTypes()[0]);
}
private static Method getMethod(Object o, String name) {
Method ret = null;
for (Method m : o.getClass().getMethods()) {
if (m.getName().equals(name)) {
ret = m;
break;
}
}
return ret;
}
/**
* Locate all directories in given package
*
* @param path
* @return Map<URL, File>
* @throws IOException
*/
public static List<URL> getDirectories(String path) throws IOException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
assert classLoader != null;
Enumeration<URL> resources = classLoader.getResources(path);
List<URL> dirs = new ArrayList<URL>();
while (resources.hasMoreElements()) {
dirs.add(resources.nextElement());
}
return dirs;
}
/**
* Locates all classes in given package
*
* @param packageName
* @return array of the classes
* @throws ClassNotFoundException
* @throws IOException
*/
public static List<Class<?>> getClasses(String packageName) throws ClassNotFoundException,
IOException {
String path = packageName.replace('.', '/');
List<URL> dirs = getDirectories(path);
ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
ClassLoader loader = URLClassLoader.newInstance(dirs.toArray(new URL[0]),
Thread.currentThread().getContextClassLoader());
for (URL directory : dirs) {
String resource = directory.getPath().replace("/"+path+"/", "");
if (resource.endsWith(".jar")) {
classes.addAll(getClassNamesInJarPackage(loader, resource, packageName));
} else {
classes.addAll(getClassNamesInPackage(new File(directory.getFile()), packageName));
}
}
return classes;
}
/**
* Locates all classes in given package
*
* @param directory
* @param packageName
* @return List of classes
* @throws ClassNotFoundException
*/
private static List<Class<?>> getClassNamesInPackage(File directory, String packageName)
throws ClassNotFoundException {
List<Class<?>> classes = new ArrayList<Class<?>>();
if (!directory.exists()) {
return classes;
}
File[] files = directory.listFiles();
for (File file : files) {
if (file.isDirectory()) {
assert !file.getName().contains(".");
classes.addAll(getClassNamesInPackage(file, packageName + "." + file.getName()));
} else if (file.getName().endsWith(".class")) {
classes.add(Class.forName(packageName + '.'
+ file.getName().substring(0, file.getName().length() - 6)));
}
}
return classes;
}
/**
* Locates all classes in given jar package
*
* @param jarName
* @param url
* @param packageName
* @return List of classes
* @throws MalformedURLException
*/
static List<Class<?>> getClassNamesInJarPackage(ClassLoader loader, String jarName, String packageName) throws MalformedURLException {
ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
packageName = packageName.replaceAll("\\.", "/");
JarInputStream jarFileInputStream = null;
try {
jarFileInputStream = new JarInputStream(new FileInputStream(jarName));
JarEntry jarEntry;
while (true) {
jarEntry = jarFileInputStream.getNextJarEntry();
if (jarEntry == null) break;
if ((jarEntry.getName().startsWith(packageName)) && (jarEntry.getName().endsWith(".class"))) {
classes.add(loader.loadClass(jarEntry.getName().replaceAll("/", "\\.").replace(".class", "")));
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(jarFileInputStream != null) {
jarFileInputStream.close();
}
} catch (IOException e) {
//ignore
}
}
return classes;
}
}