Dynamic selection out of multiple views = feature request?

22 posts / 0 new
Last post
Marc
Offline
Joined: 07/08/2009
Dynamic selection out of multiple views = feature request?

Hi,

 

Imagine the following use case:

An employee can submit a holiday request. Subsequently he can still see his request but no longer modify it.

 

A way to implement this is JSpresso is to program in Java a condition on the save action, isn’t it? But this is not a user-friendly solution: The employee, who would still try to modify his submitted holiday request, would only get an error at the moment he is trying to save his changes.

 

It is more user-friendly to immediately indicate to the employee that his holiday request is read-only (in its current state).

 

Can we achieve this with JSpresso?

Or might it be a good candidate for a feature request?

Perhaps we need a new concept: the possibility to define multiple views on an entity and defining which view applies by means of some mapping criteria: user on one hand and the properties of the entity on the other hand. Multiple views would also allow to define other actions per view: We could also indicate that certain actions are not allowed: we could hide the action or gray it out (also better than giving an error message only when the action is pushed upon).

 

Thanks for your thoughts,

Marc

vvandens
Offline
Joined: 05/29/2008
Dynamic selection out of multiple views = feature request?

Hi Marc,

There is already such a concept in Jspresso but it's not yet documented. I would actually need 36 hours in day Wink...

Look at the org.jspresso.framework.view.descriptor.ICardViewDescriptor interface and its hierarchy (give the source code a look) :

  • AbstractCardViewDescriptor is the base class for all card view descrriptors.
  • EntityCardViewDescriptor is a concrete implementation that choses the view to display based on the entity class
  • WorkspaceCardViewDescriptor is the view descriptor used in a Jspresso application to render the application main pane based on the selected workspace/module.

A card view is a stack of views (like the swing card layout) where only the selected card is made visible. The decision to display a card is made by the getCardNameForModel(Object) method. So basically, all you would have to do is create your own subclass and implement the getCardNameForModel(Object) method to implement your business rule and select the appropriate view key accordingly.

This could be made even simpler if we could inject the card determination strategy in Spring, i.e. have a contrete BasicCardViewDescriptor that can be injected with an instance of a class responsible for determining the view based on the model instance. This could be a feature request (would you create it ?).

Just a remark : Card views are best used as detail view in a master-detail, i.e. you would include it in a container where cascadingModel=true so that the model gets dynamically assigned depending on the selection made on the master view.

 

To be complete, regarding dynamic editability of a view or view part, there is another undocumented yet feature. It is the concept of accessibility gates. You can assign to a view (or a sub view) descriptor, a collection of writability (and readability) gates (see the org.jspresso.framework.util.gate.IGate class hierarchy). What it means is for the produced view to be editable (writable) all gates must be open. And Jspresso provides built-in gate types that open and close dynamically based on model boolean properties (org.jspresso.framework.binding.model.BooleanPropertyModelGate).

I hope this helps.

 

I'm sorry I can't elaborate more at this time since I'm about to leave for 3 weeks of vacations (at last...). Of course you can continue to post your ideas/questions/bugs to the forum (and I really appreciate that), but just be aware that I won't be able to answer (at least not deeply nor regularly) until I come back.

 

Best,

Vincent

Marc
Offline
Joined: 07/08/2009
Vincent, Have a good

Vincent,

Have a good holiday!

Marc

Marc
Offline
Joined: 07/08/2009
Hi, Before choosing between

Hi,

Before choosing between cards, views and/or gates, I first would like to describe another aspect that would be part of the required behaviour:

An entity-instance being in read-only mode, should of course be read-only as well in the table showing all instances resulting from a search (the difficult part), as well in the detail view showing only a single instance (the easier part). The search table contains several instances, some being read-only, others being editable... Or if we think on field-level: read-only fields are read-only as well in the search result table as in the entity detail view.

Or is this a bridge too far? Should we in this case (simply) always have the entire serach result table in read-only mode and only allow editing in the detail view?

So my question is: do the card and gate mechanisms apply in a consitent way to the search result panel as well as to the entity detail view?

Thanks for your thoughts,

Marc

 

vvandens
Offline
Joined: 05/29/2008
Gates are also applicable on the model

Marc,

The "gates" concept is also applicable on the model layer, e.g. you can set a collection of gates to any property descriptor. In that case, all view elements backed by a property that have one of its writability gates closed will automagically turn read-only. This includes table cells, form fields, and so on (but the property remains of course writable programmatically).

However, there is no way to set a collection of accessibility gates on the entity/component level. You have to set them on every property. But this could make a good feature request Wink.

BTW, I've opened (on Pierre's suggestion) a Jspresso wiki where we can extend the Jspresso documentation on features like this one. Feel free to contribute whenever you think that there is some valuable material in the discussions. And don't worry about being erroneous or unprecise, I will double check everything. It's just a way of starting things up.

 

Best,

Vincent

vvandens
Offline
Joined: 05/29/2008
Feature requests

Marc,

I've created and implemented the 2 feature requests of this thread (2850085 and 2850082). Regarding your objectives, I've also double checked the correct behaviour of IModelGates assigned to views. There was actually a bug that would have prevented your use-case to get correctly implemented. This is all fixed now.

Everything is included in the 3.0.1-SNAPSHOT that I'm uploading now.

 

Best,

Vincent

Marc
Offline
Joined: 07/08/2009
Hi Vincent, So my intention

Hi ,

 

If I would like to experiment a bit with gates, how should I proceed?

Can gates be configured in the JSpresso/Spring/XML configuration files?

If not, I see that some classes like IPropertyDescriptors for instance are foreseen with gates. But at this moment I do not have a clue where in Java I should code somithing to use gates (and set the model etc), in order to make a specific property editable or not depending on another property (the model then).

 

Thanks for your insights,

Marc

vvandens
Offline
Joined: 05/29/2008
Gates

 

Hi Marc,

A few line of code should hopefully make things clearer. Try to move around the following Spring XML lines :

    <property name="writabilityGates">
<bean class="org.jspresso.framework.binding.model.BooleanPropertyModelGate">
<property name="accessorFactory" ref="accessorFactory"/>
<property name="booleanPropertyName" value="persistent"/>
<property name="openOnTrue" value="false"/>
<property name="grantedRoles">
<list>
<value>administrator</value>
</list>
</property>
</bean>
</property>

They basically say :

Create a gate that is open when the model is not (openOnTrue=false) persistent (booleanPropertyName="persistent"). The gate can only be opened by a logged-in user that has the administrator (grantedRoles=["administrator"]) role. The framework will do the rest, i.e. apply the model, trigger the isPersistent() method, react on property change events (when the persistent property changes, i.e. when an entity is saved), check that the subject is granted the right to open the gate.

1/ include the previous snippet in model.xml in one of your entities. All the views backed by this entity will be impacted. When the view model is transient, the view will be editable and when the view model is persistent, the view will be read-only. I must admit that it's not a real-life use-case Wink. Try to create an entity, edit some values, save and you should not be able to edit anything more...

2/ transfer the previous snippet on an entity property descriptor instead of the whole entity. Now only the fields (and table cells) backed by this property will have the behaviour described above.

3/ now transfer the snippet from the model.xml to the view.xml. Include it in a view. Only this view will be impacted.

4/ now transfer it on a "PropertyViewDescriptor" (those are used to refine table columns, using the columnViewDescriptors property and form fields using the propertyViewDescriptors property). Only the column (or the form field) of the enclosing view will be impacted.

The objective is that you never have to mess around with getting the model and so on.

Note 1 : I reworked slightly things in order to simplify using the subject roles in gates. So this code with the grantedRoles assigned to the gates will only work on tonight snapshot.

Note 2 : If you only want to display/hide fields, columns or complete views based on the logged-in user roles, you can use the grantedRoles property (but this one is in the manual) on model and/or view with the same kind of cascading mecanism as the one described above.

Note 3 : gates, as well as the simpler grantedRoles property can also be used on actions.

Hope this helps.

 

Best,

Vincent

Marc
Offline
Joined: 07/08/2009
Vincent, I applied the XML

Vincent,

I applied the XML sniplett on an entity (I tried without roles).

When I am in the entity detail view, I quite get the behaviour you described: an entity becomes read-only once saved.

But I can still change these entitie property values in the main panel (search results in my workspace/module)! Is this normal?

(PS: if this is normal, it doens't necessarily hinder me in achieving my goals. It is just for me to understand.)

Marc

vvandens
Offline
Joined: 05/29/2008
Missing writability change event in flex

Marc,

Thank you for the report ! It definitely should have worked as you described (i.e. ALL views backed by the entity have to change read-only, including table rows). We were actually missing a notification to the Flex (and Qooxdoo) frontend that prevented the result table to get notified of the writability change (Swing is much less sensible on this side). It is now fixed and I'm uploading the snapshot.

BTW, I reverted some of the changes about applying roles directly on BooleanPropertyModelGate. I've created a dedicated gate for applying roles permissions (GrantedRolesGate). This new design leads to better separation of concerns.

So the XML snippet to apply is now (see how roles permission have been transferred to the new gate) :

    <property name="writabilityGates">
<list>
<bean class="org.jspresso.framework.security.GrantedRolesGate">
<property name="grantedRoles">
<list>
<value>administrator</value>
</list>
</property>
</bean>
<bean class="org.jspresso.framework.binding.model.BooleanPropertyModelGate">
<property name="accessorFactory" ref="accessorFactory" />
<property name="booleanPropertyName" value="persistent" />
<property name="openOnTrue" value="false" />
</bean>
</list>
</property>

Thanks again,

 

Best,

Vincent

Marc
Offline
Joined: 07/08/2009
Vincent, It works! I'm quite

Vincent,

It works!

I'm quite impressed with the flexibility that JSpresso framework has shown here.

In order to get more comfortable with JSpresso, I would like to understand better its flexible architecture. It would be my pleasure to author a short wiki about it once I've understood. I think that the changes you made here are a good occasion for me to understand better how everything is wired together???? I just launch a number of questions here:

- I see that JSpresso generates java classes for entities. Also hybernate mapping and the SQL table creation script are generated. Does JSpresso generate other classes?

-I guess that all files whose name ends with "Descriptor" correspond exactly with the structures in the JSpresso/Spring/XML files that we author to model an application. Is this correct?

-About Spring Dependency Injection: I guess it is used essentially to create instances of "Descriptor"-classes that are part of the framework and have been coded manually. For instance BasicEntityDescriptors. Or does Spring Dependency Injection also create new classes by interleaving things? If yes could you give an example?

-Specificly about the example here above in this forum-item:

  • I guess that the property "persistent" of an entity is accessed through some kind of meta-invocation. I would for instance like to be able to fingerpoint the line of code in JSpresso that executes the reading of the "persistent" property.
  • I saw that an IPropertyDescriptor contains writibilityGates. In the java code, I did not immediately see writibiligates for entities and for all other gate-capable components. Is this because you added new code since 3.0.0 or does this type of combinations (gates also for entities) become available through Sping Dependency Invocation? (Or did I overlooked some superclass)
  • I think it misght also be instructive to publish the source code of this release and indicate what you changed, for instance to solve the latest bug where the gates were not propagated to table views.

I launched here a lot questions at once, also to describe my state of (un)knowledge. No hurry! Just see which is / are most instructive to possibly comment.

Greetings,

Marc

atao
Offline
Joined: 10/15/2008
Some answers

Marc,

Vincent would surely complete/correct these answers. Here is what I think I understood:

- I see that JSpresso generates java classes for entities. Also hybernate mapping and the SQL table creation script are generated. Does JSpresso generate other classes?

Short: no.

Long:

The only template is HibernateXdocletEntity.ftl, used to generate the entity interfaces. It's a FreeMarker template which has nothing to do with hibernate but to insert the right hibernate tags. (It could be JPA in a future version...)

From these entity interfaces, Hibernate is able to generate all the files it needs.

From the configuration files (i.e. the Spring files), no other files are genereted by jspresso.

Note: may be I'm wrong about some specific files for UI like the qooxdoo one.

-I guess that all files whose name ends with "Descriptor" correspond exactly with the structures in the JSpresso/Spring/XML files that we author to model an application. Is this correct?

Yes

-About Spring Dependency Injection: I guess it is used essentially to create instances of "Descriptor"-classes that are part of the framework

Yes but not only, see below.

and have been coded manually.

Mmm, if you mean instances of "Descriptor"-classes as specified in a spring configuration file, then yes. But you never code manually (i.e. in java) such a class.

At least  until you want to enhance the capabilities provided by jspresso, e.g. to deal with joda date and time, or to define a specific authentication process (it reminds me that these two topics would be good wiki entries...)

If you mean classes coded manually by you, and injected in any hook provided by jspresso, you are still right. See:

- Service delegate classes

- Extension classes

- Interceptor classes

- Processor classes

- Action classes

- ...

Or does Spring Dependency Injection also create new classes by interleaving things?

Not sure I understand what you mean here (autowire? proxy?).

It's all for now...

Pierre

 

 

 

vvandens
Offline
Joined: 05/29/2008
Some answers

 

Marc, Pierre,

@Pierre: I told you I could give you the keys of the Jspresso house during my vacations Wink.

@Marc: Don't have much to add over Pierre's answers :

  • Jspresso does not generate any code except for the domain model (and its ORM mapping). Everything else occurs at runtime, and specially the UI creation and binding. This takes place in the Default[Swing|Ulc|Wings]ViewFactory that deal with the implementation "details". This thread might give you some hints.
  • Views and model are abstracted by what we call connectors. Connectors know how to bind together and they make possible different kind of views and models to work together without knowing eachother in advance (the adaptor pattern). you have view connectors that adapt to the view components and model connectors that adapt to the model. This is the heart of Jspresso UI-agnostic binding.
  • About Spring DI: Just consider it as a smart and compact way of creating and assembling POJOs to build your app. There is really nothing more. You could actually do it in plain java, but it would be much more painful.

 

I guess that the property "persistent" of an entity is accessed through some kind of meta-invocation. I would for instance like to be able to fingerpoint the line of code in JSpresso that executes the reading of the "persistent" property.

You can put a break point in the BooleanPropertyModelGate.setModel(Object) method. This is where the gate accesses its model to query the persistent property. I strongly suggest using the simple 2-tier swing implementation for that (all in 1 JVM).

 

I think it misght also be instructive to publish the source code of this release and indicate what you changed, for instance to solve the latest bug where the gates were not propagated to table views.

You can access Jspresso svn online and see what has been changed per commit and so on. On this special case, you can visually compare what has been changed between rev 1972 and 1973.

Regarding the source code, it is publicly and anonymously accessible from svn. For the latest snapshot (trunk) :

svn checkout https://svn.jspresso.org/jspresso/framework/trunk jspresso-trunk

Then, whenever a new snapshot is published, just do a svn update to upgrade your sources.

 

HTH,

Vincent

atao
Offline
Joined: 10/15/2008
One question

Vincent,

About Spring DI: Just consider it as a smart and compact way of creating and assembling POJOs to build your app. There is really nothing more. You could actually do it in plain java, but it would be much more painful.

In a previous thread you said you were thinking about replacing xml by some king of dsl for the Spring configuration files. But what about Spring Java Configuration Project?

Regards

Pierre

vvandens
Offline
Joined: 05/29/2008
DSL

Hi Pierre,

I had a quick look (maybe too quick ?) to Spring JavaConfig a few month ago and I was not enthusiat about it at least as far as Jspresso beans assembly is concerned. This is mainly because JavaConfig seems to spread things all over the place and I'm not sure we could gain in readability.

But wait, there should be some hot news about a Jspresso DSL in a few weeks. A friend of mine is working on a Groovy based DSL for Jspresso and what I've seen is really promising. It leads to much clearer and compact application assembly with 1/4 (maybe even less) of the actual XML volume. The strategy is to plug the DSL as an entrypoint to generate Spring XML definitions. Of course, we won't reach Spring flexibility in the DSL, but the DSL generated Spring XML files (that may cover 90% of the needs) will be part of the Jspresso application context, along with hand-written XML that can override or create new bean definitions for things that the DSL may not cover.

 

Best,

Vincent

Marc
Offline
Joined: 07/08/2009
Hi, I come back on the

Hi,

I come back on the writabilitygate decribed earlier in this item.

I applied the writabilitygate on the property "code". The model is the boolean property "locked". The gate functions well for locking and hence making "code" read-only. But when I check off "locked" then "code" remains read-only, whereas I would expect that "code" becomes writable again.

I include here the XML description:

 <bean id="Product"
  class="org.jspresso.framework.model.descriptor.entity.basic.BasicEntityDescriptor">
  <constructor-arg value="com.example.helloworld.model.Product" />
  <property name="propertyDescriptors">
   <list>

    <bean
     class="org.jspresso.framework.model.descriptor.basic.BasicStringPropertyDescriptor">
     <property name="name" value="name" />
     <property name="mandatory" value="true" />
     <property name="readOnly" value="false" />
    </bean>
    <bean
     class="org.jspresso.framework.model.descriptor.basic.BasicStringPropertyDescriptor">
     <property name="name" value="code" />
     <property name="mandatory" value="true" />
     <property name="readOnly" value="false" />
     <property name="regexpPattern" value="[A-Z]{2}[\d]{3}" />
     <property name="regexpPatternSample" value="AB123" />
     
     <property name="writabilityGates">
      <list>
       <bean class="org.jspresso.framework.security.GrantedRolesGate">
        <property name="grantedRoles">
         <list>
          <value>administrator</value>
         </list>
        </property>
       </bean>
       <bean class="org.jspresso.framework.binding.model.BooleanPropertyModelGate">
        <property name="accessorFactory" ref="accessorFactory" />
        <property name="booleanPropertyName" value="locked" />
        <property name="openOnTrue" value="false" />
       </bean>
      </list>
     </property>    
    </bean>
    <bean
     class="org.jspresso.framework.model.descriptor.basic.BasicBooleanPropertyDescriptor">
     <property name="name" value="locked" />
     
     <property name="readOnly" value="false" />
     
    </bean>

   </list>
  </property>
  <property name="iconImageURL"
   value="classpath:com/example/helloworld/images/ProductIcon.jpg" />
 </bean>

vvandens
Offline
Joined: 05/29/2008
Unlocking your product

Marc,

It should work exactly as you describe.

I tried to reproduce the problem but I couldn't. The controlled field switches from r/o to writable on any subsequent change of the boolean property.

I suppose this is on Flex, right ? Does it occur in table views, component views or both ? Can you reproduce it systematically ?

 

Best,

Vincent

Marc
Offline
Joined: 07/08/2009
Vincent, The problem does not

Vincent,

The problem does not appear in AJAX, only in Flex.

The problem does not appear in the entity detail view, it only appears in the table view (in the main pain under the search criteria).

The problem is repeatable.

Marc

vvandens
Offline
Joined: 05/29/2008
Fixed it

Marc,

I couldn't reproduce the problem because I was working on a locally modified version of Jspresso that fixes it... I'm uploading a new snapshot with the complete fix.

Regarding this new snapshot, be aware of the change that has to be applied on the Qooxdoo bootstrap class that is local to your project (whenever you use Qooxdoo). Everything is detailed in this thread.

Thanks again for your report of the issue. Don't hesitate to post back if anything does not work as expected.

 

Best,

Vincent

vvandens
Offline
Joined: 05/29/2008
Wiki page

Marc,

I've just seen that you were writing a Wiki entry for gates ! I've just changed your user permissions so that you can use the advanced WYSIWYG editor for formatting.

 

Thanks for your contribution !

 

Vincent

Marc
Offline
Joined: 07/08/2009
Vincent, after all

Vincent,

after all discussions on gates and including our feature request 2880635 (writabilitygate based on enumerated type), I still have one need left open:

In the detail view on an entity, I want to display the possible actions on that entity. But the list of possible actions depends on the state of the entity.

I see two possible solutions:

1) selecting the view based on the state of the entity. If we select this solution, I would make the feature request that you decribed here above in this item: "we could inject the card determination strategy in Spring, i.e. have a contrete BasicCardViewDescriptor that can be injected with an instance of a class responsible for determining the view based on the model instance."

2) introduce a kind of gates on actions.

  • For actions in the main application pane (in the table giving the search results panel), the actions are always visible because there possibly are entities with different states. An action is of course not invokable on an entity where the gate is closed.
  • For actions in the detailed entity view: only the actions with an open gate should be shown.

Can you agree that my need, as I expressed it, makes sense from functional viewpoint?

Which of both solutions proposed would we take then? Or another solution?

Thanks,

Marc

 

vvandens
Offline
Joined: 05/29/2008
actionabililtyGates

Hi Marc,

You can already use gates on actions. Every frontend action can be assigned a list of gates to enable/disable (the actionabilityGates property). So I would go this way.

 

Don't hesitate to report any problem on this feature.

 

HTH,

Vincent