package org.dcache.gplazma.configuration.parser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import org.dcache.util.Strings;
import org.dcache.gplazma.configuration.Configuration;
import org.dcache.gplazma.configuration.ConfigurationItem;
import org.dcache.gplazma.configuration.ConfigurationItemControl;
import org.dcache.gplazma.configuration.ConfigurationItemType;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.io.Files.newReader;
/**
*
* @author timur
*/
public class PAMStyleConfigurationParser implements ConfigurationParser {
private static final Logger logger =
LoggerFactory.getLogger(PAMStyleConfigurationParser.class);
// max number of times the reg expression is applied
// when splitting the non empty configuration file line
// is SPLIT_LIMIT-1
// SPLIT_LIMIT is also the max number of results of split
private static final int SPLIT_LIMIT=4;
//min required number of the string resulting from the split
// <type> <control> <plugin>
private static final int MIN_SPLIT_RESULTS=3;
// any line starting with <white space> followed by COMMENT_START
// is a comment and is ignored by the parser
private static final String COMMENT_START="#";
/**
*
* @param configuration a string containing configuration, not a file name
* @return Configuration based on the configuration
* @throws ParseException
*/
@Override
public Configuration parse(String configuration) throws ParseException {
checkNotNull(configuration, "Configuration must not be NULL");
return parse(new BufferedReader(new StringReader(configuration)));
}
/**
*
* @param configurationFile a file containing configuration
* @return Configuration based on the configuration
* @throws ParseException
*/
@Override
public Configuration parse(File configurationFile) throws ParseException {
checkNotNull(configurationFile, "ConfigurationFile must not be NULL.");
try {
return parse(newReader(configurationFile, Charset.defaultCharset()));
} catch(FileNotFoundException e) {
throw new ParseException("GPlazma Configuration parsing failed",e);
}
}
/**
* @param bufferedReader, a reader of the configuration,
* @return Configuration based on the configuration
* @throws ParseException
* line number reported in the exception will be correct iff the bufferedReader
* was initially pointing to the first char in the underlying char stream
*/
@Override
public Configuration parse (BufferedReader bufferedReader)
throws ParseException {
List<ConfigurationItem> configItemList =
new ArrayList<>();
int offset = 0;
String line;
try {
while ( (line = bufferedReader.readLine()) != null) {
try {
ConfigurationItem configItem = parseLine(line);
if(configItem != null) {
configItemList.add(configItem);
}
} catch (ParseException pe) {
pe.setOffset(offset);
throw pe;
}
offset ++;
}
} catch (IOException ioe) {
throw new ParseException("GPlazma Configuration parsing failed",ioe,
offset);
}
return new Configuration(configItemList);
}
/**
* Parses single line of configuration file
*
* @param line
* @return instance of ConfigurationItem or null if line is empty or
* contains comments
* @throws ParseExeption if the syntax is incorrect
*/
private ConfigurationItem parseLine(String line) throws ParseException {
String trimmed = line.trim();
if(trimmed.isEmpty() || trimmed.startsWith(COMMENT_START)) {
return null;
}
String[] splitLine = trimmed.split("\\s+",SPLIT_LIMIT);
logger.debug("splitLine = "+Arrays.toString(splitLine));
if(splitLine.length == 0) {
return null;
}
if(splitLine.length < MIN_SPLIT_RESULTS) {
throw new ParseException("Syntax violation for line \""+line+'"');
}
try {
// configuration line should have the following syntax
// <type> <control> <plugin> [<configuration>]
ConfigurationItemType type =
ConfigurationItemType.getConfigurationItemType(splitLine[0]);
ConfigurationItemControl control =
ConfigurationItemControl.getConfigurationItemControl(splitLine[1]);
String name = splitLine[2];
Properties properties = new Properties();
if (splitLine.length>MIN_SPLIT_RESULTS) {
String[] args = Strings.splitArgumentString(splitLine[3]);
for (String arg : args) {
String[] kv = arg.split("=", 2);
if (kv.length==2) {
properties.put(kv[0].trim(), kv[1].trim());
}
}
}
return new ConfigurationItem(type,
control,
name,
properties);
} catch (IllegalArgumentException iae) {
throw new ParseException("Syntax violation for line \""+line+'"', iae);
}
}
}