net.paoding.rose.scanning.RoseScanner Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2007-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.paoding.rose.scanning;
import java.io.File;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
/**
* @author zhiliang.wang 王志亮 [[email protected]]
*/
public class RoseScanner {
private static SoftReference softReference;
public synchronized static RoseScanner getInstance() {
if (softReference == null || softReference.get() == null) {
RoseScanner roseScanner = new RoseScanner();
softReference = new SoftReference(roseScanner);
}
return softReference.get();
}
// -------------------------------------------------------------
protected Log logger = LogFactory.getLog(getClass());
protected Date createTime = new Date();
protected ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
private List classesFolderResources;
private List jarResources;
// -------------------------------------------------------------
private RoseScanner() {
}
public Date getCreateTime() {
return createTime;
}
// -------------------------------------------------------------
public List getJarOrClassesFolderResources() throws IOException {
return getJarOrClassesFolderResources(null);
}
public List getJarOrClassesFolderResources(String[] scope) throws IOException {
if (logger.isInfoEnabled()) {
logger.info("[findFiles] start to found classes folders "
+ "or rosed jar files by scope:" + Arrays.toString(scope));
}
List resources;
if (scope == null) {
resources = new LinkedList();
if (logger.isDebugEnabled()) {
logger.debug("[findFiles] call 'classesFolder'");
}
resources.addAll(getClassesFolderResources());
//
if (logger.isDebugEnabled()) {
logger.debug("[findFiles] exits from 'classesFolder'");
logger.debug("[findFiles] call 'jarFile'");
}
resources.addAll(getJarResources());
if (logger.isDebugEnabled()) {
logger.debug("[findFiles] exits from 'jarFile'");
}
} else if (scope.length == 0) {
return new ArrayList();
} else {
resources = new LinkedList();
for (String scopeEntry : scope) {
String packagePath = scopeEntry.replace('.', '/');
Resource[] packageResources = resourcePatternResolver.getResources("classpath*:"
+ packagePath);
for (Resource pkgResource : packageResources) {
String uri = pkgResource.getURI().toString();
uri = StringUtils.removeEnd(uri, "/");
packagePath = StringUtils.removeEnd(packagePath, "/");
uri = StringUtils.removeEnd(uri, packagePath);
int beginIndex = uri.lastIndexOf("file:");
if (beginIndex == -1) {
beginIndex = 0;
} else {
beginIndex += "file:".length();
}
int endIndex = uri.lastIndexOf('!');
if (endIndex == -1) {
endIndex = uri.length();
}
String path = uri.substring(beginIndex, endIndex);
Resource folder = new FileSystemResource(path);
ResourceRef ref = ResourceRef.toResourceRef(folder);
if (!resources.contains(ref)) {
resources.add(ref);
if (logger.isDebugEnabled()) {
logger.debug("[findFiles] found classes folders "
+ "or rosed jar files by scope:" + ref);
}
}
}
}
}
//
if (logger.isInfoEnabled()) {
logger.info("[findFiles] found " + resources.size() + " classes folders "
+ "or rosed jar files : " + resources);
}
return resources;
}
/**
* 将要被扫描的普通类地址(比如WEB-INF/classes或target/classes之类的地址)
*
* @param resourceLoader
* @return
* @throws IOException
* @throws URISyntaxException
*/
public List getClassesFolderResources() throws IOException {
if (classesFolderResources == null) {
if (logger.isInfoEnabled()) {
logger.info("[classesFolder] start to found available classes folders ...");
}
List classesFolderResources = new ArrayList();
Enumeration founds = resourcePatternResolver.getClassLoader().getResources("");
while (founds.hasMoreElements()) {
URL urlObject = founds.nextElement();
if (!"file".equals(urlObject.getProtocol())) {
if (logger.isDebugEnabled()) {
logger.debug("[classesFolder] Ignored classes folder because "
+ "not a file protocol url: " + urlObject);
}
continue;
}
String path = urlObject.getPath();
Assert.isTrue(path.endsWith("/"));
if (!path.endsWith("/classes/") && !path.endsWith("/bin/")) {
if (logger.isInfoEnabled()) {
logger.info("[classesFolder] Ignored classes folder because "
+ "not ends with '/classes/' or '/bin/': " + urlObject);
}
continue;
}
File file;
try {
file = new File(urlObject.toURI());
} catch (URISyntaxException e) {
throw new IOException(e);
}
if (file.isFile()) {
if (logger.isDebugEnabled()) {
logger.debug("[classesFolder] Ignored because not a directory: "
+ urlObject);
}
continue;
}
Resource resource = new FileSystemResource(file);
ResourceRef resourceRef = ResourceRef.toResourceRef(resource);
if (classesFolderResources.contains(resourceRef)) {
// 删除重复的地址
if (logger.isDebugEnabled()) {
logger.debug("[classesFolder] remove replicated classes folder: "
+ resourceRef);
}
} else {
classesFolderResources.add(resourceRef);
if (logger.isDebugEnabled()) {
logger.debug("[classesFolder] add classes folder: " + resourceRef);
}
}
}
// 删除含有一个地址包含另外一个地址的
Collections.sort(classesFolderResources);
List toRemove = new LinkedList();
for (int i = 0; i < classesFolderResources.size(); i++) {
ResourceRef ref = classesFolderResources.get(i);
String refURI = ref.getResource().getURI().toString();
for (int j = i + 1; j < classesFolderResources.size(); j++) {
ResourceRef refj = classesFolderResources.get(j);
String refjURI = refj.getResource().getURI().toString();
if (refURI.startsWith(refjURI)) {
toRemove.add(refj);
if (logger.isInfoEnabled()) {
logger.info("[classesFolder] remove wrapper classes folder: " //
+ refj);
}
} else if (refjURI.startsWith(refURI) && refURI.length() != refjURI.length()) {
toRemove.add(ref);
if (logger.isInfoEnabled()) {
logger.info("[classesFolder] remove wrapper classes folder: " //
+ ref);
}
}
}
}
classesFolderResources.removeAll(toRemove);
//
this.classesFolderResources = new ArrayList(classesFolderResources);
if (logger.isInfoEnabled()) {
logger.info("[classesFolder] found " + classesFolderResources.size()
+ " classes folders: " + classesFolderResources);
}
} else {
if (logger.isInfoEnabled()) {
logger.info("[classesFolder] found cached " + classesFolderResources.size()
+ " classes folders: " + classesFolderResources);
}
}
return Collections.unmodifiableList(classesFolderResources);
}
/**
* 将要被扫描的jar资源
*
* @param resourceLoader
* @return
* @throws IOException
*/
public List getJarResources() throws IOException {
if (jarResources == null) {
if (logger.isInfoEnabled()) {
logger.info("[jarFile] start to found available jar files for rose to scanning...");
}
List jarResources = new LinkedList();
Resource[] metaInfResources = resourcePatternResolver
.getResources("classpath*:/META-INF/");
for (Resource metaInfResource : metaInfResources) {
URL urlObject = metaInfResource.getURL();
if (ResourceUtils.isJarURL(urlObject)) {
try {
String path = URLDecoder.decode(urlObject.getPath(), "UTF-8"); // fix 20%
if (path.startsWith("file:")) {
path = path.substring("file:".length(), path.lastIndexOf('!'));
} else {
path = path.substring(0, path.lastIndexOf('!'));
}
Resource resource = new FileSystemResource(path);
if (jarResources.contains(resource)) {
if (logger.isDebugEnabled()) {
logger.debug("[jarFile] skip replicated jar resource: " + path);// 在多个 linux环境 下发现有重复,fix it!
}
} else {
ResourceRef ref = ResourceRef.toResourceRef(resource);
if (ref.getModifiers() != null) {
jarResources.add(ref);
if (logger.isInfoEnabled()) {
logger.info("[jarFile] add jar resource: " + ref);
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("[jarFile] not rose jar resource: " + path);
}
}
}
} catch (Exception e) {
logger.error(urlObject, e);
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("[jarFile] not rose type(not a jar) " + urlObject);
}
}
}
this.jarResources = jarResources;
if (logger.isInfoEnabled()) {
logger.info("[jarFile] found " + jarResources.size() + " jar files: "
+ jarResources);
}
} else {
if (logger.isInfoEnabled()) {
logger.info("[jarFile] found cached " + jarResources.size() + " jar files: "
+ jarResources);
}
}
return Collections.unmodifiableList(jarResources);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy