isis-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dan Haywood <...@haywood-associates.co.uk>
Subject Re: code-lists and administration thereof
Date Sun, 02 Aug 2015 13:23:47 GMT
Further to this, I've updated the kitchensink (against 1.9.0-SNAPSHOT) to
demonstrate this technique....

The code is in ReferenceObject, which you can get to from the "Data Types"
menu.  Use the fixture scripts menu to create some sample data.

The relevant code is below.

Cheers
Dan

[1]  https://github.com/isisaddons/isis-app-kitchensink


    private OtherObject someOtherObjectUsingName;

    @Property(hidden = Where.EVERYWHERE)
    @Column(allowsNull = "true")
    public OtherObject getSomeOtherObjectUsingName() {
        return someOtherObjectUsingName;
    }

    public void setSomeOtherObjectUsingName(final OtherObject
someOtherObjectUsingName) {
        this.someOtherObjectUsingName = someOtherObjectUsingName;
    }

    @NotPersistent
    public String getSomeOtherObjectUsingNameName() {
        return getSomeOtherObjectUsingName() != null?
getSomeOtherObjectUsingName().getName() : null;
    }

    public void setSomeOtherObjectUsingNameName(final String name) {
        OtherObject otherObject = name != null
                ? container.firstMatch(OtherObject.class, withName(name))
                : null;
        setSomeOtherObjectUsingName(otherObject);
    }

    public List<String> choicesSomeOtherObjectUsingNameName() {
        List<OtherObject> otherObjects =
container.allInstances(OtherObject.class);
        return Lists.newArrayList(
                Iterables.transform(otherObjects, nameOf())
        );
    }

    private static Function<OtherObject, String> nameOf() {
        return new Function<OtherObject, String>() {
            @Nullable @Override public String apply(final OtherObject input) {
                return input.getName();
            }
        };
    }

    private static Predicate<OtherObject> withName(final String name) {
        return new Predicate<OtherObject>() {
        @Override public boolean apply(final OtherObject input) {
             return Objects.equal(input.getName(), name);
            }
    };
    }





On 30 July 2015 at 13:16, Dan Haywood <dan@haywood-associates.co.uk> wrote:

> looks right to me, so I'll take a look at in this eve or tomorrow.
>
> thx
> Dan
>
>
> On 30 July 2015 at 13:12, Stephen Cameron <steve.cameron.62@gmail.com>
> wrote:
>
>> Still no luck with this one.
>>
>> The derived RegionName appears as a non-editable property, so not sure
>> what
>> was different before when I was getting an model validation error.
>>
>> My current code of interest is this:
>>
>>     @Column(name = "region", allowsNull = "true")
>>     //@MemberOrder(sequence = "7")
>>     @Property(hidden=Where.EVERYWHERE)
>>     public Region getRegion() {
>>         return this.region;
>>     }
>>
>>     public void setRegion(Region region) {
>>         this.region = region;
>>     }
>>
>>     public List<Region> choicesRegion() {
>>         return regions.listAllRegions();
>>     }
>>
>>     @MemberOrder(sequence = "7")
>>     public String getRegionName() {
>>         return regions.nameForRegion(getRegion());
>>     }
>>
>>     public void setRegionName(String name) {
>>         setRegion(regions.regionForName(name));
>>     }
>>
>>     public List<String> choicesRegionName(){
>>         return regions.listAllNamesExclusive(getRegion());
>>     }
>>
>> My Region class is this:
>>
>> package au.com.scds.chats.dom.modules.general.codes;
>>
>> import javax.jdo.annotations.Column;
>> import javax.jdo.annotations.IdentityType;
>> import javax.jdo.annotations.PrimaryKey;
>>
>> import org.apache.isis.applib.annotation.Action;
>> import org.apache.isis.applib.annotation.ActionLayout;
>> import org.apache.isis.applib.annotation.DomainServiceLayout;
>> import org.apache.isis.applib.annotation.DomainServiceLayout.MenuBar;
>> import org.apache.isis.applib.annotation.MemberOrder;
>> import org.apache.isis.applib.annotation.PropertyLayout;
>>
>> @javax.jdo.annotations.PersistenceCapable(
>>          identityType=IdentityType.APPLICATION)
>> public class Region {
>>
>>     public String title(){
>>         return getName();
>>     }
>>
>>     private String name;
>>
>>     @Column(name="region", allowsNull = "false")
>>     @PrimaryKey()
>>     @PropertyLayout(named="Region")
>>     @MemberOrder(sequence="1")
>>     public String getName() {
>>         return name;
>>     }
>>
>>     public void setName(String name) {
>>         this.name = name;
>>     }
>> }
>>
>> My Regions repository class is this:
>>
>> package au.com.scds.chats.dom.modules.general.codes;
>>
>> import java.util.ArrayList;
>> import java.util.List;
>>
>> import org.apache.isis.applib.DomainObjectContainer;
>> import org.apache.isis.applib.annotation.Action;
>> import org.apache.isis.applib.annotation.ActionLayout;
>> import org.apache.isis.applib.annotation.BookmarkPolicy;
>> import org.apache.isis.applib.annotation.DomainService;
>> import org.apache.isis.applib.annotation.DomainServiceLayout;
>> import org.apache.isis.applib.annotation.DomainServiceLayout.MenuBar;
>> import org.apache.isis.applib.annotation.MemberOrder;
>> import org.apache.isis.applib.annotation.ParameterLayout;
>> import org.apache.isis.applib.annotation.Programmatic;
>> import org.apache.isis.applib.annotation.SemanticsOf;
>> import org.apache.isis.applib.query.QueryDefault;
>>
>> import au.com.scds.chats.dom.modules.participant.Participant;
>>
>> @DomainService(repositoryFor = Region.class)
>> @DomainServiceLayout(menuBar = MenuBar.SECONDARY, named =
>> "Administration",
>> menuOrder = "100.1")
>> public class Regions {
>>
>>     // region > listAll (action)
>>     @Action(semantics = SemanticsOf.SAFE)
>>     @ActionLayout(bookmarking = BookmarkPolicy.AS_ROOT)
>>     @MemberOrder(sequence = "1")
>>     public List<Region> listAllRegions() {
>>         return container.allInstances(Region.class);
>>     }
>>
>>     // endregion
>>
>>     // region > create (action)
>>     @MemberOrder(sequence = "2")
>>     public Region createRegion(
>>             final @ParameterLayout(named = "Region Name") String name) {
>>         final Region obj = container.newTransientInstance(Region.class);
>>         obj.setName(name);
>>         container.persistIfNotAlready(obj);
>>         return obj;
>>     }
>>
>>     // endregion
>>
>>     // region > injected services
>>
>>     @javax.inject.Inject
>>     DomainObjectContainer container;
>>
>>     // endregion
>>
>>     @Programmatic
>>     public String nameForRegion(Region region) {
>>         return (region != null) ? region.getName() : null;
>>     }
>>
>>
>>     @Programmatic
>>     public List<String> listAllNamesExclusive(Region region) {
>>         List<Region> regions = listAllRegions();
>>         List<String> names = new ArrayList<String>();
>>         for (Region r : regions) {
>>             if (region != null && r != region) {
>>                 names.add(r.getName());
>>             }
>>         }
>>         return names;
>>     }
>>
>>
>>     @Programmatic
>>     public Region regionForName(String name) {
>>         Region region = container.firstMatch(new QueryDefault<>(
>> Region.class,
>>                  "findRegion", "name", name));
>>         return region;
>>     }
>>
>> }
>>
>> Just maybe I there is something missing still?
>>
>> I added a @Property annotation to the getRegionName() method, but that
>> gave
>> me a message saying it expected @javax.jdo.persistence.Column too.
>>
>> Note I couldn't use deprecated @Hidden in Isis 1.9.0.
>>
>>
>> On Thu, Jul 30, 2015 at 8:14 PM, Stephen Cameron <
>> steve.cameron.62@gmail.com
>> > wrote:
>>
>> > Hi Dan, When I tried this I got an model validation error message
>> relating
>> > to the choices method, I will have another go and if it fails, provide
>> the
>> > test case. Thanks for the tips.
>> >
>> > On Thu, Jul 30, 2015 at 7:57 PM, Dan Haywood <
>> dan@haywood-associates.co.uk
>> > > wrote:
>> >
>> >> You should be able to add a choicesXxx() for the derived property:
>> >>
>> >>     public List<String> choicesRegionName(){
>> >>         return Lists.newArrayList(Iterables.transform(choicesRegion(),
>> x
>> >> ->
>> >> x.getName()));
>> >>     }
>> >>
>> >> If that isn't sufficient, you might also need to add a setter:
>> >>
>> >> public void setRegionName(final String name) {
>> >> setRegion(Iterables.find(choicesRegion(), x ->
>> x.getName().equals(name)));
>> >> }
>> >>
>> >> Obviously, you might need to also add some error handling.
>> >>
>> >> ~~~
>> >>
>> >> Regarding the "external URL" idea, perhaps you could raise that as a
>> >> separate ticket, with a code sketch as to how you'd like this
>> information
>> >> specified?
>> >>
>> >> Thanks
>> >> Dan
>> >>
>> >>
>> >>
>> >>
>> >>
>> >> On 30 July 2015 at 03:17, Stephen Cameron <steve.cameron.62@gmail.com>
>> >> wrote:
>> >>
>> >> > Not so simple, as now the property cannot be updated.
>> >> >
>> >> > I have the following (@Hidden is deprecated)
>> >> >
>> >> >     @Column(allowsNull = "true")
>> >> >     @MemberOrder(sequence = "7")
>> >> >     @PropertyLayout(hidden=Where.EVERYWHERE)
>> >> >     public Region getRegion() {
>> >> >         return this.region;
>> >> >     }
>> >> >
>> >> >     public void setRegion(Region region) {
>> >> >         this.region = region;
>> >> >     }
>> >> >
>> >> >     public List<Region> choicesRegion(){
>> >> >         List<Region> regions = container.allInstances(Region.class);
>> >> >         return regions;
>> >> >     }
>> >> >
>> >> >     @MemberOrder(sequence = "7.1")
>> >> >     public String getRegionName(){
>> >> >         return (getRegion() != null) ? getRegion().getName() : null;
>> >> >     }
>> >> >
>> >> > Sure enough getRegion doesn't appear in the UI but getRegionName
>> does,
>> >> but
>> >> > then setRegion and choiceRegion don't mean anything to the UI, so the
>> >> > Region property is read-only.
>> >> >
>> >> > This issue is maybe more significant than it appears at first, in
>> terms
>> >> of
>> >> > domain modelling such code-lists are simple types that 'represent'
>> >> things
>> >> > on the boundary of the domain of interest. So we usually want to just
>> >> > represent them with a name. Presently it makes no sense to go to that
>> >> thing
>> >> > via a hyperlink as all we'll find is that name, our model extends no
>> >> > further.
>> >> >
>> >> > However we just might like to allow users to leave the domain model
>> and
>> >> go
>> >> > to a resource outside. So, extending the suppressLink=true idea, I
>> would
>> >> > add that each object could have an implicit link(URL),created by
>> Isis,
>> >> or
>> >> > an explicit one and if the explicit one is present it can optionally
>> be
>> >> > used as an alternative to the implicit one.
>> >> >
>> >> > For example, you might create a database to log fish details, species
>> >> is a
>> >> > boundary concept, we aren't likely to want to add a new species to
>> the
>> >> list
>> >> > of known species, but we'd like to keep such a list handy, but for
>> each
>> >> > named species in that list, to provide an explicit link to a resource
>> >> in a
>> >> > global fish database. It makes more sense to use this link than the
>> >> > implicit one, as if the implicit one is used we'd navigate to the
>> domain
>> >> > object page displaying the name and URL, both of which items of data
>> >> could
>> >> > have been in the explicit link.
>> >> >
>> >> > In the explicit case you might want to warn the user they are
>> navigating
>> >> > outside the Isis domain application.
>> >> >
>> >> > Perhaps all this could be done simply if there was a URI type in
>> Isis,
>> >> that
>> >> > would allow it to create 'smart links' automatically.
>> >> >
>> >> >
>> >> >
>> >> >
>> >> >
>> >> > On Wed, Jul 29, 2015 at 9:37 PM, Stephen Cameron <
>> >> > steve.cameron.62@gmail.com
>> >> > > wrote:
>> >> >
>> >> > > Thanks Jeroen, seems simple enough :)
>> >> > >
>> >> > > On Wed, Jul 29, 2015 at 9:28 PM, Jeroen van der Wal <
>> >> jeroen@stromboli.it
>> >> > >
>> >> > > wrote:
>> >> > >
>> >> > >> You could also hide the property and create a separate getter
for
>> >> > display
>> >> > >> purposes only:
>> >> > >>
>> >> > >> private MyProperty myProperty;
>> >> > >>
>> >> > >> @Hidden
>> >> > >> public MyProperty getMyProperty() {...}
>> >> > >>
>> >> > >> public void setMyProperty(...) {...}
>> >> > >>
>> >> > >> public String getMyPropertyName() {
>> >> > >>     getMyProperty.getName();
>> >> > >> }
>> >> > >>
>> >> > >> On 29 July 2015 at 13:18, Stephen Cameron <
>> >> steve.cameron.62@gmail.com>
>> >> > >> wrote:
>> >> > >>
>> >> > >> > On Wed, Jul 29, 2015 at 6:38 PM, Dan Haywood <
>> >> > >> dan@haywood-associates.co.uk
>> >> > >> > >
>> >> > >> > wrote:
>> >> > >> >
>> >> > >> > > You are right, they will be displayed as links;
there's no
>> way to
>> >> > >> disable
>> >> > >> > > it currently.
>> >> > >> > >
>> >> > >> > > We could add a bit of metadata perhaps for this,
eg
>> >> > >> > > @DomainObjectLayout(suppressLink=true) or similar.
>> >> > >> > >
>> >> > >> > > Please raise a ticket.
>> >> > >> > >
>> >> > >> >
>> >> > >> > OK https://issues.apache.org/jira/browse/ISIS-1180
>> >> > >> >
>> >> > >> > >
>> >> > >> > > Thx
>> >> > >> > > Dan
>> >> > >> > >
>> >> > >> > > PS: these entities wouldn't be value types, rather
regular
>> >> entities.
>> >> > >> But
>> >> > >> > > you are right... what we really want is full-class
support for
>> >> value
>> >> > >> > types.
>> >> > >> > >   We're just not there yet...
>> >> > >> > >
>> >> > >> > >
>> >> > >> > >
>> >> > >> >
>> >> > >> > >
>> >> > >> > >
>> >> > >> > > On 29 July 2015 at 09:34, Stephen Cameron <
>> >> > steve.cameron.62@gmail.com
>> >> > >> >
>> >> > >> > > wrote:
>> >> > >> > >
>> >> > >> > > > Thanks, but surely such object properties always
end up
>> being
>> >> > >> displayed
>> >> > >> > > as
>> >> > >> > > > links? Clicking on the link to go to such an
object page is
>> >> > >> > meaningless,
>> >> > >> > > as
>> >> > >> > > > it only has one name property, that was displayed
in the
>> link.
>> >> > Can I
>> >> > >> > > > disable that default behaviour for value types?
>> >> > >> > > >
>> >> > >> > > >
>> >> > >> > > >
>> >> > >> > > > On Wed, Jul 29, 2015 at 5:47 PM, Dan Haywood
<
>> >> > >> > > dan@haywood-associates.co.uk
>> >> > >> > > > >
>> >> > >> > > > wrote:
>> >> > >> > > >
>> >> > >> > > > > On 29 July 2015 at 08:08, Stephen Cameron
<
>> >> > >> > steve.cameron.62@gmail.com>
>> >> > >>
>> >> > >> > > > > wrote:
>> >> > >> > > > >
>> >> > >> > > > > > Hi,
>> >> > >> > > > > >
>> >> > >> > > > > > I want to do have some properties
that are essentially
>> >> String
>> >> > >> > types,
>> >> > >> > > > but
>> >> > >> > > > > > which have a limited range of values
(code-lists or
>> >> restricted
>> >> > >> > > > > > vocabularies). I want to allow these
lists to be
>> >> administered
>> >> > >> > > > centrally,
>> >> > >> > > > > so
>> >> > >> > > > > > to add them to a single Administration
menu item for
>> admin
>> >> > >> users.
>> >> > >> > > > > >
>> >> > >> > > > > > For most users these codes should
appears as lists of
>> >> strings
>> >> > >> not
>> >> > >> > as
>> >> > >> > > > > > objects, but making them objects
seems to be the
>> logical OO
>> >> > way
>> >> > >> to
>> >> > >> > > deal
>> >> > >> > > > > > with them in Isis. So they are basically
objects with
>> one
>> >> > 'name'
>> >> > >> > > > property
>> >> > >> > > > > > (and maybe an id added by datanucleus).
All users need
>> to
>> >> see
>> >> > is
>> >> > >> > the
>> >> > >> > > > name
>> >> > >> > > > > > property, no icon is needed.
>> >> > >> > > > > >
>> >> > >> > > > > > Also, if I make them objects I also
will get referencial
>> >> > >> integrity
>> >> > >> > > > > > constraints applied in the database.
>> >> > >> > > > > >
>> >> > >> > > > > >
>> >> > >> > > > > +1, do it this way.  That way they can
also hold
>> behaviour in
>> >> > the
>> >> > >> > > future.
>> >> > >> > > > >
>> >> > >> > > > >
>> >> > >> > > > >
>> >> > >> > > > >
>> >> > >> > > > > > I wonder there is a simple recipe
for this?
>> >> > >> > > > > >
>> >> > >> > > > >
>> >> > >> > > > > No magic recipe for the domain entities...
basically
>> >> > copy-n-paste
>> >> > >> the
>> >> > >> > > > > SimpleObject that's in our archetype as
many times as
>> needed,
>> >> > and
>> >> > >> > tweak
>> >> > >> > > > as
>> >> > >> > > > > required.
>> >> > >> > > > >
>> >> > >> > > > > If you want to use the code as the primary
key, then use
>> DN
>> >> > >> > application
>> >> > >> > > > > identity
>> >> > >> > > > >
>> >> > >> > > > > @javax.jdo.annotations.PersistenceCapable(
>> >> > >> > > > >         identityType=IdentityType.APPLICATION,
>> >> > >> > > > >         schema = "simple",
>> >> > >> > > > >         table = "SimpleObject"
>> >> > >> > > > > )
>> >> > >> > > > >
>> >> > >> > > > > and add @PrimaryKey to the "name" property.
 Also add
>> @Title
>> >> to
>> >> > >> that
>> >> > >> > > > 'name'
>> >> > >> > > > > property (it is in SimpleObject already).
>> >> > >> > > > >
>> >> > >> > > > >
>> >> > >> > > > > You would probably want to remove the
version column, ie
>> >> remove:
>> >> > >> > > > >
>> >> > >> > > > > @javax.jdo.annotations.Version(
>> >> > >> > > > >         strategy=VersionStrategy.VERSION_NUMBER,
>> >> > >> > > > >         column="version")
>> >> > >> > > > >
>> >> > >> > > > >
>> >> > >> > > > > In addition, if you annotate the class
as "bounded"
>> >> > >> > > > > (@DomainObject(bounded=true)) then you
are telling the
>> >> framework
>> >> > >> that
>> >> > >> > > > > there's a limited - ie bounded - set of
instances, and so
>> it
>> >> > will
>> >> > >> > > display
>> >> > >> > > > > all instances in a drop-down for you.
>> >> > >> > > > >
>> >> > >> > > > >
>> >> > >> > > > > HTH
>> >> > >> > > > > Dan
>> >> > >> > > > >
>> >> > >> > > >
>> >> > >> > >
>> >> > >> >
>> >> > >>
>> >> > >
>> >> > >
>> >> >
>> >>
>> >
>> >
>>
>
>

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message