Activité Pratique Programmation Orientée Aspect🎓💻

1.Présentation de l'activité pratique

Partie I (AspectJ)

  • On souhaite créer une application qui permet de gérer des comptes bancaires stockés en mémoire dans une collection de type Map. Chaque compte est défini par son code et son solde.
  • Les exigences fonctionnelle de l’application sont:
    • Ajouter un compte
    • Consulter un compte
    • Verser un montant dans un compte
    • Retirer un montant d’un compte
  • Les exigences techniques seront implémentées sous formes d’aspects suivants:
    • Un aspect pour la journalisation des appels de toutes les méthodes en affichant la durée d’exécution de chaque méthode
    • Un aspect pour contrôler le montant du retrait
    • Un aspect pour sécuriser l’application

Partie 2 (Spring AOP)

  • On souhaite créer une application qui offrent deux fonctionnalités métiers basiques:

    • Une opération process() permettant d’effectuer un traitement quelconque
    • Une opération permettant de retourner un résultat de calcul quelconque.
  • Nous définissons dans cette couche métier :

    • Une interface IMetier
    • Une implémentation de cette interface
  • Ensuite nous définissons deux aspects basés sur Spring AOP

    • Un Aspect pour la journalisation avec un annotation @Log qui permet de marquer dans la couche la méthode à journaliser
    • Un Aspect pour sécuriser l’application avec un authentification basique avec des rôles. Pour sécuriser l’accès à une méthode, nous définissons une annotation @SecuredByAspect(roles=["ADMIN","USER"]) qui sera placée sur les méthodes à sécuriser en spécifiant les rôles requis.

2.Architecture de l'activité pratique

Partie 1 (AspectJ):

Partie 2 (Spring AOP):

Partie 1: (AspectJ)

AspectJ

Entités et règles de gestion : 🏷️

  • Une entité "Compte"
public class Compte {
    private Long code;
    private double solde;

    public Compte(Long code, double solde) {
        this.code = code;
        this.solde = solde;
    }

    public Compte() {
    }

    public Long getCode() {
        return code;
    }

    public double getSolde() {
        return solde;
    }

    public void setCode(Long code) {
        this.code = code;
    }

    public void setSolde(double solde) {
        this.solde = solde;
    }

    @Override
    public String toString() {
        return "Compte{" +
                "code=" + code +
                ", solde=" + solde +
                '}';
    }
}

Interface "IMetier"

public interface IMetierBanque {
    void addCompte(Compte cp);
    void verser(Long code,double montant);
    void retirer(Long code,double montant);
    Compte consulter(Long code);
}

Implémentation de "IMetier"


public class MetierBanqueImpl implements IMetierBanque {
   private Map<Long,Compte> compteMap=new HashMap<>();

    @Override
    public void addCompte(Compte cp) {
        compteMap.put(cp.getCode(),cp);
    }

    @Override
    public void verser(Long code, double montant) {
        Compte compte=compteMap.get(code);
        compte.setSolde(compte.getSolde()+montant);
    }

    @Override
    public void retirer(Long code, double montant) {
        Compte compte=compteMap.get(code);
        compte.setSolde(compte.getSolde()-montant);

    }

    @Override
    public Compte consulter(Long code) {
        return compteMap.get(code);
    }
}

Aspect 1:

public aspect FirstAspect {

    //pointcut for the method "main" to be intercepted during execution
    pointcut pc1() : execution(* me..test.Application.main1(..));

    /*//before pointcut pc1 ==> code to be executed before the method "main" is executed ==> code advice
    before():pc1() {
        System.out.printf("--------------------------------------------------------");
        System.out.println("Before the main method from Aspect with AspectJ syntax");
        System.out.printf("--------------------------------------------------------");
    }

    //after pointcut pc1 ==> code to be executed after the method "main" is executed ==> code advice
    after():pc1() {
        System.out.printf("--------------------------------------------------------");
        System.out.println("After the main method from Aspect with AspectJ syntax");
        System.out.printf("--------------------------------------------------------");
    }*/

    void around():pc1(){
        System.out.println("------------------------------------------------");
        System.out.println("before main from aspectj with aspectj syntax");
        System.out.println("------------------------------------------------");

        //Execution de l'operation du pointcut
        //execution(* test.Application.main(..))
        proceed();
        System.out.println("------------------------------------------------");
        System.out.println("after main from aspectj with aspectj syntax");
        System.out.println("------------------------------------------------");

    }
}

Aspect 2

@Aspect
public class SecondAspect {
    @Pointcut("execution(* me..test.*.main1(..))")
    public void pc1(){ }

    //code advice

   /* @Before("pc1()")
    public void beforeMain(){

        System.out.println("----------****************--------------------------------------");
        System.out.println("before main from aspectj with class syntax");
        System.out.println("-----------*****************-------------------------------------");

    }
    @After("pc1()")
    public void afterMain(){

        System.out.println("----------****************--------------------------------------");
        System.out.println("after main from aspectj with class syntax");
        System.out.println("-----------*****************-------------------------------------");

    }*/

    @Around("pc1()")
    public void aroundMain(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("----------****************--------------------------------------");
        System.out.println("before main from aspectj with class syntax");
        System.out.println("-----------*****************-------------------------------------");
        //execute main
        proceedingJoinPoint.proceed();
        System.out.println("----------****************--------------------------------------");
        System.out.println("after main from aspectj with class syntax");
        System.out.println("-----------*****************-------------------------------------");

    }
}

Aspect de journalisation :

@Aspect
public class SecondAspect {
    @Pointcut("execution(* me..test.*.main1(..))")
    public void pc1(){ }

    //code advice

   /* @Before("pc1()")
    public void beforeMain(){

        System.out.println("----------****************--------------------------------------");
        System.out.println("before main from aspectj with class syntax");
        System.out.println("-----------*****************-------------------------------------");

    }
    @After("pc1()")
    public void afterMain(){

        System.out.println("----------****************--------------------------------------");
        System.out.println("after main from aspectj with class syntax");
        System.out.println("-----------*****************-------------------------------------");

    }*/

    @Around("pc1()")
    public void aroundMain(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("----------****************--------------------------------------");
        System.out.println("before main from aspectj with class syntax");
        System.out.println("-----------*****************-------------------------------------");
        //execute main
        proceedingJoinPoint.proceed();
        System.out.println("----------****************--------------------------------------");
        System.out.println("after main from aspectj with class syntax");
        System.out.println("-----------*****************-------------------------------------");

    }
}

Aspect de Retrait

@Aspect
public class PathRetraitAspect {

    //Pointcut => expression de point de coupage
    @Pointcut("execution(* me..metier.MetierBanqueImpl.retirer(..) )")
    public void pc1(){ }

    //code advice => around the  method retirer
    @Around("pc1() && args(code,montant)")
    public Object autourRetirer(Long code,double montant,ProceedingJoinPoint proceedingJoinPoint, JoinPoint joinPoint) throws Throwable {
        MetierBanqueImpl metierBanque=(MetierBanqueImpl) joinPoint.getTarget();
        Compte compte=metierBanque.consulter(code);
        if(compte.getSolde()<montant) throw new RuntimeException("solde insuffisant");
        return  proceedingJoinPoint.proceed();
    }
}

Aspect de sécurité

@Aspect
public class PathRetraitAspect {

    //Pointcut => expression de point de coupage
    @Pointcut("execution(* me..metier.MetierBanqueImpl.retirer(..) )")
    public void pc1(){ }

    //code advice => around the  method retirer
    @Around("pc1() && args(code,montant)")
    public Object autourRetirer(Long code,double montant,ProceedingJoinPoint proceedingJoinPoint, JoinPoint joinPoint) throws Throwable {
        MetierBanqueImpl metierBanque=(MetierBanqueImpl) joinPoint.getTarget();
        Compte compte=metierBanque.consulter(code);
        if(compte.getSolde()<montant) throw new RuntimeException("solde insuffisant");
        return  proceedingJoinPoint.proceed();
    }
}

Résultat:

Partie 2: (Spring AOP)

Spring AOP

Entités et règles de gestion : 🏷️

Interface IMetier


public interface IMetier {
    public void process();
    public double compute();
   // User saveUser(User user);
}

Implementation IMetier


@Service
public class IMetierImpl implements IMetier {
    @Override
    @Log
    @SecuredByAspect(roles={"USER","ADMIN"})
    public void process() {
        System.out.println("Processing...");
    }

    @Override
    @Log
    @SecuredByAspect(roles={"ADMIN"})
    public double compute() {
        double data = 80;
        System.out.println("Computing and Retirning Result");
        return data;
    }
}

Les aspects:

Aspect de journalisation 💯

annotation "Log"



@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {

}

@Component
@Aspect
@EnableAspectJAutoProxy
public class LogAspect {

    Logger logger = Logger.getLogger(LogAspect.class.getName());
    @Around("@annotation(me.elmajni.aspects.Log)")
    public Object log(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long t1 = System.currentTimeMillis();
        logger.info("From Logging Aspect ... Before "+proceedingJoinPoint.getSignature());

        Object result = proceedingJoinPoint.proceed();
        logger.info("From Logging Aspect ... After "+proceedingJoinPoint.getSignature());
        long t2 = System.currentTimeMillis();
        logger.info("Duration : "+(t2-t1));
        return result;
    }
}

Aspect de Sécurité 💯

Annotation "SecuredByAspect"

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SecuredByAspect {
    String[] roles();
}

Contexte de sécurité:


public class SecurityContext {
    private static String username="";
    private static String password="";
    private static String[] roles={};


    public static void authenticate(String u, String p, String[] r){
        if (u.equals("root") && p.equals("123")){
            username=u;
            password=p;
            roles=r;
        }else {
            throw new RuntimeException("Access denied");
        }
    }

    public static boolean hasRole(String r){
        for (String role: roles){
            if (role.equals(r))
                return true;
        }
        return false;
    }
}

Classe "User"

public class User {
    private Long id;
    private String username;
    private String cin;
}

Aspect d'Authorisation


@Component
@Aspect
@EnableAspectJAutoProxy
public class AuthorizationAspect {
    @Around(value = "@annotation(securedByAspect)", argNames = "pjp,securedByAspect")
    public Object secure(ProceedingJoinPoint pjp, SecuredByAspect securedByAspect) throws Throwable {
        String[] roles= securedByAspect.roles();
        boolean authorized=false;
        for (String r:roles) {
            if (SecurityContext.hasRole(r)){
                authorized=true;
                break;
            }
        }
        if (authorized==true){
            Object result = pjp.proceed();
            return result;
        }
        throw new RuntimeException("403 Unauthorized to acces to !"+pjp.getSignature());
    }
}

Application

@ComponentScan(value = {"me.elmajni"})
public class Application {
    public static void main(String[] args) {

        try {
            SecurityContext.authenticate("root","123",new String[]{"USER","ADMIN"});
            //SecurityContext.authenticate("rot","123",new String[]{"USER","ADMIN"});
            //SecurityContext.authenticate("root","123",new String[]{"USER"});

            ApplicationContext applicationContext = new AnnotationConfigApplicationContext(Application.class);
            IMetier metier = applicationContext.getBean(IMetier.class);
            System.out.println("*******************");
            System.out.println(metier.getClass().getName());
            System.out.println("*******************");

            metier.process();
            System.out.println(metier.compute());
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
    }

   // @Configuration
    //@ComponentScan(value = {"me.elmajni"})
    public class MyConfig{

    }
}

Résultat:

3.Les Technologies utilisées

1.Spring Core

  • * Core (spring-core) est le cœur du framework qui alimente des fonctionnalités telles que l'inversion de contrôle et l'injection de dépendances.

voir également à propos Spring Core🔗

1.Spring Context

  • * Les contextes Spring sont également appelés conteneurs Spring IoC, qui sont responsables de l'instanciation, de la configuration et de l'assemblage des beans en lisant les métadonnées de configuration à partir des annotations XML, Java et/ou du code Java dans les fichiers de configuration.

voir également à propos Spring Context🔗

1.Spring Context

  • * Dans Spring AOP, les aspects sont implémentés à l'aide de classes régulières (l'approche basée sur un schéma) ou de classes régulières annotées avec l'annotation @Aspect.

voir également à propos Spring Aspects🔗

Created by :[name=ELMAJNI KHAOULA] [time=Mon,2022,11,01][color=#EF0101] voir également à propos de moi ELMAJNI Khaoula