org.sandev.basics.util
Class AbstractFormManager

java.lang.Object
  extended byorg.sandev.basics.util.AbstractFormManager
All Implemented Interfaces:
UIFormManager
Direct Known Subclasses:
RootedFormManager, StandardFormManager

public abstract class AbstractFormManager
extends java.lang.Object
implements UIFormManager

Provides a root implementation of a UIFormManager delegating data manipulation tasks to extending classes.


Field Summary
static java.lang.String CLASS_DISAMBIGUATION_PROMPT
          Default output text used when prompting the user to disambiguate the message class.
static java.lang.String FIX_FIELDS_BEFORE_SAVE
          Default output text added if field validation fails on ACTION_SAVE.
static java.lang.String INVALID_FIELD_VALUE_PREFIX
          Default output text used as a prefix when reporting any invalid field values found.
static int RC_CANCELLED
          We asked the user to resolve the currClass, and they cancelled.
static int RC_DONE
          The currClass is unambiguous.
static int RC_QUERYING
          We are asking the user to resolve the currClass.
protected  UIFormAdaptor uifa
          Our UIFormAdaptor reference set during initialization.
 
Constructor Summary
AbstractFormManager()
           
 
Method Summary
 void disableUnsupportedActions(UIFormContext uifc)
          Turn off actions that are not supported in the current mode.
protected  void doActionAdd(UIFormContext uifc, UIFormOwner owner)
          The user has selected to switch to ADDING mode.
protected  void doActionCancel(UIFormContext uifc, UIFormOwner owner)
          The user cancels the current operation.
protected  boolean doActionDelete(UIFormContext uifc, UIFormOwner owner)
          The user has selected to delete a contained object or a top level object.
protected  void doActionDeref(UIFormContext uifc, UIFormOwner owner)
          The user has requested that the display shift to a referenced object.
protected  void doActionDrilldown(UIFormContext uifc, UIFormOwner owner)
          The user has requested that the display drill down to a contained object from our current location.
protected  void doActionEdit(UIFormContext uifc, UIFormOwner owner)
          The user has selected to switch to UPDATING mode.
protected  void doActionFind(UIFormContext uifc, UIFormOwner owner)
          The user has clicked "find", either to bring up a query form or to execute the displayed query form.
protected  void doActionHelp(UIFormContext uifc, UIFormOwner owner)
          The user has asked for help.
protected  void doActionMove(UIFormContext uifc, UIFormOwner owner, int offset)
          The user has selected to move a reference item up or down within the reference array or contained object array.
protected  void doActionNew(UIFormContext uifc, UIFormOwner owner)
          The user has selected to add a reference to an instance that they will now create.
protected  void doActionNext(UIFormContext uifc, UIFormOwner owner)
          The user has selected to move to the next page of elements.
protected  void doActionOk(UIFormContext uifc, UIFormOwner owner)
          The user has selected to complete their current action.
protected  void doActionParent(UIFormContext uifc, UIFormOwner owner)
          The user has requested that the display move up one level.
protected  void doActionPrevious(UIFormContext uifc, UIFormOwner owner)
          The user has selected to move to the previous page of elements.
protected  void doActionRemove(UIFormContext uifc, UIFormOwner owner)
          The user has selected to remove a reference to an object.
protected  boolean doActionSave(UIFormContext uifc, UIFormOwner owner)
          The user elects to save their outstanding work.
protected  void doActionSelect(UIFormContext uifc, UIFormOwner owner)
          The user has selected an instance from a collection of instances that were displayed.
protected  boolean fieldValidateCurrentInstance(UIFormContext uifc)
          Call the fieldValidate method of the currInst to make sure the field values are reasonable.
protected  java.lang.String getClassDisambiguationPrompt()
          Return the text for the UIFormQuery asking to disambiguate the class type.
protected  java.lang.String getFieldValidationFailureText()
          Accessor for field validation failure on save.
protected  java.lang.String getInvalidFieldMessagePrefix()
          Accessor for invalid field value messages.
 void initFormAdaptor(UIFormAdaptor uifa)
          Initialize the UIFormAdaptor.
protected abstract  boolean mergeChangesToParentBeforeAdd(UIFormContext uifc)
          We are about to do a contained add, so make sure any outstanding changes to the currInst are captured before it gets replaced with a new instance for editing.
protected  void okContainedAdd(UIFormContext uifc, UIFormOwner owner)
          Add a new instance contained inside of a parent object.
protected  void okNewReference(UIFormContext uifc, UIFormOwner owner)
          Add a reference from the parent to a new instance.
protected  void okTopLevelAdd(UIFormContext uifc, UIFormOwner owner)
          Add a completely new instance.
protected  void okUpdate(UIFormContext uifc, UIFormOwner owner)
          Process the update operation, tracking the necessary updates.
protected  boolean outstandingChangesExist(UIFormContext uifc)
          Returns true if there are outstanding changes to the currInst which need to be captured, false otherwise.
 boolean processForm(UIFormContext uifc, UIFormOwner owner)
          A big control switch that calls the appropriate doActionXXX method.
protected  void processUpdate(SandInstanceMessage sim, UIFormContext uifc, int updateAction, UIFormOwner owner)
          Get the update message for this struct message, fill it out, and call trackUpdates.
protected  int resolveClass(UIFormContext uifc)
          Figure out what class we are dealing with.
protected  void resolveReferences(UIFormContext uifc, UIFormOwner owner)
          Check our references make sense, adding errors to the outputText for any invalid references found.
protected abstract  boolean supportsTopLevelAdd()
          Returns true if this form manager allows new top level object instances to be created while in LISTING mode.
protected abstract  boolean supportsTopLevelFind()
          Returns true if this form manager allows other top level object instances to be found while in LISTING mode.
protected  void trace(int level, java.lang.String text)
          Debugging output statements.
protected abstract  void trackUpdates(SandUpdateMessage update, UIFormContext uifc)
          Track this update for save processing.
protected  void wrappedGenAdd(java.lang.String prefix, UIFormContext uifc, SandInstanceMessage parent, SandInstanceMessage child)
          Figures out SET/APPEND/INSERT action and calls wrappedGenMod.
protected  void wrappedGenMod(java.lang.String prefix, SandInstanceMessage sim, int action, java.lang.String field, int arrayIndex, java.lang.Object opmsg)
          Wrap the general modifier call.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

uifa

protected UIFormAdaptor uifa
Our UIFormAdaptor reference set during initialization.


RC_QUERYING

public static final int RC_QUERYING
We are asking the user to resolve the currClass. We have added a UIFormQuery to the UIFormContext and need to go get an answer from the user now.

See Also:
Constant Field Values

RC_CANCELLED

public static final int RC_CANCELLED
We asked the user to resolve the currClass, and they cancelled. The caller must now undo things to return appropriately. There is no outstanding query.

See Also:
Constant Field Values

RC_DONE

public static final int RC_DONE
The currClass is unambiguous.

See Also:
Constant Field Values

CLASS_DISAMBIGUATION_PROMPT

public static final java.lang.String CLASS_DISAMBIGUATION_PROMPT
Default output text used when prompting the user to disambiguate the message class.

See Also:
Constant Field Values

FIX_FIELDS_BEFORE_SAVE

public static final java.lang.String FIX_FIELDS_BEFORE_SAVE
Default output text added if field validation fails on ACTION_SAVE.

See Also:
Constant Field Values

INVALID_FIELD_VALUE_PREFIX

public static final java.lang.String INVALID_FIELD_VALUE_PREFIX
Default output text used as a prefix when reporting any invalid field values found.

See Also:
Constant Field Values
Constructor Detail

AbstractFormManager

public AbstractFormManager()
Method Detail

initFormAdaptor

public void initFormAdaptor(UIFormAdaptor uifa)
                     throws UIFormManagerException
Initialize the UIFormAdaptor.

Specified by:
initFormAdaptor in interface UIFormManager
Throws:
UIFormManagerException

processForm

public boolean processForm(UIFormContext uifc,
                           UIFormOwner owner)
                    throws UIFormManagerException
A big control switch that calls the appropriate doActionXXX method. This method returns true if global data has potentially been changed in processing the form, in other words after successfully processing ACTION_SAVE or ACTION_DELETE. This allows a UIScreenAdaptor to know when to refresh other forms in a screen with multiple forms.

Specified by:
processForm in interface UIFormManager
Throws:
UIFormManagerException

disableUnsupportedActions

public void disableUnsupportedActions(UIFormContext uifc)
Turn off actions that are not supported in the current mode. This method is typically called as part of procesing the form. In the event of a form load error, a UI would typically not process the form, but simply redisplay it with any error messages. Because the form was not processed in that case, the UI would need to call this method directly to turn off innapropriate actions.

These are the top level actions, not the reference or contained field actions.

Specified by:
disableUnsupportedActions in interface UIFormManager

doActionDrilldown

protected void doActionDrilldown(UIFormContext uifc,
                                 UIFormOwner owner)
                          throws UIFormManagerException
The user has requested that the display drill down to a contained object from our current location.

Examples:

  1. In the ConfigEditor, the user clicks on the selection button to the left of an initial data element.

Preconditions:

actions:

Throws:
UIFormManagerException

doActionParent

protected void doActionParent(UIFormContext uifc,
                              UIFormOwner owner)
                       throws UIFormManagerException
The user has requested that the display move up one level. This may be after they drilled down into a contained object, or after they selected a specific instance from a collection listing.

Examples:

  1. In the ConfigEditor, after drilling down into an initial data definition, the user clicks the "parent" button.
  2. In TaskHeapDemo, after selecting one of the tasks in the task screen, the user clicks the "parent" button.

Preconditions:

actions:

Throws:
UIFormManagerException

doActionDeref

protected void doActionDeref(UIFormContext uifc,
                             UIFormOwner owner)
                      throws UIFormManagerException
The user has requested that the display shift to a referenced object. Unlike a drilldown action, this is actually a shift to a new object and there is no corresponding "parent" action. To return to where they were, a user can use the back button on their browser, or other stack navigation as supported by the UI.

In a deref action, the user is typically viewing a listing display, although a deref/drilldown button may also be presented for a read-only field within an editing form. For example if a user is editing a PlanComponentReport, there is a deref link to the source PlanComponent. In this case if the user clicks the drilldown then the editing mode is effectively cancelled.

Examples:

  1. In TaskHeapDemo, within the display of a single Task instance, the user clicks on the selection button to the left of the resourceID field value.

Preconditions:

actions:

Notes:

  1. The ConfigEditor and UIEditor both override this method to translate a dereferencing action into what is essentially a move within the main object being edited. This seems like it will probably be a common application-specific override for implementations extending RootedFormManager.
  2. This method assumes we are dereferencing via uniqueID, since that is the only guaranteed unique key. Name dereference is supported in RootedFormManagers where it makes sense.

Throws:
UIFormManagerException

doActionSelect

protected void doActionSelect(UIFormContext uifc,
                              UIFormOwner owner)
                       throws UIFormManagerException
The user has selected an instance from a collection of instances that were displayed. This means we are either:
  1. LISTING a collection of instances, and the user has selected one to work with. This is effectively a drilldown from the collection to a specific instance.
  2. Adding a reference to this instance at the current position. In this case we were UPDATING an object instance (or ADDING a new top level instance), then we were FINDING the instance we want to add a reference to, and now we are selecting that instance from the LISTING. So we need to set the reference and return to UPDATING or ADDING.

Examples:

  1. In TaskHeapDemo, within the collection of Tasks displayed in the TasksDisplay, the user clicks on the selection button to the left of a task listing.
  2. In TaskHeapDemo, while editing a task, the user clicks the find button next to the resourceID field, then clicks the ok button for the user query, then selects a resource from the resulting collection display.

Preconditions:

actions:

Throws:
UIFormManagerException

doActionEdit

protected void doActionEdit(UIFormContext uifc,
                            UIFormOwner owner)
                     throws UIFormManagerException
The user has selected to switch to UPDATING mode.

Examples:

  1. In TaskHeapDemo, within the display of a single Task instance, the user clicks the "edit" button.

Preconditions:

actions:

Throws:
UIFormManagerException

doActionAdd

protected void doActionAdd(UIFormContext uifc,
                           UIFormOwner owner)
                    throws UIFormManagerException
The user has selected to switch to ADDING mode.

Examples:

  1. In TaskHeapDemo, within the top level TasksDisplay screen, the user clicks the "add" button to add a new Task.
  2. In TaskHeapDemo, after selecting a single Task to view, the user clicks the "add" button to add a new Task.
  3. In the UIEditor, the user drills down through a Screen to a Link containing multiple actions. They click "edit" and select a point to insert a new Action, then click "add".

Preconditions:

actions:

Notes:

  1. The new instance will not show up as part of a collection of instances until it is saved. Before that it doesn't actually exist yet.

Throws:
UIFormManagerException

doActionFind

protected void doActionFind(UIFormContext uifc,
                            UIFormOwner owner)
                     throws UIFormManagerException
The user has clicked "find", either to bring up a query form or to execute the displayed query form.

Find is used both to bring up the initial query form (call this Find1), and to execute the query form after it has been filled in (call this Find2). We differentiate between whether we are in Find1 or Find2 based on whether the modePath endsWith FINDING.

Examples:

  1. In TaskHeapDemo, while editing a Task, the user clicks the find button to assign a resourceID. After filling out any match information in the displayed query form, they click find to retrieve a collection of resources to select from.
  2. In TaskHeapDemo, in the TasksDisplay screen collection view, the user clicks "find" to retrieve an alternate collection.

Preconditions:

actions:

Notes:

  1. The currInst needs to be preserved since we may be ADDING or UPDATING and in the process of trying to resolve a reference. This means that FIND is not supported when an instance is being displayed, since currInst will not be cleared.
  2. In the case of a top-level FIND action from a collection display, the modePath before processing will be LISTING.FINDING and we are about to replace the collection with the results of the query. This would logically result in the modePath becoming LISTING.FINDING.LISTING, with no cancel operation to return to the previous mode. Rather than doing this we simply pop the FINDING context so the modePath becomes LISTING. For example consider the TasksDisplay in TaskHeapDemo. The user clicks the top level "find" button, specifies a query and then clicks "find" again, resulting in a new collection display. The user can repeat this operation ad infinitum and without the modePath becoming LISTING.FINDING.LISTING.FINDING....
  3. Doing a find will typically result in the findQuery and findCollection fields being used. If a form had been initialized with a collection, and a find is done while editing (such as to locate a reference) then the intial collection may be lost in the process. In this case the collection may need to be reset by form init processing.

Throws:
UIFormManagerException

doActionCancel

protected void doActionCancel(UIFormContext uifc,
                              UIFormOwner owner)
                       throws UIFormManagerException
The user cancels the current operation. This method is called anytime the user clicks the "cancel" button, except for in a UIFormQuery (user queries are resolved by the method that asked).

Examples:

  1. In TaskHeapDemo, while editing an existing task, the user clicks the "cancel" button.
  2. In TaskHeapDemo, while adding a new task instance, the user clicks the "cancel" button.
  3. In TaskHeapDemo, while editing a new task instance, the user clicks "find" to assign a resourceID. The user then clicks "cancel" when the query form is displayed.
  4. In TaskHeapDemo, while editing a new task instance, the user clicks "find" to assign a resourceID, then clicks "find" again on the query form, then clicks "cancel" when the matching instances are displayed.

Preconditions:

actions:

Notes:

  1. In the case of a general top-level query display, there would not be a cancel button since there is no previous mode to return to. So if TaskHeapDemo had a general Task finding screen with a query form on it, there wouldn't be a cancel button.
    display rule: CANCEL is supported in FINDING mode only if there is a previous mode to return to.
  2. If supporting a general FIND action from a LISTING display, cancel is supported at the query form, but not after the user clicks "find" the second time to retrieve a collection. The original listing collection will have been replaced with the results of the query. So if the user clicks "find" on the TasksDisplay screen, then clicks "find" again after filling out the query form, the resulting collection display will not have a cancel button on it.
    display rule: CANCEL is supported in LISTING mode only if there is a previous ADDING or UPDATING mode to return to.

Throws:
UIFormManagerException

doActionSave

protected boolean doActionSave(UIFormContext uifc,
                               UIFormOwner owner)
                        throws UIFormManagerException
The user elects to save their outstanding work. This method calls through to the UIFormOwner for processing. We return true if data is changed, false otherwise.

Examples:

  1. In TaskHeapDemo, the user fills out a new Task and clicks "save".
  2. In TaskHeapDemo, the user fills out a new Task, then clicks "ok" to return to the listing display, then clicks "edit" to make more changes, then clicks "save".
  3. In the ConfigEditor, the user makes changes to a node instance and then clicks "save".

Preconditions:

actions:

Notes:

  1. if we were ADDING or UPDATING, doActionOk handles the main form resolution processing and sets pendingEdits to true.
  2. It is the responsibility of the UIFormOwner to clear the updates, and set pendingEdits to false on successful conclusion of the formSave call.

Throws:
UIFormManagerException

doActionNext

protected void doActionNext(UIFormContext uifc,
                            UIFormOwner owner)
                     throws UIFormManagerException
The user has selected to move to the next page of elements.

Examples:

  1. In TaskHeapDemo, the user clicks the "next" button on the TasksDisplay screen (after entering enough tasks to trigger dataset pagination).

Preconditions:

actions:

Throws:
UIFormManagerException

doActionPrevious

protected void doActionPrevious(UIFormContext uifc,
                                UIFormOwner owner)
                         throws UIFormManagerException
The user has selected to move to the previous page of elements.

Examples:

  1. In TaskHeapDemo, after clicking the "next" button on the TasksDisplay screen, the user clicks on the "previous" button to return to the previous page of data

Preconditions:

actions:

Throws:
UIFormManagerException

doActionDelete

protected boolean doActionDelete(UIFormContext uifc,
                                 UIFormOwner owner)
                          throws UIFormManagerException
The user has selected to delete a contained object or a top level object. Return true if global data has changed, false otherwise.

Examples:

  1. In TaskHeapDemo, after selecting a specific task from the TasksDisplay, the user clicks the "delete" button.
  2. In TaskHeapDemo, while editing a Task, the user selects an existing note and clicks the "delete" button.
  3. In the ConfigEditor, while editing the configuration, the user selects an initialData element and clicks "delete".
  4. In TaskHeapDemo, after navigating to a particular item through the reference links, the user clicks the "delete" button.

Preconditions:

actions:

Notes:

  1. When deleting a contained instance, we only need to update the parent instance. When that update is confirmed, the contained instance will be gone.
  2. Deleting a contained object (either a single field instance or an element from an array of instances) is always possible.

Throws:
UIFormManagerException

doActionRemove

protected void doActionRemove(UIFormContext uifc,
                              UIFormOwner owner)
                       throws UIFormManagerException
The user has selected to remove a reference to an object.

Examples:

  1. In TaskHeapDemo, while editing a task with an assigned resourceID, the user clicks the remove button next to the resourceID field.

Preconditions:

actions:

Notes:

  1. Since the user is removing a reference, they are currently editing an instance. Changes will be tracked when the confirm the edits.
  2. We have to work solely with the currInst (so we can't call something like evalPosition) because the main references have to be preserved in case the user cancels editing.

Throws:
UIFormManagerException

doActionNew

protected void doActionNew(UIFormContext uifc,
                           UIFormOwner owner)
                    throws UIFormManagerException
The user has selected to add a reference to an instance that they will now create.

Examples:

  1. In TaskHeapDemo, while editing a Plan, the user clicks the "new" button next to the components field.

Preconditions:

actions:

Throws:
UIFormManagerException

doActionMove

protected void doActionMove(UIFormContext uifc,
                            UIFormOwner owner,
                            int offset)
                     throws UIFormManagerException
The user has selected to move a reference item up or down within the reference array or contained object array.

Examples:

  1. In TaskHeapDemo, while editing a Plan, the user selects one of the referenced plan components and clicks the "move up" or "move down" button to change its position relative to the other references.

Preconditions:

actions:

Notes:

  1. Since the user is moving something within the current instance being edited, changes will be tracked when they save/ok.
  2. We have to work solely with the currInst (so we can't call methods like evalPosition) because the main references have to be preserved in case the user cancels editing.

Throws:
UIFormManagerException

doActionOk

protected void doActionOk(UIFormContext uifc,
                          UIFormOwner owner)
                   throws UIFormManagerException
The user has selected to complete their current action. This method is called anytime the user clicks the "ok" button, except for in a UIFormQuery (user queries are handled by the method that asked).

Examples:

  1. In TaskHeapDemo, while adding a new Task, the user clicks the "ok" button to add the new instance. [top-level add]
  2. In TaskHeapDemo, while adding or updating a Task, the user clicks to add a note. After filling in the information, they click "ok" to add the note and return to their adding/editing the task. [contained add]
  3. In TaskHeapDemo, while editing an existing Task, the user clicks "ok" to complete their edits. [top-level update]
  4. In TaskHeapDemo, while listing a task, the user drills down into one of the notes. They click to edit the note, then click "ok" to confirm the changes. [contained update]
  5. In the UIEditor, the user selects a Screen, then selects a Link within the Screen and clicks "edit". They then click "add" next to the actions field to add a new Action instance. After filling out the values for the Action, they click "ok" to enter their data. [contained add]
  6. In the UIEditor, the user selects a Screen, then selects a Link within the Screen, then selects an Action within the Link and clicks "edit". They make a change and then click "ok" to enter their changes. [contained update]
  7. In TaskHeapDemo, while editing an existing Plan, the user clicks "new" next to the components field to create a reference to a new instance.

Preconditions:

actions:

Notes:

  1. If we are ADDING, then
    1. We are doing a top-level add of a new independent instance.
    2. We are adding a dependent instance, and therefore either ADDING or UPDATING it's parent. The changes will be merged into the parent and saved when the parent is saved.
    3. We are adding a reference to a NEW independent instance, and need to track the changes for the new instance before setting the parent reference to it.
  2. If we are UPDATING, then we are ultimately modifying the rootMsg, (either directly or by changing one of its contained instances). In either case we merge the currInst back in, and then track changes at the root level.
  3. In a RootedFormManager (such as the ConfigEditor or UIEditor), every modification is a contained update.

Throws:
UIFormManagerException

doActionHelp

protected void doActionHelp(UIFormContext uifc,
                            UIFormOwner owner)
                     throws UIFormManagerException
The user has asked for help.

Examples:

  1. In TaskHeapDemo, the user clicks the "help" button on the the TasksDisplay screen.
  2. In the ConfigEditor, the user clicks the "help" button on the main screen.

Preconditions:

actions:

Throws:
UIFormManagerException

outstandingChangesExist

protected boolean outstandingChangesExist(UIFormContext uifc)
Returns true if there are outstanding changes to the currInst which need to be captured, false otherwise.

Notes:


resolveClass

protected int resolveClass(UIFormContext uifc)
Figure out what class we are dealing with. Return one of the RC_* constants to let the caller know where we are.


resolveReferences

protected void resolveReferences(UIFormContext uifc,
                                 UIFormOwner owner)
                          throws UIFormManagerException
Check our references make sense, adding errors to the outputText for any invalid references found. It is generally only practical to resolve references when the known universe of potential IDs is well contained. Single-object managers (such as those used in the ConfigEditor or UIEditor) are based on a single object instance, which can be traversed and checked for internal reference consistency. Standard managers which are working off a small subset of the overall data at any time (such as TaskHeapDemo) can't check referential integrity without significant overhead.

The default implementation of this method does nothing. Override if referential integrity checking has a manageable scope.

Throws:
UIFormManagerException

fieldValidateCurrentInstance

protected boolean fieldValidateCurrentInstance(UIFormContext uifc)
Call the fieldValidate method of the currInst to make sure the field values are reasonable.


okTopLevelAdd

protected void okTopLevelAdd(UIFormContext uifc,
                             UIFormOwner owner)
                      throws UIFormManagerException
Add a completely new instance. The rootMsg and position are updated to the new object top level. The addition is tracked.

A top-level add is a button that is available while listing a collection (or under similar circumstances). So the modePath is LISTING.ADDING and we return to LISTING after the new instance is OKed.

Throws:
UIFormManagerException

okContainedAdd

protected void okContainedAdd(UIFormContext uifc,
                              UIFormOwner owner)
                       throws UIFormManagerException
Add a new instance contained inside of a parent object. Since a contained add is by definition a dependent object, there is no need to do any tracking here. We simply modify the parent, and when those updates are OKed, the contained objects will be handled in the same operation.

The currInst contains the new instance. We can find the parent off the rootMsg since any previous changes will have already been merged in before we went to add the new instance. See doActionAdd for details.

At conclusion of processing the currInst will be set to the parent, and the mode will be either ADDING or UPDATING, depending on what it was when we added the contained instance. Note that pendingEdits is still false. We have merged our changes into the updated currInst, which is either being ADDED or UPDATED. So the tracking of updates (and setting pendingEdits to true) happens either in okTopLevelAdd or okUpdate. If the user cancels, pendingEdits remains whatever it was before.

Throws:
UIFormManagerException

okNewReference

protected void okNewReference(UIFormContext uifc,
                              UIFormOwner owner)
                       throws UIFormManagerException
Add a reference from the parent to a new instance. This is kind of a mix between okContainedAdd, and okTopLevelAdd. We need to track the update to the new object, and set the reference in the object we were originally editing.

Throws:
UIFormManagerException

okUpdate

protected void okUpdate(UIFormContext uifc,
                        UIFormOwner owner)
                 throws UIFormManagerException
Process the update operation, tracking the necessary updates.

The user reaches the editing screen by first traversing to the instance they want to work with (either via drilldown or selecting from a collection). They then click "edit", possibly make changes, and click "ok" (or they click "save", which calls the same "ok" processing.

It is possible that processing may fail as part of the save if application logic is violated by the update (invalid field value or whatever). In that case the user will either fix their update and save again, or cancel. If they cancel, then the data they are working with needs to revert back to what it was before, which means that the reference copy can't be modified here. However if we are modifying a contained instance, then we must merge those changes into the current parent so they get recorded when the parent gets saved. Yet another reason why contained objects should be used only for simple structures requiring minimal validation.

Implementation notes:

  1. While it is a tempting optimization to compare uifc.getCurrInst() against uifc.getCurrentObject() via isEquivalent() and skip the update, this isn't valid. The reason is that the merge into the rootMsg may have occurred during a previous ADD of a contained object, and now we are updating the parent. In this case isEquivalent would return true, even though the update still needs to happen. It's intuitively probably better to always do the update when the user clicks the button anyway.
  2. We may be adding an element to a contained field while updating the object we are editing, so even through the default GENMOD_ACTION is SET, we check to see if it should be APPEND.

Throws:
UIFormManagerException

trace

protected void trace(int level,
                     java.lang.String text)
Debugging output statements. Level 0 is some high level method calls, level 1 is more details.


processUpdate

protected void processUpdate(SandInstanceMessage sim,
                             UIFormContext uifc,
                             int updateAction,
                             UIFormOwner owner)
                      throws UIFormManagerException
Get the update message for this struct message, fill it out, and call trackUpdates. If this is a DELETE action, then we need to process it immediately, rather than waiting to do several updates within a single transaction. Otherwise the display gets extremely unintuitive.

Throws:
UIFormManagerException

wrappedGenAdd

protected void wrappedGenAdd(java.lang.String prefix,
                             UIFormContext uifc,
                             SandInstanceMessage parent,
                             SandInstanceMessage child)
                      throws UIFormManagerException
Figures out SET/APPEND/INSERT action and calls wrappedGenMod.

Throws:
UIFormManagerException

wrappedGenMod

protected void wrappedGenMod(java.lang.String prefix,
                             SandInstanceMessage sim,
                             int action,
                             java.lang.String field,
                             int arrayIndex,
                             java.lang.Object opmsg)
                      throws UIFormManagerException
Wrap the general modifier call. This catches any thrown SandException and wraps it into a UIFormManagerException.

Throws:
UIFormManagerException

getClassDisambiguationPrompt

protected java.lang.String getClassDisambiguationPrompt()
Return the text for the UIFormQuery asking to disambiguate the class type. Defaults to CLASS_DISAMBIGUATION_PROMPT, override to return custom text.


getFieldValidationFailureText

protected java.lang.String getFieldValidationFailureText()
Accessor for field validation failure on save. Defaults to FIX_FIELDS_BEFORE_SAVE, override to return custom text.


getInvalidFieldMessagePrefix

protected java.lang.String getInvalidFieldMessagePrefix()
Accessor for invalid field value messages. Defaults to INVALID_FIELD_VALUE_PREFIX, override to return custom text.


mergeChangesToParentBeforeAdd

protected abstract boolean mergeChangesToParentBeforeAdd(UIFormContext uifc)
                                                  throws UIFormManagerException
We are about to do a contained add, so make sure any outstanding changes to the currInst are captured before it gets replaced with a new instance for editing. Return true if everything is ok, and false if the add operation should be cancelled. If returning false, set an outbound message to inform the user what happened.

The typical action here is to merge the changes back into the rootMsg, since the user can always cancel work on the particular message instance (it's only when they OK or CANCEL the rootMsg work that the updates need to be tracked or thrown away). But an editor that is working completely from a single object instance (such as the ConfigEditor or UIEditor) and does not have any of undo infrastructure (such as the webapp versions of these tools), can't just modify the rootMsg and still support cancel. In these instance this method should return false.

This method is only called if there are changes that need to be captured.

Throws:
UIFormManagerException

supportsTopLevelAdd

protected abstract boolean supportsTopLevelAdd()
Returns true if this form manager allows new top level object instances to be created while in LISTING mode. Typically a single object editor would not support this, while a general persistent object editor might.


supportsTopLevelFind

protected abstract boolean supportsTopLevelFind()
Returns true if this form manager allows other top level object instances to be found while in LISTING mode. Typically a single object editor would not support this, while a general persistent object editor might.


trackUpdates

protected abstract void trackUpdates(SandUpdateMessage update,
                                     UIFormContext uifc)
                              throws UIFormManagerException
Track this update for save processing. The update will already have been merged into the rootMsg of the uifc. This given update message is a part of the root message which has changed. It may be modified multiple times before save is called.

The update is typically either added to the AggregateUpdate in the uifc updates, or it is ignored because the rootMsg is written directly. Note that if find or add is supported at the top level, then the rootMsg may change and not be available at save time.

Throws:
UIFormManagerException