Wednesday, April 5, 2017

AspectJ: Around Advice to change value of method arguments

This is a short tutorial that explains how to write an advice to change value of method arguments.

I have implemented a MutateArgsAspect which is applied on methods annotated with @MutateArgs

The advice converts the string argument passed to the annotated method from "BEFORE" to "AFTER"

Steps 1: Implement the annotation

-------------------------------------
package com.waseem.foundation;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;

@Retention(RUNTIME)
public @interface MutateArgs {


}
-------------------------------------

Steps 2: Implement the Aspect

-------------------------------------
package com.waseem.foundation;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class MutateArgsAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(MutateArgsAspect.class);
@Around("@annotation(MutateArgs) && execution(* *(..))")
public Object before(ProceedingJoinPoint pjp) throws Throwable {
LOGGER.debug(pjp.getSignature().toLongString());
   
Object[] args = pjp.getArgs();
   
for (int i = 0; i < args.length; i++) {
        if ("BEFORE".equals(args[i])) {
        LOGGER.info("args[{}] : {}", i, args[i]);
       
            args[i] = "AFTER";
        }
    }
    Object output = pjp.proceed(args);
return output;
}
}

Note the @Around annotation. 

1- @annotation(MutateArgs) means the Aspect is applied on all the methods annotated with MutateArgs annotation

2- execution(* *(..)) means the execution of any method regardless of return or parameter types

-------------------------------------

Step 3: Apply annotation on the methods for the Advice to work.

Here is an example where this annotation is applied on an API method

@GET
@Path("/mutateInController")
@Produces(MediaType.APPLICATION_JSON)
@MutateArgs
public Response mutateArgsOfThisMethod(@QueryParam("name")  String name) {
LOGGER.info("Name in Controller : {}", name);
return Response.ok(name).build();
}

Here is another example were this annotation is applied on another simple method

@MutateArgs
public String mutateArgsOfThisMethod(String name) {
LOGGER.info("Name in Manager : {}", name);
return name;
}

Tuesday, January 10, 2017

Remove _class from Mongo documents - Spring Data MongoDB

Spring Data MongoDB adds _class in the mongo documents to handle polymorphic behavior of java inheritance. If you want to remove _class just drop following Config class in your code.


package com.waseem.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.convert.DbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultDbRefResolver;
import org.springframework.data.mongodb.core.convert.DefaultMongoTypeMapper;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;

@Configuration
public class MongoConfig {

@Autowired MongoDbFactory mongoDbFactory;
@Autowired MongoMappingContext mongoMappingContext;
@Bean
public MappingMongoConverter mappingMongoConverter() {

DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory);
MappingMongoConverter converter = new MappingMongoConverter(dbRefResolver, mongoMappingContext);
converter.setTypeMapper(new DefaultMongoTypeMapper(null));

return converter;
}
}

Wednesday, August 19, 2015

Create a Signing Authority and generate Self Signed Certificates

Create a Signing Authority

mkdir -p /etc/psc/CA
cd /etc/psc/CA
mkdir -p certs private
chmod 700 private
echo 01 > serial
touch index.txt

Create a file openssl.cnf in the /etc/psc/CA directory

vim openssl.cnf

Copy following text inside this conf file (Copy the text b/w the line. Don’t copy lines)

——————————————————————————————————————————————————————
[ ca ]
default_ca = OrchCA

[ OrchCA ]
dir = /etc/psc/CA
certificate = $dir/cacert.pem
database = $dir/index.txt
new_certs_dir = $dir/certs
private_key = $dir/private/cakey.pem
serial = $dir/serial

default_crl_days = 30
default_days = 1825
default_md = sha256

policy = OrchCA_policy
x509_extensions = certificate_extensions

[ OrchCA_policy ]
commonName = supplied
stateOrProvinceName = optional
countryName = optional
emailAddress = optional
organizationName = optional
organizationalUnitName = optional

[ certificate_extensions ]
basicConstraints = CA:false

[ req ]
default_bits = 2048
default_keyfile = /etc/psc/CA/private/cakey.pem
default_md = sha256
prompt = yes
distinguished_name = root_ca_distinguished_name
x509_extensions = root_ca_extensions

[ root_ca_distinguished_name ]
commonName = hostname

[ root_ca_extensions ]
basicConstraints = CA:true
keyUsage = keyCertSign, cRLSign

[ client_ca_extensions ]
basicConstraints = CA:false
keyUsage = digitalSignature
extendedKeyUsage = 1.3.6.1.5.5.7.3.2

[ server_ca_extensions ]
basicConstraints = CA:false
keyUsage = keyEncipherment
extendedKeyUsage = 1.3.6.1.5.5.7.3.1
——————————————————————————————————————————————————————


Generate RSA Key and Certificate for our Certificate Authority

openssl req -x509 -config /etc/psc/CA/openssl.cnf -newkey rsa:2048 -days 365 -out /etc/psc/CA/cacert.pem -outform PEM -subj /CN=OrchCA/ -nodes

openssl x509 -in /etc/psc/CA/cacert.pem -out /etc/psc/CA/cacert.cer -outform DER


Root certificate (PEM format) = cacert.pem
Root certificate (DER format) = cacert.pem
Certificate Authority Key = /etc/psc/CA/private/cakey.pem


Generate Certificate and Key for the Server


cd /etc/psc/
mkdir server
cd server

openssl genrsa -out key.pem 2048

openssl req -new -key key.pem -out req.pem -outform PEM -subj /CN=$(hostname)/O=server/ -nodes

cd ../CA

openssl ca -config openssl.cnf -in ../server/req.pem -out ../server/cert.pem -notext -batch -extensions server_ca_extensions

cd ../server

openssl pkcs12 -export -out keycert.p12 -in cert.pem -inkey key.pem -passout pass:MySecretPassword


Generate Certificate and Key for the Client

cd /etc/psc/
mkdir client
cd client

openssl genrsa -out key.pem 2048

openssl req -new -key key.pem -out req.pem -outform PEM -subj /CN=$(hostname)/O=client/ -nodes

cd ../CA

openssl ca -config openssl.cnf -in ../client/req.pem -out ../client/cert.pem -notext -batch -extensions client_ca_extensions

cd ../client

openssl pkcs12 -export -out keycert.p12 -in cert.pem -inkey key.pem -passout pass:MySecretPassword

Monday, May 5, 2014

Spring form tag : ModelAttribute VS CommandName

Take a look at the source code of FormTag below

/**
 * Set the name of the form attribute in the model.
 * <p>May be a runtime expression.
 */
public void setModelAttribute(String modelAttribute) {
    this.modelAttribute = modelAttribute;
}

/**
 * Get the name of the form attribute in the model.
 */
protected String getModelAttribute() {
    return this.modelAttribute;
}

 
/**
 * Set the name of the form attribute in the model.
 * <p>May be a runtime expression.
 * @see #setModelAttribute
 */
public void setCommandName(String commandName) {
    this.modelAttribute = commandName;
}

/**
 * Get the name of the form attribute in the model.
 * @see #getModelAttribute
 */
protected String getCommandName() {
    return this.modelAttribute;
}

 
The code from form tag shows that they are both referring to the same field/property.

Thursday, May 1, 2014

Setting up logging in Spring based project

Jakarta Commons Logging API (JCL) is the only mandatory external dependency in spring framework.  Spring framework is compiled against Jakarta Commons Logging (JCL). If you are using Maven for example for your spring based project, and wondering where you picked up the dependency on commons-logging, then it is from Spring and specifically from the central module called spring-core. 

Image

Spring documentation says 
Unfortunately, the runtime discovery algorithm in commons-logging, while convenient for the end-user, is problematic.  
If we could turn back the clock and start Spring now as a new project it would use a different logging dependency. The first choice would probably be the Simple Logging Facade for Java (SLF4J) 

Switching off commons-logging  

In this blog I will explain how to switch off commons-logging and use sl4j for logging. 
 Switching off commons-logging is easy. In Maven terms you exclude the dependency 

<dependency> 
<groupId>org.springframework</groupId> 
<artifactId>spring-context</artifactId> 
<version>${spring-framework.version}</version> 
<exclusions> 
<exclusion> 
<groupId>commons-logging</groupId> 
<artifactId>commons-logging</artifactId> 
</exclusion> 
</exclusions> 
</dependency> 

SLF4J is a cleaner dependency and more efficient at runtime than commons-logging because it uses compile-time bindings instead of runtime discovery of the other logging frameworks it integrates. 
SLF4J provides bindings to many common logging frameworks, so you can usually choose one that you already use, and bind to that for configuration and management. 

Adding SLF4J-JCL bridge dependency 

In order to use SLF4J with Spring you need to add the SLF4J-JCL bridge dependency. 

<dependency> 
<groupId>org.slf4j</groupId> 
<artifactId>jcl-over-slf4j</artifactId> 
<version>${slf4j.version}</version> 
<scope>runtime</scope> 
</dependency> 

Once you have done that then logging calls from within Spring will be translated into logging calls to the SLF4J API 

SLF4J to Logback Binding 


Next step is to provide explicit binding from SLF4J to Logback 
Logback is intended as a successor to the popular log4j project and logback-classic natively implements the SLF4J API 
Add following dependencies to do the SLF4J to Logback binding 

<dependency> 
<groupId>org.slf4j</groupId> 
<artifactId>slf4j-api</artifactId> 
<version>${slf4j.version}</version> 
<scope>compile</scope> 
</dependency> 
<dependency> 
<groupId>ch.qos.logback</groupId> 
<artifactId>logback-classic</artifactId> 
<version>${logback.version}</version> 
<scope>runtime</scope> 
</dependency> 

Logback configuration 


Last step is to drop a logback.xml in your projects src/main/resources folder. 
Add following xml in the logback.xml and then edit it to your need 

<?xml version="1.0" encoding="UTF-8"?> 
<!-- configuration file for LogBack (slf4J implementation) 
<configuration scan="true" scanPeriod="30 seconds">  
    <contextListener class="ch.qos.logback.classic.jul.LevelChangePropagator"> 
        <resetJUL>true</resetJUL> 
    </contextListener>  
    <!-- To enable JMX Management --> 
    <jmxConfigurator/>  
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender"> 
        <encoder> 
            <pattern>%-5level %logger{0} - %msg%n</pattern> 
        </encoder> 
    </appender>  
  <!--<logger name="org.hibernate" level="debug"/> --> 
   <!-- Uncomment and add your logger here: 
    <logger name="org.springframework.samples.service.service" level="debug"/> --> 
    <logger name="org.springframework" level="debug"/> 
          
    <root level="debug"> 
        <appender-ref ref="console"/> 
    </root> 
</configuration> 
  

To Use Log4J instead Logback 

If you want to use Log4j then add following 4 dependencies 

<dependency> 
 <groupId>org.slf4j</groupId> 
 <artifactId>jcl-over-slf4j</artifactId> 
 <version>1.5.8</version> 
 <scope>runtime</scope> 
</dependency> 
<dependency> 
 <groupId>org.slf4j</groupId> 
 <artifactId>slf4j-api</artifactId> 
 <version>1.5.8</version> 
 <scope>runtime</scope> 
</dependency> 
<dependency> 
 <groupId>org.slf4j</groupId> 
 <artifactId>slf4j-log4j12</artifactId> 
 <version>1.5.8</version> 
 <scope>runtime</scope> 
</dependency> 
<dependency> 
 <groupId>log4j</groupId> 
 <artifactId>log4j</artifactId> 
 <version>1.2.14</version> 
 <scope>runtime</scope> 
</dependency> 

and the log4j.xml on your projects classpath