![JAR search and dependency download from the Maven repository](/logo.png)
de.cuioss.tools.formatting.template.TemplateFormatterImpl Maven / Gradle / Ivy
/*
* Copyright 2023 the original author or authors.
*
* 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
*
* https://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 de.cuioss.tools.formatting.template;
import static de.cuioss.tools.base.Preconditions.checkState;
import static java.util.Objects.requireNonNull;
import java.util.ArrayList;
import java.util.List;
import de.cuioss.tools.formatting.template.lexer.Lexer;
import de.cuioss.tools.formatting.template.lexer.LexerBuilder;
import de.cuioss.tools.formatting.template.token.Token;
import lombok.EqualsAndHashCode;
import lombok.Synchronized;
import lombok.ToString;
/**
* Formatter which is able to replace parameter inside the template based on
* {@link FormatterSupport} information. See {@link de.cuioss.tools.formatting}
* for details.
*
* @param at least {@link FormatterSupport}
*
* @author Eugen Fischer
*/
@ToString
@EqualsAndHashCode
public final class TemplateFormatterImpl implements TemplateFormatter {
private static final long serialVersionUID = -6297959581838201331L;
private final String template;
private ArrayList parsedTokens;
private Lexer lexer;
private final boolean strict;
private TemplateFormatterImpl(final String template, final boolean strict) {
this.template = template;
this.strict = strict;
}
/**
* Lexer which should be used to scan the template
*
* @param lexerInstance must not be {@code null}
*
* @return reference to TemplateFormatter, fluent api style
*/
TemplateFormatterImpl scanBy(final Lexer lexerInstance) {
lexer = requireNonNull(lexerInstance, "Parser must not be null");
parsedTokens = null;
return this;
}
/**
* replace attributes from template by attribute values from the map. missing
* template attributes will be ignored and doesn't add to result at all.
*
* @param reference must not be null
*
* @return completed template
*/
@Override
public String format(final T reference) {
requireNonNull(reference, "Reference must not be null");
final var tokenList = getParsedTokens();
final var buffer = new StringBuilder(0);
for (var index = 0; index < tokenList.size(); index++) {
final var token = tokenList.get(index);
if (token.isStringToken()) {
if (lookUpLastTokenHasValue(tokenList, reference, index)
&& lookUpNextTokenHasValue(tokenList, reference, index)) {
buffer.append(token.substituteAttribute(reference));
}
} else {
buffer.append(token.substituteAttribute(reference));
}
}
return buffer.toString();
}
private boolean lookUpNextTokenHasValue(final List tokenList, final T reference,
final int currentTokenIndex) {
var nextTokenIndex = currentTokenIndex + 1;
while (nextTokenIndex < tokenList.size()) {
final var token = tokenList.get(nextTokenIndex);
if (!token.isStringToken()) {
final var value = token.substituteAttribute(reference);
if (!value.isEmpty()) {
return true;
}
}
nextTokenIndex++;
}
return false;
}
private boolean lookUpLastTokenHasValue(final List tokenList, final T reference,
final int currentTokenIndex) {
var result = false;
final var lastTokenIndex = currentTokenIndex - 1;
if (lastTokenIndex >= 0) {
final var value = tokenList.get(lastTokenIndex).substituteAttribute(reference);
result = !value.isEmpty();
}
return result;
}
@Synchronized
private List getParsedTokens() {
if (null == this.parsedTokens) {
checkState(null != this.lexer, "Parser must be initialized before.");
this.parsedTokens = new ArrayList<>(this.lexer.scan(this.template));
}
return this.parsedTokens;
}
/**
* The created TemplateFormatter provide only usage of simple expression
* language with squared brackets.
*
* @param template must not be null
* @param sourceType must not be null
*
* @return TemplateFormatter which using template and lexer which was forwarded
*/
public static TemplateFormatter createFormatter(final String template,
final Class sourceType) {
return TemplateBuilder.useTemplate(template).forType(sourceType);
}
/**
* @param template must not be null
* @param source must not be null
*
* @return TemplateFormatter
*/
public static TemplateFormatter createFormatter(final String template,
final F source) {
return TemplateBuilder.useTemplate(template).forSource(source);
}
/**
* @param template must not be null
* @param lexer must not be null
*
* @return TemplateFormatter which using template and lexer which was forwarded
*/
public static TemplateFormatter createFormatter(final String template,
final Lexer lexer) {
return TemplateBuilder.useTemplate(template).scanBy(lexer);
}
/**
* The created TemplateFormatter provide only usage of simple expression
* language with squared brackets.
*
* @param template must not be null
* @param sourceType must not be null
* @param strict use strict mode for pattern matching (only match exact
* name) instead of best fitting
*
* @return TemplateFormatter which using template and lexer which was forwarded
*/
public static TemplateFormatter createFormatter(final String template,
final Class sourceType, final boolean strict) {
return TemplateBuilder.useTemplate(template).strict(strict).forType(sourceType);
}
/**
* @param template must not be null
* @param source must not be null
* @param strict use strict mode for pattern matching (only match exact name)
* instead of best fitting
*
* @return TemplateFormatter
*/
public static TemplateFormatter createFormatter(final String template,
final F source, final boolean strict) {
return TemplateBuilder.useTemplate(template).strict(strict).forSource(source);
}
/**
* @param template must not be null
* @param lexer must not be null
* @param strict use strict mode for pattern matching (only match exact name)
* instead of best fitting
*
* @return TemplateFormatter which using template and lexer which was forwarded
*/
public static TemplateFormatter createFormatter(final String template,
final Lexer lexer, final boolean strict) {
return TemplateBuilder.useTemplate(template).strict(strict).scanBy(lexer);
}
/**
* @return a newly created {@link TemplateBuilder}
*/
@SuppressWarnings("squid:S2440") // owolff: False positive
public static TemplateBuilder builder() {
return new TemplateBuilder();
}
/**
* Template Builder
*
* @author Eugen Fischer
*/
public static final class TemplateBuilder {
private TemplateBuilder() {
}
static FormatterBuilder useTemplate(final String template) {
return new FormatterBuilder(template);
}
static final class FormatterBuilder {
private final String template;
private boolean strict;
FormatterBuilder(final String templateInput) {
template = templateInput;
}
/**
* @param strict use strict mode for pattern matching (only match exact name)
* instead of best fitting
* @return a {@link FormatterBuilder} with strict set to given parameter
*/
public FormatterBuilder strict(boolean strict) {
this.strict = strict;
return this;
}
public TemplateFormatter scanBy(final Lexer lexer) {
return new TemplateFormatterImpl(template, strict).scanBy(lexer);
}
public TemplateFormatter forSource(final F source) {
final Lexer lexer = LexerBuilder.useSimpleElWithSquaredBrackets().strict(strict).build(source);
return scanBy(lexer);
}
public TemplateFormatter forType(final Class classType) {
final Lexer lexer = LexerBuilder.useSimpleElWithSquaredBrackets().strict(strict).build(classType);
return scanBy(lexer);
}
}
}
}