InlineCssTranslator.java

1
package fr.sii.ogham.html.translator;
2
3
import static fr.sii.ogham.core.util.HtmlUtils.getDistinctCssUrls;
4
import static fr.sii.ogham.core.util.HtmlUtils.isHtml;
5
import static fr.sii.ogham.core.util.HtmlUtils.skipExternalUrls;
6
import static fr.sii.ogham.html.inliner.impl.jsoup.CssInlineUtils.removeOghamAttributes;
7
8
import java.io.IOException;
9
import java.util.ArrayList;
10
import java.util.List;
11
12
import org.slf4j.Logger;
13
import org.slf4j.LoggerFactory;
14
15
import fr.sii.ogham.core.exception.handler.ContentTranslatorException;
16
import fr.sii.ogham.core.exception.handler.CssInliningException;
17
import fr.sii.ogham.core.exception.resource.ResourceResolutionException;
18
import fr.sii.ogham.core.message.content.Content;
19
import fr.sii.ogham.core.message.content.HasResourcePath;
20
import fr.sii.ogham.core.message.content.MayHaveStringContent;
21
import fr.sii.ogham.core.message.content.StringContent;
22
import fr.sii.ogham.core.message.content.UpdatableStringContent;
23
import fr.sii.ogham.core.resource.path.RelativePathResolver;
24
import fr.sii.ogham.core.resource.path.ResourcePath;
25
import fr.sii.ogham.core.resource.path.UnresolvedPath;
26
import fr.sii.ogham.core.resource.resolver.ResourceResolver;
27
import fr.sii.ogham.core.translator.content.ContentTranslator;
28
import fr.sii.ogham.core.util.IOUtils;
29
import fr.sii.ogham.html.inliner.CssInliner;
30
import fr.sii.ogham.html.inliner.ExternalCss;
31
32
/**
33
 * Translator that transforms HTML content. If not HTML, the translator has no
34
 * effect. The HTML is analyzed in order to find external css files. For each
35
 * found image, it uses the resource resolver in order to find the css file.
36
 * Once all css files are found, the HTML is transformed in order to inline the
37
 * styles.
38
 * 
39
 * @author Aurélien Baudet
40
 *
41
 */
42
public class InlineCssTranslator implements ContentTranslator {
43
	private static final Logger LOG = LoggerFactory.getLogger(InlineCssTranslator.class);
44
	
45
	/**
46
	 * The CSS inliner
47
	 */
48
	private final CssInliner cssInliner;
49
50
	/**
51
	 * The resource resolver to find the CSS files
52
	 */
53
	private final ResourceResolver resourceResolver;
54
	
55
	/**
56
	 * Provides an instance used to resolve relative path from source path and relative path
57
	 */
58
	private final RelativePathResolver relativePathProvider;
59
60
	public InlineCssTranslator(CssInliner cssInliner, ResourceResolver resourceResolver, RelativePathResolver relativePathProvider) {
61
		super();
62
		this.cssInliner = cssInliner;
63
		this.resourceResolver = resourceResolver;
64
		this.relativePathProvider = relativePathProvider;
65
	}
66
67
	@Override
68
	public Content translate(Content content) throws ContentTranslatorException {
69 10 1. translate : negated conditional → SURVIVED
2. translate : negated conditional → NO_COVERAGE
3. translate : negated conditional → SURVIVED
4. translate : negated conditional → NO_COVERAGE
5. translate : negated conditional → TIMED_OUT
6. translate : negated conditional → TIMED_OUT
7. translate : negated conditional → KILLED
8. translate : negated conditional → KILLED
9. translate : negated conditional → KILLED
10. translate : negated conditional → KILLED
		if (content instanceof MayHaveStringContent && ((MayHaveStringContent) content).canProvideString()) {
70
			String stringContent = ((MayHaveStringContent) content).asString();
71 5 1. translate : negated conditional → NO_COVERAGE
2. translate : negated conditional → SURVIVED
3. translate : negated conditional → TIMED_OUT
4. translate : negated conditional → KILLED
5. translate : negated conditional → KILLED
			if (isHtml(stringContent)) {
72
				List<String> cssFiles = skipExternalUrls(getDistinctCssUrls(stringContent));
73 4 1. translate : negated conditional → NO_COVERAGE
2. translate : negated conditional → TIMED_OUT
3. translate : negated conditional → KILLED
4. translate : negated conditional → KILLED
				if (!cssFiles.isEmpty()) {
74
					// prepare list of css files/urls with their content
75
					List<ExternalCss> cssResources = load(getSourcePath(content), cssFiles);
76
					// generate the content with inlined css
77
					String inlinedContentStr = cssInliner.inline(stringContent, cssResources);
78
					// remove ogham attributes
79
					String cleaned = clean(inlinedContentStr);
80
					// update the HTML content
81 3 1. translate : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → NO_COVERAGE
2. translate : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → KILLED
3. translate : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → KILLED
					return updateHtmlContent(content, cleaned);
82
				}
83
			}
84
		} else {
85
			LOG.debug("Neither content as string nor HTML. Skip CSS inlining");
86
			LOG.trace("content: {}", content);
87
		}
88 5 1. translate : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → SURVIVED
2. translate : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → NO_COVERAGE
3. translate : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → TIMED_OUT
4. translate : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → KILLED
5. translate : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → KILLED
		return content;
89
	}
90
91
	private static ResourcePath getSourcePath(Content content) {
92 3 1. getSourcePath : negated conditional → NO_COVERAGE
2. getSourcePath : negated conditional → KILLED
3. getSourcePath : negated conditional → KILLED
		if(content instanceof HasResourcePath) {
93 2 1. getSourcePath : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::getSourcePath → NO_COVERAGE
2. getSourcePath : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::getSourcePath → KILLED
			return ((HasResourcePath) content).getPath();
94
		}
95 3 1. getSourcePath : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::getSourcePath → NO_COVERAGE
2. getSourcePath : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::getSourcePath → KILLED
3. getSourcePath : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::getSourcePath → KILLED
		return new UnresolvedPath("");
96
	}
97
98
	private List<ExternalCss> load(ResourcePath sourcePath, List<String> cssFiles) throws ContentTranslatorException {
99
		List<ExternalCss> cssResources = new ArrayList<>(cssFiles.size());
100
		for (String path : cssFiles) {
101 3 1. load : removed call to fr/sii/ogham/html/translator/InlineCssTranslator::load → NO_COVERAGE
2. load : removed call to fr/sii/ogham/html/translator/InlineCssTranslator::load → KILLED
3. load : removed call to fr/sii/ogham/html/translator/InlineCssTranslator::load → KILLED
			load(cssResources, relativePathProvider.resolve(sourcePath, path));
102
		}
103 3 1. load : replaced return value with Collections.emptyList for fr/sii/ogham/html/translator/InlineCssTranslator::load → NO_COVERAGE
2. load : replaced return value with Collections.emptyList for fr/sii/ogham/html/translator/InlineCssTranslator::load → KILLED
3. load : replaced return value with Collections.emptyList for fr/sii/ogham/html/translator/InlineCssTranslator::load → KILLED
		return cssResources;
104
	}
105
106
	private void load(List<ExternalCss> cssResources, ResourcePath path) throws ContentTranslatorException {
107
		try {
108
			cssResources.add(new ExternalCss(path, IOUtils.toString(resourceResolver.getResource(path).getInputStream())));
109
		} catch (IOException e) {
110
			throw new CssInliningException("Failed to inline CSS file " + path + " because it can't be read", e);
111
		} catch (ResourceResolutionException e) {
112
			throw new CssInliningException("Failed to inline CSS file " + path + " because it can't be resolved", e);
113
		}
114
	}
115
116
	private static Content updateHtmlContent(Content content, String inlinedContentStr) {
117
		Content inlinedContent = content;
118 3 1. updateHtmlContent : negated conditional → SURVIVED
2. updateHtmlContent : negated conditional → NO_COVERAGE
3. updateHtmlContent : negated conditional → KILLED
		if(content instanceof UpdatableStringContent) {
119
			LOG.debug("Content is updatable => update it with inlined CSS");
120 3 1. updateHtmlContent : removed call to fr/sii/ogham/core/message/content/UpdatableStringContent::setStringContent → NO_COVERAGE
2. updateHtmlContent : removed call to fr/sii/ogham/core/message/content/UpdatableStringContent::setStringContent → KILLED
3. updateHtmlContent : removed call to fr/sii/ogham/core/message/content/UpdatableStringContent::setStringContent → KILLED
			((UpdatableStringContent) inlinedContent).setStringContent(inlinedContentStr);
121
		} else {
122
			LOG.info("Content is not updatable => create a new StringContent for CSS inlining result");
123
			inlinedContent = new StringContent(inlinedContentStr);
124
		}
125 3 1. updateHtmlContent : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::updateHtmlContent → NO_COVERAGE
2. updateHtmlContent : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::updateHtmlContent → KILLED
3. updateHtmlContent : replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::updateHtmlContent → KILLED
		return inlinedContent;
126
	}
127
	
128
	private static String clean(String content) {
129 3 1. clean : replaced return value with "" for fr/sii/ogham/html/translator/InlineCssTranslator::clean → NO_COVERAGE
2. clean : replaced return value with "" for fr/sii/ogham/html/translator/InlineCssTranslator::clean → KILLED
3. clean : replaced return value with "" for fr/sii/ogham/html/translator/InlineCssTranslator::clean → KILLED
		return removeOghamAttributes(content);
130
	}
131
132
133
	@Override
134
	public String toString() {
135 3 1. toString : replaced return value with "" for fr/sii/ogham/html/translator/InlineCssTranslator::toString → SURVIVED
2. toString : replaced return value with "" for fr/sii/ogham/html/translator/InlineCssTranslator::toString → NO_COVERAGE
3. toString : replaced return value with "" for fr/sii/ogham/html/translator/InlineCssTranslator::toString → TIMED_OUT
		return "InlineCssTranslator";
136
	}
137
	
138
}

Mutations

69

1.1
Location : translate
Killed by : oghamall.it.html.translator.JsoupInlineCssTranslatorTest.unreadableCss(oghamall.it.html.translator.JsoupInlineCssTranslatorTest)
negated conditional → KILLED

2.2
Location : translate
Killed by : none
negated conditional → SURVIVED

3.3
Location : translate
Killed by : oghamcore.it.html.translator.InlineCssTranslatorTest.oghamAttributesShoulBeRemoved(oghamcore.it.html.translator.InlineCssTranslatorTest)
negated conditional → KILLED

4.4
Location : translate
Killed by : none
negated conditional → NO_COVERAGE

5.5
Location : translate
Killed by : none
negated conditional → TIMED_OUT

6.6
Location : translate
Killed by : none
negated conditional → SURVIVED

7.7
Location : translate
Killed by : oghamall.it.html.translator.JsoupInlineCssTranslatorTest.unreadableCss(oghamall.it.html.translator.JsoupInlineCssTranslatorTest)
negated conditional → KILLED

8.8
Location : translate
Killed by : oghamcore.it.html.translator.InlineCssTranslatorTest.oghamAttributesShoulBeRemoved(oghamcore.it.html.translator.InlineCssTranslatorTest)
negated conditional → KILLED

9.9
Location : translate
Killed by : none
negated conditional → NO_COVERAGE

10.10
Location : translate
Killed by : none
negated conditional → TIMED_OUT

71

1.1
Location : translate
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : translate
Killed by : none
negated conditional → TIMED_OUT

3.3
Location : translate
Killed by : oghamcore.it.html.translator.InlineCssTranslatorTest.oghamAttributesShoulBeRemoved(oghamcore.it.html.translator.InlineCssTranslatorTest)
negated conditional → KILLED

4.4
Location : translate
Killed by : oghamall.it.html.translator.JsoupInlineCssTranslatorTest.notHtml(oghamall.it.html.translator.JsoupInlineCssTranslatorTest)
negated conditional → KILLED

5.5
Location : translate
Killed by : none
negated conditional → SURVIVED

73

1.1
Location : translate
Killed by : oghamall.it.html.translator.JsoupInlineCssTranslatorTest.unreadableCss(oghamall.it.html.translator.JsoupInlineCssTranslatorTest)
negated conditional → KILLED

2.2
Location : translate
Killed by : none
negated conditional → TIMED_OUT

3.3
Location : translate
Killed by : none
negated conditional → NO_COVERAGE

4.4
Location : translate
Killed by : oghamcore.it.html.translator.InlineCssTranslatorTest.oghamAttributesShoulBeRemoved(oghamcore.it.html.translator.InlineCssTranslatorTest)
negated conditional → KILLED

81

1.1
Location : translate
Killed by : oghamall.it.html.translator.JsoupInlineCssTranslatorTest.externalStyles(oghamall.it.html.translator.JsoupInlineCssTranslatorTest)
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → KILLED

2.2
Location : translate
Killed by : none
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → NO_COVERAGE

3.3
Location : translate
Killed by : oghamcore.it.html.translator.InlineCssTranslatorTest.oghamAttributesShoulBeRemoved(oghamcore.it.html.translator.InlineCssTranslatorTest)
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → KILLED

88

1.1
Location : translate
Killed by : oghamjavamail.it.UnreadableAttachmentTest.attachmentUnreadable(oghamjavamail.it.UnreadableAttachmentTest)
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → KILLED

2.2
Location : translate
Killed by : oghamall.it.html.translator.JsoupInlineCssTranslatorTest.notHtml(oghamall.it.html.translator.JsoupInlineCssTranslatorTest)
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → KILLED

3.3
Location : translate
Killed by : none
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → SURVIVED

4.4
Location : translate
Killed by : none
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → NO_COVERAGE

5.5
Location : translate
Killed by : none
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::translate → TIMED_OUT

92

1.1
Location : getSourcePath
Killed by : oghamall.it.html.translator.JsoupInlineCssTranslatorTest.unreadableCss(oghamall.it.html.translator.JsoupInlineCssTranslatorTest)
negated conditional → KILLED

2.2
Location : getSourcePath
Killed by : none
negated conditional → NO_COVERAGE

3.3
Location : getSourcePath
Killed by : oghamcore.it.html.translator.InlineCssTranslatorTest.oghamAttributesShoulBeRemoved(oghamcore.it.html.translator.InlineCssTranslatorTest)
negated conditional → KILLED

93

1.1
Location : getSourcePath
Killed by : oghamall.it.email.EmailMultiTemplateTest.withThymeleafOneVariantWithInvalidResourcePath(oghamall.it.email.EmailMultiTemplateTest)
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::getSourcePath → KILLED

2.2
Location : getSourcePath
Killed by : none
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::getSourcePath → NO_COVERAGE

95

1.1
Location : getSourcePath
Killed by : oghamall.it.html.translator.JsoupInlineCssTranslatorTest.unreadableCss(oghamall.it.html.translator.JsoupInlineCssTranslatorTest)
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::getSourcePath → KILLED

2.2
Location : getSourcePath
Killed by : oghamcore.it.html.translator.InlineCssTranslatorTest.oghamAttributesShoulBeRemoved(oghamcore.it.html.translator.InlineCssTranslatorTest)
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::getSourcePath → KILLED

3.3
Location : getSourcePath
Killed by : none
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::getSourcePath → NO_COVERAGE

101

1.1
Location : load
Killed by : oghamcore.it.html.translator.InlineCssTranslatorTest.oghamAttributesShoulBeRemoved(oghamcore.it.html.translator.InlineCssTranslatorTest)
removed call to fr/sii/ogham/html/translator/InlineCssTranslator::load → KILLED

2.2
Location : load
Killed by : none
removed call to fr/sii/ogham/html/translator/InlineCssTranslator::load → NO_COVERAGE

3.3
Location : load
Killed by : oghamall.it.html.translator.JsoupInlineCssTranslatorTest.unreadableCss(oghamall.it.html.translator.JsoupInlineCssTranslatorTest)
removed call to fr/sii/ogham/html/translator/InlineCssTranslator::load → KILLED

103

1.1
Location : load
Killed by : oghamall.it.html.translator.JsoupInlineCssTranslatorTest.externalStyles(oghamall.it.html.translator.JsoupInlineCssTranslatorTest)
replaced return value with Collections.emptyList for fr/sii/ogham/html/translator/InlineCssTranslator::load → KILLED

2.2
Location : load
Killed by : oghamcore.it.html.translator.InlineCssTranslatorTest.oghamAttributesShoulBeRemoved(oghamcore.it.html.translator.InlineCssTranslatorTest)
replaced return value with Collections.emptyList for fr/sii/ogham/html/translator/InlineCssTranslator::load → KILLED

3.3
Location : load
Killed by : none
replaced return value with Collections.emptyList for fr/sii/ogham/html/translator/InlineCssTranslator::load → NO_COVERAGE

118

1.1
Location : updateHtmlContent
Killed by : oghamall.it.html.translator.JsoupInlineCssTranslatorTest.externalStyles(oghamall.it.html.translator.JsoupInlineCssTranslatorTest)
negated conditional → KILLED

2.2
Location : updateHtmlContent
Killed by : none
negated conditional → SURVIVED

3.3
Location : updateHtmlContent
Killed by : none
negated conditional → NO_COVERAGE

120

1.1
Location : updateHtmlContent
Killed by : none
removed call to fr/sii/ogham/core/message/content/UpdatableStringContent::setStringContent → NO_COVERAGE

2.2
Location : updateHtmlContent
Killed by : oghamcore.it.html.translator.InlineCssTranslatorTest.oghamAttributesShoulBeRemoved(oghamcore.it.html.translator.InlineCssTranslatorTest)
removed call to fr/sii/ogham/core/message/content/UpdatableStringContent::setStringContent → KILLED

3.3
Location : updateHtmlContent
Killed by : oghamall.it.html.translator.JsoupInlineCssTranslatorTest.externalStyles(oghamall.it.html.translator.JsoupInlineCssTranslatorTest)
removed call to fr/sii/ogham/core/message/content/UpdatableStringContent::setStringContent → KILLED

125

1.1
Location : updateHtmlContent
Killed by : oghamcore.it.html.translator.InlineCssTranslatorTest.oghamAttributesShoulBeRemoved(oghamcore.it.html.translator.InlineCssTranslatorTest)
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::updateHtmlContent → KILLED

2.2
Location : updateHtmlContent
Killed by : oghamall.it.html.translator.JsoupInlineCssTranslatorTest.externalStyles(oghamall.it.html.translator.JsoupInlineCssTranslatorTest)
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::updateHtmlContent → KILLED

3.3
Location : updateHtmlContent
Killed by : none
replaced return value with null for fr/sii/ogham/html/translator/InlineCssTranslator::updateHtmlContent → NO_COVERAGE

129

1.1
Location : clean
Killed by : oghamcore.it.html.translator.InlineCssTranslatorTest.oghamAttributesShoulBeRemoved(oghamcore.it.html.translator.InlineCssTranslatorTest)
replaced return value with "" for fr/sii/ogham/html/translator/InlineCssTranslator::clean → KILLED

2.2
Location : clean
Killed by : oghamall.it.html.translator.JsoupInlineCssTranslatorTest.externalStyles(oghamall.it.html.translator.JsoupInlineCssTranslatorTest)
replaced return value with "" for fr/sii/ogham/html/translator/InlineCssTranslator::clean → KILLED

3.3
Location : clean
Killed by : none
replaced return value with "" for fr/sii/ogham/html/translator/InlineCssTranslator::clean → NO_COVERAGE

135

1.1
Location : toString
Killed by : none
replaced return value with "" for fr/sii/ogham/html/translator/InlineCssTranslator::toString → SURVIVED

2.2
Location : toString
Killed by : none
replaced return value with "" for fr/sii/ogham/html/translator/InlineCssTranslator::toString → NO_COVERAGE

3.3
Location : toString
Killed by : none
replaced return value with "" for fr/sii/ogham/html/translator/InlineCssTranslator::toString → TIMED_OUT

Active mutators

Tests examined


Report generated by PIT OGHAM