/*
* #%L
* Nazgul Project: nazgul-core-parser-api
* %%
* Copyright (C) 2010 - 2017 jGuru Europe AB
* %%
* Licensed under the jGuru Europe AB license (the "License"), based
* on Apache License, Version 2.0; you may not use this file except
* in compliance with the License.
*
* You may obtain a copy of the License at
*
* http://www.jguru.se/licenses/jguruCorporateSourceLicense-2.0.txt
*
* 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.
* #L%
*
*/
package se.jguru.nazgul.core.parser.api;
import se.jguru.nazgul.core.algorithms.api.Validate;
import se.jguru.nazgul.core.parser.api.agent.ParserAgent;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Simple implementation of a String replacement parser.
*
* @author <a href="mailto:lj@jguru.se">Lennart Jörelid</a>, jGuru Europe AB
*/
public class DefaultTokenParser implements TokenParser {
// Internal state
private boolean canBeInitialized = true;
private TokenDefinitions tokenDefinitions = new DefaultTokenDefinitions();
private final List<ParserAgent> parseAgents = new ArrayList<>();
/**
* {@inheritDoc}
*/
@Override
public void initialize(@NotNull final TokenDefinitions tokenDefinitions) throws IllegalStateException {
// Check sanity
Validate.notNull(tokenDefinitions, "tokenDefinitions");
if (!canBeInitialized) {
throw new IllegalStateException("Cannot (re-)initialize a DefaultTokenParser after it has been used.");
}
// Assign the supplied TokenDefinitions
synchronized (parseAgents) {
this.tokenDefinitions = tokenDefinitions;
canBeInitialized = false;
}
}
/**
* Adds a parserAgent to the list of known AbstractParserAgents.
*
* @param parserAgent the parserAgent to add.
*/
@Override
public final void addAgent(@NotNull final ParserAgent parserAgent) {
Validate.notNull(parserAgent, "parserAgent");
if (!parseAgents.contains(parserAgent)) {
parseAgents.add(parserAgent);
}
}
/**
* Replaces the tokens found within the data.
*
* @param data The data in which to replace existing tokens.
* @return The token-substituted data.
*/
@Override
public final String substituteTokens(final String data) {
StringBuilder toReturn = new StringBuilder();
// Flip the switch.
if (canBeInitialized) {
synchronized (parseAgents) {
canBeInitialized = false;
}
}
// Find all matches within data
final Pattern pattern = tokenDefinitions.getTokenRegExpPattern();
Matcher m = pattern.matcher(data);
int currentStartIndex = 0;
while (m.find(currentStartIndex)) {
// Found a token hit within the data.
int matchStartIndex = m.start();
int matchEndIndex = m.end();
String actualToken = tokenDefinitions.getToken(m.group());
boolean handled = false;
// Let all known parseAgents attempt to replace the token.
for (ParserAgent currentParser : parseAgents) {
boolean canHandle = currentParser.canHandle(actualToken);
if (canHandle) {
handled = true;
// Inject the data into the return buffer.
String replacement = currentParser.substituteValue(actualToken);
toReturn.append(data.substring(currentStartIndex, matchStartIndex));
toReturn.append(replacement);
currentStartIndex = matchEndIndex;
break;
}
}
if (!handled) {
// Found no ParseAgents capable of handling the token substitution.
// Re-inject the original token into the return buffer.
toReturn.append(data.substring(currentStartIndex, matchEndIndex));
currentStartIndex = matchEndIndex;
}
}
// Append the rest of the data.
toReturn.append(data.substring(currentStartIndex, data.length()));
// All done.
return toReturn.toString();
}
}