MultiContentTranslator.java

package fr.sii.ogham.core.translator.content;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import fr.sii.ogham.core.exception.handler.ContentTranslatorException;
import fr.sii.ogham.core.exception.handler.NoContentException;
import fr.sii.ogham.core.exception.handler.Recoverable;
import fr.sii.ogham.core.message.content.Content;
import fr.sii.ogham.core.message.content.MultiContent;

/**
 * <p>
 * Decorator that is able to handle {@link MultiContent}. A {@link MultiContent}
 * can provide several contents to put into the final message. For example,
 * emails can send both HTML and text content.
 * </p>
 * <p>
 * This implementation calls the delegate content translator to apply
 * translation on each sub content of the {@link MultiContent}. It can be useful
 * to apply content translations on every sub content like it should be applied
 * for normal content.
 * </p>
 * <p>
 * The same translator is applied for all sub contents.
 * </p>
 * <p>
 * If the content is not a {@link MultiContent}, then the content is returned
 * as-is.
 * </p>
 * 
 * @author Aurélien Baudet
 *
 */
public class MultiContentTranslator implements ContentTranslator {
	private static final Logger LOG = LoggerFactory.getLogger(MultiContentTranslator.class);

	/**
	 * The content translator to apply on each sub content
	 */
	private ContentTranslator delegate;

	public MultiContentTranslator(ContentTranslator delegate) {
		super();
		this.delegate = delegate;
	}

	@Override
	public Content translate(Content content) throws ContentTranslatorException {
		if (!(content instanceof MultiContent)) {
			LOG.trace("Not a MultiContent => skip it");
			return content;
		}
		MultiContent result = new MultiContent();
		List<ContentTranslatorException> missing = new ArrayList<>();
		for (Content c : ((MultiContent) content).getContents()) {
			translate(c, result, missing);
		}
		if (result.getContents().isEmpty()) {
			handleEmptyContent(content, missing);
		}
		return result;
	}

	@Override
	public String toString() {
		return "MultiContentTranslator";
	}


	private void translate(Content c, MultiContent result, List<ContentTranslatorException> missing) throws ContentTranslatorException {
		LOG.debug("Translate the sub content using {}", delegate);
		LOG.trace("sub content: {}", c);
		try {
			Content translated = delegate.translate(c);
			if (translated == null) {
				LOG.debug("Sub content skipped");
				LOG.trace("sub-content: {}", c);
			} else {
				LOG.debug("Sub content added");
				LOG.trace("sub-content: {}", c);
				result.addContent(translated);
			}
		} catch (ContentTranslatorException e) {
			handleException(e, missing);
		}
	}

	private static void handleException(ContentTranslatorException e, List<ContentTranslatorException> missing) throws ContentTranslatorException {
		if (!isRecoverable(e)) {
			throw e;
		}
		LOG.info("{} => ignoring", e.getMessage(), e);
		missing.add(e);
	}

	private static void handleEmptyContent(Content content, List<ContentTranslatorException> missing) throws NoContentException {
		if (!missing.isEmpty()) {
			String notFoundTemplates = missing.stream().map(Exception::getMessage).collect(Collectors.joining("\n"));
			throw new NoContentException("The message is empty maybe due to some errors:\n" + notFoundTemplates, (MultiContent) content, missing);
		}
		throw new NoContentException("The message is empty", (MultiContent) content, missing);
	}

	private static boolean isRecoverable(ContentTranslatorException e) {
		return e.getClass().isAnnotationPresent(Recoverable.class);
	}

}