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

org.jpmml.evaluator.ModelManagerFactory Maven / Gradle / Ivy

/*
 * Copyright (c) 2020 Villu Ruusmann
 *
 * This file is part of JPMML-Evaluator
 *
 * JPMML-Evaluator is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JPMML-Evaluator is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with JPMML-Evaluator.  If not, see .
 */
package org.jpmml.evaluator;

import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;

import org.dmg.pmml.Model;
import org.dmg.pmml.Output;
import org.dmg.pmml.PMML;
import org.dmg.pmml.ResultFeature;
import org.jpmml.evaluator.annotations.Functionality;
import org.jpmml.model.PMMLException;
import org.jpmml.model.UnsupportedElementException;
import org.jpmml.model.UnsupportedMarkupException;

abstract
public class ModelManagerFactory> extends ServiceFactory {

	protected ModelManagerFactory(){
	}

	protected ModelManagerFactory(Class serviceClazz){
		super(Model.class, serviceClazz);
	}

	public S newModelManager(PMML pmml, Model model){
		return newModelManager(pmml, model, null);
	}

	public S newModelManager(PMML pmml, Model model, Set extraResultFeatures){
		pmml = Objects.requireNonNull(pmml);
		model = Objects.requireNonNull(model);

		Output output = model.getOutput();

		Set resultFeatures = ModelManager.collectResultFeatures(output);

		if(extraResultFeatures != null && !extraResultFeatures.isEmpty()){
			resultFeatures.addAll(extraResultFeatures);
		}

		try {
			List> modelManagerClasses = getServiceProviderClasses(model.getClass());

			modelManagers:
			for(Class modelManagerClazz : modelManagerClasses){
				Functionality functionality = modelManagerClazz.getAnnotation(Functionality.class);

				if(functionality != null){
					Set providedResultFeatures = EnumSet.noneOf(ResultFeature.class);
					providedResultFeatures.addAll(Arrays.asList(functionality.value()));

					if(!providedResultFeatures.containsAll(resultFeatures)){
						continue modelManagers;
					}
				}

				Constructor constructor = findConstructor(modelManagerClazz);

				try {
					S modelManager = (S)constructor.newInstance(pmml, model);

					if(extraResultFeatures != null && !extraResultFeatures.isEmpty()){
						modelManager.addResultFeatures(extraResultFeatures);
					}

					return modelManager;
				} catch(InvocationTargetException ite){
					Throwable cause = ite.getCause();

					if(cause instanceof PMMLException){

						// Unsupported by this one, might be supported by next ones
						if(cause instanceof UnsupportedMarkupException){
							continue;
						}

						throw (PMMLException)cause;
					}

					throw ite;
				}
			}
		} catch(ReflectiveOperationException | IOException e){
			throw new IllegalArgumentException(e);
		} catch(PMMLException pe){
			throw pe;
		}

		throw new UnsupportedElementException(model);
	}

	static
	private Constructor findConstructor(Class serviceProviderClass) throws NoSuchMethodException {
		Constructor[] constructors = serviceProviderClass.getConstructors();

		for(Constructor constructor : constructors){
			Class[] parameterTypes = constructor.getParameterTypes();

			if(parameterTypes.length != 2){
				continue;
			}

			if((PMML.class).isAssignableFrom(parameterTypes[0]) && (Model.class).isAssignableFrom(parameterTypes[1])){
				return constructor;
			}
		}

		throw new NoSuchMethodException();
	}
}