Usage of CDI in Oracle ADF - Part III - CDI Events

Hi,

I will bring some serie of posts about CDI usage within Oracle ADF:
In this post I want to introduce an example of the usage of CDI Events (Synchronous and Asynchronous) to enhance your Oracle ADF Skills.


The example contains the CDI Events Synchronous and Asynchronous implementation. However, as commented in previous posts, WebLogic 12.2.1.3 is shipped with CDI 1.0 which is not compatible with Asynchronous Events introduced in 2.0).

https://github.com/DanielMerchan/adf

The application is based on a Pokemon Battle where attacking takes a period of time before it completes the attack.

Each Pokemon Attack is an Event which is processed Synchronous or Asynchronus depending on the attack selected.

Which are the important parts in the example?

In the example you can find:
  • PokemonAttack.java: This class will contain the information of an Attack Event

    package com.magicpigeon.poc.model;
    
    /**
     * Encapsulates a Pokemon Attack
     * @author Daniel Merchan Garcia
     */
    public class PokemonAttack {
        
        public enum AttackType {
            LIGHTNING("Lightning"), 
            ROCK("Rock"), 
            WATER("Water"),
            PHYSICAL("Phisical"),
            NATURE("Nature");
            
            private final String attackType;
            
            AttackType (String at) {
                this.attackType = at;
            }
           
            public boolean equalsName(String attackType) {
                    return attackType.equals(this.attackType);
            }
            
            public String toString() {
                   return this.attackType;
                }
            
            public String getString() {
                return this.attackType;
            }
        }
        
        private String attackName;
        
        private AttackType attackType;
    
        public PokemonAttack(String attackName, PokemonAttack.AttackType attackType) {
            this.attackName = attackName;
            this.attackType = attackType;
        }
    
    
        public void setAttackName(String attackName) {
            this.attackName = attackName;
        }
    
        public String getAttackName() {
            return attackName;
        }
    
        public void setAttackType(PokemonAttack.AttackType attackType) {
            this.attackType = attackType;
        }
    
        public PokemonAttack.AttackType getAttackType() {
            return attackType;
        }
    }
    

  • Pokemon.java: This is a CDI Managed Bean of @RequestScoped to interact with the Pokemon UI. It generates Events of type PokemonAttack
    package com.magicpigeon.poc.view.cdi;
    
    import com.magicpigeon.poc.model.PokemonAttack;
    
    import javax.enterprise.context.RequestScoped;
    import javax.enterprise.event.Event;
    
    import javax.inject.Inject;
    import javax.inject.Named;
    
    import oracle.adf.view.rich.component.rich.layout.RichPanelGroupLayout;
    import oracle.adf.view.rich.component.rich.output.RichOutputText;
    
    import oracle.adf.view.rich.context.AdfFacesContext;
    
    /**
     * CDI Managed Bean to interact with the pokemon UI actions
     * @author Daniel Merchan Garcia
     */
    @Named("pokemon")
    @RequestScoped
    public class Pokemon {
    
        @Inject
        Event pokemonAttack;
    
    //    @Resource
    //    ManagedExecutorService threadPool;
    
        private RichPanelGroupLayout asyncPanelTextComp;
        
        private RichOutputText asyncTextComp;
    
        public Pokemon() {
            super();
        }
    
        public void attackSync(String attackName, String attackType) {
            PokemonAttack pa = new PokemonAttack(attackName, PokemonAttack.AttackType.valueOf(attackType));
            // Sync Part
            pokemonAttack.fire(pa);
            attackDone(pa);
        }
        
        public void attackAsync(String attackName, String attackType) {
            PokemonAttack pa = new PokemonAttack(attackName, PokemonAttack.AttackType.valueOf(attackType));
    
            // Async Part
    //        CompletionStage completion = this.pokemonAttack.fireAsync(pa);
    //        completion.thenAccept(this::attackDone);
        }
    
        public void attackDone(PokemonAttack pa) {
            System.out.println("The attack has completed!: " + pa.getAttackName());
            getAsyncTextComp().setValue("The attack has completed!: " + pa.getAttackName());
            AdfFacesContext.getCurrentInstance().addPartialTarget(getAsyncPanelTextComp());
        }
    
        public PokemonAttack.AttackType[] getAttackTypes() {
            return PokemonAttack.AttackType.values();
        }
    
    //    public RichOutputText getAsyncTextComp() {
    //        System.out.println(asyncTextComp);
    //        if (asyncTextComp != null) {
    //            return (RichOutputText) asyncTextComp.getComponent();
    //        }
    //        return null;
    //    }
    //
    //    public void setAsyncTextComp(RichOutputText asyncTextComp) {
    //        this.asyncTextComp = ComponentReference.newUIComponentReference(asyncTextComp);
    //    }
    
        public void setAsyncPanelTextComp(RichPanelGroupLayout asyncPanelTextComp) {
            this.asyncPanelTextComp = asyncPanelTextComp;
        }
    
        public RichPanelGroupLayout getAsyncPanelTextComp() {
            return asyncPanelTextComp;
        }
        
        public void setAsyncTextComp(RichOutputText asyncTextComp) {
            this.asyncTextComp = asyncTextComp;
        }
    
        public RichOutputText getAsyncTextComp() {
            return asyncTextComp;
        }
    
    }
    

  • PokemonAttackListener.java:This is a Java Class centralize and implements the actions to be taken when a Pokemon Attack occurs. It implements the @Observe and @ObserveAsync methods which are fired when an event is produced in Pokemon.java.

    package com.magicpigeon.poc.view.cdi;
    
    import com.magicpigeon.poc.model.PokemonAttack;
    
    import java.util.concurrent.TimeUnit;
    
    import javax.enterprise.event.Observes;
    
    public class PokemonAttackListener {
        
        public PokemonAttackListener() {
            super();
        }
        
        public void onPokemonAttackSync(@Observes PokemonAttack at) {
            onPokemonAttack(at);
        }
        
    //    public void onPokemonAttackAsync(@ObservesAsync PokemonAttack at) {
    //        onPokemonAttack(at);
    //    }
        
        private void onPokemonAttack(PokemonAttack at) {
            long initTime = System.currentTimeMillis();
            System.out.println("A Pokemon Attack has been produced");
            try {
                TimeUnit.SECONDS.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            long finalTime = System.currentTimeMillis();
            long l = TimeUnit.MILLISECONDS.toSeconds(finalTime-initTime);
            System.out.println("Attack: " + at.getAttackName() + " of type: " + at.getAttackType().toString() + "Time: " + l);
        }
    }
    
Using Asynchronous you can make multiple operations concurrently without affecting the UI / UXX experience and notifying the user when something has been completed in the background.

Using Synchronous you can decouple some internal activities such as Extra Logging or make other logic on top of User Events.

I hope a future patch of Oracle WebLogic 12c+ makes it CDI 2.0 compatible as it can open a huge world of possibilities.

Comments

Popular posts from this blog

OJET: Inter-Module communication in TypeScript Template

OJET: Build and Deploy in an Application Server

OJET: Select All options using only Checkboxset