Wednesday, May 16, 2018

Oracle Bot Cloud (IBCS): Switching Intents while in conversation (Nested Intent)

Problem Description: If we see IBCS flow generally tries to find user intent first. Once it identifies and intent, it tries to complete intent based on flow defined. There are all reasons that end user may want to switch his intent before completing first intent. For example, I am ordering pizza but while system asks me for pizza type, I decide to verify their payment options and I changed my intent. Something like below

Me: I would like to order a pizza
       
                   Bot: Which type of pizza would you like to have?

Me: Hold on, What are your payment options
     
               
In ideal conversation bot should provide me details of payment. Once payment options information is provided, it can ask me if I want to continue with Pizza order.

But in general we use either System.Text or System.List component when we want to take user input. This is the time when user can change his mind (or intent).

It looks like
askPizzaType:
    component: "System.List"
    properties:
      options: "${pizzaType.type.enumValues}"
      prompt: "Which type of pizza would you like to have?"
      variable: "pizzaType"
    transitions: {}

with this state, bot will provide a list of pizza types (say small, medium or large). Now even if user changes his mind and asks about payment options, bot will ask pizza type again and again. Very annoying.

In this blog we want to make it a bit realistic and introduce intelligence of user intent switching.

Lets say we have following initial bot configuration

1. Intents: OrderPizza, ProvideInfo
2. Entity: PizzaType (Associated with OrderPizza Intent)

3. Dialog-Flow:

Its able to complete payment option enquiry and pizza order but if user tries to switch from OrderPizza intent to ProvideInfo, bot keeps on asking about pizza type as shown below


Now lets improve it to handle intent switching.
a. To stop bot asking for pizzaType repeatedly, we can introduce maxPrompts=1 with askPizzaType (System.List) component.

b. We can add cancel action with askPizzaType (System.List) component to perform a transition, if bot can't find pizzaType even after max number of attempts ( NOTE: here we have already set max attempt as 1, so user can only provide one input. If that is not small/medium/large, cancel transition will take place)
askPizzaType:
    component: "System.List"
    properties:
      options: "${pizzaType.type.enumValues}"
      prompt: "Which type of pizza would you like to have?"
      variable: "pizzaType" 
      maxPrompts: 1
    transitions: 
      actions:
        cancel: "verifyIntentWhileOrderPizzaInProgress"    

c. verifyIntentWhileOrderPizzaInProgress can set uncompletedIntent in a variable and then perform an nlp intent-matching on user input. If its unresolved in NLP matching assume that user is trying to answer pizzaType question but some typo etc happened so lets take him back to askPizzaType.

verifyIntentWhileOrderPizzaInProgress:
    component: "System.SetVariable"
    properties:
      variable: "uncompletedIntent"
      value: "OrderPizza"
    transitions: {}        
  verifyIntent:
    component: "System.Intent"
    properties:
      variable: "iResult2"
      confidenceThreshold: 0.4
    transitions:
      actions:
        OrderPizza: "orderPizza"
        ProvideInfo: "provideInfo"
        unresolvedIntent: "askPizzaType"

d. Lets improve provideInfo state as well to handle uncompleted intent (OrderPizza). After providing information of payment option, verify if there is any uncompleted intent. If yes suggest to continue with that intent else done
provideInfo:
    component: "System.Output"
    properties:
      text: "We support credit card, debit card and cash on delivery. "
      keepTurn: true
    transitions: 
       next: "isAnyIncompleteIntent"

e. Lets introduce few states to gracefully end conversation or ask for any pending intent completion.
  isAnyIncompleteIntent:
    component: "System.ConditionEquals"
    properties:
      variable: "uncompletedIntent"
      value: "OrderPizza"
    transitions:
      actions:
        equal: "askToStartPizzaOrderAgain"
        notequal: "done"  
  askToStartPizzaOrderAgain:
    component: "System.Output"
    properties:
      text: "Lets continue with Pizza ordering."
      keepTurn: true
    transitions: 
       next: "orderPizza"   
  done:
    component: "System.Output"
    properties:
      text: "Is there any other way I can help you?"
    transitions:
      actions:
       return: "done"

Complete flow looks like below

Effectively by above improvements in flow we are trying to enable user to switch intent while in between conversation.
After above change flow looks like this.
Thats all

Tuesday, May 15, 2018

Oracle Cloud Bot Designer UI URL

Problem Description: This blog is just to remind me how to find bot designer UI. I recently created a bot cloud service. It created lots of services and it was really hard for me to find bot designer UI url.

Finally I could find it as shown in below dig.


Wednesday, April 11, 2018

Java SOAP WebService Proxy: SOAPHandler to print SOAP messages

Problem: We all know about creating webservice proxy from jdeveloper. Proxy generates few classes based on WSDL and associated XSD and allow us to invoke webservice as if we are simply calling some java method. Complexity of creating soap message and sending over network and receiving output is hidden from us. One of the problem we face many a time is to view SOAP request and response messages. If we can it would be very helpful for debugging.
In this blog I will be using SOAP handler to view SOAP messages.

Solution: Solution which I am going to show is using SOAP handler feature of web-service proxy.

Using proxy is very simple, we just work with normal java classes and complexity of invoking webservice is completely hidden. SOAP Handler is java class (with some guidelines) that can be injected with proxy and proxy will make sure to call methods of this class before sending a request and after receiving message.

SOAP Handler class must implement SOAPHandler<SOAPMessageContext> class.
A Sample SOAPHandler class can look like

import java.util.Collections;
import java.util.Set;

import javax.xml.namespace.QName;
import javax.xml.soap.SOAPException;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class CalculatorSOAPHandler implements SOAPHandler<SOAPMessageContext> {
    public Set<QName> getHeaders() {
        return Collections.emptySet();
    }

    public boolean handleMessage(SOAPMessageContext messageContext) {
                Boolean outboundProperty = (Boolean)
            messageContext.get (MessageContext.MESSAGE_OUTBOUND_PROPERTY);

        if (outboundProperty.booleanValue()) {
            System.out.println("Request message:");
        } else {
            System.out.println("Response message:");
        }
        
        try {
            System.out.println(messageContext.getMessage().getSOAPPart().getEnvelope().toString());
        } catch (SOAPException e) {
            e.printStackTrace();
        }


        return true;
    }

    public boolean handleFault(SOAPMessageContext messageContext) {
        return true;
    }

    public void close(MessageContext messageContext) {
    }
}


Now we need to inject this class in proxy or in other words we need to configure it with proxy so that it knows about this class. There are couple of ways to do that.
1. Specify SOAP handler while creating proxy in Proxy creating wizard.

In above diagram we are specifying a SOAP handler. We have not selected any port so handler will be registered against all web-service port. Jdev will not create any class. You must create class separately.

When we generate proxy, there is one most important class which has @WebServiceClient annotation. Above step will create a handler entry in that class as

@HandlerChain(file = "MyServiceProxy-HandlerChain.xml")

It will also create a HandlerChain.xml file, which will have entry of handler.
<ns0:handler-chains xmlns:ns0="http://java.sun.com/xml/ns/javaee">
    <ns0:handler-chain>
        <ns0:service-name-pattern xmlns:ns1="http://xmlns.oracle.com/SIH/SIHParentProcess/BPELParentProcess">ns1:bpelparentprocess_client_ep</ns0:service-name-pattern>
        <ns0:handler>
            <ns0:handler-name>CalculatorSOAPHandler</ns0:handler-name>
            <ns0:handler-class>com.san.wsproxy.client.CalculatorSOAPHandler</ns0:handler-class>
        </ns0:handler>
    </ns0:handler-chain>
</ns0:handler-chains>



Now when you run service you will see that handleMessage method of SOAP handler is getting called and its printing SOAP header and body.

Another way to associate SOAP handler class with proxy is simply modify client code.
2. With proxy generation you get a client class. It has a main method, which shows how to run a webservice. You can use this class to add security (WS-Security) header in soap message by setting OWSM policy. Similarly you can use this class also to associate handler with proxy.

Your client method would look something like

    public static void main(String[] args) {
        Calculator calculator = new Calculator();
        CalculatorSoap calculatorSoap = calculator.getCalculatorSoap();
        // Add your code to call the desired methods.
       
        Binding binding = ((BindingProvider)calculatorSoap).getBinding();
        List handlerList = binding.getHandlerChain();
        handlerList.add(new CalculatorSOAPHandler());
        binding.setHandlerChain(handlerList);
             
             
        System.out.println(calculatorSoap.add(5, 6));
       
    }

Thats all, Now if you run service, you will see that SOAP messages are getting printed on console.



Below is the print of messages
Calling handleMessage
<env:Header xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"/>

<S:Body xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
  <Add xmlns="http://tempuri.org/">
    <intA>5</intA>
    <intB>6</intB>
  </Add>
</S:Body>

Calling handleMessage
<env:Header xmlns:env="http://schemas.xmlsoap.org/soap/envelope/"/>

<soap:Body xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <AddResponse xmlns="http://tempuri.org/">
    <AddResult>11</AddResult>
  </AddResponse>
</soap:Body>


Instead system.out.println, you can add ADF logger also to print messages. In that case your messages would appear in weblogic log as well.

Monday, February 19, 2018

Oracle JET: Bookmark a secured pages

Problem Description: Oracle JET allows us to create SinglePage application (SPA). It changes url when we navigate between pages. What if application is secured application and pages require login to visit. In such case if we book mark a page and later try to launch it, application should verify if user is already logged in, If not redirect user to login page and once logged in user should be shown same page, which he has requested. In this blog we are trying to achieve it.

Also if user has directly started from login page then if login is successful we need to take him to default page mentioned in router configuration.

Solution:
 To implement this we need to achieve following flow

Here are the steps to achieve above flow

1. User can either launch login page or a secured page (say Page-X). If user launches login page, we can directly show him login page, but if he launches Page-X, we need to verify if user is already logged in.To verify if user has already logged in depends on server side logic.
   Here in this blog I assume there is a REST service available, which returns profile of logged in user (myprofile service). we will call this service, without passing any Authorization header. In such case browser will pass SESSIONID from cookie if user is already logged in. If not logged in then we will get 401 from server. If we get error from server, we can redirect user to login page, but we will add current url in login page url additionally, so that we can use it later to redirect user back to Page-X. Here is the common code checkIfLoginDone function written in appcontroller.js

     function ControllerViewModel() {
        $.ajaxSetup({
          xhrFields: {
            withCredentials: true
          }
        }); 

        var self = this;
        self.baseURL='http://localhost:7101';
        self.serviceContextRoot = '/myapp';
        self.serviceInitialURL = self.baseURL + self.serviceContextRoot + '/resources';

        self.router = oj.Router.rootInstance;
        self.checkIfLoginDone = function checkIfLoginDone(){
          console.log('starting login check');
          
          var promise = $.ajax({
             type: "GET",
             url: self.serviceInitialURL+ "/v1/myprofile",
             contentType: "application/json; charset=utf-8",
             crossDomain: true,
             dataType: "json"});
           
            promise.then(function(response) {
                  
                 

              }, function(error) {
                 // error handler
                 var currenturl = window.location.pathname + window.location.search ;
                window.location.href = '/?root=login&origurl='+currenturl;
              });

            return promise;
         
          
        }

In above code if we get error from server, we will be redirecting user to login page and add url of secured page as a parameter origurl. Login page url will appear like
http://<host>:<port>/?root=login&origurl=<url-path-of-secured-page>

[Assuming that login will be router state for login page]

2. To perform login check we can it checkIfLoginDone from all secured pages's ViewModel as
define(['ojs/ojcore', 'knockout', 'jquery', 'appController'],
 function(oj, ko, $, app) {
      self.handleActivated = function(info) {
        // Implement if needed
        return app.checkIfLoginDone();
      };

3. Create a login page: For this you can follow below steps
      a. Create login.html in js/views directory. Content could be
         

      <div class="oj-hybrid-padding">
        <h1>Login Content Area</h1>
          <div id="sampleDemo" style="" class="demo-container">
            <div id="componentDemoContent" style="width: 1px; min-width: 100%;">
              <div id="form-container" class="oj-form-layout">
                <div class="oj-form">
                  <div class="oj-flex">  
                    <div class="oj-flex-item">
                      <oj-label show-required for="username">User Name</oj-label>
                      <oj-input-text id="username" required value="{{username}}"></oj-input-text>
                    </div>
                  </div>
                  <div class="oj-flex">  
                    <div class="oj-flex-item">
                      <oj-label for="password" show-required>Passward</oj-label>
                      <oj-input-password id="password" required value="{{password}}"></oj-input-password>
                    </div>
                  </div>
                </div>
                <oj-button id='submit' on-click='[[doLogin]]'>Login</oj-button>
              </div>              
            </div>
    </div>
  </div>
   
In above page, we have created two fields username/password and a button Login.
Username and password are bound to ViewModel and Login button click calls doLogin method of ViewModel

    b. Create login.js as a ViewModel in js/viewModels directory. Its code would be

define(['ojs/ojcore', 'knockout', 'jquery', 'appController','ojs/ojknockout','ojs/ojlabel','ojs/ojinputtext', 'ojs/ojcheckboxset'],
 function(oj, ko, $, app) {
  
    function LoginViewModel() {
      var self = this;
      function param(name) {
            return (location.search.split(name + '=')[1] || '').split('&')[0];
        }
      self.username = ko.observable("");
      self.password = ko.observable("");
      self.doLogin = function doLogin(event){
        $("body").css("cursor", "wait");
       //do server login here
       var string = self.username() + ':' + self.password();
      var encodedString = 'Basic ' + btoa(string);
             
      var promise = $.ajax({
              type: "POST",
              url: app.serviceInitialURL + '/v1/auth/login',
              contentType: "application/json; charset=utf-8",
              headers: {
                   "Content-Type": "text/plain",
                    "Authorization": encodedString
              },
              crossDomain: true,
              dataType: "json"});
         
      promise.then(function(response){
              var origurl = param('origurl');
              if(origurl){
                window.location.href = origurl;
              }
              else{
                oj.Router.rootInstance.go('dashboard');
              }

              $("body").css("cursor", "default");
         }, function(response){
             //write logic here to show error message to end user.
         }) ;   

      }
      // Header Config
      self.headerConfig = {'viewName': 'header', 'viewModelFactory': app.getHeaderModel()};

      
     

    return new LoginViewModel();
  }
);

Important piece of above code is 
    i. username/password created as ko observable.
   ii. username password is used to create base 64 encoded authorization string
  iii. server side login using $.ajax POST request
   iv. If login is success then verify if there is any url parameter as origurl present. Navigate to the location whereever origurl points to. If not specified then get default page from router and navigate there. 

c. register login page in router configuration

self.router.configure({
          'login': {label: 'Login'},
         'dashboard': {label: 'Dashboard', isDefault: true},
         'incidents': {label: 'Incidents'},
         'customers': {label: 'Customers'},
         'profile': {label: 'Profile'},
         'about': {label: 'About'}
        });

4. Finally we need a logout button. We can keep it in header.html
<div class="oj-flex-bar-end">
    <oj-button id='button1' on-click="[[logout]]">Logout</oj-button>
</div>

logout implementation is written in appcontroller.js by changing getHeaderModel method.
 self.logout = function(event){
           $.ajax({
                 type: "GET",
                 url: self.serviceInitialURL+ "/v1/auth/logout",
                 contentType: "application/json; charset=utf-8",
                 crossDomain: true,
                 dataType: "json",
                 success: function (data, status, jqXHR) {
                        oj.Router.rootInstance.go('login');
                 },

                 error: function (jqXHR, status) {
                     // error handler
                     
                 }
              });

      }


 self.getHeaderModel = function() {
          var headerFactory = {
            createViewModel: function(params, valueAccessor) {
              var model =  {
                pageTitle: self.router.currentState().label,
                handleBindingsApplied: function(info) {
                  // Adjust content padding after header bindings have been applied
                  self.adjustContentPadding();
                },
                toggleDrawer: self.toggleDrawer,
                logout: self.logout
              };
              return Promise.resolve(model);
            }
          }
          return headerFactory;
        }

Above logout method calls server side logout and then redirect user to login page.



Saturday, February 10, 2018

ADF: Attribute Defaulting

Problem Description: Recently I came across a forum question where requirement was to make an EO attribute to be fetched value from database but should be ignored completely while saving data. User should definitely be able to update attribute from UI but it should not be posted to database.
https://community.oracle.com/message/14677169#14677169

Solution: Let us see what are our options

In ADF either we can make attribute persistent or transient. If we make persistent, it will be mapped to a database column and its value will be fetched from database and also it will get posted back to database. There is no option to say only fetch from database but ignore while posting to database.


As a solution we can mark our attribute transient so that its value will be ignored while posting to database. Now to default its value from database field we can specify default value. Value can be picked from SQL and good part is we can directly specify column name from which we want to default its value. Of course column must be present in same table. 

What if we want to fetch default value from some other table. 
You have two option
1. Write a complete SELECT statement on default value field. You can pass values from current row of EO. For example let say you are querying employee table (which has manager id) and now you want to fetch his manager name. You can simply write SQL query as [SELECT MGR.FIRST_NAME FROM EMPLOYEES MGR WHERE MGR.EMPLOYEE_ID = EmployeeEO.MANAGER_ID]

2. You can also use a ViewAccessor with expression to default value. In this case you will use VO and add it as view accessor in EO. Now in default value, you can write groovy expression to get value from view accessor. 

Same thing is applied for VO transient attributes as well. 

Out of option 1 and 2, I would chose option 1 as preference. Reason for that is if you write SQL based default expression, a single query is fired against database and result is used to set default value of all rows. Query if formed something like
SELECT EmployeeEO.EMPLOYEE_ID,         EmployeeEO.FIRST_NAME,         EmployeeEO.LAST_NAME,         EmployeeEO.EMAIL,   
EmployeeEO.PHONE_NUMBER,         EmployeeEO.HIRE_DATE,         EmployeeEO.JOB_ID,         EmployeeEO.SALARY,       
EmployeeEO.COMMISSION_PCT,         EmployeeEO.MANAGER_ID,         EmployeeEO.DEPARTMENT_ID,  
(SELECT MGR.FIRST_NAME FROM EMPLOYEES MGR WHERE MGR.EMPLOYEE_ID = EmployeeEO.MANAGER_ID) AS MGR_NAME
FROM EMPLOYEES EmployeeEO

In option 2, View accessor will be fired once for every row fetched. For example if we fetch 100 employee records and for each record a manager-vo query will fire to get manager name. You will end up with 101 queries. To improve View accessor queries, you can set RowLevelBinds = false if same view-accessor query result is ok for all records. In above case it will not fit. You need to fire separate view-accessor query with bind parameter as employee-id from source row to get correct manager name. 

Thats all





Saturday, January 13, 2018

Oracle JET: Caching data

Problem Description: Oracle JET is a client side technology and mostly it uses REST services to fetch data from server. Some of data is used on multiple pages and it does not change very frequently so its a good approach to query such data once and then cache it. Next time when you need it refer from cache.


Solution:

In Oracle JET we have index.html, which serves as main (or base) page. All other pages (module) appears on it. Some modules might be static and some are attached dynamically using router. To some up at run time, things are like below image.


Based on URL different modules keep on changing but index.html (base page) is as it is. It implies view model associated with it (also called root viewmodel) is also available all the time.

Another thing that we should know is 'LifeCycle of ViewModel instances'. In general code for viewmodels are like below

define(['ojs/ojcore', 'knockout', 'jquery', 'appController'],
 function(oj, ko, $, app) {
    
    function PageXViewModel() {
      console.log("Instantiating PageXViewModel");
      var self = this;
 
    }

    return new PageXViewModel();
  }
);

If we see ViewModels are created using RequireJS define function. RequireJS is an AMD framework. It helps creating JS objects only when needed and once object is available, it associate it with a key. Object remains in memory always and you can access it with that key. All ViewModels are created like that. Which means ViewModel instace would get created when first time you access module associated with that ViewModel. Next time when you try to access ViewModel, you will not get a fresh instance, you will get same old instance instead.
In above example  PageXViewModel instance would get created only once, when we access PageX first time. After that if we go to PageY and come back to PageX, same instance of PageXViewModel will be reused. To confirm that you can see browser console log and find how many times "Instantiating PageXViewModel" is getting printed. You will find its only once, when PageX is loaded first time.

Effectively we can say if  page is showing a module (PageX), there are two instances available PageXViewModel and RootViewModel. We can use them to cache our data. 

With that in mind, in this blog we can see various strategy to cache our data.

There are different kinds of data that we show on pages
1. Transactional data: which keeps on changing and user expects it to be latest always. For example table showing employee data. We should not try to cache such data as user expectation is to see latest data always. As we know our ViewModel instances are getting reused so how should we make sure that every time, we go to a page data is re-fetched from server. ViewModel has a function called handleActivated. This is called by framework always when a view is loaded. We can use this function to fetch data from server. For example

 self.handleActivated = function(info) {

         var promise = $.ajax({
                 type: 'GET',
                 url: 'http://myservice-url',
                 contentType: "application/json; charset=utf-8",
                 crossDomain: true,
                 dataType: "json"
              })
 
  promise.then(function(data) {
            self.data = ko.observableArray(data);

          });
 
         return promise;

        
        
     };
In above code we are setting data property of ViewModel using a REST output and this code runs every time we load page, so data will always show new values from server whenever page is loaded.

2. Setup data: which rarely changes. For example data appearing in various drop-downs (lookup).  This kind of data is ideal for caching. In this example let say we have a lookup PRIORITY and it shows values as High (H), Medium (M), Low (L). We want to show it as drop-down on customer and profile pages.

  To cache that I have two step code
  a. Add below method in appcontroller.js

function ControllerViewModel() {
        var self = this;

        //initiate global cache with empty objects
        self.globals = {lookups: []};


        //core private method responsible for fetching lookup data using rest-service
        var fetchLookupData = function fetchLookupData(lookupType){
            
            var encodedString = 'Basic ' + btoa('username:password');
            var promise = $.ajax({
                 type: 'GET',
                 url: 'my-rest-url,
                 contentType: "application/json; charset=utf-8",
                 headers: {"Authorization": encodedString},
                 crossDomain: true,
                 dataType: "json"
              });

            promise.then(function(response) {
                  self.globals.lookups.push ( {"lookupType": lookupType, 
                                              "lookupValues": response.lookupValues});
                 

              }, function(error) {
                  //alertFactory.handleServiceErrors(error);
                  console.log(error); //Handle errors in a better way
              });

            return promise;
        }

        //method to put a logic to get lookup data from cache (global) first and if not present then from rest-service
        self.initLookpCache = function initLookpCache(lookupType){
          
            var lookups = self.globals.lookups.filter(function (lookup){
              return lookup.lookupType === lookupType;
            })
            if(lookups.length > 0){
              console.log("Lookup present in cache");
              return lookups[0];
              
            }
            else{
              console.log("Reading lookup from service");
              return fetchLookupData(lookupType);
            }
          
        }
      
         //Remaining standard code of appcontroller.js is not shown.

Now on page, which requires cached data we can add below lines. Add it in customer.js and profile.js both

self.handleActivated = function(info) {
        // Implement if needed
        console.log('running handleActivated from CustomerViewModel');
        
        var promise = app.initLookpCache('MY_LOOKUP_TYPE');
        Promise.resolve(promise).then(function(lookupTypeValues) {
            self.linkTypes = ko.observableArray(lookupTypeValues.lookupValues);
        });


        return promise;

      };


We have actually put a call to Root-ViewModel's initLookupCache
It can return either Promise or lookupvalue. Promise is returned if values are getting fetched from REST service call. LookupValues are returned directly if values are coming from cache.

Promise.resolve make sure that
        if input is promise object then wait for it to get completed and once completed then only run function specified in then.
        if input is not promise but direct values then directly runs the function and pass values as input.

If you run customer and profile pages, you will find below log
running handleActivated from CustomerViewModel
Reading lookup from service

Instantiating ProfileViewModel
running handleActivated from ProfileViewModel
Lookup present in cache

You can see lookup values are coming from cache second time. Good part is its incremental cache, as and when you need lookup data first time, it will get cached. You are not loading all lookup data upfront.

Few other tips

  a. If you want to cache a data which is required very frequently (almost on all pages) you can cache such data from appcontroller.js itself.


  c. If you want to cache a data, which is required only in very very few pages you can cache them in their respective page's ViewModel itself. For that instead of calling appcontroller's method you can have local method and populate ViewModel (self.data) variable. NOTE: Even these page's viewmodel are not getting destroyed so anything cached there is also present throughout. For local caching your code of handleActivated could be be something like
self.data = ko.observable();

self.handleActivated = function(info) {
   if(!self.data()){
      //Make reset service call and populate self.data
   }
}




Thats all.

Friday, November 24, 2017

Removing a corrupted weblogic deployment.

Problem Description: What if you have deployed an application on weblogic and somehow it has got corrupted and you want to undeploy it. Most of the time you can go to weblogic console and undeploy but at times it gets corrupted so badly that you can't even start your weblogic server. I faced this issue recently while experimenting with filters. My filter code has some problem. Application got deployed successfully but when I try to use it, due to code bug in filter, it was going in infinite loop. So I stopped weblogic server. Now when I try to start my weblogic server, it by default tries to deploy previous application and this time because of problem in deployment weblogic was not starting. To sum up I need to delete my weblogic deployment offline.

Here are the changes I did

1. Find your config.xml and see app-deployment node. For integrated server config.xml is located in <System-Directory>/DefaultDomain/config/config.xml

 Your entry will be something like below

<app-deployment>
    <name>MyApplication</name>
    <target>DefaultServer</target>
    <module-type>ear</module-type>
    <source-path>D:\Oracle\Middlewares\JDEV_SystemDir\system12.2.1.0.42.151011.0031\o.j2ee\drs\MyApplication</source-path>
    <security-dd-model>DDOnly</security-dd-model>
    <staging-mode xsi:nil="true"></staging-mode>
    <plan-staging-mode xsi:nil="true"></plan-staging-mode>
    <cache-in-app-directory>false</cache-in-app-directory>
  </app-deployment>

a. Note source-path location. Remove your deployment from that location.
b. Remove entry of app-deployment from config.xml file as well.
c. Also remove your applicaton from <System-Directory>/servers\DefaultServer\tmp\_WL_user directory.
d. To my surprise even after all these changes, weblogic server was not starting. I thought of deleting DefaultDomain directory but then I decided to close jdev once and try. That worked.

To sumup you need to close jdev and then perform a,b and c task mentioned above.


Now you can start your application.

Similarly I believe you can delete invalid jndi entries also from this file if you find that your weblogic is taking long time to start because of invalid jndi entries. Actually weblogic tries to look in this file and connect with those database while starting to reserve connections in pool but if database is down or no longer valid, weblogic waits for timeout and it makes weblogic startup slow.

Thats all.