ImplementationFinder.java
package fr.sii.ogham.testing.assertion.internal.helper;
import static org.apache.commons.lang3.reflect.FieldUtils.readField;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import fr.sii.ogham.core.message.Message;
import fr.sii.ogham.core.sender.ConditionalSender;
import fr.sii.ogham.core.sender.ContentTranslatorSender;
import fr.sii.ogham.core.sender.MessageSender;
import fr.sii.ogham.core.sender.MultiImplementationSender;
import fr.sii.ogham.core.sender.MultiImplementationSender.Implementation;
import fr.sii.ogham.core.service.CleanableMessagingService;
import fr.sii.ogham.core.service.EverySupportingMessagingService;
import fr.sii.ogham.core.service.MessagingService;
import fr.sii.ogham.core.service.WrapExceptionMessagingService;
import fr.sii.ogham.core.template.parser.AutoDetectTemplateParser;
import fr.sii.ogham.core.template.parser.TemplateParser;
import fr.sii.ogham.core.template.parser.AutoDetectTemplateParser.TemplateImplementation;
import fr.sii.ogham.core.translator.content.ContentTranslator;
import fr.sii.ogham.core.translator.content.EveryContentTranslator;
import fr.sii.ogham.core.translator.content.MultiContentTranslator;
import fr.sii.ogham.core.translator.content.TemplateContentTranslator;
import fr.sii.ogham.email.message.Email;
import fr.sii.ogham.email.sender.EmailSender;
import fr.sii.ogham.sms.message.Sms;
import fr.sii.ogham.sms.sender.SmsSender;
/**
* Utility class to find implementations used by Ogham service.
*
* @author Aurélien Baudet
*
*/
public final class ImplementationFinder {
private static final String DELEGATE_FIELD = "delegate";
/**
* Find recursively a finder of the provided class
*
* @param <T>
* the type of the found sender
* @param service
* the messaging service
* @param clazz
* the class of the sender to find
* @return the found sender
*/
public static <T extends MessageSender> T findSender(MessagingService service, Class<T> clazz) {
Set<T> found = findSenders(service, clazz);
if (found.isEmpty()) {
throw new IllegalStateException("Failed to find MessageSender of " + clazz.getTypeName());
}
if (found.size() == 1) {
return found.iterator().next();
}
throw new IllegalStateException("Several matching MessageSender for " + clazz.getTypeName() + " found");
}
/**
* Find all senders for the given type
*
* @param <T>
* the type of the senders to find
* @param service
* the messaging service
* @param clazz
* the class of the senders to find
* @return the found senders
*/
@SuppressWarnings("unchecked")
public static <T extends MessageSender> Set<T> findSenders(MessagingService service, Class<T> clazz) {
try {
Set<T> found = new HashSet<>();
List<ConditionalSender> senders = (List<ConditionalSender>) readField(getRealService(service), "senders", true);
for (ConditionalSender sender : senders) {
found.addAll(findSenders(sender, clazz));
}
return found;
} catch (IllegalAccessException e) {
throw new IllegalStateException("Failed to find senders of type " + clazz.getTypeName(), e);
}
}
/**
* Find template parsers of the given type.
*
* @param <T>
* the type of the template parsers to find
* @param service
* the messaging service
* @param clazz
* the class of the template parsers to find
* @return the found parsers
*/
public static <T extends TemplateParser> Set<FoundParser<T>> findParsers(MessagingService service, Class<T> clazz) {
try {
Set<FoundParser<T>> found = new HashSet<>();
Set<ContentTranslatorSender> translatorSenders = findSenders(service, ContentTranslatorSender.class);
for (ContentTranslatorSender sender : translatorSenders) {
Set<TemplateContentTranslator> translators = findTranslators(sender, TemplateContentTranslator.class);
for (TemplateContentTranslator translator : translators) {
found.addAll(findParsers(clazz, translator, (MessageSender) readField(sender, DELEGATE_FIELD, true)));
}
}
return found;
} catch (IllegalAccessException e) {
throw new IllegalStateException("Failed to find parser of type " + clazz.getTypeName(), e);
}
}
private static MessagingService getRealService(MessagingService service) {
try {
if (service instanceof WrapExceptionMessagingService) {
return getRealService((MessagingService) readField(service, DELEGATE_FIELD, true));
}
if (service instanceof CleanableMessagingService) {
return getRealService((MessagingService) readField(service, DELEGATE_FIELD, true));
}
if (service instanceof EverySupportingMessagingService) {
return service;
}
throw new IllegalStateException("Unknown MessagingService implementation, please add it here");
} catch (IllegalAccessException e) {
throw new IllegalStateException("Failed to find real MessagingService", e);
}
}
@SuppressWarnings("unchecked")
private static <T extends MessageSender> Set<T> findSenders(MessageSender sender, Class<T> clazz) {
try {
Set<T> found = new HashSet<>();
if (clazz.isAssignableFrom(sender.getClass())) {
found.add((T) sender);
}
// Any sender that delegates in the chain (FillerSender,
// AttachmentResourceTranslatorSender, ContentTranslatorSender,
// PhoneNumberTranslatorSender)
// TODO: FallbackSender
if (delegates(sender)) {
MessageSender delegate = (MessageSender) readField(sender, DELEGATE_FIELD, true);
found.addAll(findSenders(delegate, clazz));
}
if (sender instanceof MultiImplementationSender<?>) {
found.addAll(findSenders((MultiImplementationSender<?>) sender, clazz));
}
return found;
} catch (IllegalAccessException e) {
throw new IllegalStateException("Failed to find senders of type " + clazz.getTypeName(), e);
}
}
private static boolean delegates(MessageSender sender) {
try {
Object value = readField(sender, DELEGATE_FIELD, true);
return value instanceof MessageSender;
} catch (IllegalAccessException | IllegalArgumentException e) { // NOSONAR
return false;
}
}
@SuppressWarnings("unchecked")
private static <T extends MessageSender> Set<T> findSenders(MultiImplementationSender<?> sender, Class<T> clazz) {
Set<T> found = new HashSet<>();
List<Implementation> implementations = sender.getImplementations();
for (Implementation impl : implementations) {
if (clazz.isAssignableFrom(impl.getSender().getClass())) {
found.add((T) impl.getSender());
}
}
return found;
}
@SuppressWarnings("unchecked")
private static <T extends TemplateParser> Set<FoundParser<T>> findParsers(Class<T> clazz, TemplateContentTranslator translator, MessageSender sender) throws IllegalAccessException {
Set<FoundParser<T>> found = new HashSet<>();
TemplateParser parser = (TemplateParser) readField(translator, "parser", true);
if (clazz.isAssignableFrom(parser.getClass())) {
found.add(new FoundParser<>((T) parser, getMessageType(sender)));
}
if (parser instanceof AutoDetectTemplateParser) {
found.addAll(findParsers(clazz, (AutoDetectTemplateParser) parser, sender));
}
return found;
}
@SuppressWarnings("unchecked")
private static <T extends TemplateParser> Set<FoundParser<T>> findParsers(Class<T> clazz, AutoDetectTemplateParser parser, MessageSender sender) throws IllegalAccessException {
Set<FoundParser<T>> found = new HashSet<>();
List<TemplateImplementation> implementations = (List<TemplateImplementation>) readField(parser, "implementations", true);
for (TemplateImplementation impl : implementations) {
if (clazz.isAssignableFrom(impl.getParser().getClass())) {
found.add(new FoundParser<>((T) impl.getParser(), getMessageType(sender)));
}
}
return found;
}
private static Class<? extends Message> getMessageType(MessageSender sender) {
Set<EmailSender> emailSenders = findSenders(sender, EmailSender.class);
if (!emailSenders.isEmpty()) {
return Email.class;
}
Set<SmsSender> smsSenders = findSenders(sender, SmsSender.class);
if (!smsSenders.isEmpty()) {
return Sms.class;
}
throw new IllegalStateException("Failed to find message type");
}
private static <T extends ContentTranslator> Set<T> findTranslators(ContentTranslatorSender translatorSender, Class<T> clazz) {
try {
ContentTranslator translator = (ContentTranslator) readField(translatorSender, "translator", true);
return findTranslators(translator, clazz);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Failed to find translator of type " + clazz.getTypeName(), e);
}
}
private static <T extends ContentTranslator> Set<T> findTranslators(ContentTranslator translator, Class<T> clazz) {
try {
Set<T> found = new HashSet<>();
if (translator instanceof EveryContentTranslator) {
found.addAll(findTranslators((EveryContentTranslator) translator, clazz));
}
if (translator instanceof MultiContentTranslator) {
found.addAll(findTranslators((ContentTranslator) readField(translator, DELEGATE_FIELD, true), clazz));
}
return found;
} catch (IllegalAccessException e) {
throw new IllegalStateException("Failed to read 'delegate' of MultiContentTranslator", e);
}
}
@SuppressWarnings("unchecked")
private static <T extends ContentTranslator> Set<T> findTranslators(EveryContentTranslator translator, Class<T> clazz) {
Set<T> found = new HashSet<>();
for (ContentTranslator t : translator.getTranslators()) {
if (clazz.isAssignableFrom(t.getClass())) {
found.add((T) t);
}
}
return found;
}
private ImplementationFinder() {
super();
}
}