/*
* Copyright (C) 2006 http://www.chaidb.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
package org.chaidb.db.helper;
import org.apache.log4j.Logger;
import org.chaidb.db.exception.ChaiDBException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
/**
* User: Kurt Sung (kurt@chaidb.com)
* Date: 2003-11-27
* Time: 11:55:35
*/
public abstract class AbstractControlFile {
protected String controlFilePath;
private boolean writeToTmp = false;
public static final String XML_HEADER = "<?xml version=\"1.0\" ?>";
public static final String NEW_LINE = "\n";
private static final Logger logger = Logger.getLogger(AbstractControlFile.class);
protected AbstractControlFile(String home, String filename) {
controlFilePath = home + File.separator + filename;
init();
}
protected abstract void init();
/**
* This method can write data to a tmp file, when your all operations
* successly you should call commit to commit the changes, or call rollback
* to discard changes if any operation failed.
*/
public void writeToDisk() {
try {
SafeUpdateUtils.writeToDisk(this, controlFilePath, writeToTmp);
} catch (IOException e) {
logger.error(e);
}
}
/**
* when you finish all operations you should call this method to commit
* the changes. This method rename the tmp file to its true name and
* delete the old one.
*
* @throws ChaiDBException if can't rename tmp file
*/
protected synchronized void commit() throws ChaiDBException {
if (writeToTmp) {
SafeUpdateUtils.commitWrite(controlFilePath);
}
}
/**
* if any operation faild during the process, you should call rollback
* to discard the changes to the file.
*/
protected synchronized void rollback() {
if (writeToTmp) {
SafeUpdateUtils.rollbackWrite(controlFilePath);
}
}
public String getControlFilePath() {
return controlFilePath;
}
/**
* To load a control file from disk and parse it, you should implement your
* own nodevisitor to get expected node
*
* @return true if successful
*/
protected abstract boolean readFromDisk();
public abstract String toString();
protected boolean fileExists() {
File f = new File(controlFilePath);
return !(!f.exists() || f.length() == 0);
}
/**
* Get DOM Document from controlFilePath
*
* @return Document if the file exists and is well-format. null if not.
*/
protected Document getDocument() {
if (!fileExists()) {
return null;
}
Document doc;
try {
InputSource input = new InputSource(new FileInputStream(controlFilePath));
doc = SafeUpdateUtils.parse(input);
} catch (Exception e) {
logger.error(e);
doc = null;
}
return doc;
}
/**
* readState from Control file.
*
* @param rootTag parents tag to find the node.
* @param visitor
* @return false if can't get root tag.
*/
protected boolean readState(String rootTag, NodeVisitor visitor) {
Document doc = getDocument();
if (doc == null) {
return false;
}
NodeList nodeList = doc.getElementsByTagName(rootTag);
if (nodeList.getLength() == 0) {
return false;
}
nodeList = nodeList.item(0).getChildNodes();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
visitor.readFromNode(node);
}
}
return true;
}
public abstract static class NodeVisitor {
protected abstract boolean readFromNode(Node node);
}
}