blob: 11040be4f31c988d78fbb7a766a0656d04243c43 [file] [log] [blame]
/**
* 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.apache.geronimo.microprofile.reporter.storage.front;
import static java.util.stream.Collectors.joining;
import static javax.ws.rs.core.MediaType.TEXT_HTML;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Function;
import java.util.stream.Stream;
import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import javax.ws.rs.InternalServerErrorException;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
import org.apache.geronimo.microprofile.reporter.storage.templating.TemplatingEngine;
@Provider
@Dependent
@Produces(TEXT_HTML)
public class HtmlWriter implements MessageBodyWriter<Html> {
private final boolean development = Boolean.getBoolean("geronimo.microprofile.reporter.dev");
@Inject
private TemplatingEngine templatingEngine;
private final ConcurrentMap<String, String> templates = new ConcurrentHashMap<>();
@Override
public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations,
final MediaType mediaType) {
return type == Html.class;
}
@Override
public void writeTo(final Html html, final Class<?> type, final Type genericType,
final Annotation[] annotations, final MediaType mediaType,
final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream)
throws IOException, WebApplicationException {
final String template = templates.computeIfAbsent(html.getName(), this::loadTemplate);
final Function<Object, String> compiled = templatingEngine.compileIfNeeded(template, this::loadTemplate);
entityStream.write(compiled.apply(html.getData()).getBytes(StandardCharsets.UTF_8));
if (development) {
templates.clear();
templatingEngine.clean();
}
}
private String loadTemplate(final String template) {
return Stream.of("geronimo/microprofile/reporter/" + template, template)
.flatMap(it -> Stream.of(it, '/' + it))
.map(it -> {
try (final InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(it)) {
if (stream == null) {
return null;
}
return new BufferedReader(new InputStreamReader(stream)).lines().collect(joining("\n"));
} catch (final IOException e) {
throw new InternalServerErrorException(e);
}
})
.filter(Objects::nonNull)
.findFirst()
.orElseThrow(() -> new InternalServerErrorException("Missing template: " + template));
}
}