/*
* Copyright 2013 Martin Kouba
*
* Licensed 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.trimou.engine.segment;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.trimou.annotations.Internal;
import org.trimou.engine.MustacheTagType;
import org.trimou.engine.context.ExecutionContext;
import org.trimou.engine.parser.Template;
import org.trimou.exception.MustacheException;
import org.trimou.exception.MustacheProblem;
/**
* Partial segment.
*
* @author Martin Kouba
*/
@Internal
public class PartialSegment extends AbstractSegment {
private final TextSegment indentation;
/**
* Cache the partial template if possible, i.e. if the cache is enabled, no
* expiration timeout is set and debug mode is not enabled
*/
private final AtomicReference<Template> cachedPartialTemplate;
private volatile List<List<Segment>> cachedPartialLines;
/**
*
* @param text
* @param origin
* @param indentation
*/
public PartialSegment(String text, Origin origin, String indentation) {
super(text, origin);
this.indentation = indentation != null ? new TextSegment(indentation,
new Origin(origin.getTemplate())) : null;
this.cachedPartialTemplate = Segments
.isTemplateCachingAllowed(getEngineConfiguration()) ? new AtomicReference<>()
: null;
}
@Override
public SegmentType getType() {
return SegmentType.PARTIAL;
}
@Override
public Appendable execute(Appendable appendable, ExecutionContext context) {
Template partialTemplate = Segments.getTemplate(cachedPartialTemplate,
getText(), getEngine(), getTemplate());
if (partialTemplate == null) {
throw new MustacheException(
MustacheProblem.RENDER_INVALID_PARTIAL_KEY,
"No partial found for the given key: %s %s", getText(),
getOrigin());
}
if (indentation == null) {
appendable = partialTemplate.getRootSegment().execute(appendable, context);
} else {
prependIndentation(appendable, context.setTemplateInvocation(partialTemplate), partialTemplate);
}
return appendable;
}
@Override
public String getLiteralBlock() {
return getTagLiteral(MustacheTagType.PARTIAL.getCommand() + getText());
}
@Override
protected String getSegmentName() {
return getText();
}
private void prependIndentation(Appendable appendable,
ExecutionContext context, Template partialTemplate) {
List<List<Segment>> partialLines;
if (cachedPartialTemplate != null) {
partialLines = cachedPartialLines;
if (partialLines == null) {
synchronized (this) {
partialLines = cachedPartialLines;
if (partialLines == null) {
partialLines = getPartialLines(partialTemplate);
cachedPartialLines = partialLines;
}
}
}
} else {
partialLines = getPartialLines(partialTemplate);
}
for (List<Segment> line : partialLines) {
for (Segment segment : line) {
segment.execute(appendable, context);
}
}
}
private List<List<Segment>> getPartialLines(Template partialTemplate) {
List<List<Segment>> partialLines = Segments
.readSegmentLinesBeforeRendering(partialTemplate
.getRootSegment());
for (List<Segment> line : partialLines) {
line.add(0, indentation);
}
return partialLines;
}
}