diff --git a/src/main/java/li/strolch/agent/impl/TransactionalElementMap.java b/src/main/java/li/strolch/agent/impl/TransactionalElementMap.java index 7fd93ce43..17e9d37d6 100644 --- a/src/main/java/li/strolch/agent/impl/TransactionalElementMap.java +++ b/src/main/java/li/strolch/agent/impl/TransactionalElementMap.java @@ -24,6 +24,7 @@ public abstract class TransactionalElementMap implemen @Override public boolean hasElement(StrolchTransaction tx, String type, String id) { + // TODO change to dao.hasElement(type, id) return getDao(tx).queryKeySet(type).contains(id); } diff --git a/src/main/java/li/strolch/persistence/api/AbstractTransaction.java b/src/main/java/li/strolch/persistence/api/AbstractTransaction.java index 1c3d28084..f8b65534b 100644 --- a/src/main/java/li/strolch/persistence/api/AbstractTransaction.java +++ b/src/main/java/li/strolch/persistence/api/AbstractTransaction.java @@ -15,9 +15,19 @@ */ package li.strolch.persistence.api; +import java.text.MessageFormat; +import java.util.List; + import li.strolch.agent.api.OrderMap; import li.strolch.agent.api.ResourceMap; import li.strolch.agent.impl.StrolchRealm; +import li.strolch.exception.StrolchException; +import li.strolch.model.GroupedParameterizedElement; +import li.strolch.model.Locator; +import li.strolch.model.ParameterBag; +import li.strolch.model.StrolchElement; +import li.strolch.model.Tags; +import li.strolch.model.parameter.Parameter; import li.strolch.persistence.inmemory.InMemoryTransaction; import org.slf4j.Logger; @@ -54,4 +64,58 @@ public abstract class AbstractTransaction implements StrolchTransaction { public OrderMap getOrderMap() { return this.realm.getOrderMap(); } + + @SuppressWarnings("unchecked") + @Override + public T findElement(Locator locator) { + + if (locator.getSize() < 3) { + String msg = "The locator is invalid as it does not have at least three path elements (e.g. Resource/MyType/@id): {0}"; + msg = MessageFormat.format(msg, locator.toString()); + throw new StrolchException(msg); + } else if (locator.getSize() > 5) { + // TODO handle state variables, which will probably be separated by an additional part so we can differentiate between parameters and state variables on a parameter bag + String msg = "The locator is invalid as it has more than 5 parts. The fifth part references a Parameter, which is the deepest fetchable entry: {0}"; + msg = MessageFormat.format(msg, locator.toString()); + throw new StrolchException(msg); + } + + List elements = locator.getPathElements(); + GroupedParameterizedElement groupedParameterizedElement; + String objectClassType = elements.get(0); + String type = elements.get(1); + String id = elements.get(2); + switch (objectClassType) { + case Tags.RESOURCE: + groupedParameterizedElement = getResourceMap().getBy(this, type, id); + break; + case Tags.ORDER: + groupedParameterizedElement = getOrderMap().getBy(this, type, id); + break; + default: + throw new StrolchException("Unknown object class " + objectClassType); + } + + if (groupedParameterizedElement == null) { + String msg = "No top level object could be found with locator {0}"; + throw new StrolchException(MessageFormat.format(msg, locator)); + } + + if (elements.size() == 3) + return (T) groupedParameterizedElement; + + String parameterBagId = elements.get(3); + ParameterBag bag = groupedParameterizedElement.getParameterBag(parameterBagId); + if (bag == null) { + String msg = "Could not find ParameterBag for locator {0} on element {1}"; + throw new StrolchException(MessageFormat.format(msg, locator, groupedParameterizedElement.getLocator())); + } + + if (elements.size() == 4) + return (T) bag; + + String parameterId = elements.get(4); + Parameter parameter = bag.getParameter(parameterId); + return (T) parameter; + } } diff --git a/src/main/java/li/strolch/persistence/api/StrolchDao.java b/src/main/java/li/strolch/persistence/api/StrolchDao.java index 0a03170bd..b6a35c46d 100644 --- a/src/main/java/li/strolch/persistence/api/StrolchDao.java +++ b/src/main/java/li/strolch/persistence/api/StrolchDao.java @@ -28,6 +28,8 @@ public interface StrolchDao { public Set queryKeySet(); + // TODO add method hasElement(String type, String id) + public Set queryKeySet(String type); public Set queryTypes(); @@ -47,6 +49,6 @@ public interface StrolchDao { public void updateAll(List elements); public void remove(T element); - + public void removeAll(List elements); } diff --git a/src/main/java/li/strolch/persistence/api/StrolchTransaction.java b/src/main/java/li/strolch/persistence/api/StrolchTransaction.java index 3caf3dcb6..bf3b75804 100644 --- a/src/main/java/li/strolch/persistence/api/StrolchTransaction.java +++ b/src/main/java/li/strolch/persistence/api/StrolchTransaction.java @@ -17,6 +17,13 @@ package li.strolch.persistence.api; import li.strolch.agent.api.OrderMap; import li.strolch.agent.api.ResourceMap; +import li.strolch.exception.StrolchException; +import li.strolch.model.Locator; +import li.strolch.model.Order; +import li.strolch.model.ParameterBag; +import li.strolch.model.Resource; +import li.strolch.model.StrolchElement; +import li.strolch.model.parameter.Parameter; public interface StrolchTransaction extends AutoCloseable { @@ -34,6 +41,35 @@ public interface StrolchTransaction extends AutoCloseable { public ResourceMap getResourceMap(); public OrderMap getOrderMap(); - + public PersistenceHandler getPersistenceHandler(); + + /** + *

+ * Used to find a {@link StrolchElement} by a {@link Locator}. + *

+ * + *

+ * A Locator has the form <ObjectClassType>/<Type>/<Id> - this is the least amount of path + * elements to find an object. Thus to query a {@link Resource} of type "MyType" and the id "@1" use the following + * path: Resourcee/MyType/@1 + *

+ * + *

+ * This method can also be used to find a deeper element, e.g. a specific {@link Parameter} on an + * {@link ParameterBag} on an {@link Order}. This would be done as follows: Order/MyType/@1/myParam + *

+ * + * @param locator + * the locator defining the path to the element which is to be found + * + * @return the element described by the locator + * + * @throws StrolchException + * if the element could not be found + * @throws ClassCastException + * if the querying code is not asking for the correct instance. Do not query a {@link Parameter} if the + * variable to which the result is to be is stored is a {@link Resource}, etc. + */ + public T findElement(Locator locator) throws StrolchException, ClassCastException; } diff --git a/src/test/java/li/strolch/runtime/test/query/inmemory/FindByLocatorTest.java b/src/test/java/li/strolch/runtime/test/query/inmemory/FindByLocatorTest.java new file mode 100644 index 000000000..08cb2ff30 --- /dev/null +++ b/src/test/java/li/strolch/runtime/test/query/inmemory/FindByLocatorTest.java @@ -0,0 +1,63 @@ +/* + * Copyright 2013 Robert von Burg + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package li.strolch.runtime.test.query.inmemory; + +import static org.junit.Assert.assertNotNull; +import li.strolch.agent.api.ComponentContainer; +import li.strolch.agent.api.StrolchAgent; +import li.strolch.model.Locator; +import li.strolch.model.ParameterBag; +import li.strolch.model.Resource; +import li.strolch.model.parameter.FloatParameter; +import li.strolch.model.parameter.StringParameter; +import li.strolch.persistence.api.StrolchTransaction; +import li.strolch.runtime.test.component.ComponentContainerTest; + +import org.junit.Test; + +/** + * @author Robert von Burg + */ +public class FindByLocatorTest { + + private static final String PATH_FIND_BY_LOCATOR_RUNTIME = "target/FindByLocatorTest/"; + + @Test + public void shouldFindByLocator() { + + StrolchAgent agent = ComponentContainerTest.startContainer(PATH_FIND_BY_LOCATOR_RUNTIME, + ComponentContainerTest.PATH_TRANSIENT_CONTAINER); + ComponentContainer container = agent.getContainer(); + + try (StrolchTransaction tx = container.getDefaultRealm().openTx()) { + Locator locResStringParam = Locator.valueOf("Resource/TestType/MyTestResource/@bag01/@param5"); + StringParameter resStringParam = tx.findElement(locResStringParam); + assertNotNull("Should have found a StringParameter with the locator " + locResStringParam, resStringParam); + + Locator locOrderFloatParam = Locator.valueOf("Order/TestType/MyTestOrder/@bag01/@param2"); + FloatParameter orderFloatP = tx.findElement(locOrderFloatParam); + assertNotNull("Should have found a FloatParameter with the locator " + locOrderFloatParam, orderFloatP); + + Locator locOrderBag = Locator.valueOf("Order/TestType/MyTestOrder/@bag01"); + ParameterBag orderBag = tx.findElement(locOrderBag); + assertNotNull("Should have found a FloatParameter with the locator " + locOrderBag, orderBag); + + Locator locResource = Locator.valueOf("Resource/TestType/MyTestResource"); + Resource resource = tx.findElement(locResource); + assertNotNull("Should have found a FloatParameter with the locator " + locResource, resource); + } + } +}