diff --git a/src/main/java/li/strolch/persistence/impl/XmlPersistenceHandler.java b/src/main/java/li/strolch/persistence/impl/XmlPersistenceHandler.java index bc2ddb1c9..b283a09cf 100644 --- a/src/main/java/li/strolch/persistence/impl/XmlPersistenceHandler.java +++ b/src/main/java/li/strolch/persistence/impl/XmlPersistenceHandler.java @@ -36,6 +36,7 @@ import li.strolch.persistence.impl.model.ResourceContextFactory; import li.strolch.runtime.component.ComponentContainer; import li.strolch.runtime.component.StrolchComponent; import li.strolch.runtime.configuration.ComponentConfiguration; +import li.strolch.runtime.observer.ObserverHandler; import ch.eitchnet.xmlpers.api.IoMode; import ch.eitchnet.xmlpers.api.PersistenceConstants; import ch.eitchnet.xmlpers.api.PersistenceManager; @@ -51,8 +52,8 @@ public class XmlPersistenceHandler extends StrolchComponent implements StrolchPe public static final String DB_STORE_PATH = "dbStore/"; //$NON-NLS-1$ private PersistenceManager persistenceManager; - public XmlPersistenceHandler(ComponentContainer container) { - super(container, StrolchPersistenceHandler.class.getName()); + public XmlPersistenceHandler(ComponentContainer container, String componentName) { + super(container, componentName); } @Override @@ -72,6 +73,8 @@ public class XmlPersistenceHandler extends StrolchComponent implements StrolchPe new ResourceContextFactory()); this.persistenceManager.getCtxFactory().registerPersistenceContextFactory(Order.class, Tags.ORDER, new OrderContextFactory()); + + super.initialize(componentConfiguration); } public StrolchTransaction openTx() { @@ -79,10 +82,13 @@ public class XmlPersistenceHandler extends StrolchComponent implements StrolchPe } @SuppressWarnings("resource") - // caller must close + // caller will/must close public StrolchTransaction openTx(String realm) { PersistenceTransaction tx = this.persistenceManager.openTx(realm); XmlStrolchTransaction strolchTx = new XmlStrolchTransaction(tx); + if (getContainer().hasComponent(ObserverHandler.class)) { + strolchTx.setObserverHandler(getContainer().getComponent(ObserverHandler.class)); + } return strolchTx; } diff --git a/src/main/java/li/strolch/persistence/impl/XmlStrolchTransaction.java b/src/main/java/li/strolch/persistence/impl/XmlStrolchTransaction.java index d37d3b541..a58bb7829 100644 --- a/src/main/java/li/strolch/persistence/impl/XmlStrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/impl/XmlStrolchTransaction.java @@ -1,20 +1,53 @@ package li.strolch.persistence.impl; +import java.util.Set; + +import li.strolch.model.StrolchElement; import li.strolch.persistence.api.StrolchPersistenceException; import li.strolch.persistence.api.StrolchTransaction; import li.strolch.persistence.api.TransactionCloseStrategy; +import li.strolch.runtime.observer.ObserverHandler; +import ch.eitchnet.xmlpers.api.ModificationResult; import ch.eitchnet.xmlpers.api.PersistenceTransaction; +import ch.eitchnet.xmlpers.api.TransactionResult; public class XmlStrolchTransaction implements StrolchTransaction { + private ObserverHandler observerHandler; + private boolean suppressUpdates; private PersistenceTransaction tx; private TransactionCloseStrategy closeStrategy; + private TransactionResult txResult; public XmlStrolchTransaction(PersistenceTransaction tx) { + this.suppressUpdates = false; this.tx = tx; this.closeStrategy = TransactionCloseStrategy.COMMIT; } + /** + * @param observerHandler + * the observerHandler to set + */ + public void setObserverHandler(ObserverHandler observerHandler) { + this.observerHandler = observerHandler; + } + + /** + * @param suppressUpdates + * the suppressUpdates to set + */ + public void setSuppressUpdates(boolean suppressUpdates) { + this.suppressUpdates = suppressUpdates; + } + + /** + * @return the suppressUpdates + */ + public boolean isSuppressUpdates() { + return this.suppressUpdates; + } + PersistenceTransaction getTx() { return this.tx; } @@ -26,7 +59,25 @@ public class XmlStrolchTransaction implements StrolchTransaction { @Override public void autoCloseableCommit() { + + if (!this.suppressUpdates && this.observerHandler != null) { + this.txResult = new TransactionResult(); + this.tx.setTransactionResult(this.txResult); + } + this.tx.autoCloseableCommit(); + + if (!this.suppressUpdates && this.observerHandler != null) { + + Set keys = this.txResult.getKeys(); + for (String key : keys) { + ModificationResult modificationResult = this.txResult.getModificationResult(key); + + this.observerHandler.add(key, modificationResult. getCreated()); + this.observerHandler.update(key, modificationResult. getUpdated()); + this.observerHandler.remove(key, modificationResult. getDeleted()); + } + } } @Override diff --git a/src/test/java/li/strolch/persistence/impl/dao/test/AbstractDaoImplTest.java b/src/test/java/li/strolch/persistence/impl/dao/test/AbstractDaoImplTest.java index 3214c805c..2204970f6 100644 --- a/src/test/java/li/strolch/persistence/impl/dao/test/AbstractDaoImplTest.java +++ b/src/test/java/li/strolch/persistence/impl/dao/test/AbstractDaoImplTest.java @@ -22,15 +22,11 @@ package li.strolch.persistence.impl.dao.test; import java.io.File; -import java.text.MessageFormat; -import li.strolch.persistence.impl.XmlPersistenceHandler; -import li.strolch.runtime.component.ComponentContainer; -import li.strolch.runtime.configuration.ComponentConfiguration; -import li.strolch.runtime.configuration.ConfigurationParser; -import li.strolch.runtime.configuration.StrolchConfiguration; +import li.strolch.persistence.api.StrolchPersistenceHandler; import li.strolch.testbase.runtime.RuntimeMock; +import org.junit.AfterClass; import org.junit.BeforeClass; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,13 +35,14 @@ import org.slf4j.LoggerFactory; * @author Robert von Burg * */ -public abstract class AbstractDaoImplTest { +public abstract class AbstractDaoImplTest extends RuntimeMock { private static final String RUNTIME_PATH = "target/strolchRuntime/"; //$NON-NLS-1$ + private static final String DB_STORE_PATH_DIR = "dbStore"; //$NON-NLS-1$ private static final String CONFIG_SRC = "src/test/resources/runtime/config"; //$NON-NLS-1$ protected static final Logger logger = LoggerFactory.getLogger(AbstractDaoImplTest.class); - protected static XmlPersistenceHandler persistenceHandler; + protected static StrolchPersistenceHandler persistenceHandler; @BeforeClass public static void beforeClass() { @@ -53,21 +50,15 @@ public abstract class AbstractDaoImplTest { File rootPath = new File(RUNTIME_PATH); File configSrc = new File(CONFIG_SRC); RuntimeMock.mockRuntime(rootPath, configSrc); - - File dbStorePath = new File(rootPath, XmlPersistenceHandler.DB_STORE_PATH); - if (!dbStorePath.mkdirs()) { - String msg = "Failed to create path {0}"; //$NON-NLS-1$ - msg = MessageFormat.format(msg, dbStorePath.getAbsolutePath()); - throw new RuntimeException(msg); - } + new File(rootPath, DB_STORE_PATH_DIR).mkdir(); + RuntimeMock.startContainer(rootPath); // initialize the component configuration - StrolchConfiguration strolchConfiguration = ConfigurationParser.parseConfiguration(rootPath); - ComponentConfiguration componentConfiguration = strolchConfiguration - .getComponentConfiguration("PersistenceHandler"); //$NON-NLS-1$ - ComponentContainer container = new ComponentContainer(); - persistenceHandler = new XmlPersistenceHandler(container); - persistenceHandler.initialize(componentConfiguration); + persistenceHandler = getContainer().getComponent(StrolchPersistenceHandler.class); + } + @AfterClass + public static void afterClass() { + RuntimeMock.destroyRuntime(); } } diff --git a/src/test/java/li/strolch/persistence/impl/dao/test/ObserverUpdateTest.java b/src/test/java/li/strolch/persistence/impl/dao/test/ObserverUpdateTest.java new file mode 100644 index 000000000..489758ce8 --- /dev/null +++ b/src/test/java/li/strolch/persistence/impl/dao/test/ObserverUpdateTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2012, Robert von Burg + * + * All rights reserved. + * + * This file is part of the XXX. + * + * XXX 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 3 of the License, + * or (at your option) any later version. + * + * XXX 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. + * + * You should have received a copy of the GNU General Public License + * along with XXX. If not, see + * . + */ +package li.strolch.persistence.impl.dao.test; + +import static li.strolch.testbase.model.ModelBuilder.createOrder; +import static li.strolch.testbase.model.ModelBuilder.createResource; +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import li.strolch.model.Order; +import li.strolch.model.Resource; +import li.strolch.model.State; +import li.strolch.model.StrolchElement; +import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.runtime.observer.Observer; +import li.strolch.runtime.observer.ObserverHandler; + +import org.junit.Test; + +import ch.eitchnet.xmlpers.api.ModificationResult; + +/** + * @author Robert von Burg + * + */ +public class ObserverUpdateTest extends AbstractDaoImplTest { + + public final class ElementAddedObserver implements Observer { + + Map results = new HashMap<>(); + + private ModificationResult getModificationResult(String key) { + ModificationResult result = this.results.get(key); + if (result == null) { + result = new ModificationResult(key); + this.results.put(key, result); + } + return result; + } + + @Override + public void update(String key, List elements) { + getModificationResult(key).getUpdated().addAll(elements); + } + + @Override + public void remove(String key, List elements) { + getModificationResult(key).getDeleted().addAll(elements); + } + + @Override + public void add(String key, List elements) { + getModificationResult(key).getCreated().addAll(elements); + } + } + + @Test + public void shouldReceiveUpdates() { + + // register an observer for orders and resources + ElementAddedObserver observer = new ElementAddedObserver(); + getContainer().getComponent(ObserverHandler.class).registerObserver("Order", observer); //$NON-NLS-1$ + getContainer().getComponent(ObserverHandler.class).registerObserver("Resource", observer); //$NON-NLS-1$ + + // create order + Order newOrder = createOrder("MyTestOrder", "Test Name", "TestType", System.currentTimeMillis(), State.CREATED); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + try (StrolchTransaction tx = persistenceHandler.openTx();) { + persistenceHandler.getOrderDao(tx).save(newOrder); + } + + // create resource + Resource newResource = createResource("MyTestResource", "Test Name", "TestType"); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + try (StrolchTransaction tx = persistenceHandler.openTx();) { + persistenceHandler.getResourceDao(tx).save(newResource); + } + + assertEquals(2, observer.results.size()); + assertEquals(1, observer.results.get("Order").getCreated().size()); //$NON-NLS-1$ + assertEquals(1, observer.results.get("Resource").getCreated().size()); //$NON-NLS-1$ + + } +} diff --git a/src/test/resources/runtime/config/StrolchConfiguration.xml b/src/test/resources/runtime/config/StrolchConfiguration.xml index 89ea0f543..b3397b6d2 100644 --- a/src/test/resources/runtime/config/StrolchConfiguration.xml +++ b/src/test/resources/runtime/config/StrolchConfiguration.xml @@ -14,4 +14,9 @@ true + + ObserverHandler + li.strolch.runtime.observer.ObserverHandler + li.strolch.runtime.observer.DefaultObserverHandler + \ No newline at end of file