[New] Implemented notifying of observers of changed objects after a TX

So that components/observers can be notified of changes to the model,
the completion of a TX now triggers an ObserverHandler update of the
modified objects
This commit is contained in:
Robert von Burg 2013-11-14 21:36:01 +01:00
parent ede49b6d20
commit 904b89f809
5 changed files with 181 additions and 24 deletions

View File

@ -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;
}

View File

@ -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<String> keys = this.txResult.getKeys();
for (String key : keys) {
ModificationResult modificationResult = this.txResult.getModificationResult(key);
this.observerHandler.add(key, modificationResult.<StrolchElement> getCreated());
this.observerHandler.update(key, modificationResult.<StrolchElement> getUpdated());
this.observerHandler.remove(key, modificationResult.<StrolchElement> getDeleted());
}
}
}
@Override

View File

@ -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 <eitch@eitchnet.ch>
*
*/
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();
}
}

View File

@ -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
* <http://www.gnu.org/licenses/>.
*/
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 <eitch@eitchnet.ch>
*
*/
public class ObserverUpdateTest extends AbstractDaoImplTest {
public final class ElementAddedObserver implements Observer {
Map<String, ModificationResult> 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<StrolchElement> elements) {
getModificationResult(key).getUpdated().addAll(elements);
}
@Override
public void remove(String key, List<StrolchElement> elements) {
getModificationResult(key).getDeleted().addAll(elements);
}
@Override
public void add(String key, List<StrolchElement> 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$
}
}

View File

@ -14,4 +14,9 @@
<verbose>true</verbose>
</Properties>
</Component>
<Component>
<name>ObserverHandler</name>
<api>li.strolch.runtime.observer.ObserverHandler</api>
<impl>li.strolch.runtime.observer.DefaultObserverHandler</impl>
</Component>
</StrolchConfiguration>