Validate Query Trigger

You can add a trigger to the query execution event so that administrators may control the types of queries that users are allowed to perform. You can customize the behavior of queries (even block them from evaluating) depending on the query patterns specified.

The following topics are discussed:

About the Validate Query Trigger

This section provides background details about the validate query trigger.

The trigger is fired from the Find or Find Like windows in both the desktop and Web versions of ENOVIA Matrix Navigator, where wide-open query definitions are allowed, as well as on specific queries in MQL or ENOVIA Studio Customization Toolkit programs. The Validate Query trigger has two main purposes:


  • To block certain types of queries that are inefficient
  • To change the query patterns in the background to perform a more specific query than originally attempted. For example, if the vault pattern is a wildcard (*), the value can be changed to be a list of all local vaults instead.

In addition, you can create customized error and notice messages. For example, for a blocked query, the program could display a message indicating the reason for blocking it, such as more information is required.

The validate query trigger is different from other triggers. It executes a single program that works as a combined check and override trigger, and is designed as a way to modify the current query (via the RPE).

Enabling the Validate Query Trigger

The validate query trigger is enabled in the desktop application by default, as long as a program object named ValidateQuery exists in the database.

Because it makes an additional call to the database, performance can be affected. To enable Query triggers for use in the Web version of ENOVIA Matrix Navigator, add the following to the HTML page that starts it:

document.writeln("<param name='QueryTrigger' value='True'>");

If you will use custom applets, your pages may use the straight HTML syntax:

<PARAM name="QueryTrigger" value="True">

In MQL, the evaluate query and temp query commands can include the querytrigger clause, which will cause the ValidateQuery program execute (if it exists) For example:

<mql> temp query bus * * * querytrigger vault v1;
<mql> evaluate query q1 querytrigger;

Even with triggers turned off, when querytrigger is included in a query command, the ValidateQuery program executes.

Program objects that perform queries are not affected by default in either the desktop or Web version of ENOVIA Matrix Navigator. If required, the querytrigger flag must be included in the program code.

Using the Validate Query Trigger in Studio Customization Toolkit Program

ENOVIA Studio Customization Toolkit methods are available to set and get the query trigger flag.

By default the flag is set to false. The methods are:

public setQueryTrigger(boolean queryTrigger)
public boolean getQueryTrigger ()

The following example performs a temporary query and the validate query trigger fires as long as the program object exists:

Query myQuery = new Query("");
myQuery.setType("*");
myQuery.setName("*");
myQuery.setRevision("*");
myQuery.setVault("*");
myQuery.setQueryTrigger(true);
myQuery.evaluate(getContext()));
...

Writing the ValidateQuery Program

The validate query trigger fires before the query is evaluated.

The program should check the query patterns specified as described in Query Event Macros.

If the ValidateQuery program is a JPO, no macros are available as input arguments. As a workaround, the ValidateQuery program should be a Tcl program that calls the JPO to do the actual work.

When changing query patterns, use global variables. For example, to change the vault pattern in the background if only a wildcard is provided, you could use:

tcl;
eval {
   set sVault [mql get env VAULT_PATTERN ] 
   if { $sVault=="*" } {
     set sVault "vault1,vault2,vault3"
   }
   mql set env global VAULT_PATTERN
exit 0
}

As is the case with other event triggers, the exit code determines if the event is blocked or overridden. If the exit code is a zero, the query is performed; the global query pattern RPE variables are read and used by the query, which allows the program code to change them before the query is evaluated. (Remember, the validate query trigger is really a combination of a check and an override trigger.) If the exit code is a non-zero value, a soft block occurs. In this case the query as entered is not executed; the query event is overridden and the transaction is committed, closing the Find or Find Like window. It is up to the trigger program code that overrides the query to generate a message to inform the user that the query did not get executed.

While overriding the query code with other events is possible, the main purpose of a query trigger is to block unqualified queries and modify the query patterns via RPE variables. If overriding the query code, query performance, Tcl limitations (such as the fact that Tcl is single threaded) and recursive queries must be considered. The query is a fundamental part of ENOVIA Live Collaboration and overwriting the code must be done carefully. To return business objects to the current window in the desktop or Web version of ENOVIA Matrix Navigator, the MQL commands, appl icons and appl details can be used to populate the window with business objects.

Validate Query Use Case

The validate query trigger can ensure that user-defined queries satisfy some pre-defined requirements.

For example, the program below is one solution for ensuring that:


  • All queries in local vaults have at least one filter (for example, type, name, rev, or owner for basic queries), but partial wildcards are permitted.
  • A query on all vaults (*) does not include foreign vaults.
  • Queries on a specified foreign vault have both type and name filters.

The ValidateQuery program to satisfy above:

tcl;
eval {
    eval [ mql print program utList.tcl select code dump ]
    ###############################################################
    proc tclListToMxList {tclList} {
    
       set mxList ""
    
       foreach i $tclList {
          append mxList $i
          append mxList ","
       }
       set length [expr [string length $mxList] - 2 ]
       set mxList [ string range $mxList 0 $length ]       
       return $mxList
    }
    
    ###############################################################
    proc mxListToTclList {mxList} {
    
       set tclList [ split $mxList "," ]
       return $tclList
    }
    
    ###############################################################
    proc MatchingVaults {sPattern tclVaultList} {
    
       set lVaultsToBeSearched ""       
       set firstIndex [ lsearch $tclVaultList $sPattern ]          
       while { $firstIndex != -1 } {
          lappend lVaultsToBeSearched [ lindex $tclVaultList 
$firstIndex]          
          set index [expr $firstIndex + 1 ]          
          set tclVaultList [lrange $tclVaultList $index end]
          set firstIndex [ lsearch $tclVaultList $sPattern ]
       }
       return $lVaultsToBeSearched
    }
    
    ###############################################################
    proc onlyWildcardsInString {sString} {
    
       set wildcard "*"
       set bReturn FALSE       
       set iFirstIndex [string first $wildcard $sString]       
       if {$iFirstIndex != -1 } {
    
          # To discover many stars (ex ***)
          set bReturn TRUE          
          for {set i 0} {$i < [string length $sString]} {incr i} 
{
             if { [string index $sString $i] != $wildcard } {
                set bReturn FALSE
                break
             }
          }
       }
       return $bReturn
    }
    
    ###############################################################
    #
    # Variable definition
    #
    ###############################################################
    
    # Default values
    set iExit 0
    set sErrorMessage ""
    
    # Get all vaults from Matrix
    set sAllVaultsList [ mql list vault ]
    set lAllVaultsList [ split $sAllVaultsList \n ]
    
    # Defined adaplets
    set lAdapletVaults {a1 a2}
    set lRemoteVaults {r1 r2}
    
    # Local vaults
    set lLocalVaults [ utListSubtract $lAllVaultsList [ concat 
$lAdapletVaults $lRemoteVaults ] ]
    
    # Get query env
    set sVault [mql get env VAULT_PATTERN ]
    set sType [mql get env TYPE_PATTERN ]
    set sName [mql get env NAME_PATTERN ]
    set sRevision [mql get env REVISION_PATTERN ]
    set sOwner [mql get env OWNER_PATTERN ]
    
    
set lVaultsToBeSearched {}
    
    ###############################################################
    #
    # Find out which vault(s)are going to be queried
    #
    ###############################################################
    
    # If vault pattern is a wildcard change the vault to only 
search local vaults
    if { [onlyWildcardsInString $sVault] } {
       set sVault [ tclListToMxList $lLocalVaults ]
    }
       mql set env global VAULT_PATTERN $sVault
       
    # if vault pattern is a comma separated list of vaults
    if { [string match *,* $sVault] == 1} {
       set lVaultList [ split $sVault "," ]
       foreach v $lVaultList {
          set lVaultsToBeSearched [ concat $lVaultsToBeSearched 
[MatchingVaults $v $lAllVaultsList ]]
       }      
    # not a list of vaults
    } else {
       set lVaultsToBeSearched [MatchingVaults $sVault 
$lAllVaultsList ]
    }
    
    ###############################################################
    #
    # Go through the vaults that are going to be searched and
    # check if all criteria are satisfied
    #
    ###############################################################
    
    set bGeneralCheck FALSE
    
    foreach v $lVaultsToBeSearched {       
       # Foreign vault a1 is not allowed to have * only ? is 
allowed
       if { $v == "a1" } {
          if { ([string first * $sType] != -1) && ([string first 
* $sName] != -1)} {
             set iExit 1
             append sErrorMessage "Query not allowed. When 
searching in Vault $v, none of the query patterns type and name 
is allowed include a wildcard (*). Use one or many question 
marks (?) for unknown characters instead\n\n"          
          }
       } elseif {$v == "a2"} {
          if { [string first * $sName] != -1 } {
             set iExit 1
             append sErrorMessage "Query not allowed. When 
searching in Vault $v, the query patterns type is allowed 
include a wildcard (*). Use one or many question marks (?) for 
unknown characters instead\n\n"          
          }
       } else {
          set bGeneralCheck TRUE
       }
    }
    
    if {$bGeneralCheck} {       
       set iAllowedWildards 3
       set iCurrent 0
        
       if { [onlyWildcardsInString $sType] } {
          incr iCurrent
       }
       if { [onlyWildcardsInString $sName]} {
          incr iCurrent
       }
       if { [onlyWildcardsInString $sRevision]} {
          incr iCurrent
       }
       if { [onlyWildcardsInString $sOwner]} {
          incr iCurrent
       }
       if {$iCurrent > $iAllowedWildards } {
          set iExit 1
          append sErrorMessage "Query not allowed. One of the 
query patterns type, name, revision or owner must be more 
qualified than a wildcard (*)\n\n"          
       }
    }
    
    #
    # Pop up error message if needed
    #
    if {$iExit == 1} {
       mql error $sErrorMessage
    }
    exit $iExit
}