All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.hyperledger.composer.bna.util.JavaParser Maven / Gradle / Ivy

/*
 * Copyright IBM Corp. 2017 All Rights Reserved.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

package org.hyperledger.composer.bna.util;

import org.hyperledger.composer.ComposerException;
import org.hyperledger.composer.annotation.DataField;
import org.hyperledger.composer.annotation.Pointer;
import org.hyperledger.composer.annotation.Query;
import org.hyperledger.composer.bna.model.*;
import org.hyperledger.composer.bna.part.CTOPart;
import org.hyperledger.composer.bna.part.QueryPart;
import org.hyperledger.composer.query.QueryBuilder;
import org.hyperledger.composer.query.SelectQuery;
import org.reflections.Reflections;
import org.reflections.scanners.FieldAnnotationsScanner;
import org.reflections.scanners.MethodAnnotationsScanner;
import org.reflections.scanners.SubTypesScanner;
import org.reflections.scanners.TypeAnnotationsScanner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;

public class JavaParser {
	protected static final Logger logger = LoggerFactory.getLogger(JavaParser.class);

	private Reflections reflections;

	protected JavaParser(Reflections reflections) {
		this.reflections = reflections;
	}

	public JavaParser(List sourceClassFiles) {
		this(sourceClassFiles, null);
	}

	public JavaParser(List sourceClassFiles, ClassLoader parent) {
		this(new Reflections(getClassloaderForReflections(sourceClassFiles, parent),
				new TypeAnnotationsScanner(), new FieldAnnotationsScanner(),
				new SubTypesScanner(), new MethodAnnotationsScanner()));
	}

	static URLClassLoader getClassloaderForReflections(List sourceClassFiles, ClassLoader parentClassLoader) {
		List sourceClassURLs = new LinkedList<>();
		Set loadedUrl = new HashSet<>();
		if (parentClassLoader instanceof URLClassLoader) {
			loadedUrl.addAll(Arrays.asList(((URLClassLoader) parentClassLoader).getURLs()));
		}
		for (File file : sourceClassFiles) {
			try {
				URL url = file.toURI().toURL();
				logger.info("find {}", url.toString());
				if (!loadedUrl.contains(url)) {
					sourceClassURLs.add(url);
					loadedUrl.add(url);
				}
			} catch (MalformedURLException e) {
				logger.warn("fail to get uri of {}: {}", file.getAbsolutePath(), e.getMessage());
			}
		}
		return new URLClassLoader(sourceClassURLs.toArray(new URL[sourceClassURLs.size()]), parentClassLoader);
	}

	protected QueryPart parseQueryModel() throws ComposerException {
		QueryPart manager = new QueryPart();
		for (Method m : getMethodsAnnotatedWith(Query.class)) {
			if (m.getParameterCount() != 1) {
				throw new ComposerException(ComposerException.INVALID_INPUT_ERROR, "expect 1 parameters for transaction processor:" + m);
			}

			Class selectQueryClass = m.getParameterTypes()[0];
			if (!SelectQuery.class.isAssignableFrom(selectQueryClass)) {
				throw new ComposerException(ComposerException.INVALID_INPUT_ERROR, "expect the 1nd parameter typeof SelectQuery for " + m);
			}

			if (!QueryBuilder.class.isAssignableFrom(m.getReturnType())) {
				throw new ComposerException(ComposerException.INVALID_INPUT_ERROR, "expect the return value typeof QueryBuilder for " + m);
			}

			FunctionModel model = new FunctionModel(m);
			logger.debug("Found QueryBuilderFunction {}", model);
			final Query query = m.getAnnotation(Query.class);
			final QueryBuilder builder;
			try {
				builder = (QueryBuilder) model.invoke(selectQueryClass.newInstance());
			} catch (Throwable e) {
				throw new ComposerException(ComposerException.INVALID_INPUT_ERROR, "fail to build query " + m + ":" + e.getMessage());
			}
			manager.addEntry(new QueryModel(query.description(), builder.build().getSQL()));
		}
		return manager;
	}

	protected Collection parseCTOModel() throws ComposerException {
		Map result = new HashMap<>();
		for (Class annotation : Model.MODEL_ANNOTATIONS) {
			for (Class c : getTypesAnnotatedWith(annotation)) {
				parseCTOModel(result, annotation, c);
			}
		}
		return result.values();
	}

	protected void parseCTOModel(Map result, Class annotation, Class c) throws ComposerException {
		String namespace = c.getPackage().getName();
		if ("org.hyperledger.composer.system".equals(namespace)) {
			return;
		}
		Model model = new Model(result.computeIfAbsent(namespace, CTOPart::new))
				.namespace(namespace).type(annotation).name(c.getSimpleName());

		Class superClass = c.getSuperclass();
		if (!Object.class.equals(superClass)) {
			if (!superClass.isAnnotationPresent(annotation)) {
				throw new ComposerException(ComposerException.INVALID_INPUT_ERROR,
						"parent of '" + c.getName() + "' is '" + superClass.getName() + "', not annotated with @" + annotation.getSimpleName());
			} else {
				model.parent(superClass.getPackage().getName(), superClass.getSimpleName());
			}
		}

		for (Field field : c.getDeclaredFields()) {
			FieldModel fieldModel = null;

			DataField dataField = field.getAnnotation(DataField.class);
			if (dataField != null) {
				fieldModel = new FieldModel(field, dataField.optional(), dataField.embedded(),
						dataField.regex(), dataField.range(), dataField.defaultValue(), dataField.genericType());
				model.addField(fieldModel, dataField.primary());
			}
			Pointer pointerField = field.getAnnotation(Pointer.class);
			if (pointerField != null) {
				fieldModel = new FieldModel(field, pointerField.optional(), false, null,
						null, null, pointerField.genericType());
				model.addField(fieldModel, false);
			}
			if (fieldModel == null) {
				continue;
			}

			if (fieldModel.isEnum()) {
				Class enumType = field.getType();
				new EnumModel(result.computeIfAbsent(enumType.getPackage().getName(), CTOPart::new), enumType);
			}
		}
	}

	protected Set getMethodsAnnotatedWith(Class annotation) {
		return reflections.getMethodsAnnotatedWith(annotation);
	}

	protected Set getTypesAnnotatedWith(Class... annotations) {
		Set result = new HashSet<>();
		for (Class annotation : annotations) {
			result.addAll(reflections.getTypesAnnotatedWith(annotation));
		}
		return result;
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy