środa, 6 kwietnia 2011

Własny język wyrażeń (Expression Language) w JSF 2.0

Dzisiejszy wpis ma na celu pokazanie na przykładzie dwóch prostych przypadków, jak rozszerzyć istniejący język wyrażeń EL.

Przykład 1 – rozszerzenie języka wyrażeń

Załóżmy, że zaimplementowaliśmy własny mechanizm warunkowego renderowania komponentów JSF (w zależności od posiadanych przez użytkownika ról)
Wyrażenie #{userHasRole['EMPLOYEE, MANAGER']} powinno zwracać true lub false. Wymaga to utworzenia własnego mechanizmu przetwarzającego, który w pierwszym kroku zinterpretuje ciąg znaków userHasRole , a następnie ciąg 'EMPLOYEE, MANAGER'. Mechanizm ten to nic innego jak rozszerzenie klasy ELResolver , której najważniejszą dla nas jest metoda:

public Object getValue(ELContext context, Object base, Object property)

Poniżej kod własnego resolver'a
package kuba.demo.el;

import java.beans.FeatureDescriptor;
import java.util.Iterator;
import javax.el.ELContext;
import javax.el.ELResolver;
import kuba.demo.UserRolesController;

public class UserRolesResolver extends ELResolver{ 

    @Override
    public Object getValue(ELContext context, Object base, Object property) {

        // base=null  property=userHasRole

        if(base==null && "userHasRole".equals(property)){

            context.setPropertyResolved(true);

           return new UserRolesController();

        }

        // base=UserRolesController  property=EMPLOYEE, MANAGER

        if(base instanceof UserRolesController && property instanceof String){

            context.setPropertyResolved(true);

           return UserRolesController.checkUserAccess((String)property);

        }        

        return false;
    }
  

    @Override
    public Class getType(ELContext context, Object base, Object property) {



         if (base instanceof UserRolesController) {

            context.setPropertyResolved(true);

            return UserRolesController.class;

        }

      return null;

    }


    @Override
    public Class getCommonPropertyType(ELContext context, Object base) {

        if (base instanceof UserRolesController) {

            context.setPropertyResolved(true);

            return String.class;

        }

      return null;

    }


    @Override
    public boolean isReadOnly(ELContext context, Object base, Object property) {

        if (base instanceof UserRolesController) {

            context.setPropertyResolved(true);

            return true;
        }
      return false;
    }


    @Override
    public void setValue(ELContext context, Object base, Object property, Object value) {
    }


    @Override
    public Iterator getFeatureDescriptors(ELContext context, Object base) {
       return null;

    }
}

Ja, na potrzeby niniejszego przykładu, dodałem jeszcze klasę pomocniczą UserRolesController przechowującą i sprawdzającą role użytkownika
package kuba.demo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;

public class UserRolesController {

    public static boolean checkUserAccess(String roleNames) {

        List userRoles = new ArrayList(Arrays.asList("ADMIN",
                                                     "MANAGER",
                                                     "USER"
                                                    ));

        StringTokenizer token = new StringTokenizer(roleNames,",");
      
        while (token.hasMoreTokens()) {

            String roleName = ((String)token.nextElement()).trim();

            if(userRoles.contains(roleName)){

                return true;

            }
        }
        return false;
    }
}

Aby nasza klasa przetwarzająca EL była widoczna w aplikacji, musimy dodać następujący w pis w pliku faces-config.xml





Jest tutaj pewna niekonsekwencja twórców specyfikacji. Nie istnieje bowiem możliwość rejestracji własnego resolver'a przy pomocy odpowiedniej adnotacji – tak jak odbywa się to w przypadku innych elementów JSF 2.0.  

Przykład 2 – dodanie funkcji do języka wyrażeń

Załóżmy, że chcemy na tronie JSF wywołać przy pomocy EL własną funkcję przyjmującą dwa argumenty



W tym celu musimy zaimplementować statyczną metodę
package kuba.demo.el;

public class SumELFunction {

    public static int sumTwoArgs(int arg1, int arg2){
        return arg1 + arg2;
    }
}

oraz odwzorować ją w znajdującej się w katalogu WEB-INF bibliotece znaczników el.taglib.xml
















pozostaje jeszcze zarejestrować bibliotekę w pliku web.xml


Brak komentarzy:

Prześlij komentarz