/*
* Copyright 2008-2009 the original author or authors.
*
* 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 net.hasor.core.container;
import net.hasor.core.AppContext;
import net.hasor.core.classcode.aop.AopClassConfig;
import net.hasor.core.classcode.aop.AopMatcher;
import net.hasor.core.info.AopBindInfoAdapter;
import net.hasor.core.utils.IOUtils;
import net.hasor.core.utils.StringUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* 负责根据Class或BindInfo创建BeanType。
* ** 不支持热部署,该类会造成类型无法被回收。
* @version : 2015年6月26日
* @author 赵永春(zyc@hasor.net)
*/
class ClassEngine {
private static ConcurrentHashMap<Class<?>, AopClassConfig> buildEngineMap = new ConcurrentHashMap<Class<?>, AopClassConfig>();
public static Class<?> buildType(Class<?> targetType, ClassLoader rootLosder, List<AopBindInfoAdapter> aopList,//
AppContext appContext) throws ClassNotFoundException, IOException {
if (!AopClassConfig.isSupport(targetType)) {
return targetType;
}
// .动态代理
Class<?> newType = targetType;
AopClassConfig engine = buildEngineMap.get(targetType);
if (engine == null) {
// .检查是否忽略Aop
boolean aopIgnoreClass = testAopIgnore(targetType, true);
boolean aopIgnorePackage = testAopIgnore(targetType.getPackage(), true);
if (aopIgnorePackage || aopIgnoreClass) {
aopList = Collections.EMPTY_LIST;
}
//
engine = new AopClassConfig(targetType, rootLosder);
for (AopBindInfoAdapter aop : aopList) {
if (!aop.getMatcherClass().matches(targetType)) {
continue;
}
AopMatcher aopMatcher = new ClassAopMatcher(aop.getMatcherMethod());
engine.addAopInterceptor(aopMatcher, aop);
}
engine = buildEngineMap.putIfAbsent(targetType, engine);
if (engine == null) {
engine = buildEngineMap.get(targetType);
}
String workMode = appContext.getEnvironment().getWorkMode();
if ("debug".equalsIgnoreCase(workMode) && engine.hasChange()) {
String fileName = engine.getClassName();
String cacheDir = appContext.getEnvironment().evalString("%HASOR_TEMP_PATH%/debug/aopclasses");
FileOutputStream fos = null;
try {
File outFile = new File(cacheDir, fileName + ".class");
outFile.getParentFile().mkdirs();
fos = new FileOutputStream(outFile, false);
byte[] buildBytes = engine.buildBytes();
fos.write(buildBytes);
fos.flush();
} finally {
IOUtils.closeQuietly(fos);
}
}
}
if (engine.hasChange()) {
newType = engine.toClass();
} else {
newType = engine.getSuperClass();
}
//
return newType;
}
//
private static boolean testAopIgnore(Class<?> targetType, boolean isRoot) {
AopIgnore aopIgnore = targetType.getAnnotation(AopIgnore.class);
if (aopIgnore != null) {
if (isRoot) {
return true;
} else if (aopIgnore.diffuse()) {
return true;
}
}
Class<?> superclass = targetType.getSuperclass();
if (superclass != null) {
return testAopIgnore(superclass, false);
}
return false;
}
private static boolean testAopIgnore(Package targetPackage, boolean isRoot) {
if (targetPackage == null) {
return false;
}
AopIgnore aopIgnore = targetPackage.getAnnotation(AopIgnore.class);
if (aopIgnore != null) {
if (isRoot) {
return true;
} else if (aopIgnore.diffuse()) {
return true;
}
}
//
String packageName = targetPackage.getName();
for (; ; ) {
if (packageName.indexOf('.') == -1) {
break;
}
packageName = substringBeforeLast(packageName, ".");
if (StringUtils.isBlank(packageName)) {
break;
}
Package supperPackage = Package.getPackage(packageName);
if (supperPackage == null) {
continue;
}
return testAopIgnore(supperPackage, false);
}
return false;
}
private static String substringBeforeLast(final String str, final String separator) {
if (StringUtils.isEmpty(str) || StringUtils.isEmpty(separator)) {
return str;
}
int pos = str.lastIndexOf(separator);
if (pos == StringUtils.INDEX_NOT_FOUND) {
return str;
}
return str.substring(0, pos);
}
}