org.nico.aoc.aspect.AspectBuddy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of noaoc Show documentation
Show all versions of noaoc Show documentation
Provides aop and ioc capabilities
package org.nico.aoc.aspect;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.nico.aoc.ConfigKey;
import org.nico.aoc.aspect.AspectBuddy.ExecutionEntity.MethodWrapper;
import org.nico.aoc.book.Book;
import org.nico.aoc.book.Book.Relier;
import org.nico.aoc.book.shop.BookShop;
import org.nico.aoc.scan.entity.AspectDic;
import org.nico.aoc.scan.entity.AspectType;
import org.nico.aoc.throwable.DefinitionException;
import org.nico.aoc.util.reflect.FieldUtils;
import org.nico.util.string.StringUtils;
/**
* Execution expressions handle small tools.
*
* @author nico
* @version createTime:2018年3月7日 下午3:22:51
*/
public class AspectBuddy {
public static final String UNIFIED = "(.*)";
public static final String REGEX_FOR_UNIFIED = "[*]+";
/**
* Parser Expression from the aspect point
*
* @param value aspect point
* @return value
* @throws DefinitionException expression format error
*/
public static String parseExecution(String value) throws DefinitionException{
Matcher matcher = Pattern.compile(ConfigKey.REGIX_OF_PARSE_EXPRESSION).matcher(value);
matcher.find();
String result = matcher.group();
if(StringUtils.isNotBlank(result)){
return result;
}else{
throw new DefinitionException("expression format error");
}
}
/**
* Match Expressions
*
* @param expression expression
* @param clazz current book
* @throws DefinitionException
* @throws SecurityException
* @throws NoSuchMethodException
*/
public static List matchExecution(String value, String proxyType, Book book) throws DefinitionException, NoSuchMethodException, SecurityException{
if(value == null){
throw new NullPointerException("execution is null");
}
if(! value.startsWith(ConfigKey.KEY_OF_ASPECT_EXPRESSION)){
throw new DefinitionException("around must start with 'execution'");
}
List entities = new ArrayList();
String expression = parseExecution(value).replaceAll(REGEX_FOR_UNIFIED, UNIFIED);
if(proxyType.equalsIgnoreCase(AspectType.JDK_PROXY.toString())){
return handlerExpression(BookShop.getInstance().getBooks(), UNIFIED + expression + UNIFIED);
}
// Set books = new HashSet();
// books.add(book);
// if(aspect.type() == AspectType.JDK_PROXY){
// return handlerExpression(books, UNIFIED + value + UNIFIED);
// }
return entities;
}
/**
* Match the method in the execution in the books.
*
* @param books Be matched books
* @param expression execution
* @return List
*/
public static List handlerExpression(Set books, String expression){
if(books != null && books.size() > 0){
List entities = new ArrayList();
Class> clazz = null;
Method[] methods = null;
Method currentMethod = null;
for(Book book: books){
clazz = book.getClazz();
methods = clazz.getDeclaredMethods();
if(methods != null){
List accessMethods = new ArrayList();
for(int index = 0; index < methods.length; index ++){
currentMethod = methods[index];
if(currentMethod.toString().matches(expression)){
accessMethods.add(new MethodWrapper(currentMethod));
}
}
if(accessMethods.size() > 0){
entities.add(new ExecutionEntity(book, accessMethods));
}
}
}
return entities;
}else{
return null;
}
}
/**
* Handle base Aspect
*
* @param book Proxy book
* @param aspectMethod Proxy method
* @param value Execution
* @param aspectDic Aspect type
* @throws NoSuchMethodException can't found be proxyed method
* @throws SecurityException
* @throws DefinitionException "No matches about the point definition
*/
public static void handleAspect(Book book, Method aspectMethod, String proxyType, String value, AspectDic aspectDic) throws NoSuchMethodException, SecurityException, DefinitionException{
List executionEntities = AspectBuddy.matchExecution(value, proxyType, book);
if(executionEntities == null || executionEntities.size() == 0){
throw new DefinitionException("No matches about the point definition:" + value);
}
for(ExecutionEntity entity: executionEntities){
Class> target = entity.getBook().getClazz();
if(entity.getBook() != null){
Object obj = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getInterfaces(), new AspectHandlerImpl(book.getObject(), aspectMethod, entity.getMethodWrappers(), entity.getBook().getObject(), aspectDic));
entity.getBook().setObject(obj);
flushAspectObject2Reliers(entity.getBook().getReliers(), obj);
}
}
}
/**
* Reinjecting the newly - represented object into the dependent.
*
* @param reliers
* @param newObject
*/
public static void flushAspectObject2Reliers(Set reliers, Object newObject){
if(reliers != null && reliers.size()> 0){
Iterator relierItems = reliers.iterator();
while(relierItems.hasNext()){
Relier relier = relierItems.next();
Object target = relier.getBook().getObject();
if(target != null){
Class> clazz = target.getClass();
try {
Field field = FieldUtils.getField(relier.getFieldName(), clazz);
FieldUtils.set(field, target, clazz, newObject);
} catch (Exception e) {
}
}
}
}
}
/**
* Get target Object from proxy Object.
*
* @param proxyObject
* Proxy Object
* @return Target Object
*/
public static Object getTargetObject(Object proxyObject){
Object target = proxyObject;
/**
* JDK Proxy
*/
if(proxyObject instanceof Proxy){
InvocationHandler handler = Proxy.getInvocationHandler(proxyObject);
if(handler instanceof AspectHandlerInfo){
target = ((AspectHandlerInfo) handler).getBeProxyObject();
}
}
if(target instanceof Proxy){
return getTargetObject(target);
}
return target;
}
/**
* The method used to store the retrieved Book and the corresponding proxy.
* On the other hand, the clazz field is used to store the classes that
* need to be represented if the class that represents static classes or is
* not managed by the noaoc container.
*/
public static class ExecutionEntity{
private Book book;
private Class> clazz;
private List MethodWrappers;
public ExecutionEntity(Class> clazz,
List methodWrappers) {
super();
this.clazz = clazz;
MethodWrappers = methodWrappers;
}
public ExecutionEntity(Book book, List methodWrappers) {
super();
this.book = book;
MethodWrappers = methodWrappers;
}
public Book getBook() {
return book;
}
public void setBook(Book book) {
this.book = book;
}
public Class> getClazz() {
return clazz;
}
public void setClazz(Class> clazz) {
this.clazz = clazz;
}
public List getMethodWrappers() {
return MethodWrappers;
}
public void setMethodWrappers(List methodWrappers) {
MethodWrappers = methodWrappers;
}
public static class MethodWrapper{
private Method method;
public MethodWrapper(Method method) {
this.method = method;
}
@Override
public boolean equals(Object arg0) {
try{
MethodWrapper wrapper = (MethodWrapper) arg0;
if(wrapper.method.getName().equals(method.getName())){
Type[] types = wrapper.method.getGenericParameterTypes();
Type[] types1 = method.getGenericParameterTypes();
if(types == null && types1 == null){
return true;
}else if(types.length == types1.length){
boolean isSame = true;
for(int index = 0; index < types.length; index ++){
if(!types[index].toString().equals(types1[index].toString())){
isSame = false;
}
}
if(isSame){
return true;
}
}
}
}catch(Exception e){
}
return false;
}
@Override
public String toString() {
return method.toString();
}
}
}
}