Permalink
Browse files

code cleanup and additional documentation

Signed-off-by: gburgett <gordon.burgett@gmail.com>
  • Loading branch information...
1 parent 83c1661 commit 2acd0e77d4b6ed140de97ad6f238074cb5afe126 @gburgett committed Jan 27, 2013
Showing with 672 additions and 504 deletions.
  1. +60 −1 Examples.md
  2. +8 −6 README.md
  3. +1 −1 java/XFlat/src/org/gburgett/xflat/Cursor.java
  4. +4 −2 java/XFlat/src/org/gburgett/xflat/Database.java
  5. +66 −50 java/XFlat/src/org/gburgett/xflat/DatabaseConfig.java
  6. +2 −2 java/XFlat/src/org/gburgett/xflat/DuplicateKeyException.java
  7. +3 −2 java/XFlat/src/org/gburgett/xflat/EngineStateException.java
  8. +40 −0 java/XFlat/src/org/gburgett/xflat/Id.java
  9. +2 −2 java/XFlat/src/org/gburgett/xflat/KeyNotFoundException.java
  10. +12 −11 java/XFlat/src/org/gburgett/xflat/Table.java
  11. +9 −10 java/XFlat/src/org/gburgett/xflat/TableConfig.java
  12. +4 −4 java/XFlat/src/org/gburgett/xflat/{XflatException.java → XFlatException.java}
  13. +12 −4 java/XFlat/src/org/gburgett/xflat/convert/converters/JAXBPojoConverter.java
  14. +11 −0 java/XFlat/src/org/gburgett/xflat/convert/package-info.java
  15. +22 −22 java/XFlat/src/org/gburgett/xflat/db/ConvertingTable.java
  16. +13 −13 java/XFlat/src/org/gburgett/xflat/db/ElementTable.java
  17. +6 −6 java/XFlat/src/org/gburgett/xflat/db/Engine.java
  18. +2 −2 java/XFlat/src/org/gburgett/xflat/db/EngineBase.java
  19. +1 −1 java/XFlat/src/org/gburgett/xflat/db/EngineFactory.java
  20. +7 −14 java/XFlat/src/org/gburgett/xflat/db/EngineTransactionManager.java
  21. +63 −6 java/XFlat/src/org/gburgett/xflat/db/IdAccessor.java
  22. +0 −1 java/XFlat/src/org/gburgett/xflat/db/IdGenerator.java
  23. +7 −7 java/XFlat/src/org/gburgett/xflat/db/ShardedEngineBase.java
  24. +18 −5 java/XFlat/src/org/gburgett/xflat/db/TableMetadata.java
  25. +10 −10 java/XFlat/src/org/gburgett/xflat/db/TableMetadataFactory.java
  26. +2 −2 java/XFlat/src/org/gburgett/xflat/db/TimestampIdGenerator.java
  27. +6 −6 java/XFlat/src/org/gburgett/xflat/db/XFlatDatabase.java
  28. +14 −0 java/XFlat/src/org/gburgett/xflat/db/package-info.java
  29. +15 −15 java/XFlat/src/org/gburgett/xflat/engine/CachedDocumentEngine.java
  30. +5 −6 java/XFlat/src/org/gburgett/xflat/engine/DefaultEngineFactory.java
  31. +15 −15 java/XFlat/src/org/gburgett/xflat/engine/IdShardedEngine.java
  32. +13 −0 java/XFlat/src/org/gburgett/xflat/engine/package-info.java
  33. +11 −0 java/XFlat/src/org/gburgett/xflat/package-info.java
  34. +3 −3 java/XFlat/src/org/gburgett/xflat/query/InvalidQueryException.java
  35. +35 −37 java/XFlat/src/org/gburgett/xflat/query/{XpathQuery.java → XPathQuery.java}
  36. +8 −8 java/XFlat/src/org/gburgett/xflat/query/{XpathUpdate.java → XPathUpdate.java}
  37. +7 −42 java/XFlat/src/org/gburgett/xflat/transaction/ThreadContextTransactionManager.java
  38. +0 −33 java/XFlat/src/org/gburgett/xflat/transaction/TransactionValues.java
  39. +0 −2 java/XFlat/src/org/gburgett/xflat/util/DocumentFileWrapper.java
  40. +3 −7 java/XFlat/src/org/gburgett/xflat/util/XPathExpressionEqualityMatcher.java
  41. +11 −11 java/XFlat/test/org/gburgett/xflat/db/ConvertingTableTest.java
  42. +19 −19 java/XFlat/test/org/gburgett/xflat/db/DatabaseIntegrationTest.java
  43. +11 −11 java/XFlat/test/org/gburgett/xflat/db/ElementTableTest.java
  44. +26 −26 java/XFlat/test/org/gburgett/xflat/db/EngineTestsBase.java
  45. +2 −2 java/XFlat/test/org/gburgett/xflat/db/XFlatDatabaseTest.java
  46. +5 −5 java/XFlat/test/org/gburgett/xflat/engine/IdShardedEngineIntegrationTests.java
  47. +2 −2 java/XFlat/test/org/gburgett/xflat/engine/IdShardedEngineTest.java
  48. +54 −57 java/XFlat/test/org/gburgett/xflat/query/{XpathQueryTest.java → XPathQueryTest.java}
  49. +12 −13 java/XFlat/test/org/gburgett/xflat/query/{XpathUpdateTest.java → XPathUpdateTest.java}
  50. +10 −0 java/XFlat/test/test/Foo.java
View
@@ -126,4 +126,63 @@ An example of a table persisted to an XML file:
</foo>
</db:row>
</db:table>
-```
+```
+
+#### Transactions
+
+Open a transaction and commit multiple updates atomically
+```java
+Table<Foo> fooTable = db.getTable(Foo.class);
+
+try(Transaction tx = db.getTransactionManager().openTransaction()){
+
+ Foo newFoo = new Foo();
+ newFoo.setFooInt(17);
+
+ fooTable.insert("1", newFoo);
+
+ XpathQuery query = XpathQuery.eq(XPathFactory.instance().compile("foo/fooInt"), 34);
+ XpathUpdate update = XpathUpdate.set(XPathFactory.instance().compile("foo/fooString"), "updated text");
+
+ fooTable.update(query, update);
+
+ tx.commit(); //can throw TransactionException
+}
+```
+
+Open a read-only transaction that is automatically reverted when closed; the transaction reads a snapshot of the committed data at the time the transaction was opened.
+```java
+Table<Foo> fooTable = db.getTable(Foo.class);
+
+try(Transaction tx = db.getTransactionManager().openTransaction(new TransactionOptions().withReadOnly(true))){
+
+ Foo foo1 = fooTable.find("1");
+
+ XpathQuery query = XpathQuery.gt(XPathFactory.instance().compile("foo/fooInt"), 21);
+ List<Foo> moreFoos = fooTable.findAll(query);
+}
+```
+
+Open and commit a transaction spanning multiple tables
+```java
+Table<Foo> fooTable = db.getTable(Foo.class, "Table_1");
+Table<Bar> barTable = db.getTable(Bar.class, "Table_2");
+
+try(Transaction tx = db.getTransactionManager().openTransaction()){
+
+ Foo newFoo = new Foo();
+ newFoo.setFooInt(17);
+
+ fooTable.insert("1", newFoo);
+
+ XpathQuery query = XpathQuery.lte(XPathFactory.instance().compile("bar/barDouble"), 34.1);
+ Baz newBaz = new Baz();
+ newBaz.setData("some data");
+ XpathUpdate update = XpathUpdate.set(XPathFactory.instance().compile("bar/barBaz"), newBaz);
+
+ barTable.update(query, update);
+
+ //commits to both Table_1 and Table_2
+ tx.commit(); //can throw TransactionException
+}
+```
View
@@ -55,10 +55,11 @@ using Hamcrest Matchers. Breaking the query into XPath expressions and values a
effectively, much more easily than if we used XQuery. Future versions may support XQuery.
-* Multiple hot-swapped Engines (to be implemented)
+* Multiple swappable Engines (to be implemented)
* The management of each table is handled by an Engine. As a table grows or shrinks, the appropriate Engine for managing
the data is swapped in behind the scenes. For example, very small tables can use an engine that loads the whole
-XML DOM in-memory, while very large tables can use an engine that manipulates a memory-mapped file.
+XML DOM in-memory, while very large tables can use an engine that manipulates a memory-mapped file. Only one engine
+is implemented for version 1.
@@ -69,19 +70,20 @@ to the row and binary search indexes to improve performance.
-* Sharding on XPath expressions (to be implemented)
+* Sharding by ID (implemented) or on arbitrary XPath expressions (to be implemented)
* A table can be sharded across multiple files based on a sharding key selected by an XPath expression. The expression
selects a part of the `Element` that is converted to a `Comparable`, then a `RangeProvider` determines which file to store
the Element in.
-* ACID Transactions (to be implemented)
- * XFlat can support Transactions which can be saved and resumed. All uncommitted transactional data is persisted in
-the same file as the table data, so transactions can be resumed between program execution.
+* Transactions
+ * XFlat supports Transactions that by default span all tables in the database. Currently XFlat only implements snapshot-isolation transactions,
+serializable transactions are planned for a future version.
====
Required dependencies:
+* Java 7
* JDOM 2
* jdom-2.0.4.jar
@@ -13,5 +13,5 @@
public interface Cursor<T> extends Iterable<T>, AutoCloseable {
@Override
- void close() throws XflatException;
+ void close() throws XFlatException;
}
@@ -4,11 +4,13 @@
*/
package org.gburgett.xflat;
-import org.gburgett.xflat.Table;
+import org.gburgett.xflat.transaction.Transaction;
import org.gburgett.xflat.transaction.TransactionManager;
/**
- * An interface for a Database managing one or more Tables.
+ * An interface for a Database managing one or more Tables.<br/>
+ * The Database allows getting and using Tables, and also provides access to
+ * the {@link TransactionManager} which can open {@link Transaction Transactions}.
* @author gordon
*/
public interface Database {
@@ -4,36 +4,84 @@
*/
package org.gburgett.xflat;
-import org.gburgett.xflat.TableConfig;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.gburgett.xflat.convert.PojoConverter;
import org.gburgett.xflat.db.IdGenerator;
-import org.gburgett.xflat.db.IdGenerator;
-import org.gburgett.xflat.db.IntegerIdGenerator;
import org.gburgett.xflat.db.IntegerIdGenerator;
import org.gburgett.xflat.db.TimestampIdGenerator;
-import org.gburgett.xflat.db.TimestampIdGenerator;
-import org.gburgett.xflat.db.UuidIdGenerator;
import org.gburgett.xflat.db.UuidIdGenerator;
+import org.gburgett.xflat.db.XFlatDatabase;
/**
- *
+ * The Configuration for a new XFlat Database.
+ * <br/>
+ * This Configuration must be
+ * passed to the {@link XFlatDatabase#setConfig(org.gburgett.xflat.DatabaseConfig) }
+ * method before initialization, or the default values will be used.
+ * <p/>
+ * This class is immutable, all set methods return new objects.
* @author gordon
*/
public class DatabaseConfig {
private List<Class<? extends IdGenerator>> idGeneratorStrategy;
+ /**
+ * Gets the ID generator strategy used by this Database.
+ * <p/>
+ * ID generators are selected on a per-table basis by the {@link Database}
+ * based on an ID generation strategy. The strategy selects the first IdGenerator
+ * in the list that supports the ID property's type.
+ * @return An unmodifiable list of the ID generators in the strategy.
+ */
+ public List<Class<? extends IdGenerator>> getIdGeneratorStrategy(){
+ if(idGeneratorStrategy == null){
+ return Collections.EMPTY_LIST;
+ }
+ return this.idGeneratorStrategy;
+ }
private int threadCount;
+ /**
+ * Gets the number of threads that this Database will spool up in its executor service.
+ * <p/>
+ * This is unused if an executor service is provided to the Database upon construction.
+ * @return the size of the database's thread pool
+ * @see #setThreadCount(int)
+ */
+ public int getThreadCount(){
+ return this.threadCount;
+ }
+
private String pojoConverterClass;
+ /**
+ * Gets the binary name of the class used by the database to convert
+ * POJOs for the database.
+ * <p/>
+ * The database will load this class using its {@link ClassLoader} in order
+ * to convert pojos.
+ * @return
+ */
+ public String getPojoConverterClass(){
+ return this.pojoConverterClass;
+ }
private TableConfig defaultTableConfig;
- private DatabaseConfig(){
+ /**
+ * Creates a new DatabaseConfig with the default values.
+ */
+ public DatabaseConfig(){
+ this.threadCount = 4;
+ this.pojoConverterClass = "org.gburgett.xflat.convert.converters.JAXBPojoConverter";
+ this.defaultTableConfig = new TableConfig();
+ this.idGeneratorStrategy = Arrays.asList(
+ UuidIdGenerator.class,
+ TimestampIdGenerator.class,
+ IntegerIdGenerator.class);
}
private DatabaseConfig(DatabaseConfig other){
@@ -45,25 +93,17 @@ private DatabaseConfig(DatabaseConfig other){
this.idGeneratorStrategy = other.idGeneratorStrategy;
}
+
/**
- * Gets the ID generator strategy used by this Database.
- * @return An unmodifiable list of the ID generators in the strategy.
- */
- public List<Class<? extends IdGenerator>> getIdGeneratorStrategy(){
- if(idGeneratorStrategy == null){
- return Collections.EMPTY_LIST;
- }
- return this.idGeneratorStrategy;
- }
- /**
- * Sets the ID generator strategy used by this Database.
+ * Sets the ID generator strategy used by this Database.
+ * <p/>
* ID generators are selected on a per-table basis by the {@link Database}
* based on an ID generation strategy. The strategy selects the first IdGenerator
* in the list that supports the ID property's type.
* @param strategy The strategy to use for this database.
* @return A new instance of the DatabaseConfig using this strategy.
*/
- public DatabaseConfig setIdGeneratorStrategy(List<Class<? extends IdGenerator>> strategy){
+ public DatabaseConfig withIdGeneratorStrategy(List<Class<? extends IdGenerator>> strategy){
if(strategy.size() <= 0){
throw new IllegalArgumentException("Id Generator strategy must contain at least " +
"one ID generator");
@@ -74,34 +114,22 @@ public DatabaseConfig setIdGeneratorStrategy(List<Class<? extends IdGenerator>>
return ret;
}
+
/**
- * Gets the number of threads that this Database can use.
- * @return the size of the database's thread pool
- * @see #setThreadCount(int)
- */
- public int getThreadCount(){
- return this.threadCount;
- }
- /**
- * Sets the number of threads that this Database can use.
+ * Sets the number of threads that this Database will spool up in its executor service.
+ * <p/>
* The database uses an ExecutorService to manage scheduled and recurring tasks.
- * This sets the size of its thread pool.
+ * This sets the size of its thread pool.<br/>
+ * This is unused if an executor service is provided to the Database upon construction.
* @param threadCount The number of threads in the database's thread pool.
* @return A new instance with the ThreadCount property set.
*/
- public DatabaseConfig setThreadCount(int threadCount){
+ public DatabaseConfig withThreadCount(int threadCount){
DatabaseConfig ret = new DatabaseConfig(this);
ret.threadCount = threadCount;
return ret;
}
- /**
- * Gets the binary name of the class used by the database to convert
- * POJOs for the database.
- * @return
- */
- public String getPojoConverterClass(){
- return this.pojoConverterClass;
- }
+
/**
* Sets the binary name of the class used by the database to convert
* POJOs for the database. The class MUST be an implementation of
@@ -137,16 +165,4 @@ public DatabaseConfig setDefaultTableConfig(TableConfig tableConfig){
ret.defaultTableConfig = tableConfig;
return ret;
}
-
- /**
- * The default configuration used by the Database.
- */
- public static DatabaseConfig Default = new DatabaseConfig()
- .setThreadCount(4)
- .setPojoConverterClass("org.gburgett.xflat.convert.converters.JAXBPojoConverter")
- .setDefaultTableConfig(TableConfig.Default)
- .setIdGeneratorStrategy(Arrays.asList(
- UuidIdGenerator.class,
- TimestampIdGenerator.class,
- IntegerIdGenerator.class));
}
@@ -5,10 +5,10 @@
package org.gburgett.xflat;
/**
- *
+ * An XflatException thrown when a unique ID is duplicated in a table.
* @author gordon
*/
-public class DuplicateKeyException extends XflatException {
+public class DuplicateKeyException extends XFlatException {
/**
* Creates a new instance of
@@ -7,10 +7,11 @@
import org.gburgett.xflat.db.EngineState;
/**
- *
+ * An XflatException thrown when the engine is in an unusable state for the
+ * current operation.
* @author gordon
*/
-public class EngineStateException extends XflatException {
+public class EngineStateException extends XFlatException {
private final EngineState state;
public EngineState getEngineState(){
@@ -4,11 +4,51 @@
*/
package org.gburgett.xflat;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import org.gburgett.xflat.convert.PojoConverter;
+import org.gburgett.xflat.query.XPathQuery;
+import org.jdom2.Element;
+
/**
* Marks one java bean property as the ID. The ID will be uniquely generated
* and assigned if it does not already exist.
+ * <p/>
+ * The {@link #value() } property instructs XFlat that this object serializes
+ * its ID property to the XML Element, and gives the XPath expression that should
+ * be treated as equivalent to {@link XpathQuery#Id} when XFlat inspects a query.
+ * <p/>
+ * Example (inside class Foo):<br/>
+ * <pre>
+ * @Id(value="foo/@t:id", namespaces={"xmlns:t='http://www.example.com/ns'"})
+ * public String getId(){
+ * </pre>
* @author gordon
*/
+@Retention(RetentionPolicy.RUNTIME)
public @interface Id {
+ /**
+ * The XPath expression which selects this property once it has been converted to an {@link Element}.
+ * <br/>
+ * This tells XFlat that this expression is equivalent to {@link XpathQuery#Id}, so that XFlat can
+ * apply optimizations based on ID if it encounters this expression in a query.<br/>
+ * This must be the exact same expression used in queries in order for XFlat to match it.
+ * <p/>
+ * If this is not set, the {@link PojoConverter} will be invoked to take a "best guess".
+ * @return
+ */
+ String value() default "";
+ /**
+ * A set of XML namespace declarations that declare the namespaces used
+ * in the XPath expression. If the {@link #value() } expression includes
+ * a namespace, this must declare the namespace.<br/>
+ * Example:<br/>
+ * <pre>
+ * xmlns:a="http://www.example.com/ns"
+ * </pre>
+ *
+ * @return
+ */
+ String[] namespaces() default "";
}
Oops, something went wrong.

0 comments on commit 2acd0e7

Please sign in to comment.