package com.intrbiz.bergamot.compat.config.builder;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.TreeMap;
import org.apache.log4j.Logger;
import com.intrbiz.bergamot.compat.config.builder.object.ObjectBuilder;
import com.intrbiz.bergamot.compat.config.model.ConfigObject;
import com.intrbiz.bergamot.compat.config.model.NagiosHostCfg;
import com.intrbiz.bergamot.compat.config.model.NagiosCommandCfg;
import com.intrbiz.bergamot.compat.config.model.NagiosContactCfg;
import com.intrbiz.bergamot.compat.config.model.NagiosContactgroupCfg;
import com.intrbiz.bergamot.compat.config.model.NagiosHostgroupCfg;
import com.intrbiz.bergamot.compat.config.model.NagiosServicegroupCfg;
import com.intrbiz.bergamot.compat.config.model.NagiosTimeperiodCfg;
import com.intrbiz.bergamot.compat.config.model.NagiosServiceCfg;
import com.intrbiz.bergamot.compat.config.parser.NagiosConfigParser;
import com.intrbiz.bergamot.compat.config.parser.model.Directive;
import com.intrbiz.bergamot.compat.config.parser.model.IncludeDir;
import com.intrbiz.bergamot.compat.config.parser.model.IncludeFile;
import com.intrbiz.bergamot.compat.config.parser.model.ObjectDefinition;
/**
* Read Nagios config files / directories and construct a object model of the configuration. Resolving inheritance but not constructing a complete object model.
*
*/
public class NagiosConfigBuilder
{
private static final Map<String, ObjectBuilder> builders = new TreeMap<String, ObjectBuilder>();
private static final void registerObjectBuilder(ObjectBuilder builder)
{
builders.put(builder.getType(), builder);
}
static
{
registerObjectBuilder(ObjectBuilder.create(NagiosHostCfg.class));
registerObjectBuilder(ObjectBuilder.create(NagiosHostgroupCfg.class));
registerObjectBuilder(ObjectBuilder.create(NagiosServiceCfg.class));
registerObjectBuilder(ObjectBuilder.create(NagiosServicegroupCfg.class));
registerObjectBuilder(ObjectBuilder.create(NagiosContactCfg.class));
registerObjectBuilder(ObjectBuilder.create(NagiosContactgroupCfg.class));
registerObjectBuilder(ObjectBuilder.create(NagiosTimeperiodCfg.class));
registerObjectBuilder(ObjectBuilder.create(NagiosCommandCfg.class));
}
private Logger logger = Logger.getLogger(NagiosConfigBuilder.class);
private File basePath;
private Set<File> parsedFiles = new HashSet<File>();
private List<ConfigObject<?>> configObjects = new LinkedList<ConfigObject<?>>();
private List<NagiosHostCfg> hosts = new LinkedList<NagiosHostCfg>();
private List<NagiosHostgroupCfg> hostgroups = new LinkedList<NagiosHostgroupCfg>();
private List<NagiosServiceCfg> services = new LinkedList<NagiosServiceCfg>();
private List<NagiosServicegroupCfg> servicegroups = new LinkedList<NagiosServicegroupCfg>();
private List<NagiosTimeperiodCfg> timeperiods = new LinkedList<NagiosTimeperiodCfg>();
private List<NagiosCommandCfg> commands = new LinkedList<NagiosCommandCfg>();
private List<NagiosContactCfg> contacts = new LinkedList<NagiosContactCfg>();
private List<NagiosContactgroupCfg> contactgroups = new LinkedList<NagiosContactgroupCfg>();
private Map<TemplateKey, ConfigObject<?>> templates = new LinkedHashMap<TemplateKey, ConfigObject<?>>();
private Stack<File> toParse = new Stack<File>();
public NagiosConfigBuilder(File basePath)
{
super();
this.basePath = basePath;
}
// access to the parsed objects
public File getBasePath()
{
return basePath;
}
public Set<File> getParsedFiles()
{
return parsedFiles;
}
public List<NagiosHostgroupCfg> getHostgroups()
{
return hostgroups;
}
public List<NagiosServiceCfg> getServices()
{
return services;
}
public List<NagiosServicegroupCfg> getServicegroups()
{
return servicegroups;
}
public List<NagiosTimeperiodCfg> getTimeperiods()
{
return timeperiods;
}
public List<NagiosCommandCfg> getCommands()
{
return commands;
}
public List<NagiosContactCfg> getContacts()
{
return contacts;
}
public List<NagiosContactgroupCfg> getContactgroups()
{
return contactgroups;
}
public List<ConfigObject<?>> getConfigObjects()
{
return configObjects;
}
public List<NagiosHostCfg> getHosts()
{
return hosts;
}
public Map<TemplateKey, ConfigObject<?>> getTemplates()
{
return this.templates;
}
public ConfigObject<?> getTemplate(Class<? extends ConfigObject<?>> type, String name)
{
return this.templates.get(new TemplateKey(type, name));
}
//
public NagiosConfigBuilder includeFile(File file)
{
this.toParse.add(file);
return this;
}
public NagiosConfigBuilder includeDir(File dir)
{
Stack<File> work = new Stack<File>();
work.push(dir);
while (!work.isEmpty())
{
File f = work.pop();
if (f.isFile() && f.getName().endsWith(".cfg"))
{
this.toParse.push(f);
}
else if (f.isDirectory())
{
for (File c : f.listFiles())
{
work.push(c);
}
}
}
return this;
}
public NagiosConfigBuilder parse() throws IOException
{
// parse all files
while (!this.toParse.isEmpty())
{
this.parseConfigFile(this.toParse.pop());
}
// compute the inheritance
this.computeInheritanceGraph();
return this;
}
private void parseConfigFile(File configFile) throws IOException
{
if (!this.parsedFiles.contains(configFile))
{
this.parsedFiles.add(configFile);
try (NagiosConfigParser parser = new NagiosConfigParser(new FileReader(configFile)))
{
Directive d;
while ((d = parser.readNext()) != null)
{
logger.trace("Processing directive " + d);
// process object definitions
if (d instanceof ObjectDefinition)
{
ObjectDefinition def = (ObjectDefinition) d;
ObjectBuilder builder = builders.get(def.getType());
if (builder != null)
{
ConfigObject<?> co = builder.build(def);
co.setLoadedFrom(configFile);
this.configObjects.add(co);
// is it a template?
if (co.getName() != null)
{
logger.trace("Registering template " + co.getName() + " " + co);
this.templates.put(new TemplateKey(co.getClass(), co.getName()), co);
}
// object specific lists
if (co instanceof NagiosHostCfg)
{
this.hosts.add((NagiosHostCfg) co);
}
else if (co instanceof NagiosHostgroupCfg)
{
this.hostgroups.add((NagiosHostgroupCfg) co);
}
else if (co instanceof NagiosServiceCfg)
{
this.services.add((NagiosServiceCfg) co);
}
else if (co instanceof NagiosServicegroupCfg)
{
this.servicegroups.add((NagiosServicegroupCfg) co);
}
else if (co instanceof NagiosTimeperiodCfg)
{
this.timeperiods.add((NagiosTimeperiodCfg) co);
}
else if (co instanceof NagiosContactCfg)
{
this.contacts.add((NagiosContactCfg) co);
}
else if (co instanceof NagiosContactgroupCfg)
{
this.contactgroups.add((NagiosContactgroupCfg) co);
}
else if (co instanceof NagiosCommandCfg)
{
this.commands.add((NagiosCommandCfg) co);
}
}
else
{
logger.warn("Unsupported object " + def.getType() + " skipping");
}
}
else if (d instanceof IncludeFile)
{
IncludeFile incFl = (IncludeFile) d;
File toInclude = new File(this.basePath, incFl.getFile());
logger.info("Including file: " + toInclude.getAbsolutePath());
this.includeFile(toInclude);
}
else if (d instanceof IncludeDir)
{
IncludeDir incDr = (IncludeDir) d;
File toInclude = new File(this.basePath, incDr.getFile());
logger.info("Including directory: " + toInclude.getAbsolutePath());
this.includeDir(toInclude);
}
}
}
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private void computeInheritanceGraph()
{
for (ConfigObject<?> co : this.configObjects)
{
for (String inherits : co.getInherits())
{
logger.trace("The " + co + " inherits from " + inherits);
ConfigObject<?> inherited = this.templates.get(new TemplateKey(co.getClass(), inherits));
if (inherited != null)
{
((ConfigObject) co).addInheritedObject(inherited);
}
else
{
logger.error("Could not find inherited object '" + inherits + "'");
}
}
}
}
public static final class TemplateKey
{
private final Class<?> type;
private final String name;
public TemplateKey(Class<?> type, String name)
{
this.type = type;
this.name = name;
}
public Class<?> getType()
{
return type;
}
public String getName()
{
return this.name;
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
@Override
public boolean equals(Object obj)
{
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
TemplateKey other = (TemplateKey) obj;
if (name == null)
{
if (other.name != null) return false;
}
else if (!name.equals(other.name)) return false;
if (type == null)
{
if (other.type != null) return false;
}
else if (!type.equals(other.type)) return false;
return true;
}
}
}