package com.limegroup.gnutella.templates;
import java.text.ParseException;
import java.util.Map;
/**
* A generic Template Processor. Given a template, and a mapping of template values to substitution
* values, attempts to fill the template with the substituted values. If the template is not
* valid, an IllegalTemplateException will be thrown. Otherwise a successful template will be
* created.
*/
public abstract class StoreTemplateProcessor {
/**
* Substitutable values, currently on artist, album, track title, and track number are
* substitutable.
*/
public final static String ARTIST_LABEL = "artist";
public final static String ALBUM_LABEL = "album";
public final static String TITLE_LABEL = "title";
public final static String TRACK_LABEL = "track";
/**
* States of the substitution.
*/
protected static enum States {
LOOKING_FOR_START_DELIM,
INSIDE_START_DELIM;
}
/**
* Substitutable values must be wrapped in a START_DELIM value END_DELIM
* ex. <artist>
*/
protected final static char START_DELIM = '<';
protected final static char END_DELIM = '>';
protected String performSubstitution(final String template, final Map<String,String> substitutions)
throws IllegalTemplateException {
final StringBuilder outputBuffer = new StringBuilder();
StringBuilder subBuffer = new StringBuilder();
States state = States.LOOKING_FOR_START_DELIM;
for (int i=0; i<template.length(); i++) {
final char c = template.charAt(i);
if(state == States.LOOKING_FOR_START_DELIM ) {
if(c == START_DELIM) {
state = States.INSIDE_START_DELIM;
subBuffer = new StringBuilder();
}
else {
outputBuffer.append(c);
}
} else if( state == States.INSIDE_START_DELIM ) {
if( c == END_DELIM ) {
final String variable = subBuffer.toString().replaceAll("\\s", "");
String replacement = substitutions.get(variable);
if (replacement == null) {
throw new IllegalTemplateException(i,TEMPLATE_PROCESSOR_UNKNOWN_REPLACEMENT, template);
}
outputBuffer.append(replacement);
state = States.LOOKING_FOR_START_DELIM;
} else {
subBuffer.append(c);
}
}
}
// if still inside a delim, template must be wrong, throw an exception
if (state == States.INSIDE_START_DELIM) {
throw new IllegalTemplateException(template.length(),TEMPLATE_PROCESSOR_UNCLOSED_VARIABLE, template);
}
outputBuffer.trimToSize();
return outputBuffer.toString();
}
/*
* Illegal Argument Descriptions
* TODO: need to add a translator for each of these, currently no code in the UI cares about the actual
* message so no rush to get this done currently
*/
final static int TEMPLATE_PROCESSOR_ILLEGAL_CHARACTER = 0; //Illegal character in template
final static int TEMPLATE_PROCESSOR_MISSING_DELIMETER = 1; //Missing delimeter < or >
final static int TEMPLATE_PROCESSOR_UNKNOWN_REPLACEMENT = 2; //Unknown replacement character
final static int TEMPLATE_PROCESSOR_UNCLOSED_VARIABLE = 3; //Unenclosed variable
/**
* Thrown for an invalid template.
*/
@SuppressWarnings("serial")
public final static class IllegalTemplateException extends ParseException {
private final int messageType;
private final String template;
public IllegalTemplateException(int pos, final int msgType, final String template) {
super("",pos);
this.messageType = msgType;
this.template = template;
}
@Override
public String getMessage() {
final StringBuilder sb = new StringBuilder();
//
// This is used for testing
//
String s = null;
try {
s = super.getMessage();
} catch(Exception e){
s = e.getLocalizedMessage();
}
sb.append(s);
sb.append(System.getProperty("line.separator"));
sb.append(template);
sb.append(System.getProperty("line.separator"));
for (int i=0, N=getErrorOffset(); i<N; i++) sb.append(' ');
sb.append('^');
return sb.toString();
}
public String getTemplate(){
return template;
}
public int getMessageType(){
return messageType;
}
}
}