[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:
parent
ede49b6d20
commit
904b89f809
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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$
|
||||
|
||||
}
|
||||
}
|
|
@ -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>
|
Loading…
Reference in New Issue