/**
* This Source Code Form is subject to the terms of the Mozilla Public License,
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
* obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
* the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
*
* Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
* graphic logo is a trademark of OpenMRS Inc.
*/
package org.openmrs.module.webservices.rest.web;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.util.OpenmrsClassLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
/**
* Reflection utilities to search the classpath for classes
*/
public class OpenmrsClassScanner {
protected final Log log = LogFactory.getLog(getClass());
private static final OpenmrsClassScanner instance = new OpenmrsClassScanner();
private final MetadataReaderFactory metadataReaderFactory;
private final ResourcePatternResolver resourceResolver;
OpenmrsClassScanner() {
this.metadataReaderFactory = new SimpleMetadataReaderFactory(OpenmrsClassLoader.getInstance());
this.resourceResolver = new PathMatchingResourcePatternResolver(OpenmrsClassLoader.getInstance());
}
/**
* @return the instance
*/
public static OpenmrsClassScanner getInstance() {
return instance;
}
/**
* Searches for classes extending or implementing the given type.
*
* @param <T>
* @param type
* @param concrete true if only concrete classes should be returned
* @return the list of found classes
* @throws IOException
*/
public <T> List<Class<? extends T>> getClasses(Class<? extends T> type, boolean concrete) throws IOException {
List<Class<? extends T>> types = new ArrayList<Class<? extends T>>();
String pattern = "classpath*:org/openmrs/**/*.class";
Resource[] resources = resourceResolver.getResources(pattern);
TypeFilter typeFilter = new AssignableTypeFilter(type);
for (Resource resource : resources) {
try {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
if (typeFilter.match(metadataReader, metadataReaderFactory)) {
if (concrete == metadataReader.getClassMetadata().isConcrete()) {
String classname = metadataReader.getClassMetadata().getClassName();
try {
@SuppressWarnings("unchecked")
Class<? extends T> metadata = (Class<? extends T>) OpenmrsClassLoader.getInstance().loadClass(
classname);
types.add(metadata);
}
catch (ClassNotFoundException e) {
throw new IOException("Class cannot be loaded: " + classname, e);
}
}
}
}
catch (IOException e) {
log.debug("Resource cannot be loaded: " + resource);
}
}
return types;
}
}