Author Archives: chw

Testing Spring Controllers with Spring Security, Embedded LDAP, and Different Application Contexts

To test a secured Spring application with Spring Security and LDAP authentication, we need to take the following steps:

  1. Activate and configure your embedded LDAP server for your tests.
  2. Define users and roles of your choice for your embedded LDAP server.
  3. Write Spring Tests.

Activate and configure your embedded LDAP server

There are at least the two following possibilities to start an embedded LDAP server with Spring:

  1. With Spring Boot
  2. With Spring Security

With Spring Boot

Spring Boot starts for each application context an embedded LDAP server automatically if Spring Boot finds an LDAP server implementation in the classpath and you declare some configuration properties in the application.properties. For the LDAP server implementation called unboundid, you need to declare at least the following properties:

spring.ldap.embedded.ldif=classpath:bootstrap.ldif
spring.ldap.embedded.base-dn=dc=springframework,dc=org

# Further properties are:
spring.ldap.embedded.port
spring.ldap.embedded.validation.enabled
spring.ldap.embedded.credential.username
spring.ldap.embedded.credential.password
spring.ldap.embedded.ur

As highlighted above, Spring Boot starts an embedded LDAP server for each application context. Logically, that means, it starts an embedded LDAP server for each test class. Practically, this is not always true since Spring Boot caches and reuses application contexts. However, you should always expect that there is more than one LDAP server running while executing your tests. For this reason, you may not declare a port for your LDAP server. In this way, it will automatically uses a free port. Otherwise, your tests will fail with “Address already in use”.

With Spring Security

If you want to use – for your tests – an embedded LDAP server as your central authentication management system with Spring Security, then you need to configure Spring Security as follows. Tip: Use two Spring Security configuration classes: one in your src/main/java and one in your src/test/java. The one in src/main/java could simply connect to an existing, non-embedded LDAP server. The one in src/test/java starts one embedded LDAP server for each new test context.

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecurityTestConfiguration extends WebSecurityConfigurerAdapter {

	private static final Logger LOGGER = LoggerFactory.getLogger(SecurityTestConfiguration.class);

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
		// @formatter:off
		auth.ldapAuthentication()
			.userDnPatterns("uid={0},ou=people")
			.groupSearchBase("ou=groups")
			.contextSource()	// starts an LDAP server if url is not provided
				.ldif("classpath:bootstrap-spring-security.ldif")
				.root("dc=springframework,dc=org")
				// automatically adds the entry indicated by .root()
				.and()
			.passwordCompare()
				.passwordEncoder(passwordEncoder)
				.passwordAttribute("userPassword")
			.and();
		// @formatter:on
		LOGGER.info("Security configuration loaded.");
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// @formatter:off
		http.sessionManagement()
			.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
			.and();
		http.authorizeRequests()
			.anyRequest().authenticated()
			.and()
		.httpBasic();
		// @formatter:on
	}
}

If you do not declare a URL, but an LDIF file path instead, then Spring Security starts an embedded LDAP server automatically – again – for each application context.

One very important difference to Spring Boot is that the root entry is automatically created by Spring Security! So, your LDIF file must not contain the root entry. Otherwise, your application or your tests will fail with “An entry with DN ‘<dn of your root entry>’ already exists in the server.” We highlight this critical root entry in the next section.

Define users and roles of your choice for your embedded LDAP server

Below, you find an example LDIF file. The first entry is the root entry whose dn has to be used as value for the property spring.ldap.embedded.base-dn or, respectively, as argument for the method root(). Note that Spring Security automatically adds the root entry to the LDAP server. Hence, your LDIF file may not contain the root entry.

dn: dc=springframework,dc=org
objectclass: top
objectclass: domain
objectclass: extensibleObject
dc: springframework

dn: ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: groups

dn: ou=subgroups,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: subgroups

dn: ou=people,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: people

dn: ou=space cadets,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: space cadets

dn: ou=\"quoted people\",dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: "quoted people"

dn: ou=otherpeople,dc=springframework,dc=org
objectclass: top
objectclass: organizationalUnit
ou: otherpeople

dn: uid=ben,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Ben Alex
sn: Alex
uid: ben
userPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=

dn: uid=bob,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Bob Hamilton
sn: Hamilton
uid: bob
userPassword: {noop}bobspassword

dn: uid=joe,ou=otherpeople,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Joe Smeth
sn: Smeth
uid: joe
userPassword: joespassword

dn: cn=mouse\, jerry,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Mouse, Jerry
sn: Mouse
uid: jerry
userPassword: jerryspassword

dn: cn=slash/guy,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: slash/guy
sn: Slash
uid: slashguy
userPassword: slashguyspassword

dn: cn=quote\"guy,ou=\"quoted people\",dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: quote\"guy
sn: Quote
uid: quoteguy
userPassword: quoteguyspassword

dn: uid=space cadet,ou=space cadets,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Space Cadet
sn: Cadet
uid: space cadet
userPassword: spacecadetspassword

dn: cn=developers,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfUniqueNames
cn: developers
ou: developer
uniqueMember: uid=ben,ou=people,dc=springframework,dc=org
uniqueMember: uid=bob,ou=people,dc=springframework,dc=org

dn: cn=managers,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfUniqueNames
cn: managers
ou: manager
uniqueMember: uid=ben,ou=people,dc=springframework,dc=org
uniqueMember: cn=mouse\, jerry,ou=people,dc=springframework,dc=org

dn: cn=submanagers,ou=subgroups,ou=groups,dc=springframework,dc=org
objectclass: top
objectclass: groupOfUniqueNames
cn: submanagers
ou: submanager
uniqueMember: uid=ben,ou=people,dc=springframework,dc=org

Write Spring Tests

And here are two example tests which tests the same thing but each with a different application context (see the different class annotations). As you will notice in the console output, two LDAP servers with different ports will be started and the tests will pass.

import static org.hamcrest.Matchers.*;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class HelloController1Test {

	@Autowired
	private MockMvc mvc;

	@Test
	public void getHelloWithValidLogin() throws Exception {
		// @formatter:off
		mvc.perform(get("/").with(httpBasic("bob", "bobspassword")).with(csrf()))
			.andExpect(status().isOk())
			.andExpect(content().string(equalTo("Greetings from Spring Boot!")));
		// @formatter:on
	}

	@Test
	public void getHelloWithInvalidPassword() throws Exception {
		MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/")
				.accept(MediaType.APPLICATION_JSON);

		mvc.perform(requestBuilder.with(httpBasic("bob", "wrong password"))).andExpect(status().isUnauthorized());
	}
}
import static org.hamcrest.Matchers.*;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.ldap.AutoConfigureDataLdap;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;

import chw.tutorial.springboot.SecurityTestConfiguration;

@RunWith(SpringRunner.class)
@WebMvcTest(value = HelloController.class)
@Import(SecurityTestConfiguration.class)
@AutoConfigureDataLdap
public class HelloController3Test {

	@Autowired
	private MockMvc mvc;

	@Test
	public void getHelloWithValidLogin() throws Exception {
		// @formatter:off
		mvc.perform(get("/").with(httpBasic("bob", "bobspassword")).with(csrf()))
			.andExpect(status().isOk())
			.andExpect(content().string(equalTo("Greetings from Spring Boot!")));
		// @formatter:on
	}

	@Test
	public void getHelloWithInvalidPassword() throws Exception {
		MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/")
				.accept(MediaType.APPLICATION_JSON);

		mvc.perform(requestBuilder.with(httpBasic("bob", "wrong password"))).andExpect(status().isUnauthorized());
	}
}

Pitfalls

As described above, you may get one of the following error messages if you have not correctly configured your embedded LDAP server. In this blog post, we explained why these errors occur and gave appropriate solutions.

  1. “Address already in use: NET_bind”
  2. “com.unboundid.ldap.sdk.LDAPException: An entry with DN ‘dc=springframework,dc=org’ already exists in the server.”

Scheduling Tasks/Jobs with Spring (Boot)

Static Scheduling

Spring offers the annotation @Scheduled to define a task and its corresponding scheduling, e.g., execute this method every 5 minutes. The annotation saves you a great deal of work: in the background, it creates or looks up a scheduler, creates a task which invokes your method, and passes the task to the scheduler with your scheduling arguments (here: every 5 minutes).

Scheduling Parameters

The annotation @Scheduled allows to specify a fixed delay (in ms), a fixed rate (in ms), or a more flexible cron expression if the first two options are not expressive enough for your use case. The following code snippet shows an implementation of our “every 5 seconds”-example from above:

@Component // or any subtype like @Service
public class AnyComponent {

    private static final Logger log = LoggerFactory.getLogger(AnyComponent.class);

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

    @Scheduled(fixedRate = 5000)
    public void reportCurrentTime() { // visibility is irrelevant: even private is possible
        log.info("The time is now {}", dateFormat.format(new Date()));
    }
}
Task Method Requirements

The method, which is annotated with @Scheduled, must fulfill the following requirements:

  • The enclosing class of the method must be a Spring component. That is, the class must be annotated with the annotation @Component or an annotation which includes @Component like @Service, for example.
  • The method must be void.
  • The method must have no parameters.
  • The method may be private.
Read Parameter Values from a Properties File

If you do not want to specify the delay or the rate directly in the code, you can read it from the configuration context. For this purpose, Spring provides the parameters fixedDelayString and fixedRateString. The following example reads the seconds of the delay from the configuration key my.property.fixed.delay.seconds. If the value is not available or invalid, a default value of 60 is used. Since the delay expects a value in milliseconds, 000 is appended to the read value.

// with a default value of 60
@Scheduled(fixedDelayString = "${my.property.fixed.delay.seconds:60}000")

Further examples:

// without a default value
@Scheduled(fixedDelayString = "${my.property.fixed.delay.seconds}000")
// without appending
@Scheduled(fixedDelayString = "${my.property.fixed.delay.milliseconds}")
// hard-coded value as string (not recommended due to missing static type checking)
@Scheduled(fixedDelayString = "7000")

With these *String variants, you can define the delay or, respectively, the rate from aproperties file. Note that the value is read only once at startup time. Thus, this approach is still static. You cannot change the value at runtime. We refer to the Javadoc of @Scheduled for more detailed information on the parameters.

Dynamic Scheduling

If you need to read your scheduling arguments dynamically, that is, at runtime, then you @Scheduled is not sufficient. Instead, your can use Spring’s interface TaskScheduler. Declare a field with this type and annotate it with Spring’s @Autowired annotation. Then, you can pass a dynamically created task to the scheduler and specify whether it should be executed once or repeatable with a fixed delay or at a fixed rate. We refer to the documentation of the TaskScheduler for more information.

Sources

Pitfalls with “Convention over Configuration”

The paradigm Convention over Configuration is a great way to develop software (web) application. I like it…IFF it is implemented well.

Problem

Unfortunately, many frameworks which rely on this paradigm are hard to work with. One example is Spring Boot. Users who are new to Spring Boot must read many pages of documentation to learn the “sensible defaults”. These defaults are often not intutive to new users because the users do not yet know the underlying concepts for which the defaults are ment to be. Hence, the first steps with Spring Boot take time – more time than necessary.

Moreover, the defaults seem to work in a magical way – just by putting some new annotations at a class or a method. The javadoc often does not explain how the annotations work. It’s so easy to add a short text that describes that Spring searches the classpath for annotations.

Furthermore, annotations can also cause incompatibility issues with other annotations and conventions. For example, the annotation @DataJpaTest disables full auto-configuration such that you wonder why auto-wiring is not working anymore. Although the javadoc mentions this issue, it is unnecessarily complicated. I wish that adding annotations only adds behavior.

Finally, you can often do one thing in more than one way. Usually, basic annotations are provided which are used by aggregated annotations to cover recurring use cases. This approach often results in annotated classes which have several basic annotations twice or thrice. Although this approach does not influence the functionality, it is really confusing for (new) users who need to write some piece of code: when should I use which (aggregated) annotations? Users who read the code could ask themselves: why did the author of this code add these annotations more than once?

Proposed Solution

  1. Uncover all conventions, e.g., by a configuration file with default values, such that the conventions are visible for (new) users. In this way, the user can read through the config file and learn what features and conventions are provided by the framework. We follow this approach with our framework Kieker.
  2. Each annotation should explain how it is processed. If you have a bunch of similar annotations, either copy and paste the same text or add a javadoc link to the processing engine where the approach is described once at a central place.
  3. Let annotations only add new behavior. Let them not disable other features.
  4. Only provide one way to do something to reduce confusion and time to read/understand. When the (new) user has several possibilities to do the same thing, it is laborious to understand when to use which approach. If there is no other choice, provide at least recommendations when to use which approach.

How to write a Software Architecture Chapter?

If you need to document your planned or existing software architecture, it’s often difficult to know where to start. And even if you have thought about it some time, you probably don’t know how to structure your text so that a novice reader is able to follow you.

There are a few books out there whose autors describe very well how to write such software architecture desciptions. For example, have a look at “Softwarearchitekturen dokumentieren und kommunizieren” (ISBN-10: 3446443487). They explain in detail which contents are required in which order. However, who has time to read these books and find the relevant paragraphs?

For this reason, I put together the most important parts below. Of course, this overview is from my point of view. Nevertheless, it should give you a faster introduction to this topic compared to finding and reading the relevant paragraphs of interest in a book of many hundreds of pages.

I like templates (but not in the form of cooking or baking recipe). Templates ease the start of writing. They give you a predefined structure that you could easily follow. In this way, you know what to write and in which order. So, here is my template for describing an arbitrary software architecture:

Introduction (without a section title)

  1. Introduce the domain of application of your architecture so that the reader knows what he or she should expect from your description. Otherwise, if you do not give context, the reader might expect everything, but probably not what you want him or her to tell.
  2. One sentence about the content of each following subsection so that the reader knows what you will describe in which order.

Architectural Drivers

  1. Requirements on your architecture, including corresponding justifications
    1. Use phrases like
      • “we expect from your architecture …” or
      • “our architecture must be able to …” or
      • “our architecture should …”
  2. Constraints of your architecture, including corresponding justifications
    1. Your software architecture will not represent the one-and-only architecture which matches to all of the problems in the world. Hence, you should name the constraints of your architecture.

Components of your Architecture

  1. Describe each component in a separate section
    1. Give it a name
    2. Describe what the component represents (and, if useful, what it does intentionally not represent)
    3. Describe the structure of your component, including corresponding justifications
    4. Describe the responsibilities of your component, that means, what are the specific tasks of the component, including corresponding justifications
    5. Describe what tasks are intentionally not part of the component

Progress Monitoring of Loops

When coding a loop, we often insert some logging code for debugging or progress monitoring purposes. The following code snippet shows an example:

for (int i = 0; i < invocations.size(); i++) {
  // loop body begin
  ...
  // loop body end
  System.out.println("current index: "+i); // pure java
  currentTimeInMs = ...;
  if (currentTimeInMs % 1000 == 0) {  // log every econd
    logger.debug("current index: {}", i);    // slf4j
  }
}

Disadvantages of the Naive Approach

However, this approach has some disadvantages. First, the logging code is executed by the same thread which executes the loop body. If the logging code causes an exception, for example, due to a NullPointerException, the execution of the loop body is interrupted. Thus, the execution of the application can break because of some fault in the logging code.

Moreover, the executing thread is thwarted by the addtional logging code. Remember that executing I/O operations, like printing to the console or to a file, is slower by several orders of magnitude. Especially for performance critical code regions, this approach is not recommended.

Finally, the logging code is executed in each and every iteration of the loop although it is often sufficient to log the loop’s state every second or every minute. If you now think of a solution similar to the one shown above in Line 5, then remember that this additional if statement causes even more runtime overhead and further increases the potential for errors.

A Better Approach

A less intrusive, less error-prone, and faster approach is the following. First, we declare a volatile field progressIndex which represents the current index of the loop we want to monitor. For this purpose, we update the value of this field as shown in the following code snippet. We do not insert our original logging code here.

for (int i = 0; i < invocations.size(); i++) {
    progressIndex = i;
    // loop body
}

Instead, we create an additional thread which executes our logging code now. This thread performs a do-while loop as shown in the following code snippet from Line 7 to Line 28. We use `Thread.sleep()` to implement a user-defined time interval (here: 1000 ms). The thread reads the current index of the loop under monitoring indicated by the variable progressIndex in Line 13. As we declared it as volatile, it is synchronized between our new monitoring thread and the application thread(s). We cache the progressIndex as local variable, since the value of this variable can change on each subsequent read-access. In this way, the value is consistent within an iteration of the do-while loop.

To avoid interfering with the application, we declare our new monitoring thread as a deamon. In this way, the thread is automatically terminated by the JVM when all application threads have terminated.

The rest of theĀ do-while loop computes the remaining execution time of the application and executes the domain-specific logging code. In this example, we print out the current number of NoSql queries which were already executed by the application loop.

Thread progressMonitoringThread = new Thread(new Runnable() {
    @Override
    public void run() {
        long lastTimestamp = System.currentTimeMillis();
        int lastProgressIndex = progressIndex;
        
        do {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
            final int localProgressIndex = progressIndex;
            
            long currentTimestamp = System.currentTimeMillis();
            long durationInMs = currentTimestamp - lastTimestamp;
            int count = localProgressIndex - lastProgressIndex;
            if (count <= 0) continue;
            long durationInMsPerElement = durationInMs / count;
            
            long remainingDurationInMs = durationInMsPerElement * (numQueries - (localProgressIndex + 1));
            String message = String.format("Executing query %s/%s (%s sec. remaining)", localProgressIndex + 1,
            numQueries, Duration.ofMillis(remainingDurationInMs).getSeconds());
            System.out.println(message);
            
            lastTimestamp = currentTimestamp;
            lastProgressIndex = localProgressIndex;
        } while (progressIndex < numQueries);
    }
});
progressMonitoringThread.setDaemon(true);

progressMonitoringThread.start()

This approach does not break the execution of the application if the logging code is faulty. In the worst case, our monitoring thread terminates – no interfering with the application. Moreover, the runtime overhead is reduced to a minimum. We only set the progressIndex in each iteration of the application loop. Finally, the approach allows to log the state of the loop at a user-defined time interval. We are not forced to log it on each iteration anymore. Hence, we have changed the type of notification from an event-driven style to a time-driven style.

Join Points and their Pointcuts in AspectJ

In the following list, we name each join point with its corresponding pointcut because it was initially not apparent to me how to capsure all calls (or executions). You cannot use one single * wildcard to match all method and constructor calls. You need to define a composite pointcut which capsures on the one hand all method calls and on the other hand all constructor calls. This differentiation by AspectJ is not directly reflected by the documentation, but only by AspectJ’s different pattern syntax for call (or execution). To capsure method calls, you need to use MethodPattern. To capsure constructor calls, you need to use ConstructorPattern. The complete syntax for all patterns of AspectJ can be found here.

  • method-calls: call(MethodPattern)
  • method-execution: execution(MethodPattern)
  • ctor-calls: call(ConstructorPattern)
  • ctor-execution: execution(ConstructorPattern)
  • static init: staticinitialization(TypePattern)
  • preinit: preinitialization(ConstructorPattern)
  • init: initialization(ConstructorPattern)
  • field-reference (a.k.a. field-read): get(FieldPattern)
  • field-set (a.k.a. field-write): set(FieldPattern)
  • handler: handler(TypePattern)
  • advice-execution: adviceexecution()

Aspect-oriented Programming with AspectJ

AspectJ is an open-source framework that allows you to write Java code following the aspect-oriented programming (AOP) paradigm. AOP provides an alternative way of programming in the following situation:

Let us assume you want to implement some functionality which is required at multiple locations in your application’s source code. If we follow the object-oriented programming (OOP) paradigm, we would proceed as follows. First, we declare a new class. Then, within this class, we declare a new method which implements the required functionality. If necessary, we add some associated fields. Afterwards, we place an invocation of the method (together with the class instantiation) at each of the required locations in our source code.

If we follow the AOP paradigm, we would proceed as follows. First, we declare a new aspect which is similar to a class. Then, within this aspect, we declare a new advice which corresponds to the method from above. If necessary, we add some associated fields to the aspect. So far, we have proceeded exactly as if we had followed the OOP paradigm – only with different terms. But now, we do not place an invocation of the advice at each of the required locations. Instead, we write down these locations in our aspect and pass it to an additional compiler – the AOP compiler. This AOP compiler reads in the aspect and automatically places an invocation of the advice at each of the designated locations. Thereby, it also handles the instantiation of the aspect. The set of our locations is called a pointcut and is associated with our advice. In this way, the AOP compiler knows which code it should place at which locations. However, most AOP compilers cannot insert advices at arbitrary locations, but only at well-defined locations. For example, the AspectJ compiler can insert advices at method calls and field accesses, but not at loops or if-statements. Such well-defined locations are called joinpoints. Thus, a pointcut is not a set of arbitrary locations, but a set of joinpoints.

Hence, an aspect is not instantiated and accessed directly from within your source code. Instead, it is automatically inserted into your source code by the AOP compiler. For this reason, we do not term it class, but aspect. In summary, the AOP paradigm allows to insert some functionality at multiple locations in your application without the effort of touching the source code at each individual location by hand. In this way, it provides a clean modularization of crosscutting concerns and thus serves as a complement to the OOP paradigm.

AOP terms in short:

  • A jointpoint is a location in code at which the AOP compiler is able to automatically insert new code either before, after, or around (i.e., before and after). Valid joinpoints in AspectJ are, for example, method declarations, method calls, and field read/write accesses. So far, AspectJ does not support inserting code at loops and if-statements. So, AspectJ does not consider these constructs as joinpoints.
  • A pointcut is a set of joinpoints at which we want to insert the same new code. This set of joinpoints is not described as an enumeration of each and every individual joinpoint, but instead as a single compact expression similar to a regular expression.
  • An advice contains the new code which we want to insert at multiple joinpoints in our application’s source code.
  • An aspect contains one or more advices and their associated pointcuts. By default, AspectJ creates and uses one instance per aspect. So, you can consider an aspect as singleton. However, you can change this behavior to a per-object or per-joinpoint base (see aspect instantiation for more details).

For more information, we refer to the official Getting Started and the mapping of join points and pointcuts.

Writing your own custom PMD rules: PMD, Eclipse, Maven

How to write an own PMD rule?

  1. Create a new class (called rule in the following) that extends the PMD class AbstractJavaRule (see PMD documentation: How to write a rule class?).
    1. Override the visit methods which represent the Java syntax elements you want to analyze.
    2. Use the addViolation() methods within the visit methods to indicate a violation of your rule.
    3. Use the definePropertyDescriptor() method in the constructor to define a configuration parameter for your rule. Use the getProperty() method to read a configuration parameter within the visit method.
  2. Add your rule to a custom ruleset xml file (see PMD documentation: How to write a PMD rule?). Let us assume it is stored in a/b/c/my-ruleset.xml.
    Example ruleset file:

    <?xml version="1.0"?>
    <ruleset name="chw's custom rules" xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
    
    <description>Christian Wulf's custom rules</description>
    
    <rule class="de.chw.MissingPluralVariableName" name="MissingPluralVariableName"
    message="The variable {0} is not named in plural although its type {1} represents a collection.">
    <description>
    A variable that represents a collection (incl. set and list) should be named in plural form.
    </description>
    
    <priority>1</priority>
    
    <example>
      <![CDATA[
      List<Stage> stages;
      Collection<String> words;
      ]]>
    </example>
    </rule>
    
    </ruleset>
  3. Package your compiled rule and the ruleset file (into an archive file, e.g., zip or jar).
  4. Now, you can include your ruleset archive into an arbitrary project ruleset file by inserting the following line:
    rule ref="a/b/c/my-ruleset.xml"

How to let the PMD Eclipse plugin recognize your own rule?

Shortest answer: avoid using the PMD Eclipse plugin. Instead, use the Lightweight Eclipse Plugin for Quality Assurance Tools.

Short answer: if you really need to use the PMD Eclipse plugin, then build an Eclipse fragment plugin for the PMD Eclipse plugin (see this link).

The most important paragraphs of the link are:

  1. Creating the plugin fragment in Eclipse
  2. Packaging and distributing the new rule
  3. Installing the new rule

How to check your own PMD rule via Maven

  1. Add the maven-pmd-plugin as plugin to your pom.xml.
  2. Add (your own) custom ruleset archives as a <dependency> of the plugin.
  3. Add your project-specific ruleset in <configuration><rulesets>....
  4. Define what goals should be executed in which phases in <executions>....

Example excerpt of a pom.xml:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-pmd-plugin</artifactId>
  <version>3.4</version>
  <dependencies>
    <dependency>
      <groupId>de.chw</groupId>
      <artifactId>pmd.ruleset</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <scope>system</scope>
      <systemPath>${project.basedir}/conf/quality-config/pmd/CustomPmdRules_1.0.0.201505130542.jar</systemPath>
    </dependency>
  </dependencies>
  <configuration>
    <rulesets>
      <ruleset>${project.basedir}/conf/quality-config/pmd-ruleset.xml</ruleset>
    </rulesets>
    <linkXref>true</linkXref>
    <includeTests>true</includeTests>
    <targetJdk>${java.version}</targetJdk>
    <failOnViolation>true</failOnViolation>
  </configuration>
  <executions>
    <execution>
      <phase>test</phase>
      <goals>
        <goal>pmd</goal>
        <goal>cpd</goal>
      </goals>
    </execution>
  </executions>
</plugin>

 

What is a UML Software Component?

Introduction

Since I work at the Kiel University, I teach UML to the students in the 3rd and 4th semester of computer science. At the latest when they need to work out a UML component diagram and a corresponding deployment diagram, the following questions arise:

What is a UML software component? What is the difference between a class, a package, and a component?

For this reason, we address these questions in this post. First, we look at some definitions to distinguish a component from other UML entites.

Component vs. (Class, Package, and Library)

Let’s start with the most important message of this post: Consider a component as a composition of classes, packages, and sub components that is accessible only by other components and only via interfaces.

TODO

Communication within and between components

TODO UML notation

Example Component Diagram

When creating a component diagram, remember that it must depict additional semantics compared to all other diagram types such as class and package diagrams. Otherwise a component diagram is useless and can be thrown away.

TODO diagram with components (android, server, db) and sub components: A3, User, Role, ORM, …

Example Component Representations in Java

Since the Java programming language does not provide the abstraction of components, we need to represent it with the means Java offers us.
Hence, we discuss the three following representations of a component possible in the Java universe.

  1. The class-based approach
  2. The package-based approach
  3. The library-based approach

Due to Java’s direct support for interfaces, we represent a component’s interface by one or more Java interfaces.

The class-based approach

In this approach, we represent a component by a class that implements all interfaces the corresponding component should provide.

 

The package-based approach

TODO

The library-based approach

TODO

Ajax-based Form Tag

Limitations of Current Approaches

Although Grails provides the tag to send an HTML formular via AJAX, it is not recommended to use it for at least two reasons:

Introduction

Suppose we already have a web project with some views that contain some <form>ulars. We now want to replace their default submit behavior with an ajax-based one.

For this reason, we show in this post how to define an ajax-based HTML formular with the help of jQuery.
First, we define the requirements we impose on such a concept. Then, we describe our solution and show an example implementation.

Requirements

  1. Less modification: We want to modify an existing form tag as less as possible to minimize the modification effort
  2. Less code: We do not want to encapsulate the ajax functionality within an own tag to keep our project’s code size small and its complexity as simple as possible

A Solution

If we want to ajaxify an existing <form>, we first need to declare it to use ajax—of course.
Moreover, we need to define where the ajax response should be written to.
A common approach is to replace the contents of an html element with this response.

In order to meet requirement 1 (Less modification), we add a CSS class to the target form tag (we name it ajax) indicating that this form should use an ajax-based request on submit.
We then bind an onsubmit event handler to all form tags that belong to this CSS class.
In this way, we simultaneously meet requirement 2 (Less code) because the event handler with the ajax logics needs to be declared only once at a central place, e.g., in a javascript file.

An Example Implementation

$(function() {
    $(document.body).on('submit', 'form.ajax', function(event) {
        event.preventDefaults();

        $.ajax({
    
        }).done(function(data) {
        
        });
    });
});