<?xml version='1.0' encoding='UTF-8'?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-544624334919507846</atom:id><lastBuildDate>Sat, 28 Mar 2026 11:13:18 +0000</lastBuildDate><category>How To</category><category>Configuration</category><category>eScript</category><category>eScript Framework</category><category>Strategy</category><category>User Properties</category><category>Integration</category><category>Troubleshooting</category><category>Workflow</category><category>Barcodes</category><category>RARE</category><category>BI</category><category>GUI Best Practice</category><category>Classes</category><category>SQL</category><title>The Siebel Scholar</title><description></description><link>http://thesiebelscholar.blogspot.com/</link><managingEditor>noreply@blogger.com (Mik)</managingEditor><generator>Blogger</generator><openSearch:totalResults>65</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-2352544806971522664</guid><pubDate>Thu, 20 Jun 2019 18:27:00 +0000</pubDate><atom:updated>2019-06-20T14:27:47.286-04:00</atom:updated><title>Workflow Monitoring - On Demand</title><description>The out of the box Workflow Monitoring level specified when deploying a version of a workflow is a great tool but it requires it having been explicitly turned on in order to be of value.  I have found that while this was turned on for all users in a production environment, we would have a massive surplus of log data that would fill up the logging tables unnecessarily, some users logins may be setup to only do troubleshooting.  Alternatively, a specific user could have logging turned up for so that all workflows are tracked rather than having to know all the workflow process names where an error is going to occur as the user may not know before hand which workflow is causing the problem.  What is needed is to add logic to the &#39;Workflow Process Manager&#39; business service.&amp;nbsp; The PreInvoke needs the following script added:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 100px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function Service_PreInvokeMethod (MethodName, Inputs, Outputs) {
  if (MethodName.indexOf(&quot;Run&quot;) &amp;gt;=0) {
    TheApplication().Utility.logRaiseWF(Inputs, MethodName);
  }
  return (ContinueOperation);
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The Invoke needs the following script added:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 100px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function Service_InvokeMethod (MethodName, Inputs, Outputs) {
  if (MethodName.indexOf(&quot;Run&quot;) &amp;gt;=0) {
    TheApplication().Utility.logResetWF(Inputs, MethodName);
  }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The Utility service is enabled in the Application start event.  The &#39;XXX Utilities&#39; business service uses two additional methods. 
&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 200px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function logRaiseWF(Inputs, callingMethod) {
// Method called from Workflow Process Manager, PreInvoke method for methods having &#39;Run&#39; in the method name if the
// Utilities Service is enabled for the OM Component the session is running within.

  //If The Troubleshoot process property is passed (when invoking from a Named Method user prop) or as a child prop (when
  //invoked from a WF as a subprocess) or the user&#39;s log level is 3 or higher, temporarily set WF monitoring for the WF
  //process to detail.  logResetWF is called immediately after invokation to turn WF monitoring off.
  if (gCurrentLogLvl &amp;gt;= 3 || 
   Inputs.GetProperty(&quot;Troubleshoot&quot;) == &quot;Y&quot; || 
   (Inputs.GetChildCount() &amp;gt; 0 &amp;amp;&amp;amp; Inputs.GetChild(0).GetProperty(&quot;Troubleshoot&quot;) == &quot;Y&quot;)) { 
    if (TheApplication().GetProfileAttr(&quot;IsStandaloneWebClient&quot;) == &quot;TRUE&quot;) {
      logStep(&quot;PPT Utilities.logRaiseWF.callingMethod: &quot;+callingMethod+&quot; - ProcessName: &quot;+Inputs.GetProperty(&quot;ProcessName&quot;)); 
      logPS(Inputs);
    } else {
      logSetWFLevel(Inputs, &quot;3 - Detail&quot;);
    }
  }

  //The first WF Called in a stack uses the RunProcess method.  If subprocess is called from a WF, the _ method is used. 
  //All payloads captured after the initial RunProcess call are stored in an array and dumped if an error occurs.  If 
  //system preference &#39;PPT Hold Buffer Max&#39; is greater than 0 then the array is instead always kept at that count rather
  //than resetting on WF start
  if (gsTraceIntfaceReqResp != &quot;FALSE&quot; &amp;amp;&amp;amp; callingMethod.indexOf(&quot;Run&quot;)== 0 &amp;amp;&amp;amp; gHoldBufferMax == 0) gHoldReqResp = [];
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 200px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function logResetWF(Inputs, callingMethod) {
// Method called from Workflow Process Manager, Invoke method for methods having &#39;Run&#39; in the method name if the
// Utilities Service is enabled for the OM Component the session is running within.

  //Conditions controlling whether to reset WF monitoring level must mirror those in the logRaiseWF function
  if (gCurrentLogLvl &amp;gt;= 3 || 
   Inputs.GetProperty(&quot;Troubleshoot&quot;) == &quot;Y&quot; || 
   (Inputs.GetChildCount() &amp;gt; 0 &amp;amp;&amp;amp; Inputs.GetChild(0).GetProperty(&quot;Troubleshoot&quot;) == &quot;Y&quot;)) { 
    if (TheApplication().GetProfileAttr(&quot;IsStandaloneWebClient&quot;) == &quot;TRUE&quot;) {
      logStep(&quot;PPT Utilities.logResetWF.callingMethod: &quot;+callingMethod+&quot; - ProcessName: &quot;+Inputs.GetProperty(&quot;ProcessName&quot;)); 
    } else {
      logSetWFLevel(Inputs, &quot;0 - None&quot;);
    }
  }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
Finally, these wrapper functions call a function to actually set and reset the monitoring level on a deployed workflow:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 300px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function logSetWFLevel (Inputs, logLevel) {
//Use:  
//Returns: 
  var boWF:BusObject = TheApplication().GetBusObject(&quot;PPT Workflow Process Deployment&quot;);
  var bcWF:BusComp = boWF.GetBusComp(&quot;Workflow Process Deployment&quot;);
  var found:Boolean = false;
  var propName = Inputs.GetFirstProperty();

  while (propName != &quot;&quot;) {
    if (propName.indexOf(&quot;ProcessName&quot;) == 0) {
      with (bcWF) {
        ActivateField(&quot;Monitoring Level&quot;);
        ClearToQuery();
        SetSearchSpec(&quot;Name&quot;, Inputs.GetProperty(propName));
        SetSearchSpec(&quot;Deployment Status&quot;, &quot;Active&quot;);
        ExecuteQuery(ForwardOnly);
        found = FirstRecord();
        if (found) {
          SetFieldValue(&quot;Monitoring Level&quot;, logLevel);
          WriteRecord();
        }
      }     
    }
    propName = Inputs.GetNextProperty();
  }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
To minimize the times where logging is actually raised, one of the following conditions must be true:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;An input process property called &#39;Troubleshoot&#39; has a &#39;Y&#39; value.&amp;nbsp; I use this process prop across most of my workflows and only pass the &#39;Y&#39; value when passed as a command/Named Method BC User property from a button on an admin view or an applet gear menu option.&amp;nbsp; It is useful to expose manually triggering a workflow this way to replicate a process that is normally triggered by the system in some way.&lt;/li&gt;
&lt;li&gt;Users log level is 3 or higher&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Note that if using the thick client, logging is NOT turned on so minimize SQL in the siebel.log file and since this information can easily be set through the SIEBEL_LOG_EVENTS system variable along with the Step and Process execution events.</description><link>http://thesiebelscholar.blogspot.com/2019/06/workflow-monitoring-on-demand.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-3658764515160936972</guid><pubDate>Thu, 20 Jun 2019 17:37:00 +0000</pubDate><atom:updated>2019-06-20T13:50:17.762-04:00</atom:updated><title>XML Logger - EAI Data Transformation Engine</title><description>If you are already capturing the XML payloads of a web service using the &lt;a href=&quot;https://thesiebelscholar.blogspot.com/2013/05/the-xml-logger.html&quot;&gt;XML Logger&lt;/a&gt;, then extending it to further troubleshoot how you might have ended up with that payload might be useful since integration workflows frequently undergo multiple transformations. The existing logRequest and logResponse as invoked by the PreInvoke method of the &#39;XXX Utilities&#39; business service are central to the actual logic.&amp;nbsp; What is needed now is to add logic to the &#39;EAI Data Transformation Engine&#39; business service.&amp;nbsp; The PreInvoke needs the following script added:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 100px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function Service_PreInvokeMethod (MethodName, Inputs, Outputs){
  if (MethodName==&quot;Execute&quot;) {
    TheApplication().Utility.InvokeMethod(&quot;logTransformRequest&quot;, Inputs, TheApplication().NewPropertySet());
  } 
  return (ContinueOperation);
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The Invoke needs the following script added:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 100px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function Service_InvokeMethod (MethodName, Inputs, Outputs) {
  if (MethodName==&quot;Execute&quot;) {
    TheApplication().Utility.InvokeMethod(&quot;logTransformResponse&quot;, Outputs, TheApplication().NewPropertySet());
  } 
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The logRequest and logResponse methods set the direction attribute to &#39;EAI Transform&#39; to distinguish it and uses the MapName attribute as the functional name.&amp;nbsp; The Record Id is assumed to be an element called &#39;Id&#39; in the first top level container.&lt;br /&gt;
&lt;br /&gt;
I made a personal decision that logging these payloads was not universally necessary and therefore wanted to make logging these records conditional.&amp;nbsp; In my case I made it run in two scenarios:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;If the executing user&#39;s log level is 5 and payload logging is enabled&lt;/li&gt;
&lt;li&gt;If the payload logging is not generally enabled but an error occurred subsequently in the executing workflow of a subprocess it called.&lt;/li&gt;
&lt;/ul&gt;
</description><link>http://thesiebelscholar.blogspot.com/2019/06/xml-logger-eai-data-transformation.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-356538244215902799</guid><pubDate>Thu, 20 Jun 2019 17:18:00 +0000</pubDate><atom:updated>2019-06-20T13:18:51.839-04:00</atom:updated><title>Get Process and Thread Ids</title><description>It is sometimes useful to know the PID or Thread.&amp;nbsp; For instance if an error occurs and I want to get the specific server OM Log file I can find that file if I knew the Thread and PID.&amp;nbsp; I am not aware of any way to get these values directly though it is obvious the Siebel application OM has these values internally.&amp;nbsp; The TraceOn function allows these values to be used while opening and naming the trace file:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
TheApplication().TraceOn(&quot;TraceFile_$p_$t.log&quot;, &quot;Allocation&quot;, &quot;All&quot;);&lt;/blockquote&gt;
results in name like&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
TraceFile_7382_8188.log&lt;/blockquote&gt;
So the trick is to create this file then read the relevant values out of the name.&amp;nbsp; To do so, I create the file with a unique name that will be known to the script creating it:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
var unique = TheApplication().LoginName()+&quot;-&quot;+TimeStamp(&quot;DateTimeMilli&quot;);&lt;br /&gt;
TheApplication().TraceOn(path+&quot;Trace-&quot;+unique+&quot;_$p_$t.log&quot;, &quot;Allocation&quot;, &quot;All&quot;);&lt;/blockquote&gt;
&lt;div&gt;
To get the values I am interested in, I need to output the directory listing of only this known file to a log I can then open and read, then use format of the name of this file to extract the two values I am interested in:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style=&quot;height: 300px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function SetThreadPID() {
  var pid = TheApplication().GetProfileAttr(&quot;XXX OS PID&quot;);
  var threadId = TheApplication().GetProfileAttr(&quot;PPT OS Thread ID&quot;);
  var line, pidThread, path, command, outs;

  try {
    if (threadId == &quot;&quot;) {
      if (TheApplication().GetProfileAttr(&quot;IsStandaloneWebClient&quot;) == &quot;TRUE&quot;) {
        path = gsLogPath;
      } else {
        path = TheApplication().GetProfileAttr(&quot;Syspref Error Trace Temp Loc&quot;);
      }

      if (path != &quot;&quot; &amp;amp;&amp;amp; path.toUpperCase() != &quot;FALSE&quot;) {
        var unique = TheApplication().LoginName()+&quot;-&quot;+TimeStamp(&quot;DateTimeMilli&quot;);
        TheApplication().TraceOn(path+&quot;Trace-&quot;+unique+&quot;_$p_$t.log&quot;, &quot;Allocation&quot;, &quot;All&quot;);
        TheApplication().Trace(&quot;TEST&quot;);
        TheApplication().TraceOff();  
    
        command = &quot;dir &quot;+path+&quot;Trace-&quot;+unique+&quot;_*.log &amp;gt; &quot;+path+&quot;Trace-&quot;+unique+&quot;.log&quot;;
        outs = Clib.system(command);
        var fp:File = Clib.fopen(path+&quot;Trace-&quot;+unique+&quot;.log&quot;,&quot;r&quot;);
        if (fp != null){
          while(Clib.feof(fp) == 0){
            line = Clib.fgets(fp);
            if (line.length &amp;gt; 0){
              if (line.indexOf(unique)&amp;gt;=0) {
                pidThread = line.substring(line.indexOf(unique)+unique.length+1, line.length - 5)
                pid = pidThread.substring(0, pidThread.indexOf(&quot;_&quot;));
                threadId = pidThread.substring(pidThread.indexOf(&quot;_&quot;)+1);
                TheApplication().SetProfileAttr(&quot;PPT OS PID&quot;, pid);
                TheApplication().SetProfileAttr(&quot;PPT OS Thread ID&quot;, threadId);
                Clib.fclose(fp);
                outs = Clib.remove(path+&quot;Trace-&quot;+unique+&quot;_&quot;+pid+&quot;_&quot;+threadId+&quot;.log&quot;)
                outs = Clib.remove(path+&quot;Trace-&quot;+unique+&quot;.log&quot;)
                break;
              }
            }
          }
        }
      }
    }
  } catch(e) {
    RaiseError(e);
  } finally {
    fp = null;
  }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
Once the PID and Thread are stored in profile attributes they are available to the business layer to for instance set a PID or thread column on a custom error table.&lt;br /&gt;
&lt;br /&gt;
Note that &#39;Syspref Error Trace Temp Loc&#39; is a custom field added to the &#39;Personalization Profile&#39; BC which has the calculation:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
SystemPreference(&quot;PPT Error Trace Temp Loc&quot;)&lt;/blockquote&gt;
This is then set to a directory that the Siebel application server has access to (the Siebel temp directory can generally be used safely).</description><link>http://thesiebelscholar.blogspot.com/2019/06/get-process-and-thread-ids.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-391097022155837013</guid><pubDate>Thu, 20 Jun 2019 15:06:00 +0000</pubDate><atom:updated>2019-06-20T11:06:17.172-04:00</atom:updated><title>Use Open UI to Dynamiclly Manipulate Detail Tabs</title><description>In a screen with many view tabs it may be useful for process automation to&amp;nbsp;minimize clicking on detail tabs if user does not need to navigate there when no records are present.&amp;nbsp; Open UI allows changing the view tab labels to provide indicators to signal to the user information about that tab.&amp;nbsp; In order to do so, join fields or calculations based on MV fields relevant to the child BC need to exist and be exposed as controls on the parent BC applet (they can be hidden).&lt;br /&gt;
&lt;br /&gt;
One additional feature is to hide the view tabs not requiring navigation for UI optimization but keeping them available in case the user needs them.&amp;nbsp; Siebel uses a UI dropdown widget when there are too many views to fit horizontally across.&amp;nbsp; We can leverage this widget to conditionally place additional views based on the values in BC fields.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf6seeo5cB9Rs7PS4IF_ZnmH1unv9X9ZZI4UsN3tua5osN7vGnAeIFjsm4dymqTy7XZRo9UyBkZJ8h-xpy2Oc3f0rsC_5KFwuDvxCGBO80sRmSIe70Iqbq68zDWchQTbNPqUJgU_WjVP1E/s1600/Capture.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;131&quot; data-original-width=&quot;877&quot; height=&quot;47&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf6seeo5cB9Rs7PS4IF_ZnmH1unv9X9ZZI4UsN3tua5osN7vGnAeIFjsm4dymqTy7XZRo9UyBkZJ8h-xpy2Oc3f0rsC_5KFwuDvxCGBO80sRmSIe70Iqbq68zDWchQTbNPqUJgU_WjVP1E/s320/Capture.PNG&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
The following script is attached to a navigation manifest event:&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-3JRLJVjxLB0hkeQQE-T1xCTwh6VqikRHHq-ZCownYUllqfNneXnUoanEeMNmp8tpGsegztuyJKdZCwRt1R6Agn-Mo7SLtkEpcWftu1yP6z1_cF_fRnPJ8uP6bh9OTFIZM-gUbOiq5jYu/s1600/Capture.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;430&quot; data-original-width=&quot;1583&quot; height=&quot;86&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-3JRLJVjxLB0hkeQQE-T1xCTwh6VqikRHHq-ZCownYUllqfNneXnUoanEeMNmp8tpGsegztuyJKdZCwRt1R6Agn-Mo7SLtkEpcWftu1yP6z1_cF_fRnPJ8uP6bh9OTFIZM-gUbOiq5jYu/s320/Capture.PNG&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 300px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre class=&quot;brush: javascript&quot; name=&quot;code&quot;&gt;if(typeof(SiebelAppFacade.pptCustomNavigationPR) === &quot;undefined&quot;){ 
  SiebelJS.Namespace(&quot;SiebelAppFacade.pptCustomNavigationPR&quot;); 
  define (&quot;siebel/custom/pptCustomNavigationPR&quot;, [&quot;siebel/accnavigationphyrender&quot;], function () { 
    SiebelAppFacade.pptCustomNavigationPR = (function(){ 
      var PM; 
      var PRName = &quot;&quot;; 
      function pptCustomNavigationPR(pm){ 
      SiebelAppFacade.pptCustomNavigationPR.superclass.constructor.apply(this,arguments);} 
      SiebelJS.Extend(pptCustomNavigationPR, SiebelAppFacade.AccNavigationPhyRenderer); 
            
      pptCustomNavigationPR.prototype.Init = function() { 
        SiebelAppFacade.pptCustomNavigationPR.superclass.Init.apply(this, arguments); 
        PM = this.GetPM(); 
        PRName = PM.GetPMName(); 
      }; 
      /*pptCustomNavigationPR.prototype.ShowUI = function(){ 
        SiebelAppFacade.pptCustomNavigationPR.superclass.ShowUI.apply(this, arguments); 
        //implement ShowUI method here 
      }; 
      pptCustomNavigationPR.prototype.BindEvents = function(){ 
        SiebelAppFacade.pptCustomNavigationPR.superclass.BindEvents.apply(this, arguments); 
        //implement BindEvents method here 
      };*/
            
      pptCustomNavigationPR.prototype.BindData = function(bRefresh){ 
        SiebelAppFacade.pptCustomNavigationPR.superclass.BindData.call(this, bRefresh); 
                
        //Prototype for child record counter on view tabs 
        if (PRName == &quot;NavigationDetailObject_PM&quot;){ 
          //the framework is processing detail navigation, this is a good place for code that manipulates view tabs. Get applet, control, value and properties 
          //Code assumes the top form applet has a control that exposes a count 
          var oView = SiebelApp.S_App.GetActiveView();
                                  
          if (typeof(oView) != &#39;undefined&#39; &amp;amp;&amp;amp; oView != null &amp;amp;&amp;amp; oView.hasOwnProperty(&quot;GetName&quot;) == true) {
            var sViewName = oView.GetName();
                 
            //Limit execution of this script to only views matching a naming convention as it must have a parent form applet containing the hidden calculated fields
            if ( sViewName.indexOf(&quot;XXX Search Text&quot;) &amp;gt;= 0 ){
              var suppressTabs = true;

              //This applet must have controls containing the BC fields that will be used in the array
              var applet = oView.GetAppletMap()[&quot;XXX Parent Form Applet&quot;];

              //Declared Array where index is UI display name of the detail tab and value is either BC Field Name or &#39;-&#39;.  If field name, non 0/non null value indicate tab should
              //be displayed.  &#39;-&#39; indicates tab should always be hidden.  If tab should always be displayed, do not put it in the array
              var tabList = {&quot;Contacts&quot;:&quot;XXX Contact Count&quot;,&quot;Activities&quot;:&quot;XXX Activity Count&quot;,&quot;Service Requests&quot;:&quot;XXX SR Count&quot;,&quot;Notes&quot;:&quot;XXX Notes Flag&quot;,&quot;Fees&quot;:&quot;XXX Fees Flag&quot;,&quot;Audit Trail&quot;:&quot;-&quot;};
              var hitCount, fieldName;
              var tabIndex = 0;
              var tabs = [];
              var tabScreens = [];
              var showWidget = false;
              var lastTab;
      
              //loop through each visible detail tab... 
              $(&quot;.siebui-subview-navs .siebui-nav-tabScreen .ui-tabs-nav a&quot;).each(function(index){ 
                //get the current tab label text 
                var currentLabel = $(this).text(); 
                  
                //check if tab is in array of labels that need modification
                fieldName = tabList[currentLabel];
                if (typeof(fieldName)!=&#39;undefined&#39; &amp;amp;&amp;amp; fieldName != &quot;&quot;){  //we found the tab 
                  if (fieldName == &quot;-&quot;) hitCount = &quot;&quot;;
                  else hitCount = applet.GetBusComp().GetFieldValue(fieldName);

                  //Either modify the label if an indicator needs to be appended or if tab is to be suppressed, add to an array of labels to appear in the option list
                  if (hitCount != &quot;&quot; &amp;amp;&amp;amp; hitCount != &quot;0&quot;) {
                  //now change the text 
                    $(this).text(currentLabel + &quot; (&quot; + hitCount + &quot;)&quot;); 
                    lastTab = $(this);
                  } else if (suppressTabs) {
                  //If this tab should be generally suppressed, there are no indicators needing to be displayed, and it is not currently selected
                    if (fieldName != &quot;&quot; &amp;amp;&amp;amp; (hitCount == &quot;&quot; || hitCount == 0) &amp;amp;&amp;amp; $(this).parent().attr(&quot;tabindex&quot;)!= &quot;0&quot;) {
                      showWidget = true;
                      tabs[tabIndex] = currentLabel;
                      tabScreens[tabIndex++] = $(this).attr(&quot;data-tabindex&quot;).substring(9);
                      $(this).remove();
                    } else {
                      lastTab = $(this);
                    }
                  }   
                }
              }); 
              
              //If any tabs need to be suppressed, display a drop down at the end of the detail tab row with list of view tabs that have been suppressed
              if (showWidget == true) {
                var j=0;
                var htmlstring = lastTab.parent().parent().html();
                var append = &#39;&amp;lt;li&amp;gt;&amp;lt;select aria-atomic=&quot;true&quot; aria-label=&quot;Third&quot; bar=&quot;&quot; class=&quot;siebui-nav-links siebui-nav-viewlist&quot; id=&quot;j_s_vctrl_div_tabScreen&quot; level=&quot;&quot; role=&quot;combo&quot; view=&quot;&quot;&amp;gt;==$0&amp;lt;option hidden=&quot;&quot; value=&quot;&quot;&amp;gt;&amp;lt;/option&amp;gt;&#39;;&amp;lt;/select&amp;gt;&amp;lt;/li&amp;gt;
                while (j &amp;lt; tabIndex) {
                  append = append + &#39;&amp;lt;option value=&quot;tabScreen&#39;+tabScreens[j]+&#39;&quot;&amp;gt;&#39;+tabs[j++]+&#39;&amp;lt;/option&amp;gt;&#39;;
                }
                append = append + &#39;&amp;lt;/select&amp;gt;&amp;lt;/li&amp;gt;&#39;;
                lastTab.parent().parent().html(htmlstring+append);
              }
            }
          }
        }        
      }; 
              
      return pptCustomNavigationPR; 
    }()); 
    return &quot;SiebelAppFacade.pptCustomNavigationPR&quot;; 
  }); 
}
&lt;/pre&gt;
&lt;/div&gt;
</description><link>http://thesiebelscholar.blogspot.com/2019/06/use-open-ui-to-dynamiclly-manipulate.html</link><author>noreply@blogger.com (Mik)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf6seeo5cB9Rs7PS4IF_ZnmH1unv9X9ZZI4UsN3tua5osN7vGnAeIFjsm4dymqTy7XZRo9UyBkZJ8h-xpy2Oc3f0rsC_5KFwuDvxCGBO80sRmSIe70Iqbq68zDWchQTbNPqUJgU_WjVP1E/s72-c/Capture.PNG" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-3621624339871467254</guid><pubDate>Tue, 08 Mar 2016 17:55:00 +0000</pubDate><atom:updated>2016-03-08T12:55:43.970-05:00</atom:updated><title>Thick Client Event Logging</title><description>There are surprisingly few blog posts out there about vanilla options for logging in the thick client. &amp;nbsp;Perhaps this is because everyone knows how to do it and if so feel free to ignore this. &amp;nbsp;But perhaps it is because most people just struggle through using inefficient methodologies.&lt;br /&gt;
&lt;br /&gt;
Here is a simple tip for troubleshooting when using the thick client. &amp;nbsp;There is an OS environment variable called SIEBEL_LOG_EVENTS (if it does not exist you can create it). Many developers know how to set this to an integer between 0 and 5, but values of 4 and 5 where good detail is provided create a file that unreasonably large and hard to parse. &amp;nbsp;When troubleshooting on the thin client you can set individual event log levels from the Administration - Server Configuration screen, component events view. &amp;nbsp;You can do the same when using a thick client though you need to do it using the SIEBEL_LOG_EVENTS variable. &amp;nbsp;You can use any combination of event aliases and levels, but the value I have found useful is the following:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
StpExec=4,PrcExec=4,ObjMgrSqlLog=4,SQLParseAndExecute=4,ObjMgrBusServiceLog=4,EventContext=4,ProcessRequest=4,ObjMgrDBConnLog=5,SecAdpLog=5,ObjMgrSessionLog=5,ObjMgrBusCompLog=2&lt;/blockquote&gt;
Basically you can enter any comma separated list of event aliases.&lt;br /&gt;
&lt;br /&gt;
One coda is that if I were trying to troubleshoot a WF issue, I could open this log and do a find for the word &#39;Instantiating&#39;. &amp;nbsp;The first instance I would find is the Start step of the WF Process followed by the values of the process properties being set by that step:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
PrcExec&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;Create&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;4&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;00000002569f1a98:0&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;2016-01-20 15:31:33&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;Instantiating process definition &#39;PPT Passport History Response Integration&#39;.&lt;br /&gt;PrcExec&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;PropSet&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;4&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;00000002569f1a98:0&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;2016-01-20 15:31:33&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;Setting runtime value of property &#39;Namespace: &#39;USER&#39; Name: &#39;ConfigItem&#39; Datatype: &#39;String&#39;&#39; to:&lt;br /&gt;PrcExec&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;PropSet&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;4&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;00000002569f1a98:0&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;2016-01-20 15:31:33&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;Start&lt;br /&gt;PrcExec&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;PropSet&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;4&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;00000002569f1a98:0&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;2016-01-20 15:31:33&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;Setting runtime value of property &#39;Namespace: &#39;USER&#39; Name: &#39;ObjectName&#39; Datatype: &#39;String&#39;&#39; to:&lt;br /&gt;PrcExec&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;PropSet&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;4&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;00000002569f1a98:0&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;2016-01-20 15:31:33&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;Workflow - PPT Test Error Process&lt;br /&gt;PrcExec&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;PropSet&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;4&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;00000002569f1a98:0&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;2016-01-20 15:31:33&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;Setting runtime value of property &#39;Namespace: &#39;USER&#39; Name: &#39;CurrentStep&#39; Datatype: &#39;String&#39;&#39; to:&lt;br /&gt;PrcExec&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;PropSet&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;4&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;00000002569f1a98:0&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;2016-01-20 15:31:33&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;Convert Siebel Message PPH&lt;/blockquote&gt;
Subsequent occurrences look like this:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
StpExec&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;Create&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;4&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;00000002569f1a98:0&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;2016-01-20 15:31:33&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;Instantiating step definition &#39;Start&#39;.&lt;br /&gt;StpExec&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;End&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;4&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;00000002569f1a98:0&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;2016-01-20 15:31:33&lt;span class=&quot;Apple-tab-span&quot; style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;Stopping step instance of &#39;Start&#39; with a &#39;Completed&#39; status.&lt;/blockquote&gt;
In this way you can step through the WF. &amp;nbsp;The advantage of this logging level over say looking at the WF Instance Monitor or only using WF Simulator, is you will be able to see the SQL executed and the bind variables used, what BCs were instantiated along the way, and what BS methods might have been called.&lt;br /&gt;
&lt;br /&gt;</description><link>http://thesiebelscholar.blogspot.com/2016/03/thick-client-event-logging.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-3761646210861244963</guid><pubDate>Tue, 09 Feb 2016 13:53:00 +0000</pubDate><atom:updated>2019-05-30T13:12:20.512-04:00</atom:updated><title>EAI Integration Map expressions</title><description>While there are many posts I have seen that talk about expressions supported by &#39;EAI Data Transformation Engine&#39;, I have never seen an attempt to compile a list of supported functions and examples of there uses. &amp;nbsp;So this will be a humble beginning that will hopefully grow over time. &amp;nbsp;Note that these functions are mostly VB so if trying out one that is not listed, start with what is supported in VB. &amp;nbsp;They can also be found in Siebel Bookshelf as Siebel Query Language expressions&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Do not include XML element (use System type)&lt;/b&gt;&lt;br /&gt;
IfNull([Middle Name], [Conflict Id])&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Transforming Dates&lt;/b&gt;&lt;br /&gt;
(from &#39;YYYYMMDD&#39; to &#39;MM/DD/YYYY&#39;):&lt;br /&gt;
Right(Left([Source Field Name],7),2) +&quot;/&quot;+Right([Source Field Name], 2)+&quot;/&quot;+Left([Source Field Name], 4)&lt;br /&gt;
&lt;br /&gt;
(from Siebel Date to externally recognized format):&lt;br /&gt;
ToChar([Birth Date], &#39;YYYY-MM-DD&#39;)&lt;br /&gt;
ToChar([Completion Date], &#39;YYYY-MM-DDThh:mm:ss&#39;)&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Conditional Logic&lt;/b&gt;:&lt;br /&gt;
IIF([Source Field Name] = &quot;false&quot;, &quot;N&quot;, &quot;Y&quot;)&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;SSN formatting (Strip hyphens)&lt;/b&gt;:&lt;br /&gt;
IIF(InStr([PPT Social Security Number], &quot;-&quot;) &amp;gt; 0, Left([PPT Social Security Number], 3)+Mid([PPT Social Security Number], 5, 2)+Right([PPT Social Security Number], 4), [PPT Social Security Number])&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;EAI Lookup for an Inbound Interface&lt;/b&gt;:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;EAILookupSiebel(&quot;XXX&quot;,[Source Field Name])&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;XXX is the Type in the EAI Lookup table. &amp;nbsp;This needs also needs to be setup as a value under the EAI_LOOKUP_MAP_TYPE LOV type.&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;IIF([Source Field Name] IS NULL, &quot;&quot;, EAILookupSiebel(&quot;XXX&quot;,[Source Field Name]))&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;EAILookupSiebel fails if no value is found so minimize this possibility unless an exception is desired&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;b&gt;Extract the file name from a File Path&lt;/b&gt;:&lt;br /&gt;
Mid([Source Field Name], InStr([Source Field Name], &quot;/&quot;, -1) + 1)&lt;br /&gt;
&lt;br /&gt;</description><link>http://thesiebelscholar.blogspot.com/2016/02/eai-integration-map-expressions.html</link><author>noreply@blogger.com (Mik)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-1151134808449548922</guid><pubDate>Thu, 22 Oct 2015 15:35:00 +0000</pubDate><atom:updated>2015-10-22T11:35:07.876-04:00</atom:updated><title>Interesting Web Service approach</title><description>I was recently working on a client where all the integration used HTTP Web Services but were not implemented using what I think most Siebel Developers would think of as the &quot;Best Practice&quot;.&amp;nbsp; Basically, the payloads were created using XSLT and the actual call to the Web Service was invoked using &#39;EAI HTTP Transport&#39; rather than a custom WS Proxy BS created using the Tools wizard.&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
The reasoning provided to me behind using XSLT to create the payload is that it was more flexible.&amp;nbsp; What do I mean by that?&amp;nbsp; Well assume an outbound interface is needed&amp;nbsp;where the &quot;Best Practice&quot;&amp;nbsp;alternative would be to use &#39;EAI Siebel Adapter&#39; to query an Integration Objects , then to use &#39;EAI Data Transformation Engine&#39; to transform the payload into an IO (that was initially created by consuming a WSDL) recognizable by the Web Service.&amp;nbsp; The limitation in this approach is around a couple pieces that Siebel Tools wizards have trouble with.&amp;nbsp; The first is that some modern standards compliant &amp;nbsp;WSDL definitions that use recursive data types cannot be imported at all.&amp;nbsp; The second is that the SOAP Header follows a standard that is somewhat outdated, is not configurable, and basically requires scripting to create a custom header anyway.&amp;nbsp; So the question is whether it is better to create the custom header using a scripted Filter Service, or to create the payload using XSLT.&amp;nbsp; Once you go down the path of using XSLT, you basically cant use a Proxy Service anymore (since the proxy would be adding the SOAP envelope)&amp;nbsp;so &#39;EAI HTTP Transport&#39; is used instead.&lt;br /&gt;
&lt;br /&gt;
I can think of a number of downsides to this approach:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Deployment Complexity increases&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;XSLT files must be deployed to the File System and kept in sync across however many app servers (and failover servers) are used by EAI in the respective environments&lt;/li&gt;
&lt;li&gt;No WSDL is actually consumed in this approach so web service end points must be stored somewhere which will likely be different in each environment&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;More Steps in the WF&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;&#39;EAI XSLT Service&#39;&amp;nbsp; uses&amp;nbsp;UTF-16 input so it is likely Encoding will need to occur both to and from using &#39;Transcode Service&#39;&lt;/li&gt;
&lt;li&gt;Reading the XSL File from the file system&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Mainainability&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Siebel resources that know XSLT are presumably more rare than Siebel resources familiar with more &quot;Best Practice&quot; approaches&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Performance&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Calls to the File System to get the XSLT file might add significant load to a high volume interface&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Data Integrity&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;The integrity of the outbound message data structure is not really enforceable in Siebel.&amp;nbsp;Using XSLT requires the developer to create a payload that is correct as only the external system would be able to validate it.&amp;nbsp; This is perhaps debateable because ultimately the developer will probably need to resolve this one way or the other during development.&amp;nbsp; While I personally believe it is easier to troubleshoot problems that are actually identified within Siebel due to the strict defintion of the messages maintained in Siebel, I will concede&amp;nbsp;that might be personal preference.&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
I am curious what others think and whether developers that use this approach can defend it better than I can.&amp;nbsp; Ultimately, I think a scripted filter service is a better solution to the custom Soap Header issue, though I think this approach seems reasonable if the WSDL cannot be consumed, and modifying it is not possible.</description><link>http://thesiebelscholar.blogspot.com/2015/10/interesting-web-service-approach.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-3989519942793460433</guid><pubDate>Thu, 22 Oct 2015 14:21:00 +0000</pubDate><atom:updated>2015-10-22T10:21:17.777-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Configuration</category><category domain="http://www.blogger.com/atom/ns#">User Properties</category><title>Scriptless OK/Cancel popup</title><description>In the early days of configuring in Siebel, if a user wanted a confirmation or warning message before proceeding, it would require Browser Script to implement and most Siebel configurators would try to discourage the requirement on purely technical grounds.&amp;nbsp; And to be fair, an application littered with popup warnings may not be a great idea on functional grounds either, but there are probably good reasons to implement a warning message on occasion and it would be nice if it could be done in a way that does not have technical repercussions.&amp;nbsp; So here you go.&lt;br /&gt;
&lt;br /&gt;
On a BC, configure a &#39;Named Method&#39; user property with value:&lt;br /&gt;
&quot;YourMethodName&quot;, &quot;INVOKESVC&quot;, &quot;FDNS IDENT Encounter&quot;, &quot;LS Pharma Signature UI Service&quot;, &quot;ShowConfirmDialog&quot;, &quot;&#39;Cancel Method Name&#39;&quot;, &quot;YourCancelMethodName&quot;, &quot;&#39;OK Method Name&#39;&quot;, &quot;YourOKMethodName&quot;, &quot;&#39;Confirm Text&#39;&quot;, &quot;&#39;Are you sure you want to Proceed or some other message?&#39;&quot;&lt;br /&gt;
&lt;br /&gt;
The method &#39;YourMethodName&#39; would be invoked according to your requirements.&amp;nbsp; In a simple case, a custom action button on an applet could invoke this method but it could really be invoked anywhere.&lt;br /&gt;
&lt;br /&gt;
The methods &#39;YourOKMethodName&#39; and &#39;YourCancelMethodName&#39; need to be&amp;nbsp;callable methods, either that you also configured as additional Named Methods, or&amp;nbsp;vanilla methods (or&amp;nbsp;scripted ones defined in PreInvoke but that would sort of defeat the point).&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
When &#39;YourMethodName&#39; is invoked, a popup message containing the message parameter is shown with an Ok and Cancel button.&amp;nbsp; Clicking either button calls the methods defined.&amp;nbsp; Enjoy</description><link>http://thesiebelscholar.blogspot.com/2015/10/scriptless-okcancel-popup.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-6351930120595495512</guid><pubDate>Thu, 22 Oct 2015 14:11:00 +0000</pubDate><atom:updated>2015-10-22T10:21:31.152-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Configuration</category><title>Vanilla Merge Behavior</title><description>&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;I recently encountered an issue when adding a DB View based EBC to a BO.&amp;nbsp; When I attempted to perform a MergeRecords operation on two records in the primary BC (Contact in this case), I got an error:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;[1] An error has occurred writing to a record&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;Please continue or ask your system administrator to check your application configuration if the problem persists.(SBL-DBC-00111)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;[2]ORA-06550: line 137, column 15: &lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;PL/SQL: ORA-01031: insufficient privleges&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;ORA-06550: line 137, column 1:&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;PL/SQL: SQL Statement ignored&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;It turns out this error is caused because siebel is attempting to update a column in a DB View.&amp;nbsp; Why would it try to do that you might ask?&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;If we reverse engineer what is happening, we find that when
performing a MergeRecords operation, Siebel determines the underlying table of the
active business component and uses the SRF to find all links where the
identified table is shared with the source business component of the Link and
the source field is ‘Id’ (or null which is the same thing).&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&amp;nbsp; &lt;/span&gt;The merge algorithm then takes this list to
write the SQL to update the appropriate destination field to the new value of
the Id field on the Source BC.&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&amp;nbsp; &lt;/span&gt;Since
merge is a data integrity operation, the use of Links using the ‘Id’ field is a
proxy for those links configured to have a data integrity implication.&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&lt;/span&gt;Ideally, Siebel would provide a configurable
mechanism to exclude a particular link from a Merge, or, at a minimum, to recognize
that when a link points to a destination BC that is based on a table object
whose type is ‘External View’, no update is possible and hence should not be attempted.&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&amp;nbsp; &lt;/span&gt;Alas that is not the case.&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;; font-size: 11pt; line-height: 115%; mso-ansi-language: EN-US; mso-ascii-theme-font: minor-latin; mso-bidi-font-family: &amp;quot;Times New Roman&amp;quot;; mso-bidi-language: AR-SA; mso-bidi-theme-font: minor-bidi; mso-fareast-font-family: Calibri; mso-fareast-language: EN-US; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin;&quot;&gt;&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&lt;/span&gt;Therefore a way to trick the algorithm into
excluding this link is to define the link on one which is not based on data
integrity, and instead make it just informational.&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&amp;nbsp; &lt;/span&gt;This can be done by making the Source field
of the link something other than Id.&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&amp;nbsp; &lt;/span&gt;But
since we do not want&amp;nbsp;to actually change the definition of the view this link
points to, a column whose value matches the ROW_ID column is desireable.&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&amp;nbsp; &lt;/span&gt;In the case of the Contact BC, there are a
couple of potential options.&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&amp;nbsp; &lt;/span&gt;PERSON_UID
defaults to the Id field but since this column&amp;nbsp;might be&amp;nbsp;populated by EIM to be a
value other than it’s ultimate row id, the values may not match on that data
set.&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&amp;nbsp; &lt;/span&gt;But since Contact is based on the
Party model, the PAR_ROW_ID should always match since this points to the
S_PARTY record and the same ROW_ID is always used. This column is not exposed
on the Contact BC though so it needs to first be exposed and then the new BC
field can be used in the links.&lt;/span&gt;</description><link>http://thesiebelscholar.blogspot.com/2015/10/vanilla-merge-behavior.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-2897433364144825763</guid><pubDate>Fri, 10 May 2013 14:04:00 +0000</pubDate><atom:updated>2019-06-20T13:19:27.250-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">eScript</category><category domain="http://www.blogger.com/atom/ns#">eScript Framework</category><category domain="http://www.blogger.com/atom/ns#">Integration</category><title>The XML Logger - Reviewing the Payload</title><description>In my last &lt;a href=&quot;http://thesiebelscholar.blogspot.com/2013/05/the-xml-logger.html&quot;&gt;post&lt;/a&gt;, I talked about how to capture XML Payloads by splitting large values across a series of DB records. In order to look at the data, we need to reassemble the payloads into a single text block again. I expose my Payload BC in a view tied to either the User&#39;s session: &lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSYBHfbCy-4rcUgTDg8BwvDxnlj-mZ3foosq0c7xeEXe41Jh68tP8m9luvA2B3iBIZ0JYrhfJOVvxgt1IMQDwH1dozkRqIZv0Kilaj5yjcC4H-P8gUhZOl6PJ7aNpVBH9KX30vSw2ArqJ5/s1600/XMLLoggerBySession.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;808&quot; data-original-width=&quot;1597&quot; height=&quot;161&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSYBHfbCy-4rcUgTDg8BwvDxnlj-mZ3foosq0c7xeEXe41Jh68tP8m9luvA2B3iBIZ0JYrhfJOVvxgt1IMQDwH1dozkRqIZv0Kilaj5yjcC4H-P8gUhZOl6PJ7aNpVBH9KX30vSw2ArqJ5/s320/XMLLoggerBySession.PNG&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
or to the record on which the interface was executed: &lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkTdAO-IZO0RYtW9VB7MSd1VjV__sMh7vl8mswisNYmzt9euAuARGaish_Chtcp6L7d4wDS8LuHWZxY-s6WgDjrv9j0V8JpH0_oteSSOgcOAQdWLgKEYgfoqVUzR3oJRdt6Uu2JhaBhgDz/s1600/XMLLoggerByObject.PNG&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;785&quot; data-original-width=&quot;1597&quot; height=&quot;157&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkTdAO-IZO0RYtW9VB7MSd1VjV__sMh7vl8mswisNYmzt9euAuARGaish_Chtcp6L7d4wDS8LuHWZxY-s6WgDjrv9j0V8JpH0_oteSSOgcOAQdWLgKEYgfoqVUzR3oJRdt6Uu2JhaBhgDz/s320/XMLLoggerByObject.PNG&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
The latter is accomplished through the payload parsing I talked about which allows us to create a view which links an object record to the payload record once the transaction id is stored on the payload record. On these views, I expose I nice looking form applet which displays both the request and response sides of the interface. The form fields are actually calculated fields, defined as DTYPE_TEXT, with the following expression: &lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
InvokeServiceMethod(&quot;XXX Utilities&quot;, &quot;ConcatenateField&quot;, &quot;bo.bc=&#39;XXX User Session.XXX User Session XML Detail&#39;, FieldName=&#39;Log Text&#39;, SearchExpr=&#39;[Parent Id]=&quot;&quot;+[Id]+&quot;&quot; AND [Field]=&quot;Request&quot;&#39;&quot;, &quot;Out&quot;) &lt;/blockquote&gt;
where: &lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&#39;XXX Utilities&#39; is my eScript framework service with many commonly used functions &lt;/li&gt;
&lt;li&gt;&#39;ConcatenateField&#39; is a method on that service &#39;bo.bc&#39; is a parameter name for that method &lt;/li&gt;
&lt;li&gt;&#39;XXX User Session&#39; is the name of the business object where my user sessions are stored &lt;/li&gt;
&lt;li&gt;&#39;XXX User Session XML Detail&#39; is the name of the business component containing the split up log data &#39;FieldName&#39; is another parameter for this method &lt;/li&gt;
&lt;li&gt;&#39;Log Text&#39; is the name of the field on the &#39;XXX User Session XML Detail&#39; BC where the split payload text is stored defined as DTYPE_CLOB &lt;/li&gt;
&lt;li&gt;&#39;SearchExpr&#39; is another parameter for this method &lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
Finally the search expression looks a bit complicated as passing quotes to the InvokeServiceMethod is difficult. I have improvised by using a commonly used XML expression of &quot; which the method then recognizes and converts back to a quote. Here is the method:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 300px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function ConcatenateField(Inputs, Outputs) {
//Inputs: bo.bc  &quot;boName.bcName&quot;
//   FieldName
//   SearchExpr BC Search Expression (Optional)
 var retValue = &quot;&quot;;
 var found = false;
 var search = Inputs.GetProperty(&quot;SearchExpr&quot;);
 try {
  var arSplit = Inputs.GetProperty(&quot;bo.bc&quot;).split(&quot;.&quot;);
  var bcQuery:BusComp;
  if (arSplit[0] == &quot;ACTIVE&quot;) 
   bcQuery = TheApplication().ActiveBusObject().GetBusComp(arSplit[1]);
  else 
   bcQuery = TheApplication().GetBusObject(arSplit[0]).GetBusComp(arSplit[1]);
   
  var delimeter = (Inputs.GetProperty(&quot;delimeter&quot;) != &quot;&quot; ? Inputs.GetProperty(&quot;delimeter&quot;) : &quot;\n&quot;);
 
  with (bcQuery) {
   if (search != &quot;&quot;) {
    ClearToQuery();
    arSplit = Inputs.GetProperty(&quot;SearchExpr&quot;).split(&quot;&quot;&quot;);
    search = arSplit.join(&quot;&#39;&quot;);
    SetSearchExpr(search);
    ActivateField(Inputs.GetProperty(&quot;FieldName&quot;));
    SetViewMode(AllView);
    ExecuteQuery(ForwardOnly);
   }
  
   found = FirstRecord();
   while(found) {
    retValue += GetFieldValue(Inputs.GetProperty(&quot;FieldName&quot;));
    found = NextRecord();
    if (found) retValue += delimeter;
   }

      Outputs.SetProperty(&quot;Out&quot;, retValue);
  }
 } catch(e) {
  TheApplication().RaiseError(e);
 } finally {
  bcQuery = null;
  arSplit = null;
 }
}
&lt;/pre&gt;
&lt;/div&gt;
</description><link>http://thesiebelscholar.blogspot.com/2013/05/the-xml-logger-revieing-payload.html</link><author>noreply@blogger.com (Mik)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSYBHfbCy-4rcUgTDg8BwvDxnlj-mZ3foosq0c7xeEXe41Jh68tP8m9luvA2B3iBIZ0JYrhfJOVvxgt1IMQDwH1dozkRqIZv0Kilaj5yjcC4H-P8gUhZOl6PJ7aNpVBH9KX30vSw2ArqJ5/s72-c/XMLLoggerBySession.PNG" height="72" width="72"/><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-8482906744708560708</guid><pubDate>Tue, 07 May 2013 22:55:00 +0000</pubDate><atom:updated>2019-06-20T12:47:18.618-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">eScript</category><category domain="http://www.blogger.com/atom/ns#">eScript Framework</category><category domain="http://www.blogger.com/atom/ns#">Integration</category><title>The XML Logger</title><description>In my last &lt;a href=&quot;http://thesiebelscholar.blogspot.com/2013/05/state-of-logging-introduction.html&quot;&gt;post&lt;/a&gt;, I promised to try to bring us up to date on the current implementation of the logging framework, and specifically the XML Logger component of it. &amp;nbsp;The &lt;a href=&quot;http://thesiebelscholar.blogspot.com/2011/09/escript-framework-on-81.html&quot;&gt;framework&lt;/a&gt; is initialized on the Application Start event making all these methods available from script. &amp;nbsp;From an XML Logging perspective, it can be initiated in one of two ways:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;As a standard business service from within the Integration WF (or business service). &amp;nbsp;In this approach, just before the outbound WS or HTTP call, you would call the logRequest or logResponse methods of the framework business service, passing in at a minimum the property set about to be interfaced. &amp;nbsp;There are many other attributes of the payload record which can be optionally used which I won&#39;t go into detail over. &amp;nbsp;You can always add attributes to meet your needs and you don&#39;t need to populate any of them really.&lt;/li&gt;
&lt;li&gt;As a Filter Service. &amp;nbsp;This is used for Web Services and is useful in that it can be turned on or off without modifying any existing Integration WFs. &amp;nbsp;On the Web Service admin views, for each web service operation that you want to log, just specify the Request/Response Filter Service as the Framework business service and the Request/Response Filter Method as logRequest/logResponse respectively.&lt;/li&gt;
&lt;li&gt;Can be implemented to capture other payloads as needed, for instance before and after messages of the EAI Data Transformation Service&lt;/li&gt;
&lt;/ul&gt;
Ok, now for the nitty gritty. &amp;nbsp;What do the&amp;nbsp;logRequest/logResponse&amp;nbsp;methods do? &amp;nbsp;Both are similar and different only in that all interface logging records have a placeholder for a request and a response payload, which the two methods are differentiated to populate. &amp;nbsp;The main input to these methods is an XML payload. &amp;nbsp;At a high level, here is the algorithm:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Navigate the property set until the first &#39;ListOf*&#39; tag is found which is assumed to be the beginning of the Integration Object data.&lt;/li&gt;
&lt;li&gt;Call a method to Parse the remaining child data to correctly name and categorize the interface based on the IO Type and iddentify the record id and unique identifier attributes. &amp;nbsp;This allows for optional scripting to tailor the logging service to your client&#39;s unique needs&lt;/li&gt;
&lt;li&gt;Call the logInterface method which:&lt;/li&gt;
&lt;ol&gt;
&lt;li&gt;Checks if in an EAI Transaction. &amp;nbsp;If so, add the payload to an array, otherwise continue (This is currently only implemented to support outbound interfaces when using the Filter service implementation)&lt;/li&gt;
&lt;li&gt;Creates a session record if one does not already exist (Inbound interfaces executed by an EAI OM typically)&lt;/li&gt;
&lt;li&gt;Deal with anonymous logins (when used on an inbound interface the request method will be executed under the Anonymous login but the response method with be performed by the interface user id)&lt;/li&gt;
&lt;li&gt;Creates a payload record to store the attributes extracted from the payload parsing&lt;/li&gt;
&lt;li&gt;Split the payload into chunks no larger than the BLOB length and create detail records for each chunk&lt;/li&gt;
&lt;/ol&gt;
&lt;/ol&gt;
&lt;div&gt;
First the PreInvoke method.&amp;nbsp; This mostly speaks for itself but since we may want to save processing overhead the calling of the parseInterface method is parameterized and controlled by which method is actually invoked.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 300px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function Service_PreInvokeMethod (MethodName, Inputs, Outputs){
  var retValue      = CancelOperation;

  switch(MethodName) {
  case &quot;logInterface&quot;:     
    var key = logInterface(Inputs, Outputs);
    Outputs.SetProperty(&quot;key&quot;, key)
    break;
  case &quot;logParseRequest&quot;:     
    logRequest(Inputs, Outputs, true, &quot;&quot;);
    break;
  case &quot;logParseResponse&quot;:     
    logResponse(Inputs, Outputs, true, &quot;&quot;);
    break;
  case &quot;logRequest&quot;:     
    logRequest(Inputs, Outputs, false, &quot;&quot;);
    break;
  case &quot;logResponse&quot;:     
    logResponse(Inputs, Outputs, false, &quot;&quot;);
    break;
  case &quot;logTransformRequest&quot;:     
    logRequest(Inputs, Outputs, false, &quot;Transform&quot;);
    break;
  case &quot;logTransformResponse&quot;:     
    logResponse(Inputs, Outputs, false, &quot;Transform&quot;);
    break;
  }
  return (retValue);
}
&lt;/pre&gt;
&lt;/div&gt;
Next the logRequest and logResponse Methods.&amp;nbsp; Like I said they are very similar except for which field the payload is passed to.&amp;nbsp; Also the logResponse method has some additional logic for parsing SOAP faults.&lt;/div&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 300px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function logRequest(Inputs, Outputs, parse, mode) {
/* ***********************************
Purpose: Log interface request from/to an external interface in the session log
Usage: In Web Service definition, operations applet, set the Request Filter BS to &#39;PPT Utilities&#39;
  and the method to logRequest.  Clear the cache
Arguments: 1 - SoapMessage will implicily be passed as a child property set
**************************************** */
try {
  var soapEnv, soapBody, divePS, direction, progress;
  var bodyType=&quot;&quot;;
  var msgType=&quot;&quot;;
  var parseResults = new Object();
  var key = TimeStamp(&quot;DateTimeMilli&quot;);
  var max = 3;
  var dives = 0;

  if(Inputs.GetChildCount() &amp;gt; 0) {
    // Get the SOAP envelope from the SOAP hierarchy.  If payload is passed as an input property set, skip down an extra level
    soapEnv = Inputs.GetChild(0);        //Like env:Envelope

    //Minimize processing if payloads/logging information will not be stored
    if (gHoldBufferDump == true || gsTraceIntfaceReqResp == &quot;TRUE&quot;) {
      //if called from EAI Data Transformation Engine and user logging level is 5 capture passing specific props
      if (mode==&quot;Transform&quot; &amp;amp;&amp;amp; (gHoldBufferDump == true || gCurrentLogLvl &amp;gt;= 5)) {
        parseResults.recId = soapEnv.GetChild(0).GetChild(0).GetProperty(&quot;Id&quot;);
        parseResults.recBC = soapEnv.GetChild(0).GetChild(0).GetType();
        msgType = Inputs.GetProperty(&quot;MapName&quot;);
        parseResults.funcName = Inputs.GetProperty(&quot;MapName&quot;);
        direction = &quot;EAI Transform&quot;;
      } else {
        try { // Try to process the message to get functional data 
          if (soapEnv.GetType().toUpperCase().indexOf(&quot;ENVELOPE&quot;) &amp;lt;0 ) soapEnv = soapEnv.GetChild(0);
          direction = Inputs.GetProperty(&quot;WebServiceType&quot;)+&quot; &quot;+Inputs.GetProperty(&quot;Direction&quot;);
          for (var i=0; i &amp;lt; soapEnv.GetChildCount(); i++) {   
            bodyType = soapEnv.GetChild(i).GetType();    //Like env:Body
            if (bodyType.toUpperCase() == &quot;BODY&quot; || bodyType.substr(bodyType.indexOf(&quot;:&quot;)+1).toUpperCase() == &quot;BODY&quot;) {
              soapBody = soapEnv.GetChild(i);
              for (var j=0; j &amp;lt; soapBody.GetChildCount(); j++) {   
                msgType = soapBody.GetChild(j).GetType();  //Full Port name of the WS 
  
                //Parse to check for faults and create a text string to be used in the key
                if (msgType.indexOf(&quot;:&quot;) &amp;gt;= 0)  msgType = msgType.substr(msgType.indexOf(&quot;:&quot;)+1); //strip namespace
                if (msgType.indexOf(&quot; &quot;) &amp;gt;= 0)  msgType = msgType.substr(0, msgType.indexOf(&quot; &quot;)); //strip namespace declaration
                if (msgType.indexOf(&quot;_&quot;) &amp;gt;= 0)  msgType = msgType.substr(0, msgType.lastIndexOf(&quot;_&quot;));//strip port operation
  
                //if true, attempt to find Row Id in payload to stamp on log record so log can be linked to Siebel record  
                if (parse == true) {
                  divePS = soapBody.GetChild(j); //.GetChild(0)
                  while (divePS.GetType().indexOf(&quot;ListOf&quot;) &amp;lt; 0 &amp;amp;&amp;amp; dives &amp;lt;= max) {
                    if (divePS.GetChildCount() &amp;gt; 0) {
                      divePS = divePS.GetChild(0);
                      dives++;
                    } else dives = max + 1;
                  }
   
                  //If a ListOf... container is found, this is a SiebelMessage generated by Siebel. Otherwise parse the SOAP Body
                  if (divePS.GetType().indexOf(&quot;ListOf&quot;) &amp;gt;= 0) parseInterface(divePS, parseResults);
                  else parseInterface(soapBody, parseResults);
                }
              } 
        
              break;
            }
   }         
 } catch(e) {
          //If an error occurs while parsing, just try to write the message whole
        }
            
      } //SOAP Message scenario

      //If msgType is identified then insert a log for this payload
      if (msgType != &quot;&quot;) {
        msgType = msgType.replace(/_spc/g, &quot;&quot;).replace(/\s/g, &quot;&quot;);
        key = msgType+&quot;_&quot;+key;

        TheApplication().SetProfileAttr(&quot;InterfaceKeyInbound&quot;, key);
        progress = logInterface(key, soapEnv, null, direction, parseResults.recId, parseResults.recBC, &quot;Pending&quot;, msgType, parseResults.funcName, null, null, null, parseResults.ref1, null, null, parseResults.refField);
      }
    } else if (gsTraceIntfaceReqResp == &quot;FALSE&quot;) {
      //Do Nothing
    } else { //Store payloads in case an error occurs
      //var holdPayload = [&quot;Request&quot;, Inputs, parse, mode];
      gHoldReqResp.push([&quot;Request&quot;, Inputs, parse, mode]);
      if (gHoldBufferMax &amp;gt; 0 &amp;amp;&amp;amp; gHoldReqResp.length &amp;gt; gHoldBufferMax) gHoldReqResp.shift();
    }
  } // Inputs.GetChildCount()
  Outputs.InsertChildAt(soapEnv,0);
} catch(e) {
  RaiseError(e);
} finally {
  divePS = null;
  soapBody = null;
  soapEnv = null;
  parseResults =  null;
}

}
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 300px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function logResponse(Inputs, Outputs, parse, mode) {
/* ***********************************
Purpose: Log interface response from/to an external interface in the session log
Usage: In Web Service definition, operations applet, set the Response Filter BS to &#39;PPT Utilities&#39;
  and the method to logResponse.  Clear the cache
Arguments: 1 - SoapMessage will implicily be passed as a child property set
**************************************** */
try {
  var soapEnv, soapBody, divePS, direction, progress;
  var bodyType=&quot;&quot;;
  var msgType=&quot;&quot;;
  var parseResults = new Object();
  var fault=null;
  var key = TheApplication().GetProfileAttr(&quot;InterfaceKeyInbound&quot;);
  var max = 3;
  var dives = 0;
  var dump = false;

  if(Inputs.GetChildCount() &amp;gt; 0) {
    // Get the SOAP envelope from the SOAP hierarchy
    soapEnv = Inputs.GetChild(0);

    //Minimize processing if payloads/logging information will not be stored
    if (gHoldBufferDump == true || gsTraceIntfaceReqResp == &quot;TRUE&quot;) {
      if (mode==&quot;Transform&quot; &amp;amp;&amp;amp; (gHoldBufferDump == true || gCurrentLogLvl &amp;gt;= 5)) {
        dump = true;
        direction = &quot;EAI Transform&quot;;
        if (soapEnv.GetChild(0).GetChild(0).PropertyExists(&quot;Id&quot;)) {
          parseResults.recId = soapEnv.GetChild(0).GetChild(0).GetProperty(&quot;Id&quot;);
          parseResults.recBC = soapEnv.GetChild(0).GetChild(0).GetType();
        }
      } else if (mode==&quot;&quot;) {
        dump = true;
        try { // Try to process the message to get functional data
          direction = Inputs.GetProperty(&quot;WebServiceType&quot;)+&quot; &quot;+Inputs.GetProperty(&quot;Direction&quot;);
          //Soap Envelope Request may have a Header and a Body so loop to the Body
          for (var i=0; i &amp;lt; soapEnv.GetChildCount(); i++) {
            bodyType = soapEnv.GetChild(i).GetType();
            if (bodyType.toUpperCase() == &quot;BODY&quot; || bodyType.substr(bodyType.indexOf(&quot;:&quot;)+1).toUpperCase() == &quot;BODY&quot;) {
              soapBody = soapEnv.GetChild(i);
  
              //Soap Body typically has a container for the Message
              for (var j=0; j &amp;lt; soapBody.GetChildCount(); j++) {   
                msgType = soapBody.GetChild(j).GetType();
   
                //Parse to check for faults and create a text string to be used in the key
                if (msgType.indexOf(&quot;:&quot;) &amp;gt;= 0)  msgType = msgType.substr(msgType.indexOf(&quot;:&quot;)+1)
                if (msgType.indexOf(&quot; &quot;) &amp;gt;= 0)  msgType = msgType.substr(0, msgType.indexOf(&quot; &quot;))
                if (msgType.indexOf(&quot;_&quot;) &amp;gt;= 0)  msgType = msgType.substr(0, msgType.lastIndexOf(&quot;_&quot;))
  
                if (msgType.toUpperCase() == &quot;FAULT&quot;) fault = soapBody.GetChild(j).GetProperty(&quot;faultstring&quot;);
                else if (parse == true) { 
                  //if true, attempt to find Row Id in payload to stamp on log record so log can be linked to Siebel record  
                  divePS = soapBody.GetChild(j); //focus on the Message level
                  while (divePS.GetType().indexOf(&quot;ListOf&quot;) &amp;lt; 0 &amp;amp;&amp;amp; dives &amp;lt;= max) {
                    if (divePS.GetChildCount() &amp;gt; 0) {
                      divePS = divePS.GetChild(0);
                      dives++;
                    } else dives = max + 1;
                  }
   
                  //If a ListOf... container is found, this is a SiebelMessage generated by Siebel. Otherwise parse the child of the Body
                  if (divePS.GetType().indexOf(&quot;ListOf&quot;) &amp;gt;= 0) parseInterface(divePS, parseResults);
                  else parseInterface(soapBody, parseResults);
                }
              }
              break;
            }
          }
        } catch(e) {
          //If an error occurs while parsing, just try to write the message whole
        }
      }
 
      if (key == &quot;&quot;) {
        key = TimeStamp(&quot;DateTimeMilli&quot;);
        if (msgType != &quot;&quot;) {
          msgType = msgType.replace(/_spc/g, &quot;&quot;);
          key = msgType+&quot;_&quot;+key;
        }
      }
         
      if (dump == true) {
        if (fault != null) {
          logInterface(key, null, soapEnv, null, parseResults.recId, parseResults.recBC, &quot;error&quot;, null, null, fault);
        } else {
          var recId = (parseResults.recId != &quot;&quot; ? parseResults.recId : null);
          var recBC = (parseResults.recBC != &quot;&quot; ? parseResults.recBC : null);
          var ref1 = (parseResults.ref1 != &quot;&quot; ? parseResults.ref1 : null);
          var funcName = (parseResults.funcName != &quot;&quot; ? parseResults.funcName : null);
          progress = logInterface(key, null, soapEnv, direction, recId, recBC, &quot;Complete&quot;, msgType, funcName, null, null, null, ref1);
        }
      }
    } else if (gsTraceIntfaceReqResp == &quot;FALSE&quot;) {
      //Do Nothing
    } else { //Store payloads in case an error occurs
      gHoldReqResp.push([&quot;Response&quot;, Inputs, parse, mode]);
      if (gHoldBufferMax &amp;gt; 0 &amp;amp;&amp;amp; gHoldReqResp.length &amp;gt; gHoldBufferMax) gHoldReqResp.shift();
    }
  } // Inputs.GetChildCount()
  Outputs.InsertChildAt(soapEnv,0);
} catch(e) {
  RaiseError(e);
} finally {
  divePS = null;
  soapBody = null;
  soapEnv = null;
  parseResults =  null;
  TheApplication().SetProfileAttr(&quot;InterfaceKeyInbound&quot;, &quot;&quot;);
}
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The parseInterface method passes the ListOf container of the Integration Object to a&amp;nbsp;switch statement where each BC type can be evaluated.&amp;nbsp; This is useful only when using the Filter Service triggering mechanism otherwise the Record Id and Interface Name attributes can just be explicitly passed as parameters.&amp;nbsp;&amp;nbsp;A case section should be created for each Integration Object being processed. This function really needs to be manually manipulated for every implementation and integration point to explicitly specify how to find the record id for a particular integration.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 300px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function parseInterface(ListOfIC, oReturn) {    //Input ListOfIC is a ListOf...
//Called from logRequest and logResponse to parse a message and get the row id or reference ids of different
//objects
try {
  if (ListOfIC.GetChildCount() &amp;gt; 0) {
    var IC = ListOfIC.GetChild(0);   //Integration Component Instance
    var icNameSpace = &quot;&quot;;
    var intCompType = IC.GetType();
    var propName;
    var stop = false;
    var childIC;
    var childFlds;
      
    if (intCompType.indexOf(&quot;:&quot;) &amp;gt;= 0) {
      icNameSpace = intCompType.substr(0, intCompType.indexOf(&quot;:&quot;)+1);
      intCompType = intCompType.substr(intCompType.indexOf(&quot;:&quot;)+1);
    }

    //For these types, dive an additional level
    switch(intCompType) {
    case &quot;ATPCheckInterfaceRequestOrders&quot;:
      IC = IC.GetChild(0);
      intCompType = IC.GetType();
      if (intCompType.indexOf(&quot;:&quot;) &amp;gt;= 0) {
        icNameSpace = intCompType.substr(0, intCompType.indexOf(&quot;:&quot;)+1);
        intCompType = intCompType.substr(intCompType.indexOf(&quot;:&quot;)+1);
      }
      break;
    }
 
    for (var flds = 0; flds &amp;lt; IC.GetChildCount(); flds++) { //Loop through Fields
      propName = IC.GetChild(flds).GetType();
      switch (intCompType) {
      case &quot;Quote&quot;:
      case &quot;SWIQuote&quot;:
        oReturn.recBC = &quot;Quote&quot;;
        if (propName == icNameSpace+&quot;Id&quot;) {
          oReturn.recId = IC.GetChild(flds).GetValue();
          stop = true;
        }
        break;

      case &quot;ProductIntegration&quot;:
        oReturn.recBC = &quot;Internal Product&quot;;
        if (propName == icNameSpace+&quot;ListOfProductDefinition&quot;) {
          childIC = IC.GetChild(flds).GetChild(0);
          for (childFlds = 0; childFlds &amp;lt; childIC.GetChildCount(); childFlds++) { //Loop through Fields
            propName = childIC.GetChild(childFlds).GetType();
            if (propName == icNameSpace+&quot;Id&quot; || propName == icNameSpace+&quot;ProductId&quot;) {
              oReturn.recId = childIC.GetChild(childFlds).GetValue();
              stop = true;
            }
            if (stop) break;                              
          }
        }
        break;
     
      default:
        if (propName.indexOf(&quot;Id&quot;) &amp;gt;= 0) {
          oReturn.recId = IC.GetChild(flds).GetValue();
          stop = true;
        }
        oReturn.recBC = intCompType;
        stop = true;
      }
      if (stop) break;                              
    }
  }
} catch(e) {
  RaiseError(e);
} finally {
  childIC = null;
  IC = null;
}
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The logInterface method is called by both logRequest and logResponse to manage the session records for inbound interfaces and create the actual payload record.&amp;nbsp; I will have to go into more detail about the Anonymous login processing at some other time.&amp;nbsp; Suffice to say this works under a variety of web service setups.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 300px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function logInterface() {
if (gHoldBufferDump == true || gsTraceIntfaceReqResp == &quot;TRUE&quot;) {
  try {
    var key, dir, recId, recBC, status, srcObj, name, logText, userText, retCode, ref1, ref2, ref3, refField, findResponseMethod;
    var request:PropertySet, response:PropertySet;
    var progress = &quot;&quot;;

    //if attributes passed as an input property set, set variables from them
    if (typeof(arguments[0]) == &quot;object&quot;) {
      progress = progress+&quot;\n&quot;+&quot;REF1: typeof(arguments[0]) == object&quot;;
      var Inputs:PropertySet = arguments[0];
      name = Inputs.GetProperty(&quot;FunctionalName&quot;);
      key = Inputs.GetProperty(&quot;Key&quot;);
   
      for (var i=0;i &amp;lt; Inputs.GetChildCount();i++) {
        if (Inputs.GetChild(i).GetType() == &quot;Request&quot;) request = Inputs.GetChild(0);
        if (Inputs.GetChild(i).GetType() == &quot;Response&quot;) response = Inputs.GetChild(0);
      }
      dir = Inputs.GetProperty(&quot;Direction&quot;);
      recId = Inputs.GetProperty(&quot;LinkId&quot;);
      recBC = Inputs.GetProperty(&quot;LinkBC&quot;);
      status = Inputs.GetProperty(&quot;Status&quot;);
      srcObj = Inputs.GetProperty(&quot;SourceObject&quot;);
      logText = Inputs.GetProperty(&quot;LogText&quot;);
      userText = Inputs.GetProperty(&quot;UserText&quot;);
      retCode = Inputs.GetProperty(&quot;ReturnCode&quot;);
      ref1 = Inputs.GetProperty(&quot;Reference1&quot;);
      ref2 = Inputs.GetProperty(&quot;Reference2&quot;);
      ref3 = Inputs.GetProperty(&quot;Reference3&quot;);
      refField = Inputs.GetProperty(&quot;RefField&quot;);
    } else {
      progress = progress+&quot;\n&quot;+&quot;REF1: else typeof(arguments[0])&quot;;
      key = arguments[0];
      request = arguments[1];
      response = arguments[2];
      dir = arguments[3];
      recId = arguments[4];
      recBC = arguments[5];
      status = arguments[6];
      srcObj = arguments[7];
      name = arguments[8];
      logText = arguments[9];
      userText = arguments[10];
      retCode = arguments[11];
      ref1 = arguments[12];
      ref2 = arguments[13];
      ref3 = arguments[14];
      refField = arguments[15];
    }
  
    //When called though WF as Payload logger, generate the key if not provided
    if (key == &quot;&quot; || key == undefined || key == null) {
      if (name == &quot;&quot; || name == undefined || name == null) name = &quot;None&quot;;
      key = name.replace(/_spc/g, &quot;&quot;).replace(/\s/g, &quot;&quot;)+TimeStamp();
    }

    var found:Boolean = false;
    var sessionId:String = &quot;&quot;;
    var guestSessionId:String = &quot;&quot;;
    var guestSessionFound = false;
    var createSession = false;
    var firstMessage = false;
    var boSessionFlat;
    var bcSessionXMLFlat;
    var useGuestSession = (response != null &amp;amp;&amp;amp; gsMergeGuestSessions==&quot;TRUE&quot; &amp;amp;&amp;amp; gsGuest != &quot;&quot; ? true : false);
    var boSession:BusObject = TheApplication().GetBusObject(&quot;PPT User Session&quot;);
    var bcSession:BusComp;
 
    if (gHoldBuffer == true) {
      progress = progress+&quot;\n&quot;+&quot;REF2: gHoldBuffer == true&quot;;
      //If in a EAI Txn, store all payloads in an array so they can be written after the commit or rollback
      gHoldPayloads[gHoldPayloads.length] = arguments;
    } else {
      progress = progress+&quot;\n&quot;+&quot;REF2: gsTraceIntfaceReqResp == TRUE &amp;amp; key == &quot;+key;
      //If an interface is being logged for the first time, need to instantiate the session
      if (gSessionId == &quot;&quot;) {
        progress = progress+&quot;\n&quot;+&quot;REF3: gSessionId == &#39;&#39;&quot;;
        //If Guest connections are not used, a simplified session management can be used 
        if (gsGuest == &quot;&quot; &amp;amp;&amp;amp; key != &quot;&quot;) {
          progress = progress+&quot;\n&quot;+&quot;REF4: gsGuest == &#39;&#39; &amp;amp; key == &quot;+key;
          bcSession = boSession.GetBusComp(&quot;PPT User Session&quot;);
          with (bcSession) {
            NewRecord(NewBefore);
            SetFieldValue(&quot;Employee Id&quot;,TheApplication().LoginId());
            SetFieldValue(&quot;Session Stamp&quot;,gsLogSession);
            WriteRecord();
            gSessionId = GetFieldValue(&quot;Id&quot;);
          }
          createSession = false; //skip logic below to create/merge a guest session
          firstMessage = true; //will always insert the input message rather than querying to update
          //Reset the variable to check whether to merge the guest session.  This allows a log buffer dump
          gsMergeGuestSessions = &quot;FALSE&quot;;
        } else {
          progress = progress+&quot;\n&quot;+&quot;REF4: else: gsGuest == &#39;&#39; &amp;amp; key == &quot;+key;
          createSession = true;
  
          //confirm that current session has not been created yet
          bcSession = boSession.GetBusComp(&quot;PPT User Session&quot;);
          with (bcSession) {
            ClearToQuery();
            SetSearchSpec(&quot;Session Stamp&quot;, gsLogSession);
            ExecuteQuery(ForwardOnly);
            found = FirstRecord();
 
            if (found == true) {
              gSessionId = GetFieldValue(&quot;Id&quot;);
              createSession = false;
            } else {
              firstMessage = true;
            }
          }
        }
      }
 
      if (createSession == true || useGuestSession == true) {
        progress = progress+&quot;\n&quot;+&quot;REF5: createSession == true || useGuestSession == true&quot;;
        bcSession = boSession.GetBusComp(&quot;PPT User Session&quot;);
 
        //Because EAI logins can trigger logging from the anonymous login, the response logging will trigger
        //from a different session. Query for the most recent corresponding request log and update it
        if (useGuestSession) {
          progress = progress+&quot;\n&quot;+&quot;REF6: useGuestSession&quot;;
          boSessionFlat = TheApplication().GetBusObject(&quot;PPT User Session Flat&quot;);
          bcSessionXMLFlat = boSessionFlat.GetBusComp(&quot;PPT User Session XML&quot;);
          bcSessionXMLFlat.ActivateField(&quot;Parent Id&quot;);
          bcSessionXMLFlat.ClearToQuery();
          if (typeof(srcObj) != &quot;undefined&quot; &amp;amp;&amp;amp; srcObj != null) bcSessionXMLFlat.SetSearchSpec(&quot;Source Object&quot;, srcObj);
          if (typeof(ref1) != &quot;undefined&quot; &amp;amp;&amp;amp; ref1 != null) bcSessionXMLFlat.SetSearchSpec(&quot;Reference Id 1&quot;, ref1);
          bcSessionXMLFlat.SetSearchSpec(&quot;Response&quot;, &quot;IS NULL&quot;);
          bcSessionXMLFlat.SetSearchSpec(&quot;Employee Login&quot;, gsGuest);
          bcSessionXMLFlat.SetSortSpec(&quot;Created (DESC)&quot;);
          bcSessionXMLFlat.ExecuteQuery(ForwardBackward);
          guestSessionFound = bcSessionXMLFlat.FirstRecord();
    
          if (guestSessionFound == true) guestSessionId = bcSessionXMLFlat.GetFieldValue(&quot;Parent Id&quot;);
        }
    
        if (guestSessionFound == false &amp;amp;&amp;amp; createSession == true) {
          progress = progress+&quot;\n&quot;+&quot;REF7: guestSessionFound == false &amp;amp; createSession == true&quot;;
          //Anonymous login session not found and there is no current session.  Create a new one
          with (bcSession) {
            NewRecord(NewBefore);
            SetFieldValue(&quot;Employee Id&quot;,TheApplication().LoginId());
            SetFieldValue(&quot;Session Stamp&quot;,gsLogSession);
            WriteRecord();
            gSessionId = GetFieldValue(&quot;Id&quot;);
          }
        } else if (guestSessionFound == true &amp;amp;&amp;amp; createSession == false) {
          progress = progress+&quot;\n&quot;+&quot;REF7: guestSessionFound == true &amp;amp; createSession == false&quot;;
          //Anonymous login session found and there is a current session. 
          //Link child records to the parent session for the Interface User and delete the guest session (faster than a merge)
          while (guestSessionFound) {
            bcSessionXMLFlat.SetFieldValue(&quot;Parent Id&quot;,gSessionId);
            bcSessionXMLFlat.WriteRecord();
            guestSessionFound = bcSessionXMLFlat.NextRecord();
          }
          with (bcSession) {
            ClearToQuery();
            SetSearchSpec(&quot;Id&quot;, guestSessionId);
            SetSortSpec(&quot;&quot;);
            ExecuteQuery(ForwardOnly);
            guestSessionFound = FirstRecord();
     
            if (guestSessionFound == true) DeleteRecord();
            ClearToQuery();
            SetSortSpec(&quot;&quot;);
            SetSearchSpec(&quot;Id&quot;, gSessionId);
            ExecuteQuery(ForwardOnly);
          }
        } else if (guestSessionFound == true &amp;amp;&amp;amp; createSession == true) {
          progress = progress+&quot;\n&quot;+&quot;REF7: guestSessionFound == true &amp;amp; createSession == true&quot;;
          //Anonymous login session found and there is no current session.  Update the guest session to EAI values
          with (bcSession) {
            ActivateField(&quot;Employee Id&quot;);
            ActivateField(&quot;Session Stamp&quot;);
            ClearToQuery();
            SetSearchSpec(&quot;Id&quot;, guestSessionId);
            SetSortSpec(&quot;&quot;);
            ExecuteQuery(ForwardBackward);
            found = FirstRecord();
     
            if (found == true) {
              SetFieldValue(&quot;Employee Id&quot;,TheApplication().LoginId());
              SetFieldValue(&quot;Session Stamp&quot;,gsLogSession);
              WriteRecord();
            }
          }
        } else {
          progress = progress+&quot;\n&quot;+&quot;REF7: Anonymous login session not found and there is a current session.  Do Nothing&quot;;
          //Anonymous login session not found and there is a current session.  Do Nothing
        }
 
        //Reset the variable to check whether to merge the guest session.  This allows a log buffer dump
        gsMergeGuestSessions = &quot;FALSE&quot;;
      }
      var bcSessionXML = boSession.GetBusComp(&quot;PPT User Session XML&quot;);
      var bcSessionXMLDtl = boSession.GetBusComp(&quot;PPT User Session XML Detail&quot;);
 
      with (bcSessionXML) {
        if (firstMessage) {
          progress = progress+&quot;\n&quot;+&quot;REF8: firstMessage&quot;;
          //This is an insert so no query needed to update an existing record
          found = false;
          findResponseMethod = &quot;Do Not Search&quot;;
        } else if (useGuestSession &amp;amp;&amp;amp; guestSessionFound) {
          progress = progress+&quot;\n&quot;+&quot;REF8: useGuestSession &amp;amp; guestSessionFound&quot;;
          //If this is the first update after a guest session is used, the key will not match but there should only be one XML record
          ClearToQuery();
          SetSearchSpec(&quot;Created By Login&quot;, gsGuest);
          SetSearchSpec(&quot;Parent Id&quot;, gSessionId);
          SetSearchSpec(&quot;Request&quot;, &quot;IS NOT NULL&quot;);
          SetSearchSpec(&quot;Response&quot;, &quot;IS NULL&quot;);
          ExecuteQuery(ForwardBackward);
          found = FirstRecord();
          findResponseMethod = &quot;Session/Guest Login: &quot;+gSessionId+&quot;/&quot;+gsGuest;
        } else if ((typeof(response) != &quot;undefined&quot; &amp;amp;&amp;amp; response != null) ||
          (typeof(ref1) != &quot;undefined&quot; &amp;amp;&amp;amp; ref1 != null &amp;amp;&amp;amp; typeof(request) != &quot;undefined&quot; &amp;amp;&amp;amp; request != null &amp;amp;&amp;amp; gsReplaceSyncResponseWAsyncRequest == &quot;TRUE&quot;)) {
          progress = progress+&quot;\n&quot;+&quot;REF8: normal response update OR inbound request to a previously sent asynchronous request&quot;;
          //This is a normal response update to an existing message record or 
          //it is an inbound request to a previously sent asynchronous request with a matching Reference Id AND we want to log the Async request as the response
          ClearToQuery();
          SetSearchSpec(&quot;Parent Id&quot;, gSessionId);
 
          //If this is an Inbound request and Ref1 is provided, lookup by Ref1 
          if (typeof(ref1) != &quot;undefined&quot; &amp;amp;&amp;amp; ref1 != null &amp;amp;&amp;amp; typeof(request) != &quot;undefined&quot; &amp;amp;&amp;amp; request != null) {
            SetSearchSpec(&quot;Reference Id 1&quot;, ref1.substring(0, 100));
            findResponseMethod = &quot;Reference 1: &quot;+ref1.substring(0, 100);
          } else {
            SetSearchSpec(&quot;Name&quot;, key);
            findResponseMethod = &quot;Key: &quot;+key;
          }
          SetSortSpec(&quot;&quot;);
          ExecuteQuery(ForwardBackward);
          found = FirstRecord();
        }
    
        //This is a normal request or an existing record could not be found for some reason
        if (found == false) {
          progress = progress+&quot;\n&quot;+&quot;REF9: This is a normal request or an existing record could not be found for some reason (&quot;+findResponseMethod+&quot;)&quot;;
          NewRecord(NewBefore);
          SetFieldValue(&quot;Name&quot;,key);
          SetFieldValue(&quot;Parent Id&quot;,gSessionId);
        }
    
        if (useGuestSession == true) {
          progress = progress+&quot;\n&quot;+&quot;REF10: Set Name Key: &quot;+key.substring(0, 100);
          SetFieldValue(&quot;Name&quot;, key.substring(0, 100));
        }
 
        //Since payloads can be any size, very large ones greater than CLOB size 131k need to be split with the text being 
        //put into multiple records
        if (typeof(request) != &quot;undefined&quot; &amp;amp;&amp;amp; request != null) {
          progress = progress+&quot;\n&quot;+&quot;REF11: Set Request&quot;;
          SetFieldValue(&quot;Request Time&quot;, TimeStamp(&quot;DateTimeFormatted&quot;));
          splitPayload(bcSessionXML, bcSessionXMLDtl, &quot;Request&quot;, request, 131072)
        }
        if (typeof(response) != &quot;undefined&quot; &amp;amp;&amp;amp; response != null) {
          progress = progress+&quot;\n&quot;+&quot;REF12: Set Response&quot;;
          SetFieldValue(&quot;Response Time&quot;, TimeStamp(&quot;DateTimeFormatted&quot;));
          splitPayload(bcSessionXML, bcSessionXMLDtl, &quot;Response&quot;, response, 131072)
        }
  
        if (typeof(dir) != &quot;undefined&quot; &amp;amp;&amp;amp; dir != null &amp;amp;&amp;amp; dir != &quot;&quot;)   SetFieldValue(&quot;Direction&quot;, dir.substring(0, 30));
        if (typeof(recId) != &quot;undefined&quot; &amp;amp;&amp;amp; recId != null &amp;amp;&amp;amp; recId != &quot;&quot;) SetFieldValue(&quot;Record Id&quot;, recId.substring(0, 15));
        if (typeof(recBC) != &quot;undefined&quot; &amp;amp;&amp;amp; recBC != null &amp;amp;&amp;amp; recBC != &quot;&quot;) SetFieldValue(&quot;Record BC&quot;, recBC.substring(0, 50));
        if (typeof(status) != &quot;undefined&quot; &amp;amp;&amp;amp; status != null &amp;amp;&amp;amp; status !=&quot;&quot;) SetFieldValue(&quot;Status&quot;, status.substring(0, 30));
        if (typeof(srcObj)!=&quot;undefined&quot; &amp;amp;&amp;amp; srcObj != null &amp;amp;&amp;amp; srcObj !=&quot;&quot;) SetFieldValue(&quot;Source Object&quot;, srcObj.substring(0, 50));
        if (typeof(name) != &quot;undefined&quot; &amp;amp;&amp;amp; name != null &amp;amp;&amp;amp; name != &quot;&quot;)  SetFieldValue(&quot;Functional Name&quot;, name.substring(0, 50));
        if (typeof(logText)!= &quot;undefined&quot; &amp;amp;&amp;amp; logText != null &amp;amp;&amp;amp; logText !=&quot;&quot;) SetFieldValue(&quot;Log Text&quot;, logText.substring(0, 131072));
        if (typeof(userText)!= &quot;undefined&quot; &amp;amp;&amp;amp; userText != null &amp;amp;&amp;amp; userText !=&quot;&quot;) SetFieldValue(&quot;User Text&quot;, userText.substring(0, 255));
        if (typeof(retCode) != &quot;undefined&quot; &amp;amp;&amp;amp; retCode != null &amp;amp;&amp;amp; retCode != &quot;&quot;)  SetFieldValue(&quot;Return Code&quot;, retCode.substring(0, 30));
        if (typeof(refField) != &quot;undefined&quot; &amp;amp;&amp;amp; refField != null &amp;amp;&amp;amp; refField!=&quot;&quot;) {
          SetFieldValue(refField, ref1);
          SetFieldValue(&quot;Reference Id 2&quot;, refField);
        } else {
          if (typeof(ref1) != &quot;undefined&quot; &amp;amp;&amp;amp; ref1 != null)   SetFieldValue(&quot;Reference Id 1&quot;, ref1.substring(0, 100));
          if (typeof(ref2) != &quot;undefined&quot; &amp;amp;&amp;amp; ref2 != null)   SetFieldValue(&quot;Reference Id 2&quot;, ref2.substring(0, 100));
        }
        if (typeof(ref3) != &quot;undefined&quot; &amp;amp;&amp;amp; ref3 != null)   SetFieldValue(&quot;Reference Id 3&quot;, ref3.substring(0, 100));
        progress = progress+&quot;\n&quot;+&quot;REF13: PreWrite&quot;;
        WriteRecord();
      }
      if (gsLogMode == &quot;FILE&quot;) {
        progress = progress+&quot;\n&quot;+&quot;REF14: gsLogMode == FILE&quot;;
        if (typeof(request) != &quot;undefined&quot; &amp;amp;&amp;amp; request != null)  PropSetToFile(key+&quot;_Request&quot;, request);
        if (typeof(response) != &quot;undefined&quot; &amp;amp;&amp;amp; response != null) PropSetToFile(key+&quot;_Response&quot;, response);
      }
    }
  } catch(e) {
    RaiseError(e, progress);
  } finally {
    request = null;
    response = null;
    Inputs = null;
    bcSessionXML = null;
    bcSessionXMLFlat = null;
    boSessionFlat = null;
    bcSession = null;
    boSession = null;
    TheApplication().SetProfileAttr(&quot;C1 Session Id&quot;, gSessionId);
  }
  return(progress);
}
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The trimPS method is actually deprecated in my service but I include it in case it is useful to anyone.&amp;nbsp; I basically just takes a property set, converts it to text, then&amp;nbsp;sets a specified&amp;nbsp;field on an instantiated BC passed as an input&amp;nbsp;to the converted text of the property set.&amp;nbsp; The assumption in using this method is that there is a limit to how large the stored payload can be.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 300px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function trimPS(ps, fieldName, bc, maxLength){
try {
  var psIn      = TheApplication().NewPropertySet();
  var psOut     = TheApplication().NewPropertySet();
  var bsService = TheApplication().GetService (&quot;XML Converter (Data in Child PropSet)&quot;);
  psIn.SetProperty(&quot;EscapeNames&quot;, &quot;False&quot;);
  var text:String = &quot;&quot;;

  psIn.AddChild(ps);
  bsService.InvokeMethod(&quot;PropSetToXML&quot;, psIn, psOut);
  bc.SetFieldValue(fieldName, ToString(psOut).substring(0, maxLength));
  bc.SetFieldValue(fieldName+&quot; Time&quot;, TimeStamp(&quot;DateTimeFormatted&quot;));
  text = bc.GetFieldValue(fieldName);
  text = text.lTrim();
  if (text.substring(0, 14) == &quot;PropertySet [ &quot;) text = text.substring(14);
  text = text.rTrim(&quot;]&quot;);
  bc.SetFieldValue(fieldName,text);
} catch (e) {
  throw(e);
} finally { 
  psOut = null;
  psIn = null;
  bsService = null;
}
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
The splitPayload method is what replace the trimPS method.&amp;nbsp; It is no longer limited in being able store only a certain character length of payload as this method splits the payload into chunks of a specified size and inserts records into the instantiated BC passed as an input.&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;height: 300px; overflow-x: scroll; overflow-y: scroll; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;function splitPayload(parentbc, detailbc, fieldName, ps, maxLength) {
try {
  var psIn      = TheApplication().NewPropertySet();
  var psOut     = TheApplication().NewPropertySet();
  var bsService = TheApplication().GetService (&quot;XML Converter (Data in Child PropSet)&quot;);
  psIn.SetProperty(&quot;EscapeNames&quot;, &quot;False&quot;);
  var text:String = &quot;&quot;;
  var stripPS = false;
  var textPS = &quot;&quot;;
  
  psIn.AddChild(ps);
  bsService.InvokeMethod(&quot;PropSetToXML&quot;, psIn, psOut);
  textPS = ToString(psOut);

  if (textPS.length &amp;gt; maxLength) {
    while (textPS.length &amp;gt; 0) {
      detailbc.NewRecord(NewAfter);
      detailbc.SetFieldValue(&quot;Field&quot;, fieldName);
      detailbc.SetFieldValue(&quot;Log Text&quot;, textPS.substring(0, maxLength));
 
      //Service adds a Prefix that needs to be removed
      text = detailbc.GetFieldValue(&quot;Log Text&quot;);
      text = text.lTrim();
      if (text.substring(0, 14) == &quot;PropertySet [ &quot;) {
        stripPS = true;
        text = text.substring(14);
      }
 
      textPS = textPS.substring(maxLength, textPS.length); 
 
      //If the Text is broken up across multiple records, need to remove the trailing ] from the last record
      if (stripPS &amp;amp;&amp;amp; textPS.length &amp;lt; maxLength) {
        text = text.rTrim(&quot;]&quot;);
      }
      detailbc.SetFieldValue(&quot;Log Text&quot;,text);
      detailbc.WriteRecord();
    }
  } else {
    parentbc.SetFieldValue(fieldName, textPS);
    text = parentbc.GetFieldValue(fieldName);
    text = text.lTrim();
    if (text.substring(0, 14) == &quot;PropertySet [ &quot;) {
      stripPS = true;
      text = text.substring(14).rTrim(&quot;]&quot;);
      parentbc.SetFieldValue(fieldName, text);
    }
//  parentbc.WriteRecord();
  }
} catch (e) {
  RaiseError(e);
} finally { 
  psOut = null;
  psIn = null;
  bsService = null;
}
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
Next: &lt;a href=&quot;http://thesiebelscholar.blogspot.com/2013/05/the-xml-logger-revieing-payload.html&quot;&gt;Viewing the Payload&lt;/a&gt;</description><link>http://thesiebelscholar.blogspot.com/2013/05/the-xml-logger.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-6381792465182957730</guid><pubDate>Tue, 07 May 2013 20:33:00 +0000</pubDate><atom:updated>2013-05-07T18:59:27.808-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">eScript Framework</category><title>State of Logging - An Introduction</title><description>I was reading Jason Le&#39;s recent post about &lt;a href=&quot;http://www.impossiblesiebel.com/2013/03/an-xml-logger.html#comment-form&quot;&gt;XML Logging&lt;/a&gt; and I realized the problem statement he was describing was intimately familiar to me because it is something I have been dealing with over the years and have evolved a solution for it. &amp;nbsp;I say evolved because it has gone though so many iterations by this point I am not sure where to begin. &amp;nbsp;So let me start with a verbal explanation, and then I will get into the details.&lt;br /&gt;
&lt;br /&gt;
I built an eScript &lt;a href=&quot;http://thesiebelscholar.blogspot.com/2010/05/escript-framework-logging.html&quot;&gt;Logging Service&lt;/a&gt; back in the day to help with tracing processing through custom script. &amp;nbsp;This was written out to a text file in the file system. &amp;nbsp;I don&#39;t recall the sequence of events after that but at some point I added an XML logging utility to this so that the XML files would be written to the file system as well. This was initially an explicit call to a business service within the integration WF to pass an XML Property Set &amp;nbsp;so it could be written out. &amp;nbsp;I then moved to a client which was using a business service to create custom SOAP headers so I modified the logging service so that it could be called as a custom filtering service itself. &amp;nbsp;This allowed the exact payload to be captured as it was leaving/returning to the Siebel application.&lt;br /&gt;
&lt;br /&gt;
At some point I ended up on a client that had UNIX Application servers, needed me to do production support post go-live AND was very restrictive about granting access to the production file system. &amp;nbsp;Rather than deal with the UNIX and access issues, I opted to modify the service so it could operate in two modes. &amp;nbsp;When using a thick client, it would continue to write all information out to the local file system as defined by the SIEBEL_LOG_DIR environment variable. &amp;nbsp;But I allowed thin client users to output logging data to a new set of custom tables. &amp;nbsp;Basically when a user logs in, a session record is created. &amp;nbsp;All escript logging data is written out to a 1:M detail table in buffered chunks to minimize performance hits. &amp;nbsp;XML Logging does the same (though in a slightly different way). &amp;nbsp;Each detail record has the opportunity to store a row id which allows a session to be linked to a particular record that was logged, like an Order Id. &amp;nbsp;This allows for audit views to be created which show all the user sessions with logging information tied to a particular record.&lt;br /&gt;
&lt;br /&gt;
The other problem I needed to solve was that when an error occurs, Siebel rolls back transactions. &amp;nbsp;Therefore all interfaces use the EAI Transaction Service and I have modified this service to set a flag so that when in a transaction, all XML payloads are stored in memory until the transaction is either aborted or committed, at which point all the messages are written to the DB in the order they were executed.&lt;br /&gt;
&lt;br /&gt;
To view logging information, whether XML or escript, requires the many detail records to be reassembled into a viewable format. &amp;nbsp;There is a method of the service that basically just queries all the detail records for a particular session or XML Payload and concatenates the text into a single value. &amp;nbsp;This method can be invoked from a calculated field and the calculated field exposed on a form applet. &amp;nbsp;Because form applet fields are not the best way to see the data, I typically copy the data out of the field and into a text editor of choice. &amp;nbsp;For instance I use Notepad++ &amp;nbsp;with a Pretty Print add on to view XML payloads.&lt;br /&gt;
&lt;br /&gt;
It will take several posts to go over the implementation in detail, but hopefully this whets people&#39;s appetites&lt;br /&gt;
&lt;br /&gt;
Next: &lt;a href=&quot;http://thesiebelscholar.blogspot.com/2013/05/the-xml-logger.html&quot;&gt;The XML Logger&lt;/a&gt;</description><link>http://thesiebelscholar.blogspot.com/2013/05/state-of-logging-introduction.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-1523130145721518811</guid><pubDate>Wed, 12 Dec 2012 18:33:00 +0000</pubDate><atom:updated>2019-06-26T15:12:28.974-04:00</atom:updated><title>Miscellaneous SQL Repository Research</title><description>I frequently use SQL to track down potential issues in the repository.&amp;nbsp; Here are a couple of statements that help solve common problems:&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;Fields Inactivated in the BC but Active in the Integration Object&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
select io.name int_obj, ic.name int_comp, icf.NAME int_field from siebel.S_INT_FIELD icf, siebel.S_INT_COMP ic, siebel.S_INT_OBJ io, siebel.s_repository r, siebel.s_buscomp bc, siebel.s_field f&lt;br /&gt;
where icf.INT_COMP_ID = ic.row_id and ic.INT_OBJ_ID = io.row_id and io.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39;&lt;br /&gt;
and ic.EXT_NAME = bc.name and icf.EXT_NAME = f.name and f.buscomp_id = bc.row_id and bc.repository_id = r.row_id and f.inactive_flg = &#39;Y&#39;&lt;br /&gt;
and io.inactive_flg = &#39;N&#39; and ic.inactive_flg = &#39;N&#39; and icf.inactive_flg = &#39;N&#39; and f.last_upd &amp;gt; to_date(&#39;11/01/2012&#39;, &#39;MM/DD/YYYY&#39;); 
&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;&lt;strong&gt;Identify potential causes of the Truncation or Null Fetch error&lt;/strong&gt;&lt;br /&gt;
&lt;br /&gt;
This can sometimes be caused by not compiling the Table object too.&amp;nbsp; The first query finds business component joined fields where the BC field length or data type&amp;nbsp;does not match the column length.&amp;nbsp; The second does the same but only analyzes base table columns and adds a last updated parameter which could be added or removed from either.&amp;nbsp; The last updated date is useful because vanilla actually has numerous instances of this potential problem.&amp;nbsp; I say potential because any records returned need to be checked against the data.&amp;nbsp; The error will only occur if the data in the column is longer than the BC length specified.&amp;nbsp; The Third query is an example of how to check assuming for instance S_ORDER_ITEM.ATTRIB_40 is mapped to a DTYPE_ID BC field.. 
&lt;br /&gt;
&lt;br /&gt;
select bc.name Bus_comp, f.name field, f.join_name Join, j.DEST_TBL_NAME Tbl_name, f.col_name Col_name, f.type Field_Type, f.textlen Fld_Lgth, c.DATA_TYPE Col_type, c.LENGTH col_lgth 
&lt;br /&gt;
from siebel.s_field f, siebel.s_repository r, siebel.s_join j, siebel.s_buscomp bc, siebel.s_column c, siebel.s_table t&lt;br /&gt;
where bc.REPOSITORY_ID = r.row_id and r.name = &#39;Siebel Repository&#39;&lt;br /&gt;
and bc.row_id = f.buscomp_id and j.name = f.join_name and j.buscomp_id = bc.row_id&lt;br /&gt;
and c.TBL_ID = t.row_id and t.NAME = j.DEST_TBL_NAME and c.name = f.col_name&lt;br /&gt;
and r.row_id = t.REPOSITORY_ID and r.row_id = f.REPOSITORY_ID and r.row_id = c.REPOSITORY_ID&lt;br /&gt;
and t.INACTIVE_FLG = &#39;N&#39; and c.INACTIVE_FLG = &#39;N&#39; and bc.INACTIVE_FLG = &#39;N&#39; and f.INACTIVE_FLG = &#39;N&#39;&lt;br /&gt;
and ((f.type = &#39;DTYPE_ID&#39; and c.length &amp;gt; 15)&lt;br /&gt;
or (f.type = &#39;DTYPE_PHONE&#39; and c.length &amp;gt; 40)&lt;br /&gt;
or (f.type = &#39;DTYPE_BOOL&#39; and c.length &amp;gt; 1)&lt;br /&gt;
or (f.type = &#39;DTYPE_TEXT&#39; and c.DATA_TYPE like &#39;Date%&#39;))&lt;br /&gt;
order by j.DEST_TBL_NAME, f.col_name; 
&lt;br /&gt;
&lt;br /&gt;
select bc.name Bus_comp, f.name field, t.NAME tbl_name, f.col_name Col_name, f.type Field_Type, f.textlen Fld_Lgth, c.DATA_TYPE Col_type, c.LENGTH col_lgth 
&lt;br /&gt;
from siebel.s_field f, siebel.s_repository r, siebel.s_buscomp bc, siebel.s_column c, siebel.s_table t&lt;br /&gt;
where bc.REPOSITORY_ID = r.row_id and r.name = &#39;Siebel Repository&#39;&lt;br /&gt;
and bc.row_id = f.buscomp_id&lt;br /&gt;
and c.TBL_ID = t.row_id and t.NAME = bc.TABLE_NAME and c.name = f.col_name&lt;br /&gt;
and r.row_id = t.REPOSITORY_ID and r.row_id = f.REPOSITORY_ID and r.row_id = c.REPOSITORY_ID&lt;br /&gt;
and t.INACTIVE_FLG = &#39;N&#39; and c.INACTIVE_FLG = &#39;N&#39; and bc.INACTIVE_FLG = &#39;N&#39; and f.INACTIVE_FLG = &#39;N&#39;&lt;br /&gt;
and ((f.type = &#39;DTYPE_ID&#39; and c.length &amp;gt; 15)&lt;br /&gt;
or (f.type = &#39;DTYPE_PHONE&#39; and c.length &amp;gt; 40)&lt;br /&gt;
or (f.type = &#39;DTYPE_BOOL&#39; and c.length &amp;gt; 1)&lt;br /&gt;
or (f.type = &#39;DTYPE_TEXT&#39; and c.DATA_TYPE like &#39;Date%&#39;))&lt;br /&gt;
and f.last_upd &amp;gt; to_date(&#39;06/01/2010&#39;, &#39;MM/DD/YYYY&#39;)&lt;br /&gt;
order by t.NAME, f.col_name; 
&lt;br /&gt;
&lt;br /&gt;
select ATTRIB_40 from siebel.S_ORDER_ITEM_XM where length(ATTRIB_40) &amp;gt; 15;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;WF Deployed but not activated:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
select wpr.proc_name, wpr.version from siebel.S_WFR_PROC wpr, siebel.s_repository r&lt;br /&gt;
where r.row_id = wpr.REPOSITORY_ID and r.name = &#39;Siebel Repository&#39; and wpr.STATUS_CD = &#39;COMPLETED&#39;&lt;br /&gt;
and wpr.name like &#39;PPT%&#39;&lt;br /&gt;
and exists (select &#39;x&#39; from siebel.S_WFA_DPLOY_DEF wpd where wpd.NAME = wpr.proc_name and wpd.TYPE_CD = &#39;PROCESS&#39; and wpd.DEPLOY_STATUS_CD = &#39;ACTIVE&#39;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; and wpd.REPOSITORY_VERSION &amp;lt;&amp;gt; wpr.VERSION)&lt;br /&gt;
and wpr.version = (select max(wpr1.version) from siebel.S_WFR_PROC wpr1&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; where r.row_id = wpr1.REPOSITORY_ID and wpr1.STATUS_CD = &#39;COMPLETED&#39; and wpr1.proc_name = wpr.proc_name)&lt;br /&gt;
order by wpr.proc_name;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;BC Fields not configured as boolean that should be&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
select bc.name, f.name, f.type, f.CALCVAL from siebel.s_field f, siebel.s_buscomp bc, siebel.s_repository r&lt;br /&gt;
where f.BUSCOMP_ID = bc.row_id and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39;&lt;br /&gt;
and (f.CALCVAL like &#39;%,%Y%,%N%)&#39; OR f.CALCVAL like &#39;%,%N%,%Y%)&#39;)&lt;br /&gt;
and f.TYPE &amp;lt;&amp;gt;&amp;nbsp;&#39;DTYPE_BOOL&#39;&lt;br /&gt;
and f.inactive_flg = &#39;N&#39; and bc.name like &#39;PPT%&#39; and bc.inactive_flg = &#39;N&#39;&lt;br /&gt;
order by bc.name, f.name;&lt;br /&gt;
&lt;br /&gt;
select bc.name, f.name, f.type, f.CALCVAL from siebel.s_field f, siebel.s_buscomp bc, siebel.s_repository r&lt;br /&gt;
where f.BUSCOMP_ID = bc.row_id and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39;&lt;br /&gt;
and f.TEXTLEN = 1&lt;br /&gt;
and f.TYPE &amp;lt;&amp;gt;&amp;nbsp;&#39;DTYPE_BOOL&#39;&lt;br /&gt;
and f.inactive_flg = &#39;N&#39; and bc.name like &#39;PPT%&#39; and bc.inactive_flg = &#39;N&#39;&lt;br /&gt;
order by bc.name, f.name;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Applet controls where checkbox not configured correctly&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
select a.name, lc.name, lc.field_name, lc.HTML_TYPE, lc.HTML_ICON_MAP, f.type from siebel.s_list_column lc, siebel.s_list l, siebel.s_applet a, siebel.s_repository r, siebel.s_field f, siebel.s_buscomp bc&lt;br /&gt;
where lc.list_id = l.row_id and l.applet_id = a.row_id and a.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and lc.inactive_flg = &#39;N&#39; and a.inactive_flg = &#39;N&#39;&lt;br /&gt;
and (lc.HTML_ICON_MAP is null or lc.HTML_TYPE &amp;lt;&amp;gt;&amp;nbsp;&#39;CheckBox&#39;)&lt;br /&gt;
and f.name = lc.FIELD_NAME and f.BUSCOMP_ID = bc.row_id and bc.name = a.BUSCOMP_NAME and f.TYPE = &#39;DTYPE_BOOL&#39; and a.name like &#39;PPT%&#39;;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;b&gt;Integration Object Maps that have changed since a prior release:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
select release, Map_Name, change_level, Field_Upd, Field_User, Comp_Upd, Comp_User, Obj_Upd, Obj_user, Comp_Name, src_expr, dst_int_fld_name, Obj_Comments&lt;br /&gt;
from ( -- Object level&lt;br /&gt;
select o.x_release release, o.name Map_Name, &#39;1-Object&#39; change_level, null Field_Upd, null Field_User, null Comp_Upd, null Comp_User, o.last_upd Obj_Upd, ou.login Obj_user, null Comp_Name, null src_expr, null dst_int_fld_name, o.comments Obj_Comments&lt;br /&gt;
from siebel.S_INT_OBJMAP o, siebel.s_user ou&lt;br /&gt;
where o.last_upd_by = ou.row_id and o.last_upd &amp;gt;= to_date(&#39;04/23/2019&#39;, &#39;MM/DD/YYYY&#39;)&lt;br /&gt;
UNION ALL -- Component level&lt;br /&gt;
select o.x_release release, o.name Map_Name, &#39;2-Component&#39; change_level, null Field_Upd, null Field_User, c.last_upd Comp_Upd, cu.login Comp_User, null Obj_Upd, null Obj_user, c.name Comp_Name, c.SRC_SRCHSPEC src_expr, null dst_int_fld_name, o.comments Obj_Comments&lt;br /&gt;
from siebel.S_INT_OBJMAP o, siebel.S_INT_COMPMAP c, siebel.s_user cu, siebel.s_user ou&lt;br /&gt;
where c.int_obj_map_id = o.row_id and c.last_upd_by = cu.row_id and o.last_upd_by = ou.row_id --and o.x_release = &#39;1.27.12&#39;&lt;br /&gt;
and c.last_upd &amp;gt;= to_date(&#39;4/23/2019&#39;, &#39;MM/DD/YYYY&#39;)&lt;br /&gt;
UNION ALL -- Field level&lt;br /&gt;
select o.x_release release, o.name Map_Name, &#39;3-Field&#39; change_level, f.last_upd Field_Upd, fu.login Field_User, null Comp_Upd, null Comp_User, null Obj_Upd, null Obj_user, c.name Comp_Name, f.src_expr, f.dst_int_fld_name, o.comments Obj_Comments&lt;br /&gt;
from siebel.S_INT_OBJMAP o, siebel.S_INT_COMPMAP c, siebel.S_INT_FLDMAP f, siebel.s_user fu, siebel.s_user cu, siebel.s_user ou&lt;br /&gt;
where f.int_comp_map_id = c.row_id and c.int_obj_map_id = o.row_id and f.last_upd_by = fu.row_id and c.last_upd_by = cu.row_id and o.last_upd_by = ou.row_id --and o.x_release = &#39;1.27.12&#39;&lt;br /&gt;
and (f.last_upd &amp;gt;= to_date(&#39;4/23/2019&#39;, &#39;MM/DD/YYYY&#39;))&lt;br /&gt;
) where release &amp;lt;&amp;gt;&amp;nbsp;&#39;1.27.13&#39;&lt;br /&gt;
order by Map_Name, change_level;&lt;/div&gt;
</description><link>http://thesiebelscholar.blogspot.com/2012/12/miscellaneous-sql-repository-research.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-2553072489000257378</guid><pubDate>Wed, 12 Dec 2012 18:21:00 +0000</pubDate><atom:updated>2012-12-12T13:21:11.488-05:00</atom:updated><title>Repository Search by SQL</title><description>Tools offers a Repository Search feature which is quite robust but it has some significant drawbacks:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Tedious to specify only those items which might have the object name you are looking for &lt;/li&gt;
&lt;li&gt;Time consuming to do a full search or a search of certain objects with high record counts&lt;/li&gt;
&lt;li&gt;Does not search UI admin objects where a field might be referenced&lt;/li&gt;
&lt;/ol&gt;
There have been times when I wanted to inactivate objects in order to streamline the application and have had difficulty identifying all the references.&amp;nbsp; Or if you see an error in the Siebel log, it is sometimes hard to forensically determine its source.&lt;br /&gt;
&lt;br /&gt;
I have written a series of SQL statements to search for the items directly against the server tools DB.&amp;nbsp; This SQL looks at both repository tables where a particular object type might be referenced as well as UI administrative objects.&amp;nbsp; It is not guaranteed to be 100% comprehensive and should be modified to the particular needs of how a client has used the application.&amp;nbsp; For instance, if Variable Maps are not modified from vanilla, it is probably not necessary to query the tables that store them.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://thesiebelscholar.blogspot.com/2012/12/sql-field-search.html&quot;&gt;Fields&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://thesiebelscholar.blogspot.com/2012/12/sql-applet-search.html&quot;&gt;Applets&lt;/a&gt;</description><link>http://thesiebelscholar.blogspot.com/2012/12/repository-search-by-sql.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-6354790171892970481</guid><pubDate>Wed, 12 Dec 2012 18:20:00 +0000</pubDate><atom:updated>2019-06-20T14:06:06.882-04:00</atom:updated><title>SQL Applet Search</title><description>Here is the SQL to find Applet References.&amp;nbsp; You will notice there are two queries of Toggle Applets.&amp;nbsp; One rolls an applet all the way up to the view it appears in while the other shows toggle applets that do not appear in any view.&amp;nbsp; Therefore, in a toggle sequence, there may be one applet that appears twice.&amp;nbsp; The wc or wildcard bind variable adds a trailing wildcard&lt;br /&gt;
&lt;br /&gt;
var :applet = &quot;Quote Form Applet&quot;;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -- Applet Name&lt;br /&gt;
var :wc = &quot;N&quot;;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;
&lt;br /&gt;
select attr_type, screen, viewname, obj_name, attr_name, Applet_Mode from (&lt;br /&gt;
select &#39;View web template item&#39; attr_type, s.name screen, v.name viewname, &#39;&#39; obj_name, vwti.APPLET_NAME attr_name, vwti.APPLET_MODE_CD Applet_Mode from siebel.s_screen s, siebel.S_SCREEN_VIEW sv, siebel.S_VIEW_WTMPL_IT vwti, siebel.S_VIEW_WEB_TMPL vwt, siebel.s_view v, siebel.s_repository r&lt;br /&gt;
where vwti.APPLET_NAME like :applet||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and vwti.VIEW_WEB_TMPL_ID = vwt.row_id and vwt.VIEW_ID = v.row_id and v.name = sv.VIEW_NAME and sv.SCREEN_ID = s.row_id and s.repository_id = r.row_id&lt;br /&gt;
and v.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and vwti.inactive_flg = &#39;N&#39; and vwt.inactive_flg = &#39;N&#39; and sv.inactive_flg = &#39;N&#39; and v.inactive_flg = &#39;N&#39; and s.inactive_flg = &#39;N&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Form Applet Pick Applet&#39; attr_type, &#39;&#39; screen, &#39;&#39; viewname, a.name obj_name, c.PICK_APPLET_NAME attr_name, &#39;&#39; Applet_Mode from siebel.s_control c, siebel.s_applet a, siebel.s_repository r&lt;br /&gt;
where c.PICK_APPLET_NAME like :applet||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and c.applet_id = a.row_id and a.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and c.inactive_flg = &#39;N&#39; and a.inactive_flg = &#39;N&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Form Applet MVG Applet&#39; attr_type, &#39;&#39; screen, &#39;&#39; viewname, a.name obj_name, c.MVG_APPLET_NAME attr_name, &#39;&#39; Applet_Mode from siebel.s_control c, siebel.s_applet a, siebel.s_repository r&lt;br /&gt;
where c.MVG_APPLET_NAME like :applet||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and c.applet_id = a.row_id and a.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and c.inactive_flg = &#39;N&#39; and a.inactive_flg = &#39;N&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;List Applet Pick Applet&#39; attr_type, &#39;&#39; screen, &#39;&#39; viewname, a.name obj_name, lc.PICK_APPLET_NAME attr_name, &#39;&#39; Applet_Mode from siebel.s_list_column lc, siebel.s_list l, siebel.s_applet a, siebel.s_repository r&lt;br /&gt;
where lc.PICK_APPLET_NAME like :applet||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and lc.list_id = l.row_id and l.applet_id = a.row_id and a.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and lc.inactive_flg = &#39;N&#39; and a.inactive_flg = &#39;N&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;List Applet MVG Applet&#39; attr_type, &#39;&#39; screen, &#39;&#39; viewname, a.name obj_name, lc.MVG_APPLET_NAME attr_name, &#39;&#39; Applet_Mode from siebel.s_list_column lc, siebel.s_list l, siebel.s_applet a, siebel.s_repository r&lt;br /&gt;
where lc.MVG_APPLET_NAME like :applet||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and lc.list_id = l.row_id and l.applet_id = a.row_id and a.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and lc.inactive_flg = &#39;N&#39; and a.inactive_flg = &#39;N&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Associate Applet&#39; attr_type, &#39;&#39; screen, &#39;&#39; viewname, a.name obj_name, a.ASSOC_APPLET_NAME attr_name, &#39;&#39; Applet_Mode from siebel.s_applet a, siebel.s_repository r&lt;br /&gt;
where a.ASSOC_APPLET_NAME like :applet||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and a.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and a.inactive_flg = &#39;N&#39;&lt;br /&gt;
union all&lt;br /&gt;
select &#39;Applet Toggle&#39; attr_type, &#39;&#39; screen, &#39;&#39; viewname, a.name obj_name, t.APPLET_NAME attr_name, &#39;&#39; Applet_Mode from siebel.S_APPLET_TOGGLE t, siebel.s_applet a, siebel.s_repository r&lt;br /&gt;
where t.APPLET_NAME like :applet||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and t.applet_id = a.row_id and a.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and t.inactive_flg = &#39;N&#39; and a.inactive_flg = &#39;N&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Applet Toggle&#39; attr_type, s.name screen, v.name viewname, a.name obj_name, t.APPLET_NAME attr_name, vwti.APPLET_MODE_CD Applet_Mode from siebel.s_screen s, siebel.S_SCREEN_VIEW sv, siebel.S_VIEW_WTMPL_IT vwti, siebel.S_VIEW_WEB_TMPL vwt, siebel.s_view v, siebel.S_APPLET_TOGGLE t, siebel.s_applet a, siebel.s_repository r&lt;br /&gt;
where t.APPLET_NAME like :applet||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and vwti.APPLET_NAME = a.name and vwti.VIEW_WEB_TMPL_ID = vwt.row_id and vwt.VIEW_ID = v.row_id and v.name = sv.VIEW_NAME and sv.SCREEN_ID = s.row_id and t.applet_id = a.row_id&lt;br /&gt;
and a.repository_id = r.row_id and v.repository_id = r.row_id and s.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39;&lt;br /&gt;
and t.inactive_flg = &#39;N&#39; and a.inactive_flg = &#39;N&#39; and vwti.inactive_flg = &#39;N&#39; and vwt.inactive_flg = &#39;N&#39; and sv.inactive_flg = &#39;N&#39; and v.inactive_flg = &#39;N&#39;&lt;br /&gt;
union all&lt;br /&gt;
select &#39;Run Time Event - Object&#39; attr_type, &#39;&#39; screen, &#39;&#39; viewname, rt.EVT_NAME obj_name, rt.OBJ_NAME attr_name, &#39;&#39; Applet_Mode from siebel.S_CT_EVENT rt&lt;br /&gt;
where rt.OBJ_NAME like decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;)||:applet||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and rt.OBJ_TYPE_CD = &#39;Applet&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Personalization - Applet Condition&#39; attr_type, &#39;&#39; screen, &#39;&#39; viewname, A.VIS_COND_EXPR obj_name, a.APPLET_NAME attr_name, &#39;&#39; Applet_Mode from siebel.S_CT_APPLET a&lt;br /&gt;
where a.APPLET_NAME like decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;)||:applet||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and (a.EFF_END_DT is null or a.EFF_END_DT &amp;gt;= sysdate) and (a.EFF_START_DT is null or a.EFF_START_DT &amp;lt;= sysdate)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;</description><link>http://thesiebelscholar.blogspot.com/2012/12/sql-applet-search.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-4092999088426154054</guid><pubDate>Wed, 12 Dec 2012 18:15:00 +0000</pubDate><atom:updated>2019-06-20T13:55:18.254-04:00</atom:updated><title>SQL Field Search</title><description>This is a Query to find references to a particular field.&amp;nbsp; Just replace the bind variables.&amp;nbsp; Use your imagination in modifying this query to find Profile attributes.&amp;nbsp; The objects searched for are those relevant to most Implementations and do not search more specialized features (such as tree applets for instance).&amp;nbsp; If those features are used, you will need to add another Union to the query.&amp;nbsp; Also, because of the limitations in searching Oracle LONG data types, this query does not search Script.&amp;nbsp; I keep a minimized repository search window open in my Tools session with all the script objects selected so that I can quickly drag the window up and paste in what I am searching for.&lt;br /&gt;
&lt;br /&gt;
var :attr_val = &quot;CMI Failure Id&quot;;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -- Field Name or string to search for&lt;br /&gt;
&lt;br /&gt;
var :buscomp = &quot;CMI Quote Simple&quot;;&amp;nbsp;&amp;nbsp;&amp;nbsp; -- Business Component of the relevant object if applicable&lt;br /&gt;
var :wc = &quot;Y&quot;;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -- Trailing Wildcard.&amp;nbsp; N indicates an exact match&lt;br /&gt;
&lt;br /&gt;
select attr_type, obj_name, attr_name, attr_val from (&lt;br /&gt;
select &#39;Applet List Column&#39; attr_type, a.name obj_name, lc.name attr_name, lc.field_name attr_val from siebel.s_list_column lc, siebel.s_list l, siebel.s_applet a, siebel.s_repository r&lt;br /&gt;
where lc.field_name like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and lc.list_id = l.row_id and l.applet_id = a.row_id and a.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and lc.inactive_flg = &#39;N&#39; and a.inactive_flg = &#39;N&#39; and a.BUSCOMP_NAME = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Applet Control&#39; attr_type, a.name obj_name, c.name attr_name, c.field_name attr_val from siebel.s_control c, siebel.s_applet a, siebel.s_repository r&lt;br /&gt;
where c.field_name like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and c.applet_id = a.row_id and a.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and c.inactive_flg = &#39;N&#39; and a.inactive_flg = &#39;N&#39; and a.BUSCOMP_NAME = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Applet User Prop&#39; attr_type, a.name obj_name, up.name attr_name, up.Value attr_val from siebel.S_APPLET_UPROP up, siebel.s_applet a, siebel.s_repository r&lt;br /&gt;
where up.Value like &#39;%&#39;||:attr_val||&#39;%&#39; and up.applet_id = a.row_id and a.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and up.inactive_flg = &#39;N&#39; and a.inactive_flg = &#39;N&#39; and a.BUSCOMP_NAME = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Applet Toggle&#39; attr_type, a.name obj_name, t.name attr_name, t.AUTO_TOG_FLD_NAME attr_val from siebel.S_APPLET_TOGGLE t, siebel.s_applet a, siebel.s_repository r&lt;br /&gt;
where t.AUTO_TOG_FLD_NAME like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and t.applet_id = a.row_id and a.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and a.inactive_flg = &#39;N&#39; and t.inactive_flg = &#39;N&#39; and a.BUSCOMP_NAME = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Applet Drilldown - Source&#39; attr_type, a.name obj_name, d.name attr_name, d.SRC_FIELD_NAME attr_val from siebel.S_DDOWN_OBJECT d, siebel.s_applet a, siebel.s_repository r&lt;br /&gt;
where d.SRC_FIELD_NAME like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and d.applet_id = a.row_id and a.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and d.inactive_flg = &#39;N&#39; and a.inactive_flg = &#39;N&#39; and a.BUSCOMP_NAME = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Applet Dynamic Drilldown&#39; attr_type, a.name obj_name, d.name attr_name, dd.FIELD_NAME attr_val from siebel.S_DDOWN_DYNDEST dd, siebel.S_DDOWN_OBJECT d, siebel.s_applet a, siebel.s_repository r&lt;br /&gt;
where dd.FIELD_NAME like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and dd.DDOWN_OBJECT_ID = d.row_id &lt;br /&gt;
and d.applet_id = a.row_id and a.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39;&lt;br /&gt;
and dd.inactive_flg = &#39;N&#39; and d.inactive_flg = &#39;N&#39; and a.inactive_flg = &#39;N&#39; and a.BUSCOMP_NAME = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Join Spec&#39; attr_type, bc.name obj_name, j.name attr_name, js.SRC_FLD_NAME attr_val from siebel.S_JOIN_SPEC js, siebel.S_JOIN j, siebel.s_buscomp bc, siebel.s_repository r&lt;br /&gt;
where js.SRC_FLD_NAME like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and js.JOIN_ID = j.row_id and j.BUSCOMP_ID = bc.row_id and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and j.inactive_flg = &#39;N&#39; and bc.name = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Predefault - Same&#39; attr_type, bc.name obj_name, f.name attr_name, f.PREDEFVAL attr_val from siebel.s_field f, siebel.s_buscomp bc, siebel.s_repository r&lt;br /&gt;
where f.PREDEFVAL like &#39;%&#39;||:attr_val||&#39;%&#39; and f.BUSCOMP_ID = bc.row_id and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and f.inactive_flg = &#39;N&#39; and bc.name = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Predefault - Other&#39; attr_type, bc.name obj_name, f.name attr_name, f.PREDEFVAL attr_val from siebel.s_field f, siebel.s_buscomp bc, siebel.s_repository r&lt;br /&gt;
where f.PREDEFVAL like &#39;%&#39;||:buscomp||&#39;.&#39;||:attr_val||&#39;%&#39; and f.BUSCOMP_ID = bc.row_id and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and f.inactive_flg = &#39;N&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Calculated Field - Same&#39; attr_type, bc.name obj_name, f.name attr_name, f.CALCVAL attr_val from siebel.s_field f, siebel.s_buscomp bc, siebel.s_repository r&lt;br /&gt;
where f.CALCVAL like &#39;%&#39;||:attr_val||&#39;%&#39; and f.BUSCOMP_ID = bc.row_id and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and f.inactive_flg = &#39;N&#39; and bc.name = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Calculated Field - Other&#39; attr_type, bc.name obj_name, f.name attr_name, f.CALCVAL attr_val from siebel.s_field f, siebel.s_buscomp bc, siebel.s_repository r&lt;br /&gt;
where f.CALCVAL like &#39;%ParentFieldValue%&#39;||:attr_val||&#39;%&#39; and f.BUSCOMP_ID = bc.row_id and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and f.inactive_flg = &#39;N&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;BC User Prop&#39; attr_type, bc.name obj_name, up.name attr_name, up.VALUE attr_val from siebel.S_BUSCOMP_UPROP up, siebel.s_buscomp bc, siebel.s_repository r&lt;br /&gt;
where up.VALUE like &#39;%&#39;||:attr_val||&#39;%&#39; and up.BUSCOMP_ID = bc.row_id and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and up.inactive_flg = &#39;N&#39; and bc.name = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;BC User Prop&#39; attr_type, bc.name obj_name, up.name attr_name, up.VALUE attr_val from siebel.S_BUSCOMP_UPROP up, siebel.s_buscomp bc, siebel.s_repository r&lt;br /&gt;
where up.NAME like &#39;%&#39;||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and up.BUSCOMP_ID = bc.row_id and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and up.inactive_flg = &#39;N&#39; and bc.name = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;BC User Prop - Child&#39; attr_type, bc.name obj_name, up.name attr_name, up.VALUE attr_val from siebel.S_BUSCOMP_UPROP up, siebel.s_buscomp bc, siebel.s_repository r&lt;br /&gt;
where up.NAME like &#39;Parent%&#39; and up.VALUE like &#39;%&#39;||:buscomp||&#39;%&#39;||:attr_val||&#39;%&#39; and up.BUSCOMP_ID = bc.row_id and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and up.inactive_flg = &#39;N&#39; and bc.name &amp;lt;&amp;gt; :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;BC User Prop - Child&#39; attr_type, bc.name obj_name, up.name attr_name, up.VALUE attr_val from siebel.S_BUSCOMP_UPROP up, siebel.s_buscomp bc, siebel.s_repository r&lt;br /&gt;
where up.NAME like &#39;Parent%&#39;||:buscomp and up.VALUE like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and up.BUSCOMP_ID = bc.row_id and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and up.inactive_flg = &#39;N&#39; and bc.name &amp;lt;&amp;gt; :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Pick Map - Same&#39; attr_type, bc.name obj_name, f.name attr_name, pm.NAME attr_val from siebel.s_pickmap pm, siebel.s_field f, siebel.s_buscomp bc, siebel.s_repository r&lt;br /&gt;
where pm.FIELD_NAME like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and pm.FIELD_ID = f.row_id and f.BUSCOMP_ID = bc.row_id and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and f.inactive_flg = &#39;N&#39; and pm.inactive_flg = &#39;N&#39; and bc.name = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Pick Map - Other&#39; attr_type, bc.name obj_name, f.name attr_name, pm.NAME attr_val from siebel.s_pickmap pm, siebel.s_field f, siebel.s_buscomp bc, siebel.s_repository r, siebel.S_PICKLIST pl&lt;br /&gt;
where pm.PICK_FIELD_NAME like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and pm.FIELD_ID = f.row_id and f.BUSCOMP_ID = bc.row_id and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and r.row_id = pl.repository_id&lt;br /&gt;
and f.inactive_flg = &#39;N&#39; and pm.inactive_flg = &#39;N&#39; and f.PICKLIST_NAME = pl.name and pl.BUSCOMP_NAME = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;MVL Primary Id Field&#39; attr_type, bc.name obj_name, mvl.name attr_name, mvl.PRIMEID_FLD_NAME attr_val from siebel.S_MVLINK mvl, siebel.s_buscomp bc, siebel.s_repository r&lt;br /&gt;
where mvl.PRIMEID_FLD_NAME like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and mvl.BUSCOMP_ID = bc.row_id and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and mvl.inactive_flg = &#39;N&#39; and bc.name = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;MVL Source Id Field&#39; attr_type, bc.name obj_name, mvl.name attr_name, mvl.SRC_FLD_NAME attr_val from siebel.S_MVLINK mvl, siebel.s_buscomp bc, siebel.s_repository r&lt;br /&gt;
where mvl.SRC_FLD_NAME like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and mvl.BUSCOMP_ID = bc.row_id and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and mvl.inactive_flg = &#39;N&#39; and bc.name = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;MVF Destination Field&#39; attr_type, bc.name obj_name, f.name attr_name, mvl.DEST_BC_NAME||&#39;.&#39;||f.DEST_FLD_NAME attr_val from siebel.s_field f, siebel.s_buscomp bc, siebel.s_repository r, siebel.S_MVLINK mvl&lt;br /&gt;
where f.DEST_FLD_NAME like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and f.BUSCOMP_ID = bc.row_id and mvl.NAME = f.MVLINK_NAME and mvl.BUSCOMP_ID = bc.row_id and mvl.DEST_BC_NAME = :buscomp&lt;br /&gt;
and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and f.inactive_flg = &#39;N&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Link - Destination&#39; attr_type, l.name obj_name, &#39;&#39; attr_name, l.DST_FLD_NAME attr_val from siebel.s_link l, siebel.s_repository r&lt;br /&gt;
where l.DST_FLD_NAME like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and l.CHILD_BC_NAME = :buscomp and l.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and l.inactive_flg = &#39;N&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Link - Search Spec&#39; attr_type, l.name obj_name, &#39;&#39; attr_name, l.SRCHSPEC attr_val from siebel.s_link l, siebel.s_repository r&lt;br /&gt;
where l.SRCHSPEC like &#39;%&#39;||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;]%&#39;) and l.CHILD_BC_NAME = :buscomp and l.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and l.inactive_flg = &#39;N&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Applet - Search Spec&#39; attr_type, a.name obj_name, &#39;&#39; attr_name, a.SRCHSPEC attr_val from siebel.s_applet a, siebel.s_repository r&lt;br /&gt;
where a.SRCHSPEC like &#39;%&#39;||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;]%&#39;) and a.BUSCOMP_NAME = :buscomp and a.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and a.inactive_flg = &#39;N&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Picklist - Search Spec&#39; attr_type, p.name obj_name, &#39;&#39; attr_name, p.SRCHSPEC attr_val from siebel.S_PICKLIST p, siebel.s_repository r&lt;br /&gt;
where p.SRCHSPEC like &#39;%&#39;||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;]%&#39;) and p.BUSCOMP_NAME = :buscomp and p.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and p.inactive_flg = &#39;N&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Bus Comp - Search Spec&#39; attr_type, bc.name obj_name, &#39;&#39; attr_name, bc.SRCHSPEC attr_val from siebel.s_buscomp bc, siebel.s_repository r&lt;br /&gt;
where bc.SRCHSPEC like &#39;%&#39;||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;]%&#39;) and bc.NAME = :buscomp and bc.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and bc.inactive_flg = &#39;N&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Action Set - Conditional Expression&#39; attr_type, cas.name obj_name, ca.name attr_name, ca.COND_EXPR attr_val from siebel.S_CT_EVENT rt, siebel.s_ct_action ca, siebel.s_ct_action_set cas&lt;br /&gt;
where rt.CT_ACTN_SET_ID = cas.row_id and ca.CT_ACTN_SET_ID = cas.row_id and ca.COND_EXPR like &#39;%&#39;||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;]%&#39;) and rt.OBJ_NAME = :buscomp and rt.OBJ_TYPE_CD = &#39;BusComp&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Action Set - Attribute Set&#39; attr_type, cas.name obj_name, ca.name attr_name, ca.SET_RHS_EXPR attr_val from siebel.S_CT_EVENT rt, siebel.s_ct_action ca, siebel.s_ct_action_set cas&lt;br /&gt;
where rt.CT_ACTN_SET_ID = cas.row_id and ca.CT_ACTN_SET_ID = cas.row_id and ca.SET_RHS_EXPR like decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;%[&#39;)||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;]%&#39;) and rt.OBJ_NAME = :buscomp and rt.OBJ_TYPE_CD = &#39;BusComp&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Run Time Event - Conditional Expression&#39; attr_type, rt.OBJ_NAME obj_name, rt.EVT_NAME attr_name, rt.ACTN_COND_EXPR attr_val from siebel.S_CT_EVENT rt&lt;br /&gt;
where rt.ACTN_COND_EXPR like decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;%[&#39;)||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;]%&#39;) and rt.OBJ_NAME = :buscomp and rt.OBJ_TYPE_CD = &#39;BusComp&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Run Time Event - Sub Event&#39; attr_type, rt.OBJ_NAME obj_name, rt.EVT_NAME attr_name, rt.EVT_SUB_NAME attr_val from siebel.S_CT_EVENT rt&lt;br /&gt;
where rt.EVT_SUB_NAME like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and rt.OBJ_NAME = :buscomp and rt.OBJ_TYPE_CD = &#39;BusComp&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Integration Component Field&#39; attr_type, io.name obj_name, ic.name attr_name, icf.NAME attr_val from siebel.S_INT_FIELD icf, siebel.S_INT_COMP ic, siebel.S_INT_OBJ io, siebel.s_repository r&lt;br /&gt;
where icf.EXT_NAME like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and icf.INT_COMP_ID = ic.row_id and ic.INT_OBJ_ID = io.row_id and io.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39;&lt;br /&gt;
and io.inactive_flg = &#39;N&#39; and ic.inactive_flg = &#39;N&#39; and icf.inactive_flg = &#39;N&#39; and ic.EXT_NAME = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;IO Maps - Source Fields&#39; attr_type, o.name obj_name, C.name attr_name, F.SRC_EXPR attr_val from siebel.S_INT_FLDMAP F, siebel.S_INT_COMPMAP C, siebel.S_INT_OBJMAP O, siebel.S_INT_OBJ IO,&lt;br /&gt;
siebel.S_INT_COMP IC, siebel.S_INT_FIELD ICF, siebel.s_repository r&lt;br /&gt;
where C.int_obj_map_id = O.row_id and F.int_comp_map_id = C.row_id and F.SRC_EXPR like &#39;%&#39;||ICF.NAME||&#39;%&#39; and IC.EXT_NAME like decode(:bcwc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;)||:buscomp||decode(:bcwc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and O.src_int_obj_name = IO.NAME and c.src_int_comp_name = IC.NAME&lt;br /&gt;
and ICF.ext_name = :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and IO.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and ICF.INT_COMP_ID = IC.row_id&lt;br /&gt;
and IC.INT_OBJ_ID = IO.row_id and io.inactive_flg = &#39;N&#39; and ic.inactive_flg = &#39;N&#39; and icf.inactive_flg = &#39;N&#39; and (O.COMMENTS is null or O.COMMENTS not like &#39;ARCHIVE%&#39;)&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;IO Maps - Destination Fields&#39; attr_type, o.name obj_name, C.name attr_name, F.dst_int_fld_name attr_val from siebel.S_INT_FLDMAP F, siebel.S_INT_COMPMAP C, siebel.S_INT_OBJMAP O, siebel.S_INT_OBJ IO,&lt;br /&gt;
siebel.S_INT_COMP IC, siebel.S_INT_FIELD ICF, siebel.s_repository r&lt;br /&gt;
where C.int_obj_map_id = O.row_id and F.int_comp_map_id = C.row_id and F.dst_int_fld_name = ICF.NAME and IC.EXT_NAME like decode(:bcwc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;)||:buscomp||decode(:bcwc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and O.dst_int_obj_name = IO.NAME and c.dst_int_comp_name = IC.NAME&lt;br /&gt;
and ICF.ext_name = :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and IO.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39; and ICF.INT_COMP_ID = IC.row_id&lt;br /&gt;
and IC.INT_OBJ_ID = IO.row_id and io.inactive_flg = &#39;N&#39; and ic.inactive_flg = &#39;N&#39; and icf.inactive_flg = &#39;N&#39; and (O.COMMENTS is null or O.COMMENTS not like &#39;ARCHIVE%&#39;)&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Data Maps - Source Fields&#39; attr_type, o.name obj_name, C.name attr_name, f.src_fld_name attr_val from siebel.S_FIELD_DMAP F, siebel.S_BUSCOMP_DMAP C, siebel.S_BUSOBJ_DMAP O&lt;br /&gt;
where C.BUSOBJ_DMAP_ID = O.row_id and F.BUSCOMP_DMAP_ID = C.row_id and F.SRC_FLD_NAME like &#39;%&#39;||:attr_val||&#39;%&#39; and c.SRC_BUSCOMP_NAME = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Data Maps - Destination Fields&#39; attr_type, o.name obj_name, C.name attr_name, f.DST_FLD_NAME attr_val from siebel.S_FIELD_DMAP F, siebel.S_BUSCOMP_DMAP C, siebel.S_BUSOBJ_DMAP O&lt;br /&gt;
where C.BUSOBJ_DMAP_ID = O.row_id and F.BUSCOMP_DMAP_ID = C.row_id and F.DST_FLD_NAME like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and c.DST_BUSCOMP_NAME = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;WF Branch Criteria - Field&#39; attr_type, wf.name obj_name, s.name attr_name, b.name attr_val from siebel.S_WFR_COND_CRIT cc, siebel.S_WFR_STP_BRNCH b, siebel.S_WFR_STP s, siebel.S_WFR_PROC wf, siebel.s_repository r&lt;br /&gt;
where cc.BUSCOMP_FLD_NAME like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and cc.BRANCH_ID = b.row_id and b.STEP_ID = s.row_id and s.PROCESS_ID = wf.row_id and wf.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39;&lt;br /&gt;
and wf.STATUS_CD = &#39;COMPLETED&#39; and cc.BUSCOMP_NAME = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;WF Branch Criteria - Expression&#39; attr_type, wf.name obj_name, s.name attr_name, b.name attr_val from siebel.S_WFR_COND_VAL cv, siebel.S_WFR_COND_CRIT cc, siebel.S_WFR_STP_BRNCH b, siebel.S_WFR_STP s, siebel.S_WFR_PROC wf, siebel.s_repository r&lt;br /&gt;
where cv.LO_CHAR5 like decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;%[&#39;)||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;]%&#39;) and cv.COND_CRIT_ID = cc.row_id and cc.BRANCH_ID = b.row_id and b.STEP_ID = s.row_id and s.PROCESS_ID = wf.row_id and wf.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39;&lt;br /&gt;
and wf.STATUS_CD = &#39;COMPLETED&#39; and cc.BUSCOMP_NAME = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;WF Branch Step - Argument&#39; attr_type, wf.name obj_name, s.name attr_name, a.name attr_val from siebel.S_WFR_STP_ARG a, siebel.S_WFR_STP s, siebel.S_WFR_PROC wf, siebel.s_repository r&lt;br /&gt;
where a.BUSCOMP_FLD_NAME like :attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and a.STEP_ID = s.row_id and s.PROCESS_ID = wf.row_id and wf.repository_id = r.row_id and r.name = &#39;Siebel Repository&#39;&lt;br /&gt;
and wf.STATUS_CD = &#39;COMPLETED&#39; and a.BUSCOMP_NAME = :buscomp&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;DVM - Rule&#39; attr_type, rs.name obj_name, r.name attr_name, r.RULE_EXPR attr_val from siebel.S_VALDN_RULE R, siebel.S_VALDN_RL_SET RS&lt;br /&gt;
where R.RULE_SET_ID = rs.row_id and r.RULE_EXPR like decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;%[&#39;)||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;]%&#39;) and r.BUSCOMP_NAME = :buscomp and rs.status_cd = &#39;Active&#39;&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Personalization - Applet Condition&#39; attr_type, a.APPLET_NAME obj_name, a.APPLET_NAME attr_name, A.VIS_COND_EXPR attr_val from siebel.S_CT_APPLET a, siebel.S_APPLET ra, siebel.s_repository r&lt;br /&gt;
where a.APPLET_NAME = ra.name and a.VIS_COND_EXPR like decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;%[&#39;)||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;]%&#39;) and r.name = &#39;Siebel Repository&#39; and ra.repository_id = r.row_id and ra.inactive_flg = &#39;N&#39;&lt;br /&gt;
and ra.buscomp_name like decode(:bcwc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;)||:buscomp||decode(:bcwc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and ra.INACTIVE_FLG = &#39;N&#39; and (a.EFF_END_DT is null or a.EFF_END_DT &amp;gt;= sysdate) and (a.EFF_START_DT is null or a.EFF_START_DT &amp;lt;= sysdate)&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Personalization - Applet Rule Set&#39; attr_type, a.APPLET_NAME obj_name, to_char(ar.SEQ_NUM) attr_name, ar.COND_EXPR attr_val from siebel.S_CT_APPLET a, siebel.S_CT_APLT_RLST ar, siebel.S_APPLET ra, siebel.s_repository r&lt;br /&gt;
where a.APPLET_NAME = ra.name and ar.ct_applet_id = a.row_id and ar.COND_EXPR like decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;%[&#39;)||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;]%&#39;) and r.name = &#39;Siebel Repository&#39; and ra.inactive_flg = &#39;N&#39; and ra.repository_id = r.row_id&lt;br /&gt;
and ra.buscomp_name like decode(:bcwc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;)||:buscomp||decode(:bcwc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;) and ra.INACTIVE_FLG = &#39;N&#39; and (a.EFF_END_DT is null or a.EFF_END_DT &amp;gt;= sysdate) and (a.EFF_START_DT is null or a.EFF_START_DT &amp;lt;= sysdate)&lt;br /&gt;
and (ar.EFF_END_DT is null or ar.EFF_END_DT &amp;gt;= sysdate) and (ar.EFF_START_DT is null or ar.EFF_START_DT &amp;lt;= sysdate)&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Personalization - Rule Condition&#39; attr_type, rs.name obj_name, r.Name attr_name, r.COND_EXPR attr_val from siebel.S_CT_RULE R, siebel.S_CT_RULE_SET RS, siebel.S_CT_APPLET a, siebel.S_CT_APLT_RLST ar, siebel.S_APPLET ra, siebel.s_repository rep&lt;br /&gt;
where a.APPLET_NAME = ra.name and ar.ct_applet_id = a.row_id and rep.name = &#39;Siebel Repository&#39; and ra.repository_id = rep.row_id and ra.inactive_flg = &#39;N&#39; and rs.row_id = ar.ct_rule_set_id&lt;br /&gt;
and R.CT_RULE_SET_ID = rs.row_id and r.COND_EXPR like decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;%[&#39;)||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;]%&#39;)&lt;br /&gt;
and ra.BUSCOMP_NAME = :buscomp and rs.ACTIVE_FLG = &#39;Y&#39; and r.ACTIVE_FLG = &#39;Y&#39; and ra.INACTIVE_FLG = &#39;N&#39; and (a.EFF_END_DT is null or a.EFF_END_DT &amp;gt;= sysdate) and (a.EFF_START_DT is null or a.EFF_START_DT &amp;lt;= sysdate)&lt;br /&gt;
and (ar.EFF_END_DT is null or ar.EFF_END_DT &amp;gt;= sysdate) and (ar.EFF_START_DT is null or ar.EFF_START_DT &amp;lt;= sysdate)&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Personalization - Rule Include Condition&#39; attr_type, rs.name obj_name, r.Name attr_name, r.INCL_RULE_EXPR attr_val from siebel.S_CT_RULE R, siebel.S_CT_RULE_SET RS, siebel.S_CT_APPLET a, siebel.S_CT_APLT_RLST ar, siebel.S_APPLET ra, siebel.s_repository rep&lt;br /&gt;
where a.APPLET_NAME = ra.name and ar.ct_applet_id = a.row_id and rep.name = &#39;Siebel Repository&#39; and ra.repository_id = rep.row_id and ra.inactive_flg = &#39;N&#39; and rs.row_id = ar.ct_rule_set_id&lt;br /&gt;
and R.CT_RULE_SET_ID = rs.row_id and r.INCL_RULE_EXPR like decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;%[&#39;)||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;]%&#39;)&lt;br /&gt;
and ra.BUSCOMP_NAME = :buscomp and rs.ACTIVE_FLG = &#39;Y&#39; and r.ACTIVE_FLG = &#39;Y&#39; and ra.INACTIVE_FLG = &#39;N&#39; and (a.EFF_END_DT is null or a.EFF_END_DT &amp;gt;= sysdate) and (a.EFF_START_DT is null or a.EFF_START_DT &amp;lt;= sysdate)&lt;br /&gt;
and (ar.EFF_END_DT is null or ar.EFF_END_DT &amp;gt;= sysdate) and (ar.EFF_START_DT is null or ar.EFF_START_DT &amp;lt;= sysdate)&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Personalization - Rule Exclude Condition&#39; attr_type, rs.name obj_name, r.Name attr_name, r.EXCL_RULE_EXPR attr_val from siebel.S_CT_RULE R, siebel.S_CT_RULE_SET RS, siebel.S_CT_APPLET a, siebel.S_CT_APLT_RLST ar, siebel.S_APPLET ra, siebel.s_repository rep&lt;br /&gt;
where a.APPLET_NAME = ra.name and ar.ct_applet_id = a.row_id and rep.name = &#39;Siebel Repository&#39; and ra.repository_id = rep.row_id and ra.inactive_flg = &#39;N&#39; and rs.row_id = ar.ct_rule_set_id&lt;br /&gt;
and R.CT_RULE_SET_ID = rs.row_id and r.EXCL_RULE_EXPR like decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;%[&#39;)||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;]%&#39;)&lt;br /&gt;
and ra.BUSCOMP_NAME = :buscomp and rs.ACTIVE_FLG = &#39;Y&#39; and r.ACTIVE_FLG = &#39;Y&#39; and ra.INACTIVE_FLG = &#39;N&#39; and (a.EFF_END_DT is null or a.EFF_END_DT &amp;gt;= sysdate) and (a.EFF_START_DT is null or a.EFF_START_DT &amp;lt;= sysdate)&lt;br /&gt;
and (ar.EFF_END_DT is null or ar.EFF_END_DT &amp;gt;= sysdate) and (ar.EFF_START_DT is null or ar.EFF_START_DT &amp;lt;= sysdate)&lt;br /&gt;
&lt;br /&gt;
union all&lt;br /&gt;
&lt;br /&gt;
select &#39;Batch Job - Search&#39; attr_type, a.DISPLAY_NAME obj_name, wf.NAME attr_name, ps.VALUE attr_val&lt;br /&gt;
from siebel.S_SRM_REQUEST q, siebel.S_SRM_ACTION a, siebel.S_SRM_REQ_PARAM ps, siebel.S_SRM_ACT_PARAM psp, siebel.S_SRM_REQ_PARAM pw, siebel.S_SRM_ACT_PARAM pwp, siebel.S_WFR_PROC wf, siebel.s_repository r, siebel.S_BUSOBJ bo&lt;br /&gt;
where ps.REQ_ID = q.row_id and ps.VALUE like decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;%[&#39;)||:attr_val||decode(:wc,&#39;Y&#39;,&#39;%&#39;,&#39;]%&#39;) and q.STATUS = &#39;ACTIVE&#39; AND q.REQ_TYPE_CD = &#39;RPT_PARENT&#39; and ps.ACTPARAM_ID = psp.ROW_ID&lt;br /&gt;
and psp.NAME = &#39;Search Specification&#39; and pw.REQ_ID = q.row_id and pw.ACTPARAM_ID = pwp.ROW_ID and pwp.NAME = &#39;Workflow Process Name&#39; and a.row_id = q.action_id and pw.value = wf.PROC_NAME and wf.REPOSITORY_ID = r.row_id&lt;br /&gt;
and r.name = &#39;Siebel Repository&#39; and bo.repository_id = r.row_id and wf.STATUS_CD = &#39;COMPLETED&#39; and wf.BUSOBJ_NAME = bo.name and bo.PR_BUSCOMP_NAME like decode(:bcwc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;)||:buscomp||decode(:bcwc,&#39;Y&#39;,&#39;%&#39;,&#39;&#39;)&lt;br /&gt;
);</description><link>http://thesiebelscholar.blogspot.com/2012/12/sql-field-search.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-1662017548312332560</guid><pubDate>Tue, 03 Jan 2012 15:55:00 +0000</pubDate><atom:updated>2012-01-09T14:08:09.921-05:00</atom:updated><title>My BI Quick Reference</title><description>I know there are a bunch of cheat sheets out there, but I frequently don&#39;t find everything I am looking for in one place so figured I would just start building my own.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Siebel Functions&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Include statement&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&amp;lt;?namespace:psfn=http://www.oracle.com/XSL/Transform/java/com.siebel.xmlpublisher.reports.XSLFunctions?&amp;gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;i&gt;Date Conversion&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&amp;lt;?psfn:totext(OrderDate,&quot;MM/dd/yyyy&quot;,&quot;MM/dd/yyyy hh:mm:ss&quot;)?&amp;gt; &lt;/blockquote&gt;
&lt;br /&gt;
&lt;b&gt;Loops:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Basic Loop where QuoteItem is the Integration Component/XML Group&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&amp;lt;?for-each:QuoteItem?&amp;gt;&lt;/blockquote&gt;
Add a where clause to constrain rows in the loop.&amp;nbsp; Multiple constraints can be added back to back with each bracketed section representing an AND.&amp;nbsp; An OR would need to be done inside a single bracketed expression.&amp;nbsp; the .// is an xpath expression to determine the XML group of the field&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&amp;lt;?for-each:QuoteItem[.//LineType=&#39;Sales&#39;]?&amp;gt; &lt;br /&gt;
&amp;lt;?for-each:QuoteItem[.//LineType=&#39;Sales&#39;][.//LineNumber&amp;lt;100]?&amp;gt; &lt;br /&gt;
&amp;lt;?for-each:QuoteItem[.//LineType=&#39;Sales&#39; or .//LineType=&#39;Service&#39;]?&amp;gt; &lt;/blockquote&gt;
&lt;i&gt;Groupings&amp;nbsp;&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
Loop that groups by the column LineType and sorts by the grouping&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&amp;lt;?for-each-group:QuoteItem;./LineType?&amp;gt;&amp;lt;?sort:current-group()/LineType;&#39;ascending&#39;;data-type=&#39;text&#39;?&amp;gt;&lt;/blockquote&gt;
A nested loop showing the sub group records for the loop above:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&amp;lt;?for-each:current-group()?&amp;gt;&amp;lt;?sort:Product;&#39;ascending&#39;;data-type=&#39;text&#39;?&amp;gt;&lt;/blockquote&gt;
&lt;br /&gt;
Loop that groups records together by a particular column and makes each grouping a column in a table&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&amp;lt;?for-each-group@column:QuoteItem;./LineType?&amp;gt;&lt;/blockquote&gt;
Similar to grouping by column is to group by section.&amp;nbsp; In this case each grouping creates a heading when the report breaks across multiple pages.&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&amp;lt;?for-each@section:G_CUSTOMER?&amp;gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;i&gt;Group Expressions&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
This expression is used to sum a column from series of records outside the context of a loop.&amp;nbsp; The expression in the bracket specifies those records to include, in this case only non null values.&amp;nbsp; This is an XPath expression.&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&amp;lt;?sum(.//ItemExtendedPriceTotal[.!=&#39;&#39;])?&amp;gt;&lt;/blockquote&gt;
&lt;b&gt;Conditionals:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;If/else&lt;/i&gt;&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&amp;lt;?if:Comment!=&#39;&#39;?&amp;gt;&lt;br /&gt;
&amp;lt;?Comment?&amp;gt;&lt;br /&gt;
&amp;lt;?end if?&amp;gt;&lt;/blockquote&gt;
&lt;br /&gt;
Keep in mind that Carriage returns outside the expression will still appear so consider this when judging where to put the donditional &lt;br /&gt;
&lt;br /&gt;
&lt;i&gt;Switch/Case/Select/Choose:&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&amp;lt;?choose:?&amp;gt;
&amp;lt;?when:MY_FIELD=&#39;value tested&#39;?&amp;gt; &amp;lt;?call:template?&amp;gt; &amp;lt;?end when?&amp;gt;
&amp;lt;?when:MY_FIELD_2=&#39;value tested 2&#39;?&amp;gt; &amp;lt;?call:template_2?&amp;gt; &amp;lt;?end when?&amp;gt;
&amp;lt;?otherwise:?&amp;gt; &amp;lt;?call:template_other?&amp;gt; &amp;lt;?end otherwise?&amp;gt;
&amp;lt;?end choose?&amp;gt;&amp;nbsp;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;b&gt;Embedding a 64 Bit Image&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
For this to work, there must be a 64 Bit attachment embedded in the Integration Object being sent to BI.  In this example,QuoteAttachment is the element name of the IC Field of type DTYPE_ATTACHMENT containing the 64 Bit inline image.&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&amp;lt;fo:instream-foreign-object content-type=&quot;image/jpg&quot;&amp;gt;&amp;lt;?QuoteAttachment?&amp;gt;&amp;lt;/fo:instream-foreign-object&amp;gt;
&lt;/blockquote&gt;
Additional attributes for the fo:instream-foreign-object tag in addition to content-type can resize the image:
Specify in pixels as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&amp;lt;fo:instream-foreign-object content type=&quot;image/jpg&quot; height=&quot;300 px&quot; width=&quot;4 px&quot;&amp;gt;
&lt;/blockquote&gt;
&lt;br /&gt;
...
or in centimeters:
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&amp;lt;fo:instream-foreign-object content type=&quot;image/jpg&quot; height=&quot;3 cm&quot; width=&quot;4 cm&quot;&amp;gt;
&lt;/blockquote&gt;
...
or as a percentage of the original dimensions:
&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&amp;lt;fo:instream-foreign-object content type=&quot;image/jpg&quot; height=&quot;300%&quot; width=&quot;300%&quot;&amp;gt;
...&lt;/blockquote&gt;</description><link>http://thesiebelscholar.blogspot.com/2012/01/my-bi-quick-reference.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-1001097647561409478</guid><pubDate>Tue, 13 Sep 2011 17:19:00 +0000</pubDate><atom:updated>2011-09-13T13:19:26.048-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">SQL</category><category domain="http://www.blogger.com/atom/ns#">Troubleshooting</category><title>Performance Tuning Methodology</title><description>I recently had an opportunity to do a bit of performance tuning on a newly deployed production App and thought I would share a methodology for tackling some of the low hanging fruit, sort of the 80/20 rule of siebel performance tuning.&amp;nbsp; My experience is that with Siebel 7.8 and higher, on Oracle 10 and higher, most performance issues are Siebel configuration issues.&amp;nbsp; Of those, most of the issues fall into one of two categories:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Missing Indexes&lt;/li&gt;
&lt;li&gt;Sort Specs&lt;/li&gt;
&lt;/ul&gt;
When customizing Siebel, you will frequently create new relationships between logical objects via a new foreign key.&amp;nbsp; There should always be a corresponding index for that foreign key on the M side of the 1:M or M:M&amp;nbsp; linked table.&amp;nbsp; Typically, it is just a single Id column but if for some reason, there are multiple columns (perhaps a join spec and a join constraint) make sure all of the columns from the child table are part of the index.&lt;br /&gt;
&lt;br /&gt;
Be aware that all the perfectly planned indexes in the world will frequently be ignored if there is a sort spec on a query.&amp;nbsp; The sort essentially takes precedence and any index that optimizes the sort will usually be used to the exclusion of other indexes that perhaps optimize what a user is doing on that view.&amp;nbsp; I frequently see performance problems on visibility views (All/All Across) without any query refinement at all.&amp;nbsp; When this occurs, it is usually because of the All Mode Sort user property settings.&amp;nbsp; If you are seeing performance problems on an All view, try changing the settings of that property for the BC to fix the issue.&lt;br /&gt;
&lt;br /&gt;
Here is a general methodology for identifying and fixing performance issues.&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;For the OM component having the issue, change the Server Configuration event logging level to 4 for these events:&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;SQL Parse and Execute&lt;/li&gt;
&lt;li&gt;Object Manager SQL Log&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Execute the operation that performs the slow query&lt;/li&gt;
&lt;li&gt;Open the corresponding OM log and find the SQL statement representing the slow query&lt;/li&gt;
&lt;li&gt;Finding the statement can be done in a couple of ways, but I use the following:&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Query for this string in the log &#39;***** SQL Statement Execute Time&#39;&lt;/li&gt;
&lt;li&gt;Look at the seconds for this line and the subsequent &#39;***** SQL Statement Initial Fetch Time&#39; to see a large value&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;Copy the preceeding SQL statement into a SQL editor such as Toad or Benthic or whatever your fancy, swapping out the bind variables&lt;/li&gt;
&lt;li&gt;Run an explain plan on the statement&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;Look for a line that says Table Access Full.&amp;nbsp; If you see such a line, look at the table being accessed this way and look back at the where clause to see how the SQL statement is joining to that table.&amp;nbsp; Then look in tools to see if there is an index for that table on the columns in the join to that table.&lt;/li&gt;
&lt;li&gt;If indexes are not an issue, but there is an Order By in the SQL statement, try commenting out the Order By and rerunning the explain plan to see how it changes.&amp;nbsp; If you see the explain plan change significantly (Cost goes down) than confirm that you really need the sort spec in the particular scenario you are in.&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
This is really just meant to be a way to find low hanging fruit performance issues.&amp;nbsp; It is important to configure with performance in mind (especially when using script or workflow algoritms).&amp;nbsp; Other sources of performance bottlenecks include (but are not limited to):&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Synchonous Interface round trips&lt;/li&gt;
&lt;li&gt;File System operations&lt;/li&gt;
&lt;li&gt;Network bandwidth&amp;nbsp; (especially if using a VPN)&lt;/li&gt;
&lt;li&gt;Memory or CPU bound servers&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;</description><link>http://thesiebelscholar.blogspot.com/2011/09/i-recently-had-opportunity-to-do-bit-of.html</link><author>noreply@blogger.com (Mik)</author><thr:total>6</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-133190848842658453</guid><pubDate>Mon, 12 Sep 2011 22:38:00 +0000</pubDate><atom:updated>2013-05-07T19:01:31.357-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">eScript</category><category domain="http://www.blogger.com/atom/ns#">eScript Framework</category><category domain="http://www.blogger.com/atom/ns#">How To</category><title>eScript Framework on 8.1</title><description>Converting the eScript framework to 8.1 proved a bit troublesome for me as the Siebel strong type engine has apparently dropped support for prototyping Siebel objects, such as a Business Service.&amp;nbsp; This makes the implementation a bit less clean since without being able to declare a prototype of the Log or Frame objects on application start, we are left with having to have every framework function be a child of the Application object.&amp;nbsp; This being the case, I consolidated the Frame and Log objects from the 7.8 framework into a single Utility object since there was not as much advantage in separating them.&amp;nbsp; Instead of the elegant 7.8 calls:&lt;br /&gt;
&lt;br /&gt;&lt;div style=&quot;overflow-x: scroll; overflow-y: hidden; width: 1000px; word-wrap: normal;&quot;&gt;
&lt;pre&gt;
Log.Stack(&quot;MyMethod&quot;,1);
Log.Step(&quot;Log the time as &quot;+Frame.Timestamp(&quot;DateTimeMilli&quot;),3);
Log.Vars(&quot;VariableName&quot;, varValue,3)
Log.Unstack(&quot;&quot;,1);&lt;/pre&gt;&lt;/div&gt;
&lt;br /&gt;
we instead do this:&lt;br /&gt;
&lt;br /&gt;&lt;div style=&quot;overflow-x: scroll; overflow-y: hidden; width: 1000px; word-wrap: normal;&quot;&gt;&lt;pre&gt;
TheApplication().logStack(&quot;Write&quot;,this)
TheApplication().Utility.logStep(&quot;Log the time as &quot;+
&amp;nbsp;&amp;nbsp;&amp;nbsp; TheApplication().Utility.Timestamp(&quot;DateTimeMilli&quot;));
TheApplication().Utility.logVars(&quot;VariableName&quot;, varValue)
TheApplication().Unstack(&quot;&quot;);&lt;/pre&gt;&lt;/div&gt;
&lt;br /&gt;
Oh well.&amp;nbsp; To mitigate this somewhat, I have added a number of enhancements since the initial series of posts, which I will try to discuss sometime soon.&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Automatically tie log level to the function doing the logging (Stack/Unstack vs variables for instance), hence no need for the numeric last parameter to all logging functions (though it is still optional as an override)&lt;/li&gt;
&lt;li&gt;Added support for unix file systems&lt;/li&gt;
&lt;li&gt;Standardize the identification of logging record Ids (by passing the &#39;this&#39; reference it will append the row id for methods with Write, Delete and Invoke in the name)&lt;/li&gt;
&lt;/ul&gt;
To implement the basic framework in 8.1, you need something like this in the Application Start event:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; this.Utility = TheApplication().GetService(&quot;ETAR Utilities&quot;);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; this.Utility.Init();&lt;br /&gt;
&lt;br /&gt;
Here is the Declarations section:&lt;br /&gt;
&lt;br /&gt;&lt;div style=&quot;overflow-x: scroll; overflow-y: hidden; width: 1000px; word-wrap: normal;&quot;&gt;&lt;pre&gt;
var gsOutPutFileName;
var gsFileName;
var gsLogMode;
var giIndent = 2; //Indent child prop sets this many spaces to the right for each level down.
var giPSDepth = 0; // How deep in the property set tree, what level
var gaFunctionStack = new Array(); //used in debugStack function to store called functions
var giStackIndex = 0; //Where in the function stack the current function resides
var gsIndent = &#39;&#39;; //used in debug methods to identify stack indents
var giLogBuffer = 0;
var giLogLines = 0;
var gsLogPath = &quot;&quot;;
var gsLogCache = &quot;&quot;;
var gsLogSession = &quot;&quot;;
var giErrorStack = 0;
var ge = new Object();
var gStack = new Object();
var gCurrentLogLvl;&lt;/pre&gt;&lt;/div&gt;
&lt;br /&gt;
The Utilities business service is a cached service in tools.&amp;nbsp; It&#39;s Init function looks like this:&lt;br /&gt;
&lt;br /&gt;&lt;div style=&quot;overflow-x: scroll; overflow-y: hidden; width: 1000px; word-wrap: normal;&quot;&gt;&lt;pre&gt;
giErrorStack = 0;
ExtendObjects();
gsLogMode = GetSysPref(&quot;Framework Log Mode&quot;);
gsLogMode = (gsLogMode == &quot;&quot; ? &quot;FILE&quot; : gsLogMode.toUpperCase());
gsLogSession = TimeStamp(&quot;DateTimeMilli&quot;);

if (TheApplication().GetProfileAttr(&quot;ETAR User Log Level&quot;) != &quot;&quot;)
&amp;nbsp;&amp;nbsp;&amp;nbsp; gCurrentLogLvl = TheApplication().GetProfileAttr(&quot;ETAR User Log Level&quot;);
else gCurrentLogLvl = GetSysPref(&quot;CurrentLogLevel&quot;);
giLogBuffer = GetSysPref(&quot;Log Buffer&quot;);
gsLogPath = GetSysPref(&quot;Framework Log Path&quot;);
try {
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; var os;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; os = Clib.getenv(&quot;OS&quot;);
} catch(e) { os = &quot;UNIX Based&quot;; }
try {
&amp;nbsp;&amp;nbsp; gsFileName = &quot;Trace-&quot;+TheApplication().LoginName()+&quot;-&quot;+gsLogSession+&quot;.txt&quot;
&amp;nbsp; //A Windows OS indicates a thick client. Assume the path is the dynamicly
&amp;nbsp; //determined Siebel_Home\Log directory, or ..\log
&amp;nbsp; if (os.substring(0, 7) == &quot;Windows&quot;) {
//&amp;nbsp; gsLogPath = gsLogPath.replace(/\\$/, &quot;&quot;);&amp;nbsp; //Remove trailing backslash if used
//&amp;nbsp; gsLogPath = gsLogPath.replace(/\x47/, &quot;\\&quot;);&amp;nbsp; //switch invalid OS directory seperators
&amp;nbsp;&amp;nbsp;&amp;nbsp; gsLogPath = &quot;..\\Log\\&quot;;
&amp;nbsp; &amp;nbsp; gsOutPutFileName = gsLogPath+gsFileName;
&amp;nbsp; } else {
&amp;nbsp;&amp;nbsp;&amp;nbsp; gsLogPath = gsLogPath.replace(/\x47$/, &quot;&quot;);&amp;nbsp; //Remove trailing backslash if used
&amp;nbsp;&amp;nbsp;&amp;nbsp; gsLogPath = gsLogPath.replace(/\\/, &quot;/&quot;);&amp;nbsp; //switch invalid OS directory seperators
&amp;nbsp;&amp;nbsp;&amp;nbsp; gsLogPath = gsLogPath+&quot;/&quot;;
&amp;nbsp;&amp;nbsp;&amp;nbsp; gsOutPutFileName = gsLogPath+gsFileName;
&amp;nbsp;}
} catch(e) {
&amp;nbsp; gsLogPath = &quot;&quot;;
&amp;nbsp; gsOutPutFileName = gsFileName;
}
&lt;/pre&gt;&lt;/div&gt;</description><link>http://thesiebelscholar.blogspot.com/2011/09/escript-framework-on-81.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-8757809838257368004</guid><pubDate>Tue, 29 Mar 2011 13:38:00 +0000</pubDate><atom:updated>2011-03-30T13:24:11.034-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Configuration</category><title>Tools Bleg</title><description>Don&#39;t get me wrong.  I love Siebel Tools.  Compared to other enterprise systems where development for the most part involves modifying script, Siebel has a very elegant development platform.  OK, all that being said, after developing in Tools for over eleven years (odd writing that), there are some things I would love to do better to make my development experience more efficient.  So to that end I thought I would put some thoughts out into the cloud to see if anyone has thought of a workaround for any of these items:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Column Preferences.  Is it just me or does the Tools client not save preferences the way the Siebel client does.  Rearranging columns usually works, but changing widths do not seem to save.&lt;/li&gt;&lt;li&gt;PDQs.  The idea of Bookmarks is nice but I hate the fact that drilling down or using them loses the context of my exporer pane when I go back.  PDQs on every object like within the Siebel Client (and the ability to set default PDQs for each view) would do wonders.&lt;/li&gt;&lt;li&gt;Drilldowns.  Speaking of drilldowns, is it really necessary for drilling down to collapse the rest of my explorer pane, hence refreshing all the queries on other objects?&lt;/li&gt;&lt;li&gt;Expose Tab Order on Applets.  I am tempted to try this one out myself one day because it seems doable.  Who knows.&lt;/li&gt;&lt;li&gt;Applet Wizard.  Not for creating a new one.  That is ok.  But to synchronize with a BC down the road when I want to add a new column.  A wizard would just be a much easier way to add a new column rather than adding a control or list column, then adding it to the web template.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Allow sync of Meta Data needed by Tools without Remote Sync.  This might be a bit more out there but I find it annoying that Users (Help about record) and LOVs cannot be synced with a &#39;Get&#39;.  I know you can get them with a remote sync, but more and more, a lot of client&#39;s do not use Remote or use it so infrequently that it is not emphasized and it is a pain to keep my remote client in sync with the server in a development environment anyway.  This might sound minor, but like I said, it annoys me.&lt;/li&gt;&lt;/ul&gt;I have mainly limited this list to just applying functionality that already exists in the Siebel Client or to exposing data which I am pretty sure is there to be exposed.  Not really trying to create a forum for adding &quot;New&quot; features.  I may add to this list in the future, but feel free to add your own wishes/solutions in comments.</description><link>http://thesiebelscholar.blogspot.com/2011/03/tools-bleg.html</link><author>noreply@blogger.com (Mik)</author><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-3283341125124872862</guid><pubDate>Thu, 20 Jan 2011 14:36:00 +0000</pubDate><atom:updated>2011-03-29T09:37:53.217-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">BI</category><category domain="http://www.blogger.com/atom/ns#">Configuration</category><category domain="http://www.blogger.com/atom/ns#">Workflow</category><title>Building a BI Developer&#39;s SuperView</title><description>Another limitation I find irritating when it comes to building BI templates is how basic the sample file generator is.  My main beef is that it just takes the first 10 records in the Integration Object and spits them out.  If you have a complicated IO with child ICs, it is possible, and even likely that those first ten records do not have the child detail records you need to test your report output.  There are some ways around this, like hard coding a search spec on the BC against a thick client partial compile to generate a file with data you want, but that seems so inelegant.  My other tick regarding this feature is that the report developer once again either needs to have a Siebel thick client or access to the Siebel Server file system to actually get the xml file produced.  It seems like the whole point of all the BI Administration views is to avoid having to go to the file system.  What to do...&lt;br /&gt;&lt;br /&gt;Caveat Emptor.  Configuration steps below are to give you an idea.  I am posting this after I finished to highlight what I recall as the important pieces so not every step is included.  You will need to create the new custom table CX_TMPL (or use another), create all links, applets, view objects, make BO/Screen changes and deploy them.&lt;br /&gt;&lt;br /&gt;First I build a view with the same IO BC based applet as the vanilla view on top, and child applets for both attachments and a new object which is essentially a search spec.  First the attachment bc.  This is a new BC which you can copy from an existing attachment BC and change the names around.  Here is mine, called &#39;Sample IO Attachment&#39; based on S_FILE_ATT.  Use the field name prefix &#39;Sample&#39; instead of which ever prefix is used on the BC you are copying (Be sure to set the User Property DefaultPrefix to &#39;Sample&#39; too):&lt;table border=&quot;1&quot;&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Join&lt;/th&gt;&lt;th&gt;Column&lt;/th&gt;&lt;th&gt;Force Active&lt;/th&gt;&lt;th&gt;Predefault Value&lt;/th&gt;&lt;th&gt;Text Length&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;IO Id&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;PAR_ROW_ID&lt;/td&gt;&lt;td&gt;&lt;br /&gt;Y&lt;/td&gt;&lt;td&gt;Parent: &#39;Repository Integration Object.Id&#39;&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;DTYPE_ID&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Parent Key&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;X_PARENT_KEY&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;Parent: &#39;Repository Integration Object.Name&#39;&lt;/td&gt;&lt;td&gt;100&lt;/td&gt;&lt;td&gt;DTYPE_TEXT&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;The Search Spec applet is based on a custom BC, &#39;Report IO Sample File Template&#39;, based on the new table, CX_TMPL (I use this table for other things too so I type spec each record):&lt;table border=&quot;1&quot;&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Join&lt;/th&gt;&lt;th&gt;Column&lt;/th&gt;&lt;th&gt;Force Active&lt;/th&gt;&lt;th&gt;Predefault Value&lt;/th&gt;&lt;th&gt;Text Length&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Name&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;NAME&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;Field: &quot;Id&quot;&lt;/td&gt;&lt;td&gt;100&lt;/td&gt;&lt;td&gt;DTYPE_TEXT&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Parent Id&lt;/td&gt;&lt;td&gt;S_INT_OBJ&lt;/td&gt;&lt;td&gt;ROW_ID&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;td&gt;Parent: &quot;Repository Integration Object.Id&quot;&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;DTYPE_ID&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Parent Name&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;PARENT_FLD&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;Parent: &quot;Repository Integration Object.Name&quot;&lt;/td&gt;&lt;td&gt;50&lt;/td&gt;&lt;td&gt;DTYPE_TEXT&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Search Specification&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;CONSTRAINT&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;250&lt;/td&gt;&lt;td&gt;DTYPE_TEXT&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Type&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;TYPE&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;SAMPLE_IO_CONSTRAINT&lt;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;td&gt;DTYPE_TEXT&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Number of Records&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;LN_NUM&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;10&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;DTYPE_INTEGER&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;The join, S_INT_OBJ, is based on the specification of Parent Name = NAME.  Using name instead of Id allows the search specs to remain visible after repository moves.&lt;br /&gt;&lt;br /&gt;You will also need the following Named Method User Property:&lt;br /&gt;&lt;br /&gt;&quot;GenerateConstrainedData&quot;, &quot;INVOKESVC&quot;, &quot;Report IO Sample File Template&quot;, &quot;Workflow Process Manager&quot;, &quot;RunProcess&quot;, &quot;&#39;ProcessName&#39;&quot;, &quot;&#39;Export Sample IO To File&#39;&quot;, &quot;SearchConstraint&quot;, &quot;[Search Specification]&quot;, &quot;&#39;IOName&#39;&quot;, &quot;[Parent Name]&quot;, &quot;Path&quot;, &quot;&#39;..\XMLP\Data&#39;&quot;, &quot;Object Id&quot;, &quot;[Parent Id]&quot;, &quot;PageSize&quot;, &quot;[Number of Records]&quot;&lt;br /&gt;&lt;br /&gt;This user property is to activate the button you will need to place on the applet based on this BC. On that applet (based on class CSSSWEFrameListBase), add a button which invokes the method &#39;GenerateConstrainedData&#39;.  No additional script should be needed there.&lt;br /&gt;&lt;br /&gt;Create a Service Flow Workflow Process called &#39;Export Sample IO To File&#39;&lt;br /&gt;&lt;a href=&quot;http://2.bp.blogspot.com/_qIQCkJx1sJQ/TTi-boAdHJI/AAAAAAAAClg/-lB-Ia2kzKQ/s1600/BI%2BAdv%2BSample%2B3.png&quot;&gt;&lt;img style=&quot;display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 57px;&quot; src=&quot;http://2.bp.blogspot.com/_qIQCkJx1sJQ/TTi-boAdHJI/AAAAAAAAClg/-lB-Ia2kzKQ/s400/BI%2BAdv%2BSample%2B3.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5564406721421319314&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here are the Process Properties:&lt;br /&gt;&lt;table border=&quot;1&quot;&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;In/Out&lt;/th&gt;&lt;th&gt;Data Type&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FileName&lt;/td&gt;&lt;td&gt;In&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;IOName&lt;/td&gt;&lt;td&gt;In&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;PageSize&lt;/td&gt;&lt;td&gt;In&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Path&lt;/td&gt;&lt;td&gt;In&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SearchConstraint&lt;/td&gt;&lt;td&gt;In&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SiebelMessage&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;td&gt;Hierarchy&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ViewMode&lt;/td&gt;&lt;td&gt;In&lt;/td&gt;&lt;td&gt;String&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;The first &#39;Echo&#39; step is a Business Service based on Workflow Utilities, Echo method.  This step sets up all the variables used later in the process.  Here are the arguments:&lt;br /&gt;&lt;table border=&quot;1&quot;&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;I/O&lt;/th&gt;&lt;th&gt;Argument&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Value/Property Name&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;IOName&lt;/td&gt;&lt;td&gt;Process Property&lt;/td&gt;&lt;td&gt;IOName&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;PageSize&lt;/td&gt;&lt;td&gt;Process Property&lt;/td&gt;&lt;td&gt;PageSize&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;Path&lt;/td&gt;&lt;td&gt;Process Property&lt;/td&gt;&lt;td&gt;Path&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;SearchConstraint&lt;/td&gt;&lt;td&gt;Process Property&lt;/td&gt;&lt;td&gt;SearchConstraint&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;ViewMode&lt;/td&gt;&lt;td&gt;Process Property&lt;/td&gt;&lt;td&gt;ViewMode&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Output&lt;/td&gt;&lt;td&gt;FileName&lt;/td&gt;&lt;td&gt;Expression&lt;/td&gt;&lt;td&gt;IIF([&amp;FileName] is not null, [&amp;FileName], [&amp;IOName])&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;The next &#39;Export IO&#39; step is a Business Service based on EAI Siebel Adapter, QueryPage method.  This step queries the integration object.  Here are the arguments:&lt;br /&gt;&lt;table border=&quot;1&quot;&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;I/O&lt;/th&gt;&lt;th&gt;Argument&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Value/Property Name&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;OutputIntObjectName&lt;/td&gt;&lt;td&gt;Process Property&lt;/td&gt;&lt;td&gt;IOName&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;PageSize&lt;/td&gt;&lt;td&gt;Process Property&lt;/td&gt;&lt;td&gt;PageSize&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;SearchSpec&lt;/td&gt;&lt;td&gt;Process Property&lt;/td&gt;&lt;td&gt;SearchConstraint&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;ViewMode&lt;/td&gt;&lt;td&gt;Process Property&lt;/td&gt;&lt;td&gt;ViewMode&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Output&lt;/td&gt;&lt;td&gt;SiebelMessage&lt;/td&gt;&lt;td&gt;Output Argument&lt;/td&gt;&lt;td&gt;SiebelMessage&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;The next &#39;Write to File&#39; step is the Business Service, EAI XML Write to File, WriteEAIMsg method.  This step writes the property set out as an XML document to the file system.  Here are the arguments:&lt;br /&gt;&lt;table border=&quot;1&quot;&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;I/O&lt;/th&gt;&lt;th&gt;Argument&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Value/Property Name&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;FileName&lt;/td&gt;&lt;td&gt;Expression&lt;/td&gt;&lt;td&gt;[&amp;Path]+&quot;\&quot;+[&amp;Process Instance Id]+&quot;_&quot;+[&amp;FileName]+&quot;.xml&quot;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;SiebelMessage&lt;/td&gt;&lt;td&gt;Process Property&lt;/td&gt;&lt;td&gt;SiebelMessage&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;The final &#39;Attach&#39; step is another Business Service, this one custom.  The basic logic here is to add an Attachment to the file system which is first described in Oracle document 477534.1 (I have made some improvements which I will perhaps discuss another day).  Here are the arguments:&lt;br /&gt;&lt;table border=&quot;1&quot;&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;I/O&lt;/th&gt;&lt;th&gt;Argument&lt;/th&gt;&lt;th&gt;Type&lt;/th&gt;&lt;th&gt;Value/Property Name&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;AttBusinessComponent&lt;/td&gt;&lt;td&gt;Literal&lt;/td&gt;&lt;td&gt;Sample IO Attachment&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;AttachmentFieldName&lt;/td&gt;&lt;td&gt;Literal&lt;/td&gt;&lt;td&gt;SampleFileName&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;BusinessObject&lt;/td&gt;&lt;td&gt;Literal&lt;/td&gt;&lt;td&gt;Repository Integration Object&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;File&lt;/td&gt;&lt;td&gt;Expression&lt;/td&gt;&lt;td&gt;[&amp;Path]+&quot;\&quot;+[&amp;Process Instance Id]+&quot;_&quot;+[&amp;FileName]+&quot;.xml&quot;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;ObjectId&lt;/td&gt;&lt;td&gt;Process Property&lt;/td&gt;&lt;td&gt;Object Id&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Input&lt;/td&gt;&lt;td&gt;PrimaryBusinessComponent&lt;/td&gt;&lt;td&gt;Literal&lt;/td&gt;&lt;td&gt;Repository Integration Object&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;</description><link>http://thesiebelscholar.blogspot.com/2011/01/building-bi-developers-superview.html</link><author>noreply@blogger.com (Mik)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_qIQCkJx1sJQ/TTi-boAdHJI/AAAAAAAAClg/-lB-Ia2kzKQ/s72-c/BI%2BAdv%2BSample%2B3.png" height="72" width="72"/><thr:total>3</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-5526674352695609378</guid><pubDate>Wed, 19 Jan 2011 20:35:00 +0000</pubDate><atom:updated>2011-01-20T09:25:50.419-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">BI</category><category domain="http://www.blogger.com/atom/ns#">eScript</category><category domain="http://www.blogger.com/atom/ns#">How To</category><title>BI - Upload Limitation</title><description>I have recently been designated the BI technical resource on my project  so am looking at the BI capabilities (on 7.8) for the first time.   Despite a fairly complicated and mistake laden patch upgrade which I do  not even want to get into, it is a pretty powerful tool, much better  architected than Actuate.  Anyway, there are also some pretty glaring limitations as well on how it is administered that require so little effort to fix, I decided to just go ahead and fix them.&lt;br /&gt;&lt;br /&gt;My main beef is that the architecture requires your BI report developer to have access to both the BI file system and the Siebel Server file system.  I suppose you could set this up in a way that minimizes security risk, but it just seems so unnecessary.  Essentially, to upload a new BI Report Template, the developer creates a record in the BI Report Template administration view, attaches the two template files (an RTF and an XLF) and clicks the upload button.  So far, so good.  The problem is that these template files must also exist in a specific place in the Siebel Server file system as well to generate a report.  But the code behind that button does not take the extra step to just copy the files to where they need to go.  Also, there is an existing product defect where modifications to an existing report record require the developer to go into the BI File system and delete the entire directory containing that report template.  So that is where I step in.&lt;br /&gt;&lt;br /&gt;First I added two new System Parameters indicating the locations of the BI and Siebel home directories.  There is a way to grab environment variables through script but I did not feel like investigating this so let&#39;s call that phase II.  For example, here are my two:&lt;br /&gt;&lt;br /&gt;&lt;table border=&quot;1&quot;&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BIHomeDirectory&lt;/td&gt;&lt;td&gt;E:\OraHome&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SiebelHomeDirectory&lt;/td&gt;&lt;td&gt;E:\sea78\siebsrvr&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;br /&gt;Then, we need to trap the call to upload the templates file.  This call is performed from &#39;Report Template BC&#39; by the &#39;Upload&#39; method.  We need to always delete the directory before this upload is called.  We also want to delete the existing template file from the Siebel server file system.  Here is a script to place in the PreInvoke method to accomplish that (there are also some references to the &lt;a href=&quot;http://thesiebelscholar.blogspot.com/2010/05/escript-framework-logging.html&quot;&gt;Log&lt;/a&gt; and &lt;a href=&quot;http://thesiebelscholar.blogspot.com/2010/06/framework-revised.html&quot;&gt;Frame&lt;/a&gt; objects):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;switch (MethodName) {&lt;br /&gt;  case &quot;Upload&quot;:&lt;br /&gt;    try {&lt;br /&gt;      Log.StartStack(&quot;Business Component&quot;, this.Name()&lt;br /&gt;        +&quot;.PreInvoke&quot;, MethodName, 1);&lt;br /&gt;      this.WriteRecord();&lt;br /&gt;      var sReturn, sCommand;&lt;br /&gt;      var sSiebel = Frame.GetSysPref(&quot;SiebelHomeDirectory&quot;)&lt;br /&gt;        +&quot;\\XMLP\\TEMPLATES&quot;;&lt;br /&gt;      var sPath = Frame.GetSysPref(&quot;BIHomeDirectory&quot;);&lt;br /&gt;      var sFile = this.GetFieldValue(&quot;ReportTmplFileName&quot;)&lt;br /&gt;        +&quot;.&quot;+this.GetFieldValue(&quot;ReportTmplFileExt&quot;);&lt;br /&gt;&lt;br /&gt;      sPath = sPath&lt;br /&gt;        +&quot;\\XMLP\\XMLP\\Reports\\SiebelCRMReports\\&quot;&lt;br /&gt;        +this.GetFieldValue(&quot;Report Name&quot;);&lt;br /&gt;      Log.stepVars(&quot;BI Report Path&quot;, sPath, 3);&lt;br /&gt;&lt;br /&gt;      sCommand = &#39;rmdir &quot;&#39;+sPath+&#39;&quot; /S /Q&#39;;&lt;br /&gt;      sReturn = Clib.system(sCommand);&lt;br /&gt;      Log.stepVars(&quot;Command&quot;,sCommand,&quot;Success?&quot;,sReturn,3);&lt;br /&gt;&lt;br /&gt;      sCommand = &#39;del &quot;&#39;+sSiebel+&#39;\\&#39;+sFile+&#39;&quot;&#39;;&lt;br /&gt;      sReturn = Clib.system(sCommand);&lt;br /&gt;      Log.stepVars(&quot;Command&quot;,sCommand,&quot;Success?&quot;,sReturn,3);&lt;br /&gt;    } catch(e) {&lt;br /&gt;      Log.RaiseError(e);&lt;br /&gt;    } finally {&lt;br /&gt;      Log.Unstack(&quot;&quot;, 1);&lt;br /&gt;    }&lt;br /&gt;    break;&lt;br /&gt;}&lt;br /&gt;return (ContinueOperation);&lt;br /&gt;&lt;/pre&gt;Ok.  That addresses the product defect for updates.  Now the second part is to copy these template files to the Siebel server file system once the template files are uploaded.  The following script can be added to the InvokeMethod event:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;switch (MethodName) {&lt;br /&gt;  case &quot;Upload&quot;:&lt;br /&gt;    try {&lt;br /&gt;      Log.StartStack(&quot;Business Component&quot;, this.Name()&lt;br /&gt;        +&quot;.Invoke&quot;, MethodName, 1);&lt;br /&gt;      var sReturn, sCommand;&lt;br /&gt;    &lt;br /&gt;      var sSiebel = Frame.GetSysPref(&quot;SiebelHomeDirectory&quot;)+&lt;br /&gt;        &quot;\\XMLP\\TEMPLATES&quot;;&lt;br /&gt;      var sPath = Frame.GetSysPref(&quot;BIHomeDirectory&quot;);&lt;br /&gt;      var sFile = this.GetFieldValue(&quot;ReportTmplFileName&quot;)&lt;br /&gt;        +&quot;.&quot;+this.GetFieldValue(&quot;ReportTmplFileExt&quot;);&lt;br /&gt;&lt;br /&gt;      sPath = sPath&lt;br /&gt;        +&quot;\\XMLP\\XMLP\\Reports\\SiebelCRMReports\\&quot;&lt;br /&gt;        +this.GetFieldValue(&quot;Report Name&quot;);&lt;br /&gt;      Log.stepVars(&quot;Source Path&quot;,sPath,&quot;Target Path&quot;, &lt;br /&gt;        sSiebel,&quot;File to copy&quot;,sFile, 3);&lt;br /&gt;      sCommand = &#39;copy &quot;&#39;+sPath+&#39;\\&#39;+sFile+&#39;&quot; &quot;&#39;+sSiebel&lt;br /&gt;        +&#39;\\&#39;+sFile+&#39;&quot;&#39;;&lt;br /&gt;      sReturn = Clib.system(sCommand); &lt;br /&gt;      Log.stepVars(&quot;Command&quot;,sCommand,&quot;Success?&quot;,sReturn,3);&lt;br /&gt;    } catch(e) {&lt;br /&gt;      Log.RaiseError(e);&lt;br /&gt;    } finally {&lt;br /&gt;      Log.Unstack(&quot;&quot;, 1);&lt;br /&gt;    }&lt;br /&gt;    break;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And there you go.</description><link>http://thesiebelscholar.blogspot.com/2011/01/bi-upload-limitation.html</link><author>noreply@blogger.com (Mik)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-3155877282201577487</guid><pubDate>Fri, 07 Jan 2011 13:01:00 +0000</pubDate><atom:updated>2011-01-07T09:06:18.349-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Configuration</category><category domain="http://www.blogger.com/atom/ns#">How To</category><category domain="http://www.blogger.com/atom/ns#">Troubleshooting</category><title>ADM - List Of Values</title><description>There are plenty of posts on support web discussing the issues with migrating LOVs, but for my own sanity, I thought I would summarize all of the relevant issues in one place.&lt;br /&gt;&lt;br /&gt;First, we need to address the defects.  These are documented on support in Document 731411.1 but I will summarize here:&lt;br /&gt;&lt;blockquote&gt;(1) Go to BC &#39;List Of Values Child (UDA)&#39;&lt;br /&gt;(2) Add a new field  &#39;Parent Type&#39; based on Join &#39;Parent LOV&#39; and Column &#39;TYPE&#39; with Text Length  &#39;30&#39;.&lt;br /&gt;(3) Expand the pickmap for the &#39;Parent&#39;  field. Replace pickmap field &#39;Type&#39; with &#39;Parent Type&#39; and uncheck Constrain flg.&lt;br /&gt;(4) Go to the integration object &#39;UDA List Of Values&#39;&lt;br /&gt;(5) Find the  Integration component &#39;List Of Values Child (UDA)&#39;&lt;br /&gt;(6) Add a new field to  the integration component with Name = &#39;Parent Type&#39;. Data Type = &#39;DTYPE_TEXT&#39;,  Length = &#39;30&#39;, Type = &#39;Data&#39;, External Name = &#39;Parent Type&#39;, External Data Type  = &#39;DTYPE_TEXT&#39;, External Length = &#39;30&#39;, External Sequence = &#39;38&#39;, XML Tag =  &#39;ParentType&#39;&lt;br /&gt;(8) Compile changes. &lt;/blockquote&gt;The SR then goes into some more detail on why after all that it still does not quite work.  To understand, we need to see that the LOV ADM Integration Object is Hierarchical in one dimension.  That is, there is the LOV_TYPE record and then there are the value records.  But LOVs are frequently Hierarchical in two dimensions, by virtue of the Parent value.  What I mean is that a given LOV value record will always have one &#39;parent&#39; record, it&#39;s type or technical parent, and may have a second parent record, it&#39;s functional parent, if you will.&lt;br /&gt;&lt;br /&gt;ADM loads the first, technical parent in the standard way, through the relationships of the Integration Object.  To load the functional parent though, ADM must run in two passes, the first to create all the parent and child records, and the second to relate them.  This is necessary because we cannot guarantee the sequence with which LOV value records will be placed in the extract file.  If these value records do not exist in the target already, and the parent is alphabetically (or however else we chose to sort the records) after the child, then it would error if ADM did not take this approach.  So how ADM takes two passes is by virtue of the ADM Data Type explorer.  You will notice that the explorer does not actually specify the foreign key fields of an object to link them to each other.  Its only purpose is to run ADM in multiple passes.  But the twist is that ADM will actually process dependent data types setup in the explorer in reverse order, importing the children before the parent.  I personally find this confusing from a terminology perspective.  Perhaps a better way of naming these Data Types is to use &#39;LOV-2ndPass&#39; instead of &#39;LOV-HierParent&#39; and &#39;LOV-1stPass&#39; instead of &#39;LOV-HierChild&#39;.  This way when we set up the search specifications for an ADM Export session, it is clear what we are trying to do.&lt;br /&gt;&lt;br /&gt;OK, one more wrinkle to throw into the mix (just when you thought it was all making sense).  There is actually a third parent relationship involved.  That is the records that populate the S_LOV_REL table.  I will be honest; I do not use the LOV explorer view that often and I don&#39;t really know what the point of this table is.  In theory it can make LOVs M:M but I just don&#39;t think this is practical.  Nevertheless, there are some vanilla uses of LOVs where these records are in fact used that way.  The one that comes to mind is in payments, where the PAYMENT_TYPE_CODE values are children of the PAYMENT_METHOD_CODE and there are S_LOV_REL records created to store the relationships.  The same issue applies when migrating these relationships.  The related value must exist prior to the relationship being built.&lt;br /&gt;&lt;br /&gt;One final note.  I think the whole not deleting LOVs is well intended but more likely to cause confusion than solve anything.  Here is why.  Users can and will just change the Name/Value of a value record to something else in which case any sense of history is lost anyway.  There are no foreign key relationships to LOVs so business data using these values is unaffected regardless.  But others may disagree so this step is completely optional.  I remove the no delete properties from the &#39;List Of Values Child (UDA)&#39; BC and Integration Component.  (I also allow deletes from the GUI but that is a separate issue).  So my migration methodology is to synchronize values between environments for an initial release.  You would take a different approach on a point release where values are likely to have been added directly to production and therefore may not exist in your DEV and TEST environments.&lt;br /&gt;&lt;br /&gt;Anyway, what are we trying to do.  Quite simply, we are trying to create all the Value records in pass 1, then we need to relate them to each other in Pass 2.  I have already &lt;a href=&quot;http://thesiebelscholar.blogspot.com/2010/04/migrating-meta-data-release-field.html&quot;&gt;discussed&lt;/a&gt; how to group LOVs together for a release.  This is where I diverge from Siebel&#39;s example because I am trying to think of real life scenarios where I am deploying releases, not just one LOV_TYPE.  When creating the ADM Project/Session, here are the session items I use:&lt;br /&gt;&lt;br /&gt;&lt;table border=&quot;1&quot;&gt;&lt;br /&gt;&lt;tbody&gt;&lt;tr&gt;&lt;th&gt;Data Type&lt;/th&gt;&lt;th&gt;Child Delete&lt;/th&gt;&lt;th&gt;Deployment Filter&lt;br /&gt;&lt;/th&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LOV-2ndPass&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;td&gt;[Release] = &#39;1.1&#39;&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LOV-1stPass&lt;/td&gt;&lt;td&gt;N&lt;/td&gt;&lt;td&gt;[Release] = &#39;1.1&#39; AND [List Of Values Relationship.Name] IS NULL&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;What this means is that the first pass includes all LOV_TYPE records that have been marked for this release and all LOV value records related to them.  The second part of the expression basically just insures that no relationship records are included in the first pass.  When ADM attempts to set the parent value on a child, it may not be able to find it so it will log a warning and move on.  In the second pass, ADM will load all the Relationship records and set the Parent values that it missed on the first pass.  I have also set child delete to true on the second pass so that this job effectively synchronizes the value records for the type records marked.</description><link>http://thesiebelscholar.blogspot.com/2011/01/adm-list-of-values.html</link><author>noreply@blogger.com (Mik)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-2932997424706699358</guid><pubDate>Mon, 15 Nov 2010 11:51:00 +0000</pubDate><atom:updated>2010-11-15T07:29:37.634-05:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Configuration</category><category domain="http://www.blogger.com/atom/ns#">How To</category><category domain="http://www.blogger.com/atom/ns#">Integration</category><category domain="http://www.blogger.com/atom/ns#">User Properties</category><title>A Basic Interface - Integration Object User Props</title><description>I know this is meant to be a basic interface with so complexity, but let&#39;s be realistic about the requirements we are likely to get.  Even a simple upsert of something as basic as a service request is likely to require a bit of digging into bookshelf so that the interface is able to mimic basic GUI functionality.  I will discuss some of the most commonly used User Properties necessary to implement even an advanced interface.  When in doubt about the syntax of any of these properties, take a look for an example in the Tools flat view.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://download.oracle.com/docs/cd/B31104_02/books/EAI2/EAI2_IntObjs_Understanding10.html&quot;&gt;PICKLIST&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This is the most common Integration Component Field User Property you will see and it basically tells the EAI Siebel Adapter to validate the picklist in the interface.  This property is generally created by the wizard so I bring it up only because validating the picklist here will allow for several different ways to interpret a picklist field value described by some of the user properties below.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://download.oracle.com/docs/cd/B31104_02/books/EAI2/EAI2_IntObjs_Understanding10.html&quot;&gt;PicklistUserKeys&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In the GUI, when you type an account name in the Account field on another BC that has a picklist of Accounts, and there is more than one record matching that name (with different locations), a pick applet will pop open with the constrained list of accounts having that name.  The GUI is letting a user decide which of the multiple records returned was meant to be picked.  An interface does not have that luxury, so the PicklistUserKeys Integration Component Field User Property is provided to mimic this action.  The value of this property should be a comma separated list of fields representing the logical key of the picklist record to look up.  These fields must all be present in the integration component (though there values can be null).  The &#39;PICKLIST&#39; user property must also exist for the field where this property is used and its value must be &#39;Y&#39;.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://download.oracle.com/docs/cd/B31104_02/books/EAI2/EAI2_IntObjs_CreatingMaint11.html&quot;&gt;Ignore Bounded PickList&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;When a picklist is validated in the interface and the value passed is not found, the EAI Siebel Adapter stops processing and returns an error.  If the data is expected to sometimes be missing though, you may want the foreign key to just be left blank.  For instance, maybe the service request, in our example is tied to an order via a back office order number, but the order was never loaded.  Add this user property with a value of &#39;Y&#39; in combination with the PICKLIST user property with a value of &#39;Y&#39;.  The EAI Siebel Adapter will look up the record by the user key provided (can also be used in combination with PickListUserKeys) but if it is not found, will set the field to blank in the integration object before applying the data.  Keep in mind that this property will only work as expected if the Picklist object the underlying BC uses to constrain the field is set to No Insert equals True, otherwise, the EAI Siebel Adapter will try to insert a record.  Also note that in bookshelf there is a typo in that there should be spaces between the words of the property name.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://download.oracle.com/docs/cd/B31104_02/books/EAI2/EAI2_IntObjs_Understanding14.html&quot;&gt;FieldDependency&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It is easy in the GUI to determine the order of the fields being picked, either by training or by sequencing the fields in a particular way during applet design.  This may help set the fields that will be used to constrain the value of another field, frequently in a hierarchical picklist.  In EAI, we achieve this result through this user property.  It can be used multiple times with a sequence number, just like other BC and applet user properties.  The value is a field integration component field name.  Siebel claims that pickmapped constraints are automatically taken into account, and that may typically be the case, but I have seen times when it does not work, so this is a good fall back.</description><link>http://thesiebelscholar.blogspot.com/2010/11/basic-interface-integration-object-user.html</link><author>noreply@blogger.com (Mik)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-544624334919507846.post-2137512535069536090</guid><pubDate>Fri, 29 Oct 2010 13:41:00 +0000</pubDate><atom:updated>2010-10-29T11:17:59.928-04:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Configuration</category><category domain="http://www.blogger.com/atom/ns#">How To</category><category domain="http://www.blogger.com/atom/ns#">Integration</category><category domain="http://www.blogger.com/atom/ns#">Workflow</category><title>A Basic Interface - Web Service Workflow</title><description>Just about every interface consists of two basic components: the &lt;a href=&quot;http://thesiebelscholar.blogspot.com/2010/10/basic-web-service-interface-building.html&quot;&gt;integration object&lt;/a&gt;(s) and the workflow or business service.  I will demonstrate a workflow approach which will give you more opportunity to customize down the road.&lt;br /&gt;&lt;br /&gt;It is here that we begin to differentiate the integration by the communication mechanism.  Because I am designating this integration as a Web Service, that will drive the type of data this workflow will expect as an input and output.  The workflow I build will eventually be exposed as a WSDL to be consumed by an external program.  That WSDL should have the definition of the message it is expecting, in this case, the XSD, or definition of the Integration Object we just built.  How we accomplish this is to set the Input Process Property to a Data Type of &#39;Integration Object&#39; and to actually specify the integration object we built, in the Integration Object attribute of the process property.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://2.bp.blogspot.com/_qIQCkJx1sJQ/TMrZMMKpHQI/AAAAAAAACjE/XY4BK1MoyS8/s1600/WebService+-+PP.png&quot;&gt;&lt;img style=&quot;display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 50px;&quot; src=&quot;http://2.bp.blogspot.com/_qIQCkJx1sJQ/TMrZMMKpHQI/AAAAAAAACjE/XY4BK1MoyS8/s400/WebService+-+PP.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5533473895625596162&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;a href=&quot;http://4.bp.blogspot.com/_qIQCkJx1sJQ/TMrUi5-UN9I/AAAAAAAACi0/t4wstlUeIg4/s1600/WebService+-+PP.png&quot;&gt;&lt;br /&gt;&lt;/a&gt;You can also see my place holder for the SR Number that I want to return to the external system in the response message.  The &#39;IncomingXML&#39; property is already in the format needed to be passed to the EAI Siebel Adapter, so there is no conversion necessary.  And we are assuming that the data being passed is exactly as it should be applied. You will create the following steps which I will explain (other than Start and End which are self explanatory):&lt;br /&gt;&lt;a href=&quot;http://1.bp.blogspot.com/_qIQCkJx1sJQ/TMravr0eUpI/AAAAAAAACjU/Fi9ekMwYdkQ/s1600/Web+Service+-+Simple+WF+1.png&quot;&gt;&lt;img style=&quot;display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 365px; height: 77px;&quot; src=&quot;http://1.bp.blogspot.com/_qIQCkJx1sJQ/TMravr0eUpI/AAAAAAAACjU/Fi9ekMwYdkQ/s400/Web+Service+-+Simple+WF+1.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5533475604929598098&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;The &#39;Upsert SR&#39; is a Business Service calling &#39;EAI Siebel Adapter&#39;.  Now here is the another design decision to be made.  Each of the available methods differentiate exactly how the data should be applied.  But there are two broad determinations.  If we were to use the &lt;a href=&quot;http://download.oracle.com/docs/cd/B31104_02/books/EAI2/EAI2_UseEAIAdapt12.html&quot;&gt;Execute&lt;/a&gt; method, then the &#39;operation&#39; element which exists in each component of the IO would be used to determine how the data should be applied.  This gives more control the calling system (or a data map which I will discuss later).  The other set of &lt;a href=&quot;http://download.oracle.com/docs/cd/B31104_02/books/EAI2/EAI2_UseEAIAdapt3.html&quot;&gt;methods&lt;/a&gt; essentially comprise a One Size Fit All to applying all the data uniformly.  I will use the latter approach here and set the method to &#39;Upsert&#39;.  There is only one component in my IO, so if it exists, it will be updated, otherwise it will be inserted.  The input arguments for this step are the IncomingXML message from the external system and a parameter telling the EAI Siebel Adapter to create the Status Object.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://4.bp.blogspot.com/_qIQCkJx1sJQ/TMrZlS1CD2I/AAAAAAAACjM/euxbWdzuaeQ/s1600/WebService+-+PP+-+EAI+Inputs.png&quot;&gt;&lt;img style=&quot;display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 50px;&quot; src=&quot;http://4.bp.blogspot.com/_qIQCkJx1sJQ/TMrZlS1CD2I/AAAAAAAACjM/euxbWdzuaeQ/s400/WebService+-+PP+-+EAI+Inputs.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5533474326910734178&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;There is one Output Argument.  We no longer care about the input message at this point because it will have been applied so we just overwrite it with the return, which in this case will be the status key.&lt;br /&gt;&lt;a href=&quot;http://2.bp.blogspot.com/_qIQCkJx1sJQ/TMrbd5IuffI/AAAAAAAACjc/zLoNEcELbI8/s1600/WebService+-+EAI+Outputs.png&quot;&gt;&lt;img style=&quot;display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 43px;&quot; src=&quot;http://2.bp.blogspot.com/_qIQCkJx1sJQ/TMrbd5IuffI/AAAAAAAACjc/zLoNEcELbI8/s400/WebService+-+EAI+Outputs.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5533476398778187250&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;The last step in the WF is another Business Service step calling &#39;PRM ANI Utility Service&#39;, &#39;GetProperty&#39; method.  This business service has a plethora of useful &lt;a href=&quot;http://download.oracle.com/docs/cd/B31104_02/books/PRMAdm/PRMAdm_SetUpRealTimeInt10.html&quot;&gt;methods&lt;/a&gt; for manipulating property sets.  This particular method will extract the value of a field from an integration object instance.  Here are the inputs:&lt;br /&gt;&lt;a href=&quot;http://2.bp.blogspot.com/_qIQCkJx1sJQ/TMrkdwsSHHI/AAAAAAAACjk/UQ31Pp_VgaQ/s1600/WebService+-+PRM+Inputs.png&quot;&gt;&lt;img style=&quot;display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 60px;&quot; src=&quot;http://2.bp.blogspot.com/_qIQCkJx1sJQ/TMrkdwsSHHI/AAAAAAAACjk/UQ31Pp_VgaQ/s400/WebService+-+PRM+Inputs.png&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5533486292116053106&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;The output is to set the process property &#39;SRNumber&#39; with the Output Argument, &#39;Property Value&#39;.  When the return message is sent back to the calling system, this property will exist with the generated SR Number.&lt;br /&gt;&lt;br /&gt;Simulating/Troubleshooting this WF from within tools is difficult as built so I sometimes add a bypass step off the start branch to read the integration object from a file.  I may talk about this later but want to keep this post pretty straightforward.  So for now, this workflow can just be deployed, checked in and activated.</description><link>http://thesiebelscholar.blogspot.com/2010/10/basic-interface-web-service-workflow.html</link><author>noreply@blogger.com (Mik)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_qIQCkJx1sJQ/TMrZMMKpHQI/AAAAAAAACjE/XY4BK1MoyS8/s72-c/WebService+-+PP.png" height="72" width="72"/><thr:total>0</thr:total></item></channel></rss>