For sure! Unless you or Jeremy plan to use it immediately let me check and improve it this week through some BDD features we must implement.
Thanks, Oscar El 08/09/2013, a las 09:20, Dan Haywood <[email protected]> escribió: > Looks very good, Oscar, exactly the sort of thing that should be in the > framework, I think. > > Could you raise a ticket and provide a commit? If you have the time, > perhaps you could also refactor the ToDo app to show its use? > > Many thanks > > Cheers > Dan > > > > On 7 September 2013 19:05, GESCONSULTOR - Óscar Bou > <[email protected]>wrote: > >> >> I've just been thinking about a way to avoid to define a Spec Transformer >> for every Entity class in the Domain. >> >> As it's just "infrastructure software", I thought that was "just enough". >> >> The attached code allows to use just one Spec Transformer when the Glue is >> written like this: >> - the employee with name "PETER" >> - the employee named "PETER" >> - the property with reference "REF-001" >> - the property referenced "REF-001" >> - the product with id "PR-001" >> >> From there, we know that: >> - The Entity singular name is "employee" (so it can be obtained from the >> Isis Object Specifications, reinforcing the Ubiquitous Language use on BDD >> specifications). >> - We must search by name >> - The name must be PETER >> >> >> >> For using it, I must define a Glue like this one: >> >> Define a Glue like this one: >> @When("The company (employee with name \"[^\"]*\") has a role assigned") >> public void >> the_company_employee_with_name(@Transform(GenericIsisJdoTransformer.class) >> final Employee employee) { >> ... >> } >> >> >> >> First "proof-of-concept" code version follows this text. >> >> It can be improved in many ways, for allowing customization through >> inheritance, avoiding JDO through the use of the Apache Isis query methods, >> etc. >> >> >> But I would let you know, right to know if you think it can be useful. >> >> On this way, the only implemented classes are the ones supporting the >> Glues (and only the Spec Transformers for more specific use cases). >> >> >> HTH, >> >> Oscar >> >> >> >> >> >> --------------------- >> >> >> >> >> package com.xms.framework.testing.integration.spectransformers; >> >> import java.util.HashMap; >> import java.util.Map; >> import java.util.regex.Matcher; >> import java.util.regex.Pattern; >> >> import javax.jdo.Query; >> >> import org.opensaml.artifact.InvalidArgumentException; >> >> import org.apache.isis.applib.DomainObjectContainer; >> import org.apache.isis.core.metamodel.spec.ObjectSpecification; >> import org.apache.isis.core.runtime.system.context.IsisContext; >> import org.apache.isis.core.specsupport.scenarios.ScenarioExecution; >> import >> org.apache.isis.objectstore.jdo.datanucleus.service.support.IsisJdoSupportImpl; >> >> /** >> * Requires the Gherkin's capture in the format '([entitySingularName] >> [(.+?) >> * name(d)|(.+?) reference|(.+?) id] \"[entityId]\")'. >> * <p> >> * For example: >> * <ul> >> * <li>the employee with name "PETER"</li> >> * <li>the employee named "PETER"</li> >> * <li>the property with reference "REF-001"</li> >> * <li>the property referenced "REF-001"</li> >> * <li>the product with id "PR-001"</li> >> * </ul> >> * <p> >> * For matching the first one we will need the following Gherkin regular >> * expression: >> * <ul> >> * <li> >> * \\@When("The company's (employee with name \"[^\"]*\") has a role >> assigned")</li> >> * </ul> >> * <p> >> * From there, we know that: >> * <ul> >> * <li>The Entity singular name is "employee".</li> >> * <li>We must search by name</li> >> * <li>The name must be PETER</li> >> * </ul> >> * >> */ >> public class GenericIsisJdoTransformer extends >> NullRecognizingTransformer<Object> { >> >> private static Map<String, ObjectSpecification> >> specificationsBySingularName; >> >> /** >> * Tries to obtain the Entity class name, id and search field from the >> * Cucumber capture, and find it on the JDO Object Store. >> * >> * @see com.xms.framework.testing.integration.spectransformers. >> * NullRecognizingTransformer#transformNonNull(java.lang.String) >> */ >> @Override >> protected Object transformNonNull(final String capture) { >> >> return this.findFromCapture(capture); >> >> } >> >> /** >> * @param entityName >> * Name of the Entity specified on the Gherkin's capture. >> * @return >> */ >> private ObjectSpecification specificationOf(final String entityName) { >> >> if (IsisJdoTransformer.specificationsBySingularName == null) { >> IsisJdoTransformer.specificationsBySingularName = new >> HashMap<String, ObjectSpecification>(); >> >> for (final ObjectSpecification current : >> IsisContext.getSpecificationLoader().allSpecifications()) { >> >> >> IsisJdoTransformer.specificationsBySingularName.put(current.getSingularName().toLowerCase(), >> current); >> } >> >> } >> return >> IsisJdoTransformer.specificationsBySingularName.get(entityName.toLowerCase()); >> >> } >> >> private final Class<?> entityClassFrom(final String capture) { >> >> // The Entity Id will be between "". >> String entityName = ""; >> >> final String[] recognizedPatterns = { "( with name )", "( named >> )", "( with reference )", "( referenced )", "( with id )" }; >> >> for (final String currentPattern : recognizedPatterns) { >> final Pattern p = Pattern.compile(currentPattern); >> final Matcher m = p.matcher(capture); >> if (m.find()) { >> entityName = capture.substring(0, m.start()); >> break; >> } >> } >> >> if (entityName == "") { >> throw new InvalidArgumentException(String.format("Cannot find >> the entity's name on the capture %s. The format must be >> '([entitySingularName] [with name|with reference|named|referenced] >> \"[entityId]\")'", capture)); >> } >> >> final ObjectSpecification specification = >> this.specificationOf(entityName); >> if (specification == null) { >> throw new InvalidArgumentException(String.format("There is no >> Entity registered in Isis with '%s' as it's singular name", entityName)); >> } >> return specification.getCorrespondingClass(); >> >> } >> >> /** >> * @param capture >> * The Gherkin's capture >> * @return >> */ >> private final String filterFrom(final String capture) { >> // Find by "name". >> if (capture.matches("(.+?)name(.+?)")) { >> return String.format("name==\"%s\"", >> this.entityIdFrom(capture)); >> } >> >> // Find by "reference". >> if (capture.matches("(.+?)reference(.+?)")) { >> return String.format("reference==\"%s\"", >> this.entityIdFrom(capture)); >> } >> >> // Find by "id". >> if (capture.matches("(.+?)id(.+?)")) { >> return String.format("id==\"%s\"", this.entityIdFrom(capture)); >> } >> >> throw new InvalidArgumentException(String.format("The entity id >> has not been found on the capture '%s'. It must be between two \" >> characters.", capture)); >> } >> >> private final Object entityIdFrom(final String capture) { >> // The Entity Id will be between "". >> final Pattern p = Pattern.compile("\"(.+?)\""); >> final Matcher m = p.matcher(capture); >> if (m.find()) { >> return m.group().replace("\"", ""); >> } else { >> throw new InvalidArgumentException(String.format("The entity >> id has not been found on the capture '%s'. It must be between two \" >> characters.", capture)); >> } >> } >> >> private final Object findFromCapture(final String capture) { >> >> // Need to flush(). >> // The Entity can be created on the same transaction. >> // If we don't flush() the changes, perhaps the entity have not >> been >> // saved to the object store yet, and will not be found. >> >> ScenarioExecution.current().service(DomainObjectContainer.class).flush(); >> >> final Query query = >> ScenarioExecution.current().service(IsisJdoSupportImpl.class).getJdoPersistenceManager().newQuery(); >> query.setClass(this.entityClassFrom(capture)); >> query.setFilter(this.filterFrom(capture)); >> query.setUnique(true); >> >> final Object result = query.execute(); >> >> return result; >> >> } >> } >> >> >> >> >> --------------------- >> >> >> >> >> >> El 27/08/2013, a las 20:24, Kevin Meyer - KMZ <[email protected]> escribió: >> >>> Hi Jeremy, >>> >>> If I remember correctly, Dan has examples for overriding the "Finder" >>> methods in the ToDo demo / artefact that use JDO search classes to >>> build queries. >>> >>> In fact: >>> >>> In the "ToDoItemsJdo" class (which extends an >>> AbstractFactoryAndRepository): >>> // {{ notYetComplete (action) >>> @Override >>> protected List<ToDoItem> doNotYetComplete() { >>> return allMatches( >>> new QueryDefault<ToDoItem>(ToDoItem.class, >>> "todo_notYetComplete", >>> "ownedBy", currentUserName())); >>> } >>> // }} >>> >>> This appears in an old copy of the repo I have in the wicket JDO >>> quickstart project. >>> >>> So while you can't use "FindByPattern", JDO has implemented a >>> useful alternative. >>> >>> Regards, >>> Kevin >>> >>> >>> On 27 Aug 2013 at 14:37, Jeremy Gurr wrote: >>> >>>> I'm playing around with the cucumber support tools in isis (a testing >> framework for behavior driven development, for those who don't know), and >> have created a test that basically looks like this: >>>> >>>> <snip> >>>> >>>> It's very convenient that cucumber instantiates my ServiceClass model >> object and automatically plugs in fields according to the feature spec >> column header. This enables me to add new fields simply by adding a column >> in the spec, and adding the corresponding column in my model object. It >> skips the extra hassle of having to update the glue code as well as service >> methods to construct the object. >>>> >>>> The "exists" method contains this code: >>>> >>>> public boolean exists(ServiceClass serviceClass) { >>>> final QueryFindByPattern<ServiceClass> query = new >> QueryFindByPattern<ServiceClass>(ServiceClass.class, serviceClass); >>>> final ServiceClass firstMatch = firstMatch(query); >>>> >>>> return firstMatch != null; >>>> } >>>> >>>> I'm just trying to verify that an object exists with fields matching >> the incoming object, some fields of which may be null, meaning that they >> can be any value. The QueryFindByPattern class seemed to be a perfect fit >> since I'm passing around ServiceClass instances anyway. However, running it >> executes code that is not yet implemented: >>>> >>>> <snip> >> >>
