/*******************************************************************************
gocha.org-lib-java Библеотека общего назначения
(с) Камнев Георгий Павлович 2009 GPLv2
Данная программа является свободным программным обеспечением. Вы вправе
распространять ее и/или модифицировать в соответствии с условиями версии 2
либо по вашему выбору с условиями более поздней версии
Стандартной Общественной Лицензии GNU, опубликованной Free Software Foundation.
Мы распространяем данную программу в надежде на то, что она будет вам полезной,
однако НЕ ПРЕДОСТАВЛЯЕМ НА НЕЕ НИКАКИХ ГАРАНТИЙ,
в том числе ГАРАНТИИ ТОВАРНОГО СОСТОЯНИЯ ПРИ ПРОДАЖЕ
и ПРИГОДНОСТИ ДЛЯ ИСПОЛЬЗОВАНИЯ В КОНКРЕТНЫХ ЦЕЛЯХ.
Для получения более подробной информации ознакомьтесь
со Стандартной Общественной Лицензией GNU.
Вместе с данной программой вы должны были получить экземпляр
Стандартной Общественной Лицензии GNU.
Если вы его не получили, сообщите об этом в Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*******************************************************************************/
package org.gocha.types;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Stack;
import org.gocha.collection.Convertor;
import org.gocha.collection.Iterators;
import org.gocha.collection.NodesExtracter;
import org.gocha.collection.Predicate;
import org.gocha.common.Reciver;
import org.gocha.text.regex.Pattern;
import org.gocha.text.regex.Regex;
/**
* Утилита по работе с типами
* @author gocha
*/
public class TypesUtil
{
/**
* Выполняет конструкция A <b>instanceOf</b> B
* @param cA Класс A
* @param cB Класс B
* @return true - удалетворяет конструкции, false - не удавлетворяет
*/
public static boolean AinstanceOfB(Class cA, Class cB)
{
if (cA == null) {
throw new IllegalArgumentException("cA == null");
}
if (cB == null) {
throw new IllegalArgumentException("cB == null");
}
return cB.isAssignableFrom(cA);
}
/**
* Предикат стравения <i>value</i> <b>instanceOf</b> <i>target</i>
* @param target Класс
* @return Предикат
*/
public static Predicate<Class> classInstanceOf(Class target)
{
final Class fTarget = target;
return new Predicate<Class>() {
@Override
public boolean validate(Class value) {
if( fTarget==null )return value==null;
if( value==null )return false;
return AinstanceOfB(value,fTarget);
}
};
}
/**
* Предикат сравнения <i>value</i> <b>equals</b> ( <i>target</i> )
* @param target
* @return Предикат
*/
public static Predicate<Class> classEquals(Class target)
{
final Class fTarget = target;
return new Predicate<Class>() {
@Override
public boolean validate(Class value) {
if( fTarget==null )return value==null;
return value==null ? false : fTarget.equals(value);
}
};
}
/**
* Предикат - возвращает true, если метода возвращает указанный тип
* @param type Возвращаемый тип
* @return Предикат
*/
public static Predicate<Method> returns(Class type)
{
if (type == null) {
throw new IllegalArgumentException("type == null");
}
final Class tip = type;
return new Predicate<Method>()
{
@Override
public boolean validate(Method value)
{
Class ret = value.getReturnType();
// return ret.equals(tip);
return AinstanceOfB(ret, tip);
}
};
}
/**
* Предикат - возвращает true, если название метода начинается с указанного текста
* @param text Текст
* @return Предикат
*/
public static Predicate<Method> nameStart(String text)
{
if (text == null) {
throw new IllegalArgumentException("text == null");
}
final String txt = text;
return new Predicate<Method>() {
@Override
public boolean validate(Method value) {
return value.getName().startsWith(txt);
}
};
}
/**
* Предикат , возвращает true если метод имеет указаную аннатацию
* @param annClass Аннатация
* @return Предикат
*/
public static Predicate<Method> hasAnnotation(Class annClass)
{
if (annClass == null) {
throw new IllegalArgumentException("annClass == null");
}
final Class ann = annClass;
return new Predicate<Method>() {
@Override
public boolean validate(Method value)
{
Object a = value.getAnnotation(ann);
return a!=null;
}
};
}
/**
* Предикат: Сверяет на возможность вызова метода с указанными аргументами
* @param args Параметры
* @return Предикат
*/
public static Predicate<Method> callableArguments(Object[] args)
{
if (args == null) {
throw new IllegalArgumentException("args == null");
}
final Object[] fa = args;
return new Predicate<Method>() {
@Override
public boolean validate(Method value)
{
Class[] types = value.getParameterTypes();
return isCallableArguments(types, fa);
}
};
}
/**
* Сверяет на возможность вызова метода с указанными аргументами
* @param types Типы принимаемых параметорв
* @param args Параметры
* @return true - вызвать возможно, false - не возможно вызвать
*/
public static boolean isCallableArguments(Class[] types,Object[] args)
{
if (types == null) {
throw new IllegalArgumentException("types == null");
}
if (args == null) {
throw new IllegalArgumentException("args == null");
}
if (types.length != args.length) {
return false;
}
boolean callable = true;
for (int paramIdx = 0; paramIdx < types.length; paramIdx++) {
if (args[paramIdx] == null) {
continue;
}
Class cArg = args[paramIdx].getClass();
Class cPrm = types[paramIdx];
boolean eq = AinstanceOfB( cPrm, cArg );// cArg.equals(cPrm);
if (!eq)
{
callable = false;
break;
}
}
return callable;
}
public static Iterable<Method> methodsOf(Object src,Predicate<Method> predicate)
{
if (src == null) {
throw new IllegalArgumentException("src == null");
}
if (predicate == null) {
throw new IllegalArgumentException("predicate == null");
}
Class c = src.getClass();
return Iterators.<Method>predicate(Iterators.<Method>array(c.getMethods()), predicate);
}
/**
* Возвращает публичные методы объекта
* @param obj объект
* @return Перечисление
*/
public static Iterable<Method> methodsOf( Object obj )
{
if (obj == null) {
throw new IllegalArgumentException("obj == null");
}
return Iterators.<Method>array(obj.getClass().getMethods());
}
/**
* Возвращает публичные методы класса
* @param cls Класс
* @return Перечисление методов
*/
public static Iterable<Method> methodsOf( Class cls )
{
if (cls == null) {
throw new IllegalArgumentException("cls == null");
}
return Iterators.<Method>array(cls.getMethods());
}
/**
* Возвращает публичные поля класса
* @param cls Класс
* @return Перечисление полей
*/
public static Iterable<Field> fieldsOf( Class cls )
{
if (cls == null) {
throw new IllegalArgumentException("cls == null");
}
return Iterators.<Field>array(cls.getFields());
}
/**
* Возвращает объевленные методы только в этом классе данного объекта
* @param obj Объект
* @return Методы
*/
public static Iterable<Method> declaredMethodsOf( Object obj )
{
if (obj == null) {
throw new IllegalArgumentException("obj == null");
}
return Iterators.<Method>array(obj.getClass().getDeclaredMethods());
}
/**
* Возвращает публичные свойства объекта
* @param object Объект
* @return Свойства
*/
public static Iterable<ValueController> propertiesOf(Object object)
{
if (object == null) {
throw new IllegalArgumentException("object == null");
}
return PropertyController.buildControllers(object);
}
/**
* Копирует значения из текстовой карты
* @param map Текстовая карта (откуда копировать)
* @param valueControllers Значения (куда копировать)
* @return Кол-во скопированных значений
*/
public static int textMapToValueControllers(
Map map,
Iterable<ValueController> valueControllers)
{
return textMapToValueControllers(map, valueControllers, null, null);
}
/**
* Копирует значения в текстовую карту
* @param valueControllers Значения
* @param map Текстовая карта
* @return Кол-во скопированных значений
*/
public static int valueControllersToTextMap(
Iterable<ValueController> valueControllers,
Map map)
{
return valueControllersToTextMap(valueControllers, map, null, null);
}
/**
* Копирует текстовую карту (значения) в карту значений (свойств/полей)
* @param map Исходная карта - (текстовая)
* @param valueControllers Конечная карта - (значения)
* @param convertors Конвертор типов (текст/значение; может быть null)
* @param mapKeyConvertor Конвертор ключей текстовой карты (может быть null)
* @param valueNameConvertor Конвертор имен свойств (может быть null)
* @param errorReciver Прием сообщений ошибок (может быть null)
* @return Кол-во скопированных значений
*/
public static int textMapToValueControllers(
Map map,
Iterable<ValueController> valueControllers,
TypesConverters convertors,
Convertor<String,String> mapKeyConvertor,
Convertor<String,String> valueNameConvertor,
Reciver<Throwable> errorReciver)
{
if (valueControllers == null) {
throw new IllegalArgumentException("valueControllers == null");
}
if (map == null) {
throw new IllegalArgumentException("map == null");
}
if( convertors==null )convertors = DefaultTypesConvertors.instance();
int res = 0;
for( ValueController vc : valueControllers )
{
String vcName = vc.getName();
if( valueNameConvertor!=null )vcName = valueNameConvertor.convert(vcName);
if( vcName==null )continue;
Class vcClass = vc.getType();
ToValueConvertor c2v = convertors.toValueFor(vcClass);
if( c2v==null )continue;
try
{
if( mapKeyConvertor!=null ){
for( Object oMapKey : map.keySet() ){
if( oMapKey==null )continue;
String sMapKey = oMapKey.toString();
sMapKey = mapKeyConvertor.convert(sMapKey);
if( sMapKey==null )continue;
if( sMapKey.equals(vcName) ){
Object oval = map.get(oMapKey);
String sval = null;
if( oval!=null )sval = oval.toString();
if( sval!=null )
{
Object destValue = c2v.convertToValue(sval);
vc.setValue(destValue);
res++;
}
}
}
}else{
if( map.containsKey(vcName) )
{
Object oval = map.get(vcName);
String sval = null;
if( oval!=null )sval = oval.toString();
if( sval!=null )
{
Object destValue = c2v.convertToValue(sval);
vc.setValue(destValue);
res++;
}
}
}
}
catch(Throwable t)
{
if( errorReciver!=null ){
errorReciver.recive(t);
}else{
System.err.println(t.getMessage());
}
}
}
return res;
}
/**
* Копирует текстовую карту (значения) в карту значений (свойств/полей)
* @param map Исходная карта - (текстовая)
* @param valueControllers Конечная карта - (значения)
* @param convertors Конвертор типов (текст/значение; может быть null)
* @param errorReciver Прием сообщений ошибок (может быть null)
* @return Кол-во скопированных значений
*/
public static int textMapToValueControllers(
Map map,
Iterable<ValueController> valueControllers,
TypesConverters convertors,
Reciver<Throwable> errorReciver)
{
return textMapToValueControllers(map, valueControllers, convertors, null, null, errorReciver);
}
/**
* Копирует карту значений в текстовую карту
* @param valueControllers Исходная карта значений
* @param map Конечная текстовая карта
* @param convertors Конвертор типов (текст/значение; может быть null)
* @param mapKeyConvertor Конвертор ключей текстовой карты (может быть null)
* @param valueNameConvertor Конвертор имен свойств (может быть null)
* @param errorReciver Прием сообщений ошибок (может быть null)
* @return Кол-во скопированных значений
*/
public static int valueControllersToTextMap(
Iterable<ValueController> valueControllers,
Map map,
TypesConverters convertors,
Convertor<String,String> mapKeyConvertor,
Convertor<String,String> valueNameConvertor,
Reciver<Throwable> errorReciver
){
if (valueControllers == null) {
throw new IllegalArgumentException("valueControllers == null");
}
if (map == null) {
throw new IllegalArgumentException("map == null");
}
if( convertors==null )convertors = DefaultTypesConvertors.instance();
int count = 0;
for( ValueController vc : valueControllers )
{
String vcName = vc.getName();
if( valueNameConvertor!=null )vcName = valueNameConvertor.convert(vcName);
if( vcName==null )continue;
Class vcClass = vc.getType();
ToStringConverter c2s = convertors.toStringFrom(vcClass);
if( c2s==null )continue;
try
{
Object v = vc.getValue();
if( v==null )continue;
String sval = c2s.convertToString(v);
if( sval!=null )
{
String key = vc.getName();
if( mapKeyConvertor!=null )key = mapKeyConvertor.convert(key);
if( key==null )continue;
map.put(key, sval);
count++;
}
}
catch(Throwable t)
{
if( errorReciver!=null ){
errorReciver.recive(t);
}else{
System.err.println(t.getMessage());
}
}
}
return count;
}
/**
* Копирует карту значений в текстовую карту
* @param valueControllers Исходная карта значений
* @param map Конечная текстовая карта
* @param convertors Конвертор типов (текст/значение; может быть null)
* @param errorReciver Прием сообщений ошибок (может быть null)
* @return Кол-во скопированных значений
*/
public static int valueControllersToTextMap(
Iterable<ValueController> valueControllers,
Map map,
TypesConverters convertors,
Reciver<Throwable> errorReciver
){
return valueControllersToTextMap(valueControllers, map, convertors, null, null, errorReciver);
}
// <editor-fold defaultstate="collapsed" desc="valueControllerExpression">
/**
* Создает булево выражение проверки имени свойства.
* <p>
* <b>Синтаксис выражения</b><br/>
* Результат выражения - булева функция.
* Части выражения должны обязательно разделяться пробелами.
* <p>
* <b>Имя свойства</b><br/>
* Имя свойства сверяется с шаблоном (Wildcard).
* Шаблон может содержать следующие подстановочные символы: <b>?</b> - Любой символ (один раз),
* <b>*</b> - Любой символ от 0 и более раз (минимально возможное кол-во).
* <br/><br/>
* Пример: <br />
* Задан шаблон: def*ab?<br/>
* Ему будут соответствовать все свойства начинаюшиеся def и содержащие 3 последние буквы a, b и любую другую
* </p>
* @param exp Выражение
* @return Предикат проверки или null если выражение не правильно составлено.
*/
public static Predicate<ValueController> valueControllerExpression(String exp)
{
if (exp == null) {
throw new IllegalArgumentException("exp == null");
}
String[] toks = exp.split("\\s+");
Stack<Predicate<ValueController>> stack = new Stack<Predicate<ValueController>>();
Stack<Integer> stackOp = new Stack<Integer>(); //0-or; 1-and; 2-not
int state = 0;
int pushPopSumm = 0;
for (String tok : toks) {
boolean isNot = tok.equalsIgnoreCase("not") || tok.equalsIgnoreCase("!");
boolean isOr = tok.equalsIgnoreCase("or") || tok.equalsIgnoreCase("|");
boolean isAnd = tok.equalsIgnoreCase("and") || tok.equalsIgnoreCase("&");
boolean isPush = tok.equals("(");
boolean isPop = tok.equals(")");
boolean isMask = !(isOr || isAnd || isPush || isPop || isNot);
if (isPush) {
pushPopSumm++;
}
if (isPop) {
pushPopSumm--;
}
if (pushPopSumm < 0) {
return null;
}
switch (state) {
case 0: //accpet:
if (isMask) {
stack.push(vcNameMaskPredicate(tok));
state = 1;
}
else if (isPush) {
state = 0;
}
else if (isNot) {
stackOp.push(2);
state = 2;
}
else {
return null;
}
break;
case 1:
if (isOr || isAnd) {
Integer opCode = isOr ? 0 : (isAnd ? 1 : -1);
stackOp.push(opCode);
state = 2;
}
else if (isPop) {
if (!VCEvalOperators(stack, stackOp)) {
return null;
}
state = 1;
}
else {
return null;
}
break;
case 2:
if (isMask) {
stack.push(vcNameMaskPredicate(tok));
if (!VCEvalOperators(stack, stackOp)) {
return null;
}
state = 1;
}
else if (isPush) {
state = 0;
}
else if (isNot) {
stackOp.push(2);
state = 2;
}
else {
return null;
}
break;
}
}
if (!stack.empty() && stack.size() == 1 && stackOp.empty()) {
return stack.pop();
}
return null;
}
private static boolean VCEvalOperators(Stack<Predicate<ValueController>> stack, Stack<Integer> stackOp)
{
if (stackOp.empty()) {
return false;
}
int opCode = stackOp.pop();
if (opCode == 0 || opCode == 1) {
if (stack.size() < 2) {
return false;
}
Predicate<ValueController> pb = stack.pop();
Predicate<ValueController> pa = stack.pop();
switch (opCode) {
case 0:
stack.add(VCOROperator(pa, pb));
break;
case 1:
stack.add(VCANDOpeartor(pa, pb));
break;
}
return true;
}
if (opCode == 2) {
if (stack.size() < 1) {
return false;
}
Predicate<ValueController> s = stack.pop();
stack.add(VCNOTOperator(s));
return true;
}
return false;
}
private static Predicate<ValueController> VCNOTOperator(Predicate<ValueController> sourcePredicate)
{
VCNotOperator n = new VCNotOperator();
n.sourcePredicate = sourcePredicate;
return n;
}
private static Predicate<ValueController> VCOROperator(Predicate<ValueController>... predicates)
{
VCBinaryOpertator bOp = new VCBinaryOpertator();
bOp.vals = predicates;
bOp.opCode = 0;
return bOp;
}
private static Predicate<ValueController> VCANDOpeartor(Predicate<ValueController>... predicates)
{
VCBinaryOpertator bOp = new VCBinaryOpertator();
bOp.vals = predicates;
bOp.opCode = 1;
return bOp;
}
private static class VCPropertyNameWildcardOperator implements Predicate<ValueController>
{
public String mask = "";
@Override
public boolean validate(ValueController value)
{
Pattern ptrn = Regex.parseWildcard(mask, true, '?', '*', '\\');
String name = value.getName();
return ptrn.match(name, 0).isMatched();
}
@Override
public String toString()
{
return mask;
}
}
private static class VCNotOperator implements Predicate<ValueController>
{
public Predicate<ValueController> sourcePredicate = null;
@Override
public boolean validate(ValueController value)
{
return !sourcePredicate.validate(value);
}
}
private static Predicate<ValueController> vcNameMaskPredicate(String mask)
{
VCPropertyNameWildcardOperator uop = new VCPropertyNameWildcardOperator();
uop.mask = mask;
return uop;
}
private static class VCBinaryOpertator implements Predicate<ValueController>
{
public Predicate<ValueController>[] vals = null;
public int opCode = -1; // 0 - OR; 1- AND
@Override
public boolean validate(ValueController value)
{
switch (opCode) {
case 0:
for (Predicate<ValueController> p : vals) {
if (p.validate(value)) {
return true;
}
}
return false;
case 1:
for (Predicate<ValueController> p : vals) {
if (!p.validate(value)) {
return false;
}
}
return true;
default:
throw new Error("unknow op");
}
}
@Override
public String toString()
{
String r = "";
switch (opCode) {
case 0:
r += "or(";
break;
case 1:
r += "and(";
break;
}
int i = -1;
for (Object o : vals) {
i++;
if (i > 0) {
r += ",";
}
r += o.toString();
}
r += ")";
return r;
}
}
// </editor-fold>
private static NodesExtracter classMethodsExtracter = null;
/**
* Возвращает интерфейс доступа к методам класса
* @return интерфейс доступа к методам класса
*/
public static NodesExtracter classMethodsExtracter()
{
if( classMethodsExtracter!=null )return classMethodsExtracter;
classMethodsExtracter = new NodesExtracter() {
@Override
public Iterable extract(Object from)
{
if( from==null )return null;
if( !(from instanceof Class) )return null;
return methodsOf((Class)from);
}
};
return null;
}
/**
* Возвращает параметры/агруметы метода
* @param method Метод
* @return Пераметры
*/
public static Iterable<Class> paramtersOf(Method method){
if (method == null) {
throw new IllegalArgumentException("method == null");
}
Class[] params = method.getParameterTypes();
return Iterators.<Class>array(params);
}
private static NodesExtracter methodParametersExtracter = null;
/**
* Возвращает интерфейс доступа к типам параметров метода
* @return интерфейс доступа к типам параметров метода
*/
public static NodesExtracter methodParametersExtracter()
{
if( methodParametersExtracter!=null )return methodParametersExtracter;
methodParametersExtracter = new NodesExtracter() {
@Override
public Iterable extract(Object from)
{
if( from==null )return null;
if( !(from instanceof Method) ) {
return null;
}
return paramtersOf((Method)from);
}
};
return null;
}
public static final Class[] emptyParametersArray = new Class[]{};
/**
* Возвращает предикат проверки метода без параметров
* @return Предикат
*/
public static Predicate<Method> hasEmptyParameters()
{
return hasParameters(emptyParametersArray);
}
/**
* Возвращает предикат строгой проверкти типов аргументов метода
* @param params Типы аргметов метода
* @return Предикат
*/
public static Predicate<Method> hasParameters(Class ... params)
{
if (params == null) {
throw new IllegalArgumentException("params == null");
}
final Class[] _p = params;
return new Predicate<Method>() {
@Override
public boolean validate(Method value) {
Class[] p = value.getParameterTypes();
if( p.length!=_p.length )return false;
for( int i=0; i<p.length; i++ )
{
if( !p[i].equals(_p[i]) )return false;
}
return true;
}
};
}
}