Question

I want to increase my knowledge of AOP which isn't great at the moment. I have the following program. In main, I'm creating some User objects and printing out their username. Just before creating the user, I have a security aspect which runs and prints out an error if it finds a hazardous word (checking for SQL injection). It works, but it always creates the user and prints out the username, even if security finds an error.

Security check returns a boolean. Is it possible to only run the rest if check returns true? To do so, I'd need to access the return value of the advice. Or would it need to be done with more AOP and after-returning? If so, could someone explain how? I only know how to use before and after at the moment.

Thanks for any help. Below is my code:

public class App 
{
    public static void main( String[] args ){

        ApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
        List<String> names = new ArrayList<String>();
        List<User> users = new ArrayList<User>();

        names.add("Chris");
        names.add("Dave");
        names.add(";DROP table");
        names.add("Bob");

        User user = null;
        for(String name : names){
            user = context.getBean("user", User.class);
            user.setUsername(name);
            users.add(user);
        }
        for(User u : users){
            System.out.println(u.getUsername());
        }   
    }
}

Here is Security:

public class Security {

    private List<String> words = new ArrayList<String>();

    {
        words.add("drop");
        words.add("delete");
        words.add("truncate");
        words.add("remove");
    }

    public boolean check(String input){
        for(String word: words){
            if(input.toLowerCase().contains(word)){
                System.err.println("Unsafe word " + word + " found!!!!!");
                return false;
            }
        }
        return true;
    }
}

And here is what I have in context.xml

<bean id="user" class="com.company.springAOPExample.User" scope="prototype" />
<bean id="security" class="com.company.springAOPExample.Security" />

<aop:config>
    <aop:aspect ref="security">
        <aop:pointcut id="setUsername" expression="execution(* com.company.springAOPExample.User.setUsername(java.lang.String)) and args(username)" />
        <aop:before pointcut-ref="setUsername" method="check" arg-names="username" />
    </aop:aspect>
</aop:config>
Was it helpful?

Solution

first I think you have to add AOP on users.add(user); not user.setUsername(name); then You need to use "Around advice" and call proceed in case of true or not call it in case of false as:

public class Security {

    private List<String> words = new ArrayList<String>();

    {
        words.add("drop");
        words.add("delete");
        words.add("truncate");
        words.add("remove");
    }

    public Void check(User user, ProceedingJoinPoint pjp){
        for(String word: words){
            if(!user.getUsername().toLowerCase().contains(word)){
                return pjp.proceed();
            }
            return;
        }

    }
}

OTHER TIPS

Okay, I've solved it, thanks to the previous answer pointing me towards 'around' and also to this tutorial which was really useful (http://www.compiletimeerror.com/2013/05/spring-aop-around-advice-example.html#.UzMAJvkRAmM). Here is the main method:

public static void main( String[] args ){
    ApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
    List<String> names = new ArrayList<String>();
    List<User> users = new ArrayList<User>();

    names.add("Chris");
    names.add("Dave");
    names.add(";DROP table");
    names.add("Bob");

    User user = null;

    for(String name : names){
        user = context.getBean("user", User.class);
        user.setUsername(name);

        if(user.getUsername()!=null){
            users.add(user);
        }           
    }

    for(User u : users){
        System.out.println(u.getUsername());
    }   
}

Here is the check method in Security:

public void check(ProceedingJoinPoint pjp) throws Throwable {
    boolean match = false; 
    Object o[] = pjp.getArgs();

    for(String word: words){
        if(o[0].toString().toLowerCase().contains(word)){
            System.err.println("Unsafe word " + word + " found!!!!!");
            match = true;
        }
    }

    if(!match){
        pjp.proceed();
        return;
    }
}

And here is the context.xml:

<bean id="user" class="com.company.springAOPExample.User" scope="prototype" />
<bean id="security" class="com.company.springAOPExample.Security" />


<aop:config>
    <aop:aspect ref="security">
        <aop:pointcut id="setUsername" expression="execution(* com.company.springAOPExample.User.setUsername(java.lang.String))" />
        <aop:around pointcut-ref="setUsername" method="check" />
    </aop:aspect>
</aop:config>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top