package org.jsondoc.core.scanner; import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import org.jsondoc.core.annotation.Api; import org.jsondoc.core.annotation.flow.ApiFlow; import org.jsondoc.core.pojo.ApiDoc; import org.jsondoc.core.pojo.ApiMethodDoc; import org.jsondoc.core.pojo.ApiObjectDoc; import org.jsondoc.core.pojo.JSONDoc; import org.jsondoc.core.pojo.JSONDoc.MethodDisplay; import org.jsondoc.core.pojo.JSONDocTemplate; import org.jsondoc.core.pojo.flow.ApiFlowDoc; import org.jsondoc.core.pojo.global.ApiGlobalDoc; import org.jsondoc.core.scanner.builder.JSONDocApiAuthDocBuilder; import org.jsondoc.core.scanner.builder.JSONDocApiErrorDocBuilder; import org.jsondoc.core.scanner.builder.JSONDocApiGlobalDocBuilder; import org.jsondoc.core.scanner.builder.JSONDocApiVersionDocBuilder; import org.jsondoc.core.scanner.validator.JSONDocApiMethodDocValidator; import org.jsondoc.core.scanner.validator.JSONDocApiObjectDocValidator; import org.jsondoc.core.util.JSONDocTemplateBuilder; import org.reflections.Reflections; import org.reflections.scanners.MethodAnnotationsScanner; import org.reflections.util.ClasspathHelper; import org.reflections.util.ConfigurationBuilder; import org.reflections.util.FilterBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public abstract class AbstractJSONDocScanner implements JSONDocScanner { protected Reflections reflections = null; protected static Logger log = LoggerFactory.getLogger(JSONDocScanner.class); public abstract Set<Class<?>> jsondocControllers(); public abstract Set<Method> jsondocMethods(Class<?> controller); public abstract Set<Class<?>> jsondocObjects(List<String> packages); public abstract Set<Class<?>> jsondocFlows(); public abstract Set<Class<?>> jsondocGlobal(); public abstract Set<Class<?>> jsondocChangelogs(); public abstract Set<Class<?>> jsondocMigrations(); public abstract ApiDoc initApiDoc(Class<?> controller); public abstract ApiDoc mergeApiDoc(Class<?> controller, ApiDoc apiDoc); public abstract ApiMethodDoc initApiMethodDoc(Method method, Map<Class<?>, JSONDocTemplate> jsondocTemplates); public abstract ApiMethodDoc mergeApiMethodDoc(Method method, ApiMethodDoc apiMethodDoc); public abstract ApiObjectDoc initApiObjectDoc(Class<?> clazz); public abstract ApiObjectDoc mergeApiObjectDoc(Class<?> clazz, ApiObjectDoc apiObjectDoc); protected List<ApiMethodDoc> allApiMethodDocs = new ArrayList<ApiMethodDoc>(); protected Set<Class<?>> jsondocControllers = new LinkedHashSet<Class<?>>(); protected Set<Method> jsondocMethods = new LinkedHashSet<Method>(); protected Set<Class<?>> jsondocObjects = new LinkedHashSet<Class<?>>(); protected Map<Class<?>, JSONDocTemplate> jsondocTemplates = new HashMap<Class<?>, JSONDocTemplate>(); protected Set<Class<?>> jsondocFlows = new LinkedHashSet<Class<?>>(); protected Set<Class<?>> jsondocGlobal = new LinkedHashSet<Class<?>>(); protected Set<Class<?>> jsondocChangelogs = new LinkedHashSet<Class<?>>(); protected Set<Class<?>> jsondocMigrations = new LinkedHashSet<Class<?>>(); /** * Returns the main <code>ApiDoc</code>, containing <code>ApiMethodDoc</code> and <code>ApiObjectDoc</code> objects * @return An <code>ApiDoc</code> object */ public JSONDoc getJSONDoc(String version, String basePath, List<String> packages, boolean playgroundEnabled, MethodDisplay displayMethodAs) { Set<URL> urls = new HashSet<URL>(); FilterBuilder filter = new FilterBuilder(); log.debug("Found " + packages.size() + " package(s) to scan..."); for (String pkg : packages) { log.debug("Adding package to JSONDoc recursive scan: " + pkg); urls.addAll(ClasspathHelper.forPackage(pkg)); filter.includePackage(pkg); } reflections = new Reflections(new ConfigurationBuilder().filterInputsBy(filter).setUrls(urls).addScanners(new MethodAnnotationsScanner())); JSONDoc jsondocDoc = new JSONDoc(version, basePath); jsondocDoc.setPlaygroundEnabled(playgroundEnabled); jsondocDoc.setDisplayMethodAs(displayMethodAs); jsondocControllers = jsondocControllers(); jsondocObjects = jsondocObjects(packages); jsondocFlows = jsondocFlows(); jsondocGlobal = jsondocGlobal(); jsondocChangelogs = jsondocChangelogs(); jsondocMigrations = jsondocMigrations(); for (Class<?> clazz : jsondocObjects) { jsondocTemplates.put(clazz, JSONDocTemplateBuilder.build(clazz, jsondocObjects)); } jsondocDoc.setApis(getApiDocsMap(jsondocControllers, displayMethodAs)); jsondocDoc.setObjects(getApiObjectsMap(jsondocObjects)); jsondocDoc.setFlows(getApiFlowDocsMap(jsondocFlows, allApiMethodDocs)); jsondocDoc.setGlobal(getApiGlobalDoc(jsondocGlobal, jsondocChangelogs, jsondocMigrations)); return jsondocDoc; } public ApiGlobalDoc getApiGlobalDoc(Set<Class<?>> global, Set<Class<?>> changelogs, Set<Class<?>> migrations) { return JSONDocApiGlobalDocBuilder.build(global, changelogs, migrations); } /** * Gets the API documentation for the set of classes passed as argument */ public Set<ApiDoc> getApiDocs(Set<Class<?>> classes, MethodDisplay displayMethodAs) { Set<ApiDoc> apiDocs = new TreeSet<ApiDoc>(); for (Class<?> controller : classes) { ApiDoc apiDoc = getApiDoc(controller, displayMethodAs); apiDocs.add(apiDoc); } return apiDocs; } /** * Gets the API documentation for a single class annotated with @Api and for its methods, annotated with @ApiMethod * @param controller * @return */ private ApiDoc getApiDoc(Class<?> controller, MethodDisplay displayMethodAs) { log.debug("Getting JSONDoc for class: " + controller.getName()); ApiDoc apiDoc = initApiDoc(controller); apiDoc.setSupportedversions(JSONDocApiVersionDocBuilder.build(controller)); apiDoc.setAuth(JSONDocApiAuthDocBuilder.getApiAuthDocForController(controller)); apiDoc.setMethods(getApiMethodDocs(controller, displayMethodAs)); if(controller.isAnnotationPresent(Api.class)) { apiDoc = mergeApiDoc(controller, apiDoc); } return apiDoc; } private Set<ApiMethodDoc> getApiMethodDocs(Class<?> controller, MethodDisplay displayMethodAs) { Set<ApiMethodDoc> apiMethodDocs = new TreeSet<ApiMethodDoc>(); Set<Method> methods = jsondocMethods(controller); for (Method method : methods) { ApiMethodDoc apiMethodDoc = getApiMethodDoc(method, controller, displayMethodAs); apiMethodDocs.add(apiMethodDoc); } jsondocMethods.addAll(methods); allApiMethodDocs.addAll(apiMethodDocs); return apiMethodDocs; } private ApiMethodDoc getApiMethodDoc(Method method, Class<?> controller, MethodDisplay displayMethodAs) { ApiMethodDoc apiMethodDoc = initApiMethodDoc(method, jsondocTemplates); apiMethodDoc.setDisplayMethodAs(displayMethodAs); apiMethodDoc.setApierrors(JSONDocApiErrorDocBuilder.build(method)); apiMethodDoc.setSupportedversions(JSONDocApiVersionDocBuilder.build(method)); apiMethodDoc.setAuth(JSONDocApiAuthDocBuilder.getApiAuthDocForMethod(method)); apiMethodDoc = mergeApiMethodDoc(method, apiMethodDoc); apiMethodDoc = JSONDocApiMethodDocValidator.validateApiMethodDoc(apiMethodDoc, displayMethodAs); return apiMethodDoc; } /** * Gets the API flow documentation for the set of classes passed as argument */ public Set<ApiFlowDoc> getApiFlowDocs(Set<Class<?>> classes, List<ApiMethodDoc> apiMethodDocs) { Set<ApiFlowDoc> apiFlowDocs = new TreeSet<ApiFlowDoc>(); for (Class<?> clazz : classes) { log.debug("Getting JSONDoc for class: " + clazz.getName()); Method[] methods = clazz.getMethods(); for (Method method : methods) { if(method.isAnnotationPresent(ApiFlow.class)) { ApiFlowDoc apiFlowDoc = getApiFlowDoc(method, apiMethodDocs); apiFlowDocs.add(apiFlowDoc); } } } return apiFlowDocs; } private ApiFlowDoc getApiFlowDoc(Method method, List<ApiMethodDoc> apiMethodDocs) { ApiFlowDoc apiFlowDoc = ApiFlowDoc.buildFromAnnotation(method.getAnnotation(ApiFlow.class), apiMethodDocs); return apiFlowDoc; } public Set<ApiObjectDoc> getApiObjectDocs(Set<Class<?>> classes) { Set<ApiObjectDoc> apiObjectDocs = new TreeSet<ApiObjectDoc>(); for (Class<?> clazz : classes) { log.debug("Getting JSONDoc for class: " + clazz.getName()); ApiObjectDoc apiObjectDoc = initApiObjectDoc(clazz); apiObjectDoc.setSupportedversions(JSONDocApiVersionDocBuilder.build(clazz)); apiObjectDoc = mergeApiObjectDoc(clazz, apiObjectDoc); if(apiObjectDoc.isShow()) { apiObjectDoc = JSONDocApiObjectDocValidator.validateApiObjectDoc(apiObjectDoc); apiObjectDocs.add(apiObjectDoc); } apiObjectDoc.setJsondocTemplate(jsondocTemplates.get(clazz)); } return apiObjectDocs; } public Map<String, Set<ApiDoc>> getApiDocsMap(Set<Class<?>> classes, MethodDisplay displayMethodAs) { Map<String, Set<ApiDoc>> apiDocsMap = new TreeMap<String, Set<ApiDoc>>(); Set<ApiDoc> apiDocSet = getApiDocs(classes, displayMethodAs); for (ApiDoc apiDoc : apiDocSet) { if(apiDocsMap.containsKey(apiDoc.getGroup())) { apiDocsMap.get(apiDoc.getGroup()).add(apiDoc); } else { Set<ApiDoc> groupedPojoDocs = new TreeSet<ApiDoc>(); groupedPojoDocs.add(apiDoc); apiDocsMap.put(apiDoc.getGroup(), groupedPojoDocs); } } return apiDocsMap; } public Map<String, Set<ApiObjectDoc>> getApiObjectsMap(Set<Class<?>> classes) { Map<String, Set<ApiObjectDoc>> objectsMap = new TreeMap<String, Set<ApiObjectDoc>>(); Set<ApiObjectDoc> apiObjectDocSet = getApiObjectDocs(classes); for (ApiObjectDoc apiObjectDoc : apiObjectDocSet) { if(objectsMap.containsKey(apiObjectDoc.getGroup())) { objectsMap.get(apiObjectDoc.getGroup()).add(apiObjectDoc); } else { Set<ApiObjectDoc> groupedPojoDocs = new TreeSet<ApiObjectDoc>(); groupedPojoDocs.add(apiObjectDoc); objectsMap.put(apiObjectDoc.getGroup(), groupedPojoDocs); } } return objectsMap; } public Map<String, Set<ApiFlowDoc>> getApiFlowDocsMap(Set<Class<?>> classes, List<ApiMethodDoc> apiMethodDocs) { Map<String, Set<ApiFlowDoc>> apiFlowDocsMap = new TreeMap<String, Set<ApiFlowDoc>>(); Set<ApiFlowDoc> apiFlowDocSet = getApiFlowDocs(classes, apiMethodDocs); for (ApiFlowDoc apiFlowDoc : apiFlowDocSet) { if(apiFlowDocsMap.containsKey(apiFlowDoc.getGroup())) { apiFlowDocsMap.get(apiFlowDoc.getGroup()).add(apiFlowDoc); } else { Set<ApiFlowDoc> groupedFlowDocs = new TreeSet<ApiFlowDoc>(); groupedFlowDocs.add(apiFlowDoc); apiFlowDocsMap.put(apiFlowDoc.getGroup(), groupedFlowDocs); } } return apiFlowDocsMap; } public static String[] enumConstantsToStringArray(Object[] enumConstants) { String[] sarr = new String[enumConstants.length]; for (int i = 0; i < enumConstants.length; i++) { sarr[i] = String.valueOf(enumConstants[i]); } return sarr; } }