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

org.rapidpm.ddi.implresolver.ImplementingClassResolver Maven / Gradle / Ivy

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.rapidpm.ddi.implresolver;

import org.jetbrains.annotations.Nullable;
import org.rapidpm.ddi.DDIModelException;
import org.rapidpm.ddi.DI;
import org.rapidpm.ddi.ResponsibleFor;
import org.rapidpm.ddi.producer.ProducerLocator;
import org.rapidpm.proxybuilder.objectadapter.annotations.staticobjectadapter.IsStaticObjectAdapter;
import org.rapidpm.proxybuilder.staticgenerated.annotations.IsGeneratedProxy;
import org.rapidpm.proxybuilder.staticgenerated.annotations.IsMetricsProxy;

import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * one subtype - will return this class
 * n subtypes - will search for classresolver to decide what will be the right implementation
 * 

* no subtype - will return the interface itself, maybe on the fly implementations are available *

* Created by svenruppert on 23.07.15. */ //public class ImplementingClassResolver implements ClassResolver { public class ImplementingClassResolver { private final Map resolverCache = new ConcurrentHashMap<>(); public void clearCache() { resolverCache.clear(); } public Class resolve(Class interf) { if (!resolverCache.containsKey(interf)) { resolverCache.put(interf, resolveNewForClass(interf)); } return resolverCache.get(interf); // return resolveNewForClass(interf); } private Class resolveNewForClass(final Class interf) { if (interf.isInterface()) { final Set> subTypesOf = DI.getSubTypesOf(interf); //remove subtypes that are interfaces removeInterfacesFromSubTypes(subTypesOf); if (subTypesOf.isEmpty()) return interf; else if (subTypesOf.size() == 1) { final Class implClass = handleOneSubType(interf, subTypesOf.toArray()[0]); if (implClass != null) return implClass; } else { final Class clearedListOfResolvers = handleManySubTypes(interf, subTypesOf); if (clearedListOfResolvers != null) return clearedListOfResolvers; } } else { return interf; } throw new DDIModelException("this point should never been reached.. no decission possible for = " + interf); } private void removeInterfacesFromSubTypes(final Set> subTypesOf) { final Iterator> iteratorOfSubTypes = subTypesOf.iterator(); while (iteratorOfSubTypes.hasNext()) { final Class next = iteratorOfSubTypes.next(); if (next.isInterface() || next.isAnnotationPresent(IsStaticObjectAdapter.class) || next.isAnnotationPresent(IsMetricsProxy.class) || next.isAnnotationPresent(IsGeneratedProxy.class) ) iteratorOfSubTypes.remove(); } } @Nullable private Class handleOneSubType(final Class interf, final Object o) { final Class implClass = (Class) o; final Set> producersForInterface = new ProducerLocator().findProducersFor(interf); final Set> producersForImpl = new ProducerLocator().findProducersFor(implClass); //@formatter:off if (!producersForInterface.isEmpty() && !producersForImpl.isEmpty()) return interf; if (producersForInterface.isEmpty() && producersForImpl.isEmpty()) return implClass; if (producersForImpl.isEmpty()) return interf; if (producersForInterface.isEmpty()) return implClass; //@formatter:on return null; } @Nullable private Class handleManySubTypes(final Class interf, final Set> subTypesOf) { final Set> subTypesOfClassResolver = DI.getSubTypesOf(ClassResolver.class); final List clearedListOfResolvers = subTypesOfClassResolver .stream() .filter(aClassResolver -> aClassResolver.isAnnotationPresent(ResponsibleFor.class)) .filter(aClassResolver -> { final ResponsibleFor responsibleFor = aClassResolver.getAnnotation(ResponsibleFor.class); return interf.equals(responsibleFor.value()); }) .collect(Collectors.toList()); if (clearedListOfResolvers.size() == 1) { final Class classResolver = handleOneResolver(interf, clearedListOfResolvers); if (classResolver != null) return classResolver; } else if (clearedListOfResolvers.isEmpty()) { return handleNoResolvers(interf, subTypesOf); } else { return handleToManyResolvers(interf, clearedListOfResolvers); } return null; } @Nullable // private Class handleOneResolver(final Class interf, final List>> clearedListOfResolvers) { private Class handleOneResolver(final Class interf, final List clearedListOfResolvers) { final Class> resolver = clearedListOfResolvers.get(0); try { final ClassResolver classResolver = resolver.newInstance(); return classResolver.resolve(interf); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); throw new DDIModelException(interf + " -- " + e); } } private Class handleNoResolvers(final Class interf, final Set> subTypesOf) { final Set> producersForInterface = new ProducerLocator().findProducersFor(interf); if (producersForInterface.isEmpty()) { final StringBuilder stringBuilder = new StringBuilder("interface with multiple implementations and no ClassResolver= " + interf); final List implList = subTypesOf .stream() .map(c -> "impl. : " + c.getName()).collect(Collectors.toList()); stringBuilder.append(implList); throw new DDIModelException(stringBuilder.toString()); } if (producersForInterface.size() == 1) return interf; final StringBuilder stringBuilder = new StringBuilder("interface with multiple implementations and no ClassResolver and n Producers f the interface = " + interf); final List implList = subTypesOf.stream().map(c -> "impl. : " + c.getName()).collect(Collectors.toList()); final List prodList = producersForInterface.stream().map(c -> "producer. : " + c.getName()).collect(Collectors.toList()); stringBuilder.append(implList).append(prodList); throw new DDIModelException(stringBuilder.toString()); } private Class handleToManyResolvers(final Class interf, final List clearedListOfResolvers) { final String message = "interface with multiple implementations and more as 1 ClassResolver = " + interf + " ClassResolver: " + clearedListOfResolvers; throw new DDIModelException(message); } }