NetworkDNS/src-wip/org/handwerkszeug/dns/conf/masterfile/MasterFileParser.java

230 lines
5.6 KiB
Java
Executable File

package org.handwerkszeug.dns.conf.masterfile;
import static org.handwerkszeug.util.Validation.notNull;
import java.io.File;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.handwerkszeug.dns.DNSClass;
import org.handwerkszeug.dns.Name;
import org.handwerkszeug.dns.RRType;
import org.handwerkszeug.dns.conf.MasterDataHandler;
import org.handwerkszeug.dns.conf.MasterDataResource;
import org.handwerkszeug.dns.conf.ServerConfiguration;
import org.handwerkszeug.dns.conf.masterfile.Partition.PartitionType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import werkzeugkasten.common.util.FileUtil;
/**
* RFC1035 5. MASTER FILES
*
* @author taichi
*/
public class MasterFileParser implements MasterDataResource {
static final Logger LOG = LoggerFactory.getLogger(MasterFileParser.class);
static final int MAX_INCLUDE_DEPTH = 10; // TODO from configuration ?
final Partitioner partitioner;
ServerConfiguration conf;
Name origin;
long ttl;
IncludeContext includeContext;
int currentLine = 1; // TODO for error messages.
class IncludeContext {
int includeDepth = 0;
Set<String> includedPath = new HashSet<String>();
}
public MasterFileParser(String origin, File master) {
this(origin, FileUtil.open(master));
this.includeContext.includedPath.add(master.getAbsolutePath());
}
public MasterFileParser(String origin, InputStream in) {
this.includeContext = new IncludeContext();
this.partitioner = new Partitioner(in);
this.origin = new Name(origin);
}
protected MasterFileParser(Name origin, File file, IncludeContext context) {
this.includeContext = context;
this.partitioner = new Partitioner(FileUtil.open(file));
this.origin = origin;
}
@Override
public void initialize(ServerConfiguration conf) {
notNull(conf, "conf");
if (LOG.isInfoEnabled()) {
LOG.info("initialize");
}
this.conf = conf;
}
@Override
public void dispose() {
if (LOG.isInfoEnabled()) {
LOG.info("dispose");
}
this.partitioner.close();
}
@Override
public void process(MasterDataHandler handler) {
notNull(handler, "processor");
try {
handler.initialize(this.conf);
} catch (RuntimeException e) {
handler.rollback();
throw e;
} finally {
handler.dispose();
}
}
protected void internalProcess(MasterDataHandler handler) {
Name currentName = null;
long currentTTL = 0L;
DNSClass currentClass = DNSClass.IN;
while (true) {
Iterator<Partition> line = readLine();
if (line.hasNext()) {
break;
}
Partition first = line.next();
if (isDirective(first)) {
String directive = first.getString().toUpperCase();
if ("$INCLUDE".equals(directive)) {
String path = null;
Name newOrigin = this.origin;
if (line.hasNext()) {
path = line.next().getString();
} else {
// TODO parser error
throw new IllegalStateException();
}
if (line.hasNext()) {
String s = line.next().getString();
newOrigin = new Name(s);
}
processInclude(path, newOrigin, handler);
} else if ("$ORIGIN".equals(directive)) {
if (line.hasNext()) {
String origin = line.next().getString();
this.origin = new Name(origin);
}
} else if ("$TTL".equals(directive)) {
if (line.hasNext()) {
String num = line.next().getString();
if (isTTL(num)) {
this.ttl = Long.parseLong(num);
}
}
} else {
LOG.warn("unknown directive {}", directive);
}
continue;
}
if (first.type().equals(PartitionType.Default)) {
currentName = new Name(first.getString());
}
if (line.hasNext()) {
String second = line.next().getString();
// ttl class type
// ttl type
// class ttl type
// class type
// type
if (isTTL(second)) {
currentTTL = Long.parseLong(second);
if (line.hasNext()) {
String third = line.next().getString();
if (isDNSClass(third)) {
} else if (isRRType(third)) {
} else {
// TODO parser error
}
} else {
// TODO parser error
}
} else if (isDNSClass(second)) {
currentClass = DNSClass.valueOf(second.toUpperCase());
} else if (isRRType(second)) {
RRType type = RRType.valueOf(second.toUpperCase());
} else {
// TODO parser error.
}
} else {
// TODO parser error
}
}
}
protected void processInclude(String path, Name origin,
MasterDataHandler handler) {
if (MAX_INCLUDE_DEPTH < ++this.includeContext.includeDepth) {
// TODO error message.
throw new IllegalStateException();
}
File file = new File(path);
if (this.includeContext.includedPath.add(file.getAbsolutePath()) == false) {
// TODO error message. cyclic include.
throw new IllegalStateException();
}
MasterFileParser newone = new MasterFileParser(origin, file,
this.includeContext);
try {
newone.initialize(this.conf);
newone.process(handler);
} finally {
newone.dispose();
}
}
protected Iterator<Partition> readLine() {
// 改行のみ 空白のみ コメントのみ は読み飛ばす。
// 先頭のWhitespaceは読み飛ばさないが、他のWhitespaceは読み飛ばす。
return null;
}
protected boolean isDirective(Partition p) {
byte[] b = p.division();
return b != null && 0 < b.length && b[0] == '$';
}
protected boolean isWhitespace(Partition p) {
return PartitionType.Whitespace.equals(p.type());
}
protected boolean isTTL(String p) {
return false;
}
protected boolean isDNSClass(String p) {
DNSClass dc = DNSClass.find(p);
return dc != null;
}
protected boolean isRRType(String p) {
return false;
}
}