[New] Initial commit of the XML Persistence implementation
This is a rudimentary implementation which works in that objects can be written to the DB, read back and helper methods like keySet, size are also implemented
This commit is contained in:
parent
b8ece51dbe
commit
4956925329
|
@ -4,3 +4,6 @@
|
|||
*.jar
|
||||
*.war
|
||||
*.ear
|
||||
|
||||
# Project files
|
||||
tmp
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
log4j.rootLogger = info, stdout, file
|
||||
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d %5p [%t] %C{1} %M - %m%n
|
||||
|
||||
log4j.appender.file=org.apache.log4j.RollingFileAppender
|
||||
log4j.appender.file.File=${user.dir}/logs/app.log
|
||||
log4j.appender.file.MaxFileSize=10000KB
|
||||
log4j.appender.file.MaxBackupIndex=0
|
||||
log4j.appender.file.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.file.layout.ConversionPattern=%d %5p [%t] %C{1} %M - %m%n
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright (c) 2010 - 2011
|
||||
*
|
||||
* Apixxo AG
|
||||
* Hauptgasse 25
|
||||
* 4600 Olten
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package ch.eitchnet.xmlpers;
|
||||
|
||||
import org.w3c.dom.DOMImplementation;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.ContentHandler;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
*/
|
||||
public interface XmlDao<T> {
|
||||
|
||||
/**
|
||||
* @param object
|
||||
* @return
|
||||
*/
|
||||
public String getType(T object);
|
||||
|
||||
/**
|
||||
* @param object
|
||||
* @return
|
||||
*/
|
||||
public String getSubType(T object);
|
||||
|
||||
/**
|
||||
* @param object
|
||||
* @return
|
||||
*/
|
||||
public String getId(T object);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param object
|
||||
* @param domImplementation
|
||||
* @return
|
||||
*/
|
||||
// XXX think about returning a document, instead of an element, or use document as input
|
||||
public Document serializeToDom(T object, DOMImplementation domImplementation);
|
||||
|
||||
/**
|
||||
* @param element
|
||||
* @return
|
||||
*/
|
||||
public T parseFromDom(Element element);
|
||||
|
||||
/**
|
||||
* @param object
|
||||
* @param contentHandler
|
||||
*/
|
||||
// XXX Use the XMLSerializer object for serializing to SAX...
|
||||
public void serializeToSax(T object, ContentHandler contentHandler);
|
||||
|
||||
// XXX parse from SAX is missing...
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright (c) 2010 - 2011
|
||||
*
|
||||
* Apixxo AG
|
||||
* Hauptgasse 25
|
||||
* 4600 Olten
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package ch.eitchnet.xmlpers;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
*/
|
||||
public interface XmlDaoFactory {
|
||||
|
||||
public <T> XmlDao<T> getDao(String type);
|
||||
}
|
|
@ -0,0 +1,428 @@
|
|||
package ch.eitchnet.xmlpers;
|
||||
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import ch.eitchnet.utils.helper.FileHelper;
|
||||
|
||||
import com.sun.org.apache.xml.internal.serialize.OutputFormat;
|
||||
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;
|
||||
|
||||
/**
|
||||
*@author Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
*/
|
||||
public class XmlFilePersister {
|
||||
|
||||
//
|
||||
private static final String XML_DEFAULT_ENCODING = "UTF-8";
|
||||
|
||||
private static final Logger logger = Logger.getLogger(XmlFilePersister.class);
|
||||
|
||||
private boolean verbose;
|
||||
private XmlPersistencePathBuilder xmlPathHelper;
|
||||
|
||||
/**
|
||||
* @param xmlPathHelper
|
||||
* @param verbose
|
||||
*/
|
||||
public XmlFilePersister(XmlPersistencePathBuilder xmlPathHelper, boolean verbose) {
|
||||
this.xmlPathHelper = xmlPathHelper;
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @param subType
|
||||
* @param id
|
||||
* @param document
|
||||
*/
|
||||
public void saveOrUpdate(String type, String subType, String id, Document document) {
|
||||
|
||||
File pathF;
|
||||
if (subType != null)
|
||||
pathF = xmlPathHelper.getPathF(type, subType, id);
|
||||
else
|
||||
pathF = xmlPathHelper.getPathF(type, id);
|
||||
|
||||
// if this is a new file, then check create parents, if the don't exist
|
||||
if (!pathF.exists()) {
|
||||
File parentFile = pathF.getParentFile();
|
||||
if (!parentFile.exists() && !parentFile.mkdirs()) {
|
||||
throw new XmlPersistenceExecption("Could not create path for " + type + " / " + subType + " / " + id
|
||||
+ " at " + pathF.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
logger.info("Persisting " + type + " / " + subType + " / " + id + " to " + pathF.getAbsolutePath() + "...");
|
||||
|
||||
BufferedOutputStream outStream = null;
|
||||
try {
|
||||
|
||||
outStream = new BufferedOutputStream(new FileOutputStream(pathF));
|
||||
|
||||
OutputFormat outputFormat = new OutputFormat("XML", XML_DEFAULT_ENCODING, true);
|
||||
outputFormat.setIndent(1);
|
||||
outputFormat.setIndenting(true);
|
||||
//of.setDoctype(null, null);
|
||||
|
||||
XMLSerializer serializer = new XMLSerializer(outStream, outputFormat);
|
||||
serializer.asDOMSerializer();
|
||||
serializer.serialize(document);
|
||||
outStream.flush();
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new XmlPersistenceExecption("Could not persist object " + type + " / " + subType + " / " + id
|
||||
+ " to " + pathF.getAbsolutePath(), e);
|
||||
} finally {
|
||||
if (outStream != null) {
|
||||
try {
|
||||
outStream.close();
|
||||
} catch (IOException e) {
|
||||
logger.error(e, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
logger.info("Done.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @param subType
|
||||
* @param id
|
||||
*/
|
||||
public void remove(String type, String subType, String id) {
|
||||
|
||||
File pathF;
|
||||
if (subType != null)
|
||||
pathF = xmlPathHelper.getPathF(type, subType, id);
|
||||
else
|
||||
pathF = xmlPathHelper.getPathF(type, id);
|
||||
|
||||
if (verbose)
|
||||
logger.info("Remove persistence file for " + type + " / " + subType + " / " + id + " from "
|
||||
+ pathF.getAbsolutePath() + "...");
|
||||
|
||||
if (!pathF.exists()) {
|
||||
logger.error("Persistence file for " + type + " / " + subType + " / " + id + " does not exist at "
|
||||
+ pathF.getAbsolutePath());
|
||||
} else if (!pathF.delete()) {
|
||||
throw new XmlPersistenceExecption("Could not delete persistence file for " + type + " / " + subType + " / "
|
||||
+ id + " at " + pathF.getAbsolutePath());
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
logger.info("Done.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @param subType
|
||||
*/
|
||||
public void removeAll(String type, String subType) {
|
||||
|
||||
File pathF;
|
||||
if (subType == null)
|
||||
pathF = xmlPathHelper.getPathF(type);
|
||||
else
|
||||
pathF = xmlPathHelper.getPathF(type, subType);
|
||||
|
||||
if (!pathF.exists()) {
|
||||
if (subType == null)
|
||||
logger.error("Path for " + type + " at " + pathF.getAbsolutePath()
|
||||
+ " does not exist, so removing not possible!");
|
||||
else
|
||||
logger.error("Path for " + type + " / " + subType + " at " + pathF.getAbsolutePath()
|
||||
+ " does not exist, so removing not possible!");
|
||||
|
||||
} else {
|
||||
|
||||
File[] filesToRemove = pathF.listFiles();
|
||||
boolean removed = FileHelper.deleteFiles(filesToRemove, verbose);
|
||||
|
||||
if (!removed) {
|
||||
if (subType == null)
|
||||
throw new XmlPersistenceExecption("Could not delete persistence files for " + type + " at "
|
||||
+ pathF.getAbsolutePath());
|
||||
|
||||
throw new XmlPersistenceExecption("Could not delete persistence files for " + type + " / " + subType
|
||||
+ " at " + pathF.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param type
|
||||
* @param subType
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Set<String> queryKeySet(String type, String subType) {
|
||||
|
||||
// if a sub type is required, then it's simple:
|
||||
if (subType != null) {
|
||||
|
||||
File pathF = this.xmlPathHelper.getPathF(type, subType);
|
||||
if (!pathF.exists()) {
|
||||
logger.error("Path for " + type + " / " + subType + " at " + pathF.getAbsolutePath()
|
||||
+ " does not exist, so no objects exist!");
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Set<String> keySet = new HashSet<String>();
|
||||
for (File f : pathF.listFiles()) {
|
||||
String name = f.getName();
|
||||
keySet.add(name.substring(0, name.length() - XmlPersistencePathBuilder.FILE_EXT.length()));
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
logger.info("Found " + keySet.size() + " elements for " + type + " / " + subType);
|
||||
|
||||
return keySet;
|
||||
}
|
||||
|
||||
// otherwise we need to iterate any existing subTypes and create a combined key set
|
||||
File pathF = this.xmlPathHelper.getPathF(type);
|
||||
if (!pathF.exists()) {
|
||||
logger.error("Path for " + type + " / " + subType + " at " + pathF.getAbsolutePath()
|
||||
+ " does not exist, so no objects exist!");
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Set<String> keySet = new HashSet<String>();
|
||||
|
||||
File[] subTypeFiles = pathF.listFiles();
|
||||
for (File subTypeFile : subTypeFiles) {
|
||||
|
||||
if (subTypeFile.isFile()) {
|
||||
keySet.add(xmlPathHelper.getId(subTypeFile.getName()));
|
||||
} else {
|
||||
|
||||
for (File f : subTypeFile.listFiles()) {
|
||||
keySet.add(xmlPathHelper.getId(f.getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
logger.info("Found " + keySet.size() + " elements for " + type);
|
||||
|
||||
return keySet;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param type
|
||||
* @param subType
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public long querySize(String type, String subType) {
|
||||
|
||||
// if a sub type is required, then it's simple:
|
||||
if (subType != null) {
|
||||
|
||||
File pathF = this.xmlPathHelper.getPathF(type, subType);
|
||||
if (!pathF.exists()) {
|
||||
logger.error("Path for " + type + " / " + subType + " at " + pathF.getAbsolutePath()
|
||||
+ " does not exist, so no objects exist!");
|
||||
return 0l;
|
||||
}
|
||||
|
||||
int length = pathF.listFiles().length;
|
||||
|
||||
if (verbose)
|
||||
logger.info("Found " + length + " elements for " + type + " / " + subType);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
// otherwise we need to iterate any existing sub types and
|
||||
// return the size of the combined collection
|
||||
|
||||
File pathF = this.xmlPathHelper.getPathF(type);
|
||||
if (!pathF.exists()) {
|
||||
logger.error("Path for " + type + " / " + subType + " at " + pathF.getAbsolutePath()
|
||||
+ " does not exist, so no objects exist!");
|
||||
return 0l;
|
||||
}
|
||||
|
||||
long numberOfFiles = 0l;
|
||||
|
||||
File[] subTypeFiles = pathF.listFiles();
|
||||
for (File subTypeFile : subTypeFiles) {
|
||||
|
||||
if (subTypeFile.isFile()) {
|
||||
numberOfFiles++;
|
||||
} else {
|
||||
numberOfFiles += subTypeFile.listFiles().length;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
logger.info("Found " + numberOfFiles + " elements for " + type);
|
||||
|
||||
return numberOfFiles;
|
||||
}
|
||||
|
||||
// XXX think about allowing paged loading...
|
||||
// /**
|
||||
// * @param type
|
||||
// * @param subType
|
||||
// * @param firstResult
|
||||
// * @param maxResults
|
||||
// *
|
||||
// * @return
|
||||
// */
|
||||
// public List<Element> queryFrom(String type, String subType, int firstResult, int maxResults) {
|
||||
//
|
||||
// File pathF = this.xmlPathHelper.getPathF(type, subType);
|
||||
// if (!pathF.exists()) {
|
||||
// logger.error("Path for " + type + " / " + subType + " at " + pathF.getAbsolutePath()
|
||||
// + " does not exist, so no objects exist!");
|
||||
// return Collections.emptyList();
|
||||
// }
|
||||
//
|
||||
// File[] listFiles = pathF.listFiles();
|
||||
// Arrays.sort(listFiles, new Comparator<File>() {
|
||||
//
|
||||
// @Override
|
||||
// public int compare(File file1, File file2) {
|
||||
// return file1.getName().compareTo(file2.getName());
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// // make sure positions are not illegal
|
||||
// int size = listFiles.length;
|
||||
// if (firstResult >= size)
|
||||
// return Collections.emptyList();
|
||||
//
|
||||
// if ((firstResult + maxResults) > size)
|
||||
// maxResults = size - firstResult;
|
||||
//
|
||||
// File[] result = Arrays.copyOfRange(listFiles, firstResult, firstResult + maxResults);
|
||||
//
|
||||
// List<T> list = new ArrayList<T>();
|
||||
// for (File f : result) {
|
||||
// list.add(loadObject(clazz, f));
|
||||
// }
|
||||
//
|
||||
// return list;
|
||||
// }
|
||||
|
||||
/**
|
||||
*
|
||||
* @param type
|
||||
* @param subType
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public List<Element> queryAll(String type, String subType, DocumentBuilder docBuilder) {
|
||||
|
||||
// if a sub type is required, then it's simple:
|
||||
if (subType != null) {
|
||||
|
||||
File pathF = this.xmlPathHelper.getPathF(type, subType);
|
||||
if (!pathF.exists()) {
|
||||
logger.error("Path for " + type + " / " + subType + " at " + pathF.getAbsolutePath()
|
||||
+ " does not exist, so no objects exist!");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Element> list = new ArrayList<Element>();
|
||||
for (File subTypeF : pathF.listFiles()) {
|
||||
list.add(parseFile(subTypeF, docBuilder));
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
logger.info("Loaded " + list.size() + " elements for " + type + " / " + subType);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
// otherwise we need to iterate any existing sub types and
|
||||
// return those elements as well
|
||||
|
||||
File pathF = this.xmlPathHelper.getPathF(type);
|
||||
if (!pathF.exists()) {
|
||||
logger.error("Path for " + type + " / " + subType + " at " + pathF.getAbsolutePath()
|
||||
+ " does not exist, so no objects exist!");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Element> list = new ArrayList<Element>();
|
||||
|
||||
File[] subTypeFiles = pathF.listFiles();
|
||||
for (File subTypeFile : subTypeFiles) {
|
||||
|
||||
if (subTypeFile.isFile()) {
|
||||
list.add(parseFile(subTypeFile, docBuilder));
|
||||
|
||||
} else {
|
||||
for (File subTypeF : subTypeFile.listFiles()) {
|
||||
list.add(parseFile(subTypeF, docBuilder));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
logger.info("Loaded " + list.size() + " elements for " + type);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param type
|
||||
* @param subType
|
||||
* @param id
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Element queryById(String type, String subType, String id, DocumentBuilder docBuilder) {
|
||||
|
||||
File pathF = this.xmlPathHelper.getPathF(type, subType, id);
|
||||
if (!pathF.exists()) {
|
||||
logger.error("Path for " + type + " / " + subType + " / " + id + " at " + pathF.getAbsolutePath()
|
||||
+ " does not exist, so object does not exist!");
|
||||
return null;
|
||||
}
|
||||
|
||||
return parseFile(pathF, docBuilder);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param subTypeF
|
||||
* @return
|
||||
*/
|
||||
private Element parseFile(File subTypeF, DocumentBuilder docBuilder) {
|
||||
try {
|
||||
|
||||
Document document = docBuilder.parse(subTypeF);
|
||||
return document.getDocumentElement();
|
||||
|
||||
} catch (SAXException e) {
|
||||
throw new XmlPersistenceExecption("Failed to parse file " + subTypeF.getAbsolutePath(), e);
|
||||
} catch (IOException e) {
|
||||
throw new XmlPersistenceExecption("Failed to read file " + subTypeF.getAbsolutePath(), e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package ch.eitchnet.xmlpers;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*/
|
||||
public class XmlPersistenceExecption extends RuntimeException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* @param message
|
||||
* @param cause
|
||||
*/
|
||||
public XmlPersistenceExecption(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param message
|
||||
*/
|
||||
public XmlPersistenceExecption(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package ch.eitchnet.xmlpers;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
import ch.eitchnet.utils.helper.SystemHelper;
|
||||
import ch.eitchnet.utils.objectfilter.ITransactionObject;
|
||||
import ch.eitchnet.utils.objectfilter.ObjectFilter;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
*/
|
||||
public class XmlPersistenceHandler {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static final String CONFIG_VERBOSE = "ch.eitchnet.xmlpers.config.verbose";
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static final String CONFIG_BASEPATH = "ch.eitchnet.xmlpers.config.basepath";
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static final String CONFIG_DAO_FACTORY_CLASS = "ch.eitchnet.xmlpers.config.daoFactoryClass";
|
||||
|
||||
protected static final Logger logger = Logger.getLogger(XmlPersistenceHandler.class);
|
||||
|
||||
protected boolean verbose;
|
||||
protected ThreadLocal<XmlPersistenceTransaction> xmlPersistenceTxThreadLocal;
|
||||
protected XmlFilePersister persister;
|
||||
protected XmlDaoFactory xmlDaoFactory;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void initialize() {
|
||||
|
||||
String basePath = SystemHelper.getProperty(XmlPersistenceHandler.class.getSimpleName(), CONFIG_BASEPATH, null);
|
||||
verbose = SystemHelper.getPropertyBool(XmlPersistenceHandler.class.getSimpleName(), CONFIG_VERBOSE,
|
||||
Boolean.FALSE).booleanValue();
|
||||
|
||||
// get class to use as transaction
|
||||
String daoFactoryClassName = SystemHelper.getProperty(XmlPersistenceHandler.class.getSimpleName(),
|
||||
CONFIG_DAO_FACTORY_CLASS, null);
|
||||
try {
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<XmlDaoFactory> xmlDaoFactoryClass = (Class<XmlDaoFactory>) Class.forName(daoFactoryClassName);
|
||||
|
||||
xmlDaoFactory = xmlDaoFactoryClass.newInstance();
|
||||
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new XmlPersistenceExecption("XmlDaoFactory class does not exist " + daoFactoryClassName, e);
|
||||
} catch (Exception e) {
|
||||
throw new XmlPersistenceExecption("Failed to load class " + daoFactoryClassName, e);
|
||||
}
|
||||
|
||||
XmlPersistencePathBuilder pathBuilder = new XmlPersistencePathBuilder(basePath);
|
||||
persister = new XmlFilePersister(pathBuilder, verbose);
|
||||
|
||||
// initialize the Thread local object which is used per transaction
|
||||
xmlPersistenceTxThreadLocal = new ThreadLocal<XmlPersistenceTransaction>();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public XmlPersistenceTransaction openTx() {
|
||||
|
||||
if (verbose)
|
||||
logger.info("Opening new transaction...");
|
||||
|
||||
// make sure no previous filter exists
|
||||
XmlPersistenceTransaction xmlPersistenceTx = this.xmlPersistenceTxThreadLocal.get();
|
||||
if (xmlPersistenceTx != null)
|
||||
throw new XmlPersistenceExecption("Previous transaction not properly closed");
|
||||
|
||||
// set a new persistence transaction object
|
||||
ObjectFilter<ITransactionObject> objectFilter = new ObjectFilter<ITransactionObject>();
|
||||
xmlPersistenceTx = new XmlPersistenceTransaction();
|
||||
xmlPersistenceTx.initialize(persister, xmlDaoFactory, objectFilter, verbose);
|
||||
|
||||
this.xmlPersistenceTxThreadLocal.set(xmlPersistenceTx);
|
||||
|
||||
return xmlPersistenceTx;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public XmlPersistenceTransaction getTx() {
|
||||
XmlPersistenceTransaction xmlPersistenceTx = this.xmlPersistenceTxThreadLocal.get();
|
||||
if (xmlPersistenceTx == null)
|
||||
throw new XmlPersistenceExecption("No transaction currently open!");
|
||||
|
||||
return xmlPersistenceTx;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public void commitTx() {
|
||||
|
||||
if (verbose)
|
||||
logger.info("Committing transaction...");
|
||||
|
||||
try {
|
||||
XmlPersistenceTransaction xmlPersistenceTx = this.xmlPersistenceTxThreadLocal.get();
|
||||
if (xmlPersistenceTx == null)
|
||||
throw new XmlPersistenceExecption("No transaction currently open!");
|
||||
|
||||
xmlPersistenceTx.commitTx();
|
||||
} finally {
|
||||
this.xmlPersistenceTxThreadLocal.set(null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
package ch.eitchnet.xmlpers;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
*/
|
||||
public class XmlPersistencePathBuilder {
|
||||
private static final Logger logger = Logger.getLogger(XmlPersistencePathBuilder.class);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static final String FILE_EXT = ".xml";
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static final int EXT_LENGTH = FILE_EXT.length();
|
||||
|
||||
private String basePath;
|
||||
|
||||
/**
|
||||
* @param basePath
|
||||
*/
|
||||
public XmlPersistencePathBuilder(String basePath) {
|
||||
File basePathF = new File(basePath);
|
||||
if (!basePathF.exists())
|
||||
throw new XmlPersistenceExecption("The database store path does not exist at "
|
||||
+ basePathF.getAbsolutePath());
|
||||
if (!basePathF.canWrite())
|
||||
throw new XmlPersistenceExecption("The database store path is not writeable at "
|
||||
+ basePathF.getAbsolutePath());
|
||||
|
||||
try {
|
||||
this.basePath = basePathF.getCanonicalPath();
|
||||
} catch (IOException e) {
|
||||
throw new XmlPersistenceExecption("Failed to build canonical path from " + basePath, e);
|
||||
}
|
||||
|
||||
logger.info("Using base path " + basePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public String getFilename(String id) {
|
||||
return id.concat(FILE_EXT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param filename
|
||||
* @return
|
||||
*/
|
||||
public String getId(String filename) {
|
||||
if (filename.charAt(filename.length() - EXT_LENGTH) != '.')
|
||||
throw new XmlPersistenceExecption("The filename does not have a . at index "
|
||||
+ (filename.length() - EXT_LENGTH));
|
||||
|
||||
return filename.substring(0, filename.length() - EXT_LENGTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public String getPath(String type) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(basePath);
|
||||
sb.append("/");
|
||||
sb.append(type);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public File getPathF(String type) {
|
||||
return new File(getPath(type));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @param subType
|
||||
* @return
|
||||
*/
|
||||
public String getPath(String type, String subType) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(basePath);
|
||||
sb.append("/");
|
||||
sb.append(type);
|
||||
sb.append("/");
|
||||
sb.append(subType);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @param subType
|
||||
* @return
|
||||
*/
|
||||
public File getPathF(String type, String subType) {
|
||||
return new File(getPath(type, subType));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @param subType
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public String getPath(String type, String subType, String id) {
|
||||
|
||||
StringBuilder sb = new StringBuilder(basePath);
|
||||
sb.append("/");
|
||||
sb.append(type);
|
||||
sb.append("/");
|
||||
sb.append(subType);
|
||||
sb.append("/");
|
||||
sb.append(getFilename(id));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @param subType
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public File getPathF(String type, String subType, String id) {
|
||||
return new File(getPath(type, subType, id));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,300 @@
|
|||
/*
|
||||
* Copyright (c) 2010 - 2011
|
||||
*
|
||||
* Apixxo AG
|
||||
* Hauptgasse 25
|
||||
* 4600 Olten
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package ch.eitchnet.xmlpers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.w3c.dom.DOMImplementation;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import ch.eitchnet.utils.objectfilter.ITransactionObject;
|
||||
import ch.eitchnet.utils.objectfilter.ObjectFilter;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
*/
|
||||
public class XmlPersistenceTransaction {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(XmlPersistenceTransaction.class);
|
||||
|
||||
private boolean verbose;
|
||||
private XmlFilePersister persister;
|
||||
private XmlDaoFactory xmlDaoFactory;
|
||||
private ObjectFilter<ITransactionObject> objectFilter;
|
||||
private DocumentBuilder docBuilder;
|
||||
private DOMImplementation domImplementation;
|
||||
|
||||
/**
|
||||
* @param persister
|
||||
* @param xmlDaoFactory
|
||||
* @param objectFilter
|
||||
*/
|
||||
public void initialize(XmlFilePersister persister, XmlDaoFactory xmlDaoFactory,
|
||||
ObjectFilter<ITransactionObject> objectFilter, boolean verbose) {
|
||||
this.persister = persister;
|
||||
this.xmlDaoFactory = xmlDaoFactory;
|
||||
this.objectFilter = objectFilter;
|
||||
this.verbose = verbose;
|
||||
}
|
||||
|
||||
private DocumentBuilder getDocBuilder() {
|
||||
if (docBuilder == null) {
|
||||
try {
|
||||
docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
|
||||
} catch (ParserConfigurationException e) {
|
||||
throw new XmlPersistenceExecption("Failed to load document builder: " + e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
return docBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
protected DOMImplementation getDomImpl() {
|
||||
if (domImplementation == null)
|
||||
domImplementation = getDocBuilder().getDOMImplementation();
|
||||
return domImplementation;
|
||||
}
|
||||
|
||||
/*
|
||||
* modifying methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param object
|
||||
*/
|
||||
public void add(ITransactionObject object) {
|
||||
this.objectFilter.add(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param objects
|
||||
*/
|
||||
public void addAll(List<ITransactionObject> objects) {
|
||||
this.objectFilter.addAll(objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object
|
||||
*/
|
||||
public void update(ITransactionObject object) {
|
||||
this.objectFilter.update(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param objects
|
||||
*/
|
||||
public void updateAll(List<ITransactionObject> objects) {
|
||||
this.objectFilter.updateAll(objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object
|
||||
*/
|
||||
public void remove(ITransactionObject object) {
|
||||
this.objectFilter.remove(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param objects
|
||||
*/
|
||||
public void removeAll(List<ITransactionObject> objects) {
|
||||
this.objectFilter.removeAll(objects);
|
||||
}
|
||||
|
||||
/*
|
||||
* querying methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public Set<String> queryKeySet(String type) {
|
||||
return queryKeySet(type, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @param subType
|
||||
* @return
|
||||
*/
|
||||
public Set<String> queryKeySet(String type, String subType) {
|
||||
return this.persister.queryKeySet(type, subType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public long querySize(String type) {
|
||||
return querySize(type, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @param subType
|
||||
* @return
|
||||
*/
|
||||
public long querySize(String type, String subType) {
|
||||
return this.persister.querySize(type, subType);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public <T> List<T> queryAll(String type) {
|
||||
return queryAll(type, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @param subType
|
||||
* @return
|
||||
*/
|
||||
public <T> List<T> queryAll(String type, String subType) {
|
||||
|
||||
// XXX ok, this is very ugly, but for starters it will have to do
|
||||
XmlDao<Object> dao = xmlDaoFactory.getDao(type);
|
||||
|
||||
List<Element> elements = this.persister.queryAll(type, subType, getDocBuilder());
|
||||
List<T> objects = new ArrayList<T>(elements.size());
|
||||
|
||||
for (Element element : elements) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T object = (T) dao.parseFromDom(element);
|
||||
objects.add(object);
|
||||
}
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public <T> T queryById(String type, String id) {
|
||||
return queryById(type, null, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* @param subType
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public <T> T queryById(String type, String subType, String id) {
|
||||
|
||||
XmlDao<Object> dao = xmlDaoFactory.getDao(type);
|
||||
|
||||
Element element = this.persister.queryById(type, subType, id, getDocBuilder());
|
||||
if (element == null)
|
||||
throw new XmlPersistenceExecption("No object exists for " + type + " / " + subType + " / " + id);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
T object = (T) dao.parseFromDom(element);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
/*
|
||||
* committing
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void commitTx() {
|
||||
|
||||
if (verbose)
|
||||
logger.info("Committing...");
|
||||
|
||||
Set<String> keySet = objectFilter.keySet();
|
||||
if (keySet.isEmpty())
|
||||
return;
|
||||
|
||||
for (String key : keySet) {
|
||||
|
||||
XmlDao<Object> dao = xmlDaoFactory.getDao(key);
|
||||
|
||||
List<ITransactionObject> removed = objectFilter.getRemoved(key);
|
||||
if (removed.isEmpty()) {
|
||||
if (verbose)
|
||||
logger.info("No objects removed in this tx.");
|
||||
} else {
|
||||
if (verbose)
|
||||
logger.info(removed.size() + " objects removed in this tx.");
|
||||
|
||||
for (ITransactionObject object : removed) {
|
||||
|
||||
String type = dao.getType(object);
|
||||
String subType = dao.getSubType(object);
|
||||
String id = dao.getId(object);
|
||||
|
||||
persister.remove(type, subType, id);
|
||||
}
|
||||
}
|
||||
|
||||
List<ITransactionObject> updated = objectFilter.getUpdated(key);
|
||||
if (updated.isEmpty()) {
|
||||
if (verbose)
|
||||
logger.info("No objects updated in this tx.");
|
||||
} else {
|
||||
if (verbose)
|
||||
logger.info(updated.size() + " objects updated in this tx.");
|
||||
|
||||
for (ITransactionObject object : updated) {
|
||||
|
||||
String type = dao.getType(object);
|
||||
String subType = dao.getSubType(object);
|
||||
String id = dao.getId(object);
|
||||
|
||||
Document asDom = dao.serializeToDom(object, getDomImpl());
|
||||
persister.saveOrUpdate(type, subType, id, asDom);
|
||||
}
|
||||
}
|
||||
|
||||
List<ITransactionObject> added = objectFilter.getAdded(key);
|
||||
if (added.isEmpty()) {
|
||||
if (verbose)
|
||||
logger.info("No objects added in this tx.");
|
||||
} else {
|
||||
if (verbose)
|
||||
logger.info(updated.size() + " objects added in this tx.");
|
||||
|
||||
for (ITransactionObject object : added) {
|
||||
|
||||
String type = dao.getType(object);
|
||||
String subType = dao.getSubType(object);
|
||||
String id = dao.getId(object);
|
||||
|
||||
Document asDom = dao.serializeToDom(object, getDomImpl());
|
||||
persister.saveOrUpdate(type, subType, id, asDom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
objectFilter.clearCache();
|
||||
logger.info("Completed TX");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,311 @@
|
|||
/*
|
||||
* Copyright (c) 2010
|
||||
*
|
||||
* Apixxo AG
|
||||
* Hauptgasse 25
|
||||
* 4600 Olten
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
package ch.eitchnet.featherlite.plugin.xmlpers.test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.log4j.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import ch.eitchnet.featherlite.plugin.xmlpers.test.impl.MyClass;
|
||||
import ch.eitchnet.featherlite.plugin.xmlpers.test.impl.MyDaoFactory;
|
||||
import ch.eitchnet.utils.helper.Log4jConfigurator;
|
||||
import ch.eitchnet.utils.objectfilter.ITransactionObject;
|
||||
import ch.eitchnet.xmlpers.XmlPersistenceExecption;
|
||||
import ch.eitchnet.xmlpers.XmlPersistenceHandler;
|
||||
import ch.eitchnet.xmlpers.XmlPersistenceTransaction;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
*/
|
||||
public class XmlPersistenceTest {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(XmlPersistenceTest.class.getName());
|
||||
|
||||
private static XmlPersistenceHandler persistenceHandler;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
* if something goes wrong
|
||||
*/
|
||||
@BeforeClass
|
||||
public static void init() throws Exception {
|
||||
|
||||
try {
|
||||
// set up log4j
|
||||
Log4jConfigurator.configure();
|
||||
|
||||
String userDir = System.getProperty("user.dir");
|
||||
String basePath = userDir + "/tmp/testdb";
|
||||
File basePathF = new File(basePath);
|
||||
if (!basePathF.exists() && !basePathF.mkdirs())
|
||||
Assert.fail("Could not create temporaray database store in " + basePathF.getAbsolutePath());
|
||||
|
||||
System.setProperty(XmlPersistenceHandler.CONFIG_BASEPATH, "tmp/testdb");
|
||||
System.setProperty(XmlPersistenceHandler.CONFIG_VERBOSE, "true");
|
||||
System.setProperty(XmlPersistenceHandler.CONFIG_DAO_FACTORY_CLASS, MyDaoFactory.class.getName());
|
||||
|
||||
persistenceHandler = new XmlPersistenceHandler();
|
||||
persistenceHandler.initialize();
|
||||
|
||||
logger.info("Initialized persistence handler.");
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error(e, e);
|
||||
|
||||
throw new RuntimeException("Initialization failed: " + e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testCreate() {
|
||||
|
||||
try {
|
||||
logger.info("Trying to create...");
|
||||
|
||||
// new instance
|
||||
MyClass myClass = new MyClass("@id", "@name", "@subtype");
|
||||
|
||||
// persist instance
|
||||
XmlPersistenceTransaction tx = persistenceHandler.openTx();
|
||||
tx.add(myClass);
|
||||
persistenceHandler.commitTx();
|
||||
|
||||
logger.info("Done creating.");
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error(e, e);
|
||||
Assert.fail("Failed: " + e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testRead() {
|
||||
|
||||
try {
|
||||
logger.info("Trying to read...");
|
||||
|
||||
// query MyClass with id @id
|
||||
XmlPersistenceTransaction tx = persistenceHandler.openTx();
|
||||
MyClass myClass = tx.queryById(MyClass.class.getName(), "@subtype", "@id");
|
||||
logger.info("Found MyClass: " + myClass);
|
||||
persistenceHandler.commitTx();
|
||||
|
||||
logger.info("Done reading.");
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error(e, e);
|
||||
Assert.fail("Failed: " + e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testUpdate() {
|
||||
|
||||
try {
|
||||
logger.info("Trying to update an object...");
|
||||
|
||||
// query the instance
|
||||
XmlPersistenceTransaction tx = persistenceHandler.openTx();
|
||||
MyClass myClass = tx.queryById(MyClass.class.getName(), "@subtype", "@id");
|
||||
logger.info("Found MyClass: " + myClass);
|
||||
|
||||
// modify the instance
|
||||
myClass.setName("@name_modified");
|
||||
|
||||
// update the instance
|
||||
tx.update(myClass);
|
||||
persistenceHandler.commitTx();
|
||||
|
||||
logger.info("Done updating.");
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error(e, e);
|
||||
Assert.fail("Failed: " + e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testRemove() {
|
||||
|
||||
logger.info("Trying to remove...");
|
||||
|
||||
// query the instance
|
||||
XmlPersistenceTransaction tx = persistenceHandler.openTx();
|
||||
MyClass myClass = tx.queryById(MyClass.class.getName(), "@subtype", "@id");
|
||||
logger.info("Found MyClass: " + myClass);
|
||||
|
||||
tx.remove(myClass);
|
||||
persistenceHandler.commitTx();
|
||||
|
||||
logger.info("Done removing.");
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Test(expected = XmlPersistenceExecption.class)
|
||||
public void testQueryFail() {
|
||||
|
||||
try {
|
||||
logger.info("Trying to query removed object...");
|
||||
XmlPersistenceTransaction tx = persistenceHandler.openTx();
|
||||
MyClass myClass = tx.queryById(MyClass.class.getName(), "@subtype", "@id");
|
||||
logger.info("Found MyClass: " + myClass);
|
||||
logger.info("Done querying removed object");
|
||||
} finally {
|
||||
persistenceHandler.commitTx();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testReCreate() {
|
||||
|
||||
try {
|
||||
logger.info("Trying to recreate...");
|
||||
|
||||
// new instance
|
||||
MyClass myClass = new MyClass("@id", "@name", "@subtype");
|
||||
|
||||
// persist instance
|
||||
XmlPersistenceTransaction tx = persistenceHandler.openTx();
|
||||
tx.add(myClass);
|
||||
persistenceHandler.commitTx();
|
||||
|
||||
logger.info("Done creating.");
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error(e, e);
|
||||
Assert.fail("Failed: " + e.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// *
|
||||
// */
|
||||
// @Test
|
||||
// public void testQueryFromTo() {
|
||||
// Assert.fail("Not yet implemented");
|
||||
// }
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testQueryAll() {
|
||||
|
||||
try {
|
||||
|
||||
logger.info("Trying to query all...");
|
||||
|
||||
// query all
|
||||
XmlPersistenceTransaction tx = persistenceHandler.openTx();
|
||||
List<Object> list = tx.queryAll(MyClass.class.getName());
|
||||
Assert.assertTrue("Expected only one object, found " + list.size(), list.size() == 1);
|
||||
|
||||
// also with subtype
|
||||
list = tx.queryAll(MyClass.class.getName(), "@subtype");
|
||||
Assert.assertTrue("Expected only one object, found " + list.size(), list.size() == 1);
|
||||
|
||||
// and now something useless
|
||||
list = tx.queryAll(MyClass.class.getName(), "@inexistant");
|
||||
Assert.assertTrue("Expected no objects, found " + list.size(), list.size() == 0);
|
||||
|
||||
logger.info("Done querying.");
|
||||
|
||||
} finally {
|
||||
persistenceHandler.commitTx();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testKeySet() {
|
||||
|
||||
try {
|
||||
XmlPersistenceTransaction tx = persistenceHandler.openTx();
|
||||
|
||||
Set<String> keySet = tx.queryKeySet(MyClass.class.getName());
|
||||
Assert.assertTrue("Expected one key, found " + keySet.size(), keySet.size() == 1);
|
||||
|
||||
// also with subtype
|
||||
keySet = tx.queryKeySet(MyClass.class.getName(), "@subtype");
|
||||
Assert.assertTrue("Expected one key, found " + keySet.size(), keySet.size() == 1);
|
||||
|
||||
// and now something useless
|
||||
keySet = tx.queryKeySet(MyClass.class.getName(), "@inexistant");
|
||||
Assert.assertTrue("Expected no keys, found " + keySet, keySet.size() == 0);
|
||||
|
||||
} finally {
|
||||
persistenceHandler.commitTx();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testRemoveAll() {
|
||||
|
||||
try {
|
||||
XmlPersistenceTransaction tx = persistenceHandler.openTx();
|
||||
|
||||
List<ITransactionObject> objects = tx.queryAll(MyClass.class.getName(), "@subType");
|
||||
tx.removeAll(objects);
|
||||
|
||||
} finally {
|
||||
persistenceHandler.commitTx();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@Test
|
||||
public void testSize() {
|
||||
|
||||
try {
|
||||
XmlPersistenceTransaction tx = persistenceHandler.openTx();
|
||||
|
||||
long size = tx.querySize(MyClass.class.getName(), "@subType");
|
||||
Assert.assertTrue("Expected size = 0, found: " + size, size == 0);
|
||||
|
||||
} finally {
|
||||
persistenceHandler.commitTx();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2010 - 2011
|
||||
*
|
||||
* Apixxo AG
|
||||
* Hauptgasse 25
|
||||
* 4600 Olten
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package ch.eitchnet.featherlite.plugin.xmlpers.test.impl;
|
||||
|
||||
import ch.eitchnet.utils.objectfilter.ITransactionObject;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
*/
|
||||
public class MyClass implements ITransactionObject {
|
||||
|
||||
private long txId;
|
||||
private String id;
|
||||
private String name;
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param name
|
||||
* @param type
|
||||
*/
|
||||
public MyClass(String id, String name, String type) {
|
||||
super();
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* the id to set
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name
|
||||
* the name to set
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the type
|
||||
*/
|
||||
public String getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type
|
||||
* the type to set
|
||||
*/
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ch.eitchnet.utils.objectfilter.ITransactionObject#setTransactionID(long)
|
||||
*/
|
||||
@Override
|
||||
public void setTransactionID(long id) {
|
||||
this.txId = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ch.eitchnet.utils.objectfilter.ITransactionObject#getTransactionID()
|
||||
*/
|
||||
@Override
|
||||
public long getTransactionID() {
|
||||
return this.txId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ch.eitchnet.utils.objectfilter.ITransactionObject#resetTransactionID()
|
||||
*/
|
||||
@Override
|
||||
public void resetTransactionID() {
|
||||
this.txId = ITransactionObject.UNSET;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* Copyright (c) 2010 - 2011
|
||||
*
|
||||
* Apixxo AG
|
||||
* Hauptgasse 25
|
||||
* 4600 Olten
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package ch.eitchnet.featherlite.plugin.xmlpers.test.impl;
|
||||
|
||||
import org.w3c.dom.DOMImplementation;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Text;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.AttributesImpl;
|
||||
|
||||
import ch.eitchnet.xmlpers.XmlDao;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
*/
|
||||
public class MyClassDao implements XmlDao<MyClass> {
|
||||
|
||||
/**
|
||||
* @see ch.eitchnet.xmlpers.XmlDao#getType(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String getType(MyClass object) {
|
||||
return MyClass.class.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ch.eitchnet.xmlpers.XmlDao#getSubType(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String getSubType(MyClass object) {
|
||||
return object.getType();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ch.eitchnet.xmlpers.XmlDao#getId(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String getId(MyClass object) {
|
||||
return object.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ch.eitchnet.xmlpers.XmlDao#serializeToDom(java.lang.Object, org.w3c.dom.DOMImplementation)
|
||||
*/
|
||||
@Override
|
||||
public Document serializeToDom(MyClass object, DOMImplementation domImplementation) {
|
||||
|
||||
Document document = domImplementation.createDocument(null, null, null);
|
||||
Element element = document.createElement("MyClass");
|
||||
document.appendChild(element);
|
||||
|
||||
element.setAttribute("id", object.getId());
|
||||
element.setAttribute("type", object.getType());
|
||||
|
||||
Element nameElement = document.createElement("Name");
|
||||
element.appendChild(nameElement);
|
||||
Text textNode = document.createTextNode(object.getName());
|
||||
nameElement.appendChild(textNode);
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ch.eitchnet.xmlpers.XmlDao#parseFromDom(org.w3c.dom.Element)
|
||||
*/
|
||||
@Override
|
||||
public MyClass parseFromDom(Element element) {
|
||||
|
||||
String id = element.getAttribute("id");
|
||||
String type = element.getAttribute("type");
|
||||
Element nameElement = (Element) element.getElementsByTagName("Name").item(0);
|
||||
String name = nameElement.getTextContent();
|
||||
|
||||
MyClass myClass = new MyClass(id, name, type);
|
||||
|
||||
return myClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see ch.eitchnet.xmlpers.XmlDao#serializeToSax(java.lang.Object, org.xml.sax.ContentHandler)
|
||||
*/
|
||||
@Override
|
||||
public void serializeToSax(MyClass object, ContentHandler contentHandler) {
|
||||
|
||||
try {
|
||||
contentHandler.startDocument();
|
||||
|
||||
// MyClass element / root
|
||||
{
|
||||
AttributesImpl atts = new AttributesImpl();
|
||||
atts.addAttribute("", "", "id", "", object.getId());
|
||||
atts.addAttribute("", "", "type", "", object.getType());
|
||||
contentHandler.startElement("", "", "MyClass", atts);
|
||||
|
||||
// name element
|
||||
{
|
||||
contentHandler.startElement("", "", "Name", null);
|
||||
char[] nameArr = object.getName().toCharArray();
|
||||
contentHandler.characters(nameArr, 0, nameArr.length);
|
||||
contentHandler.endElement("", "", "name");
|
||||
}
|
||||
|
||||
// MyClass end
|
||||
contentHandler.endElement("", "", "MyClass");
|
||||
}
|
||||
|
||||
// end document
|
||||
contentHandler.endDocument();
|
||||
|
||||
} catch (SAXException e) {
|
||||
throw new RuntimeException("Failed to serialize " + object + " to SAX", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright (c) 2010 - 2011
|
||||
*
|
||||
* Apixxo AG
|
||||
* Hauptgasse 25
|
||||
* 4600 Olten
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
package ch.eitchnet.featherlite.plugin.xmlpers.test.impl;
|
||||
|
||||
import ch.eitchnet.xmlpers.XmlDao;
|
||||
import ch.eitchnet.xmlpers.XmlDaoFactory;
|
||||
|
||||
/**
|
||||
* @author Robert von Burg <eitch@eitchnet.ch>
|
||||
*
|
||||
*/
|
||||
public class MyDaoFactory implements XmlDaoFactory {
|
||||
|
||||
/**
|
||||
* @see ch.eitchnet.xmlpers.XmlDaoFactory#getDao(java.lang.String)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T> XmlDao<T> getDao(String type) {
|
||||
if (type.equals(MyClass.class.getName()))
|
||||
return (XmlDao<T>) new MyClassDao();
|
||||
|
||||
throw new RuntimeException("Class with type " + type + " is unknown!");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue