Solutions to IT problems

Solutions I found when learning new IT stuff

Archive for May 2013

Spring MVC 3 Tutorial for beginners

with one comment

Introduction

I was trying to create a very simple Web Application using Spring MVC as a usage example for MoleculeDatabaseFramework. Now Spring MVC is obviously overkill for this but it was a good change to learn it. However this endeavor turned out to be much more complicated than I had anticipated. Also it is very hard to find actual tutorials and information on how to use Spring MVC 3. A lot of stuff is from older versions and often it is not mentioned for which version a code or configuration snippet is.

Starting Point

I created a maven web application using netbeans IDE. I added MoleculeDatabaseFramework-1.0.0-SNAPSHOT as dependency. To use the same configuration as my integration test of MoleculeDatabaseFramework use, I had to add further dependencies as they are in the test-scope and not included in MoleculeDatabaseFramework-1.0.0. I also added dependencies spring-web and spring-webmvc, both are required!

Dependency Issues

MoleculeDatabaseFramework project has a dependency on spring-context-3.1.4. In the web application I chose spring-web-3.2.2 and spring-webmvc-3.2.2 which replaced spring-context-3.1.4 with spring-context-3.2.2. The problem is that spring-context-3.2.2 contains less packages than spring-context-3.1.4 and hence I kept getting an exception that EhCacheCacheManager class was missing. After wasting over an hour on this I figured out that since spring-3.2.x this is in a separate dependency spring-context-support-3.2.2. That solved this issue and here the according maven dependencies:

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-web</artifactId>
	<version>3.2.2.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-webmvc</artifactId>
	<version>3.2.2.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context-support</artifactId>
	<version>3.2.2.RELEASE</version>
</dependency>

Note: this is only required if you are using caching with ehcache in your application.

A second problem was that I was missing class javax.servlet.jsp.jstl.core.Config. This was weird because I could clearly see in netbeans that this was provided by javaee-web-api-6.0 which was added to the project automatically at creation from netbeans. However it is in the provided scope and hence not included in the war-file. To resolve this you need to manually add dependency

<dependency>
	<groupId>javax.servlet</groupId>
	<artifactId>jstl</artifactId>
	<version>1.2</version>
</dependency>

Putting it all togehter here all dependencies for the project:

    <dependencies>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>MoleculeDatabaseFramework</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>0.11.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>3.2.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>3.2.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>3.2.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.6.5</version>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-ehcache</artifactId>
            <version>4.2.1.Final</version>
        </dependency>
        <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-web-api</artifactId>
            <version>6.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>com.jolbox</groupId>
            <artifactId>bonecp-spring</artifactId>
            <version>0.8.0-rc2-SNAPSHOT</version>
        </dependency>
    </dependencies>

Configuration issues

Configuration File Locations

web.xml Spring configuration file(s) go into the myApp/src/main/webapp/WEB-INF directory or in netbeans it is displayed in myApp/Web Pages/WEB-INF (but the actual path is the prior one). If you have a properties file, that is used by the spring context, like for database config, you need to put it in myApp/src/main/resources and it then can be found with the path classpath:Application.properties. The same is true for the ehcache.xml configuration file. if you use hibernates import.sql file to load data on application start, that belongs there too.

Configuration Files

I created 2 spring configuration files, ApplicationContext.xml and mvc-config.xml. The later is used to configure Spring MVC and ApplicationContext.xml is used to configure
MoleculeDatabaseFramework and requires this entry:

<import resource="mvc-config.xml" />

web.xml

You also need to create a web.xml file in WEB-INF. web.xml contains a reference to the DispatcherServlet that accepts all request:

<servlet>
	<servlet-name>myApp</servlet-name>
	<servlet-class>
		org.springframework.web.servlet.DispatcherServlet
	</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/ApplicationContext.xml
		</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
</servlet>

Note that if you do not specify the contextConfigLocation then the application context must be named -servlet.xml and hence in this case myApp-servlet.xml. load-on-startup must be 1 so that the Spring Context loads on application start.

You also need to specify which URLs you want to map:

<servlet-mapping>
	<servlet-name>MDFSimpleWebApp</servlet-name>
	<url-pattern>/*</url-pattern>
</servlet-mapping>

This means we want to map all request to myApp.

URL Mapping Issue

After the application actually loaded and my Controller was found and accessed correctly i kept getting an error that my views are not found. Even weirder was that the path to the view displayed in the log was correct!

The solution can be found in this stackoverflow question. However it is not the accepted answer but the one from sourcedelica. You need to add an additional mapping to your web.xml.

<servlet-mapping>
	<servlet-name>jsp</servlet-name>
	<url-pattern>/WEB-INF/jsp/*</url-pattern>
</servlet-mapping>

were the url-pattern is the path to the directory of all your web pages. This leads to following complete web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5">
    <display-name>MDF Simple Web Application</display-name>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <servlet>
        <servlet-name>MDFSimpleWebApp</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                /WEB-INF/ApplicationContext.xml
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>MDFSimpleWebApp</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>/WEB-INF/jsp/*</url-pattern>
    </servlet-mapping>
</web-app>

mvc-config.xml

I chose an annotation based approach for controllers. But all in all the mvc configuration file did not pose any troubles:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:mvc="http://www.springframework.org/schema/mvc"

       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
          http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">

    <mvc:annotation-driven />
    <mvc:view-controller path="/" view-name="index"/>
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>

ApplicationContext.xml

This file is huge and configures MoleculeDatabaseframework inlcuding spring-data, hibernate, connection pooling and so forth. It is not really relevant to Spring-MVC and hence I’m intentionally omitting it to avoid any confusion. However it must contain at least

<import resource="mvc-config.xml" />

so that the mvc configuration is loaded.

Controller

I created 1 very simple controller and I’m just going to post the source code and explain id:

@Controller
@RequestMapping(value = "/compound")
public class SimpleCompoundController {

    @Autowired
    private SimpleCompoundService compoundService;

    @RequestMapping(value = "/{compoundId}", method = RequestMethod.GET)
    public String getSimpleCompound(@PathVariable Long compoundId, Model model) {
        SimpleCompound compound = compoundService.getById(compoundId);
        model.addAttribute("compound", compound);
        return "compound";
    }
}

@Controller marks the class as controller and hence spring can detect it using component scanning.

@RequestMapping(value = "/compound") on the class level tells this controller handles all request to that url. Note that it is relative to the url specified in the DispatcherServlet in web.xml. In this case this would mean myApp/compound.

@Autowired injects a service loaded in ApplicationContext.xml. This service loads data from the database.

@RequestMapping(value = "/{compoundId}", method = RequestMethod.GET) tells that the annotated method ist repsonsible for handling all request to myApp/compound/{compoundId}. So the value is relative to the mapping of the controller class (if specified). @PathVariable will then take {compoundId} from the URL and pass it into the method in which it is used to fetch the compound wit the given id form the database.

The the compound is added to the model and we return the name of the view to render. This return value is handled by InternalResourceViewResolver configured in mvc-config.xml. The resolver appends the file ending specified (.jsp) and adds the path to the views directory. The actual request will then be for myApp//WEB-INF/jsp/compound.jsp and that jsp page will be rendered.

View

The view is a very simple jsp page. It shows how you can then access the Model in your web page using expressions.

<%@page language="java" contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib prefix="s" uri="http://www.springframework.org/tags" %>
<!DOCTYPE html>

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>Compound ${compound.getId()}</title>
    </head>
    <body>
        <div><label>Compound Name:</label><label>${compound.getCompoundName()}</label></div>
    </body>
</html>
Advertisements

Written by kienerj

May 24, 2013 at 12:10

Posted in Java, Programming

Tagged with ,

Creating a Framework for Chemical Structure Search – Part 8

leave a comment »

Series Overview

This is Part 8 – Spring Security Integration of the “Creating a Framework for Chemical Structure Search“-Series.

Previous posts:

Follow-ups:

Introduction

MoleculeDatabaseFramework is integrated with Spring-Security. It offers optional method level security in the service layer. This article will explain how it works and how to configure your application to use Spring-Security.

Annotation-Based

MoleculeDatabaseFramework has been integrated with Spring-Security using annotations. This means as long as you do not enable security in you Application Context, everything will work just fine without any security. Security is applied to methods in the Service interfaces.

The security integrations allows you to limit a user to certain types of entities, eg. one user can only read SimpleCompound while his supervisor also has access to SecretCompound. You can also assign roles that allows a user to update and/or delete compounds he created himself. And of course roles that allow to update or delete any compound of a given implementation.

The security integration uses the @PreAuthorize annotation. The value of this annotation is written in SpEL – Spring Expression Language. MoleculeDatabaseFramework uses the expressions hasRole or hasPermission. hasRole directly checks if the current user has the according role (called authority in Spring Security) and if yes grants access to the method or else throws an AccessDeniedException. hasPermission requires an implementation of org.springframework.security.access.PermissionEvaluator which has 2 overloaded methods public boolean hasPermission();. This is used on the save(entity) methods to determine if the given entity can be created or updated by the current user.

See the Spring Security Method Expression Documentation for more information on this topic.

Conventions

To make use of security you need to follow certain conventions. There are 6 basic “role-types”: create, read, update, delete, update_created and delete_created. A complete role is a “role-type” followed by and underscore and the entity class implementations SimpleClassName. So if you have an entity RegistrationCompound and you want a user to be able to read RegistrationCompounds he needs the role read_RegistrationCompound. And so forth.

  • A role starts with a “role-type” followed by “_” and the simple class name: read_RegistrationCompound
  • A user can either read none or all entries for a given entity implementation.
  • A service interface method that requires read-role must be annotated with @PreAuthorize("hasRole(#root.this.getReadRole())")

Above applies to ChemicalCompound, Containable and ChemicalCompoundContainer. For ChemicalStructure there is always only the supplied entity ChemicalStructure which a user of the framework should not extend. ChemicalStructure only has a save-Role (instead of save-Permission) and any user that can create or update any type of ChemicalCompound must have this role save_ChemicalStructure. Or in code:


public interface ChemicalCompoundService<T extends ChemicalCompound>
		extends Service<T> {

	//...snipped...
		
	@Transactional(readOnly = false)
	@PreAuthorize("hasPermission(#compound, 'save_' + #root.this.getCompoundClassSimpleName())")
	@Override
	T save(T compound);
	
	//...snipped...
}

public interface ChemicalStructureService<T extends ChemicalStructure>
		extends Service<T> {	
		
	//...snipped...
	
	@Transactional(readOnly = false)
	@PreAuthorize("hasRole('save_ChemicalStructure')")
	@Override
	T save(T structure);
	
	//...snipped...
}
  • For managing Users and Roles you need to use the supplied entities User and Role and their services.

User implements UserDetails from Spring Security and UserService extends UserDetailsService. To create, update or delete a User or a Role you need the role manage_User or manage_Role respectively.

Security Behaviour

MoleculeDatabaseFramework ships with a PermissionEvaluator implementation. This PermissionEvaluator checks if a given user can create, update or delete a given domain object. (Note: For read-methods just having the read-role is enough; they use hasRole instead of hasPermission in @PreAuthorize). The supplied DefaultPermissionEvaluator internally uses Permission objects to determine a users permissions.

The supplied PermissionEvaluator allows users with create, update or delete role to perform that action on any domain object (of the given implementation). Users with update_created or delete_created role can perform that action only on domain objects they created (getCreatedBy().equals(loggedInUserName).

Services only offer a save(entity) method. If a domain object is being created or being updated is determined whether its id is set or not (id == null -> create). This is exactly the same what hibernate does.

In your application you should only create exactly 1 implementation of ChemicalCompoundContainer. However this Container can hold any type of Containable and hence any type of ChemicalCompound. To ensure that a user only sees Containers that contain a ChemicalCompound he has the read-role for, all other Containers are filtered out. This includes the count() service method. So users with different privileges on ChemicalCompounds see different numbers of Containers.

The supplied PermissionEvaluator requires a RoleHierarchy bean to be configured in the security context. RoleHierarchy is very useful as it automatically assigns a “lower” privilege to someone with a “higher” one. So you say

create_RegistrationCompound > read_RegistrationCompound

then anyone with create_RegistrationCompound role automatically also has role read_RegistrationCompound.

Cascading of Persist and Merge

ChemicalCompound, Containable and ChemicalCompoundContainer in their JPA relationships between each other all use CascadeType.PERSIST and CascadeType.REFRESH. This means changes (updates) to existing entities must always be done using that entities service.save(entity) method because CascadeType.MERGE (update) is not set and hence updates are not cascaded.

In case of creating a new entity, the Permission implementations check if the current user has the privilege to also create the associated, new entities. If you create a new ChemicalCompoundContainer that contains a new Containable which is made of a new ChemicalCompound, the ContainerPermission will verify if the current user has the privilege to not only create the new ChemicalCompoundContainer but also to create the new ChemicalCompound and new Containable. If this is not the case, an AccessDeniedException is thrown.

Below example will create a new RegistrationCompound, a new Batch and a new CompoundContainer if the current user has the privileges create_RegistrationCompound, create_Batch and create_CompoundContainer.

RegistrationCompound regCompound = new RegistrationCompound();
regCompound.setCompoundName("Registration Compound");
regCompound.setCas(cas);
regCompound.setRegNumber(regNumber);

ChemicalStructure structure =
        chemicalStructureFactory.createChemicalStructure(structureData);

ChemicalCompoundComposition composition = new ChemicalCompoundComposition();
composition.setCompound(regCompound);
composition.setChemicalStructure(structure);
composition.setPercentage(100.0);

regCompound.getCompositions().add(composition);

Batch batch = new Batch(regCompound, batchNumber);

regCompound.getBatches().add(batch);

CompoundContainer container = new CompoundContainer("C00001", batch);
container = compoundContainerService.save(container);

In case an associated entity already exists, create-privilege is not required, if the entity that is being persisted is the “parent” in the hierarchy. Or said otherwise you can associate a new ChemicalCompoundContainer with an existing Containable but you can not associate a new Containable with an existing ChemicalCompoundContainer because that Container could not exist before the Containable was created. Same logic for relationship between Containable and ChemicalCompound.

Customize Security

To do so, you need to implement your own PermissionEvaluator and / or Permission implementations.

Configuration Example

Below the SecurityContext.xml used for testing security in MoleculeDatabaseFramework.

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:security="http://www.springframework.org/schema/security"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
             http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
             http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <!-- User Service - In a real application this should use database
   and the according UserService and RoleService.  -->
    <security:user-service id="userService">
        <security:user name="user" password="password" authorities="read_TestCompound,
            read_TestContainable, create_TestCompoundContainer, create_RegistrationCompound, create_Batch"/>
        <security:user name="creator" password="password" authorities="create_TestCompound, create_TestContainable"/>
        <security:user name="owner" password="password" authorities="update_created_TestCompound, update_created_TestContainable, delete_created_TestCompound, delete_created_TestContainable, delete_created_TestCompoundContainer"/>
        <security:user name="editor" password="password" authorities="update_TestCompound, update_TestCompoundContainer, read_TestContainable"/>
        <security:user name="admin" password="admin" authorities="admin_TestCompound, admin_TestContainable, admin_TestCompoundContainer"/>
    </security:user-service>

    <!--    <bean id="userService"
        class="org.bitbucket.kienerj.moleculedatabaseframework.service.UserServiceImpl">
    </bean>-->

    <!-- Use a RoleHierarchy and a PermissionEvaluator in SpEL expression in
    @PreAuthorize -->
    <bean id = "methodSecurityExpressionHandler"
          class = "org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
        <property name="roleHierarchy" ref="roleHierarchy"/>
        <property name="permissionEvaluator" ref="permissionEvaluator"/>
    </bean>

    <!-- Role Hierachy - Probably should use database for this too in real app -->
    <bean id="roleHierarchy"
          class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
        <property name="hierarchy">
            <value>
                admin_TestCompound > update_TestCompound
                update_TestCompound > update_created_TestCompound
                update_created_TestCompound > create_TestCompound
                admin_TestCompound > create_TestCompound
                create_TestCompound > read_TestCompound
                create_TestCompound > save_ChemicalStructure
                admin_TestCompound > delete_TestCompound
                delete_TestCompound > delete_created_TestCompound
                update_RegistrationCompound > create_RegistrationCompound
                create_RegistrationCompound > read_RegistrationCompound
                create_RegistrationCompound > save_ChemicalStructure
                admin_TestContainable > update_TestContainable
                admin_TestContainable > delete_TestContainable
                update_TestContainable > create_TestContainable
                create_TestContainable > read_TestContainable
                update_created_TestContainable > create_TestContainable
                admin_TestCompoundContainer > update_TestCompoundContainer
                admin_TestCompoundContainer > delete_TestCompoundContainer
                delete_created_TestCompoundContainer > create_TestCompoundContainer
                update_TestCompoundContainer > create_TestCompoundContainer
                create_TestCompoundContainer > read_TestCompoundContainer
            </value>
        </property>
    </bean>

    <!-- Permission Evaluator supplied by framework. The constructor takes a Map
    of SimpleClassName -> PermissionImplementation associations-->
    <bean id="permissionEvaluator"
         class="org.bitbucket.kienerj.moleculedatabaseframework.security.DefaultPermissionEvaluator">
        <constructor-arg index="0">
            <map key-type="java.lang.String"
                 value-type="org.bitbucket.kienerj.moleculedatabaseframework.security.Permission">
                <entry key="TestCompound" value-ref="chemicalCompoundPermission"/>
                <entry key="RegistrationCompound" value-ref="chemicalCompoundPermission"/>
                <entry key="TestContainable" value-ref="containablePermission"/>
                <entry key="TestCompoundContainer" value-ref="chemicalCompoundContainerPermission"/>
                <entry key="Batch" value-ref="containablePermission"/>
            </map>
        </constructor-arg>
    </bean>

    <!-- Permission implementations uses -->
    <bean id="chemicalCompoundPermission"
          class="org.bitbucket.kienerj.moleculedatabaseframework.security.ChemicalCompoundPermission">
    </bean>
    <bean id="containablePermission"
          class="org.bitbucket.kienerj.moleculedatabaseframework.security.ContainablePermission">
    </bean>
    <bean id="chemicalCompoundContainerPermission"
          class="org.bitbucket.kienerj.moleculedatabaseframework.security.ChemicalCompoundContainerPermission">
    </bean>


    <security:authentication-manager alias="testAuthenticationManager">
        <security:authentication-provider user-service-ref="userService"/>
    </security:authentication-manager>

    <!-- enable annotations and set expression handler to use-->
    <security:global-method-security pre-post-annotations="enabled">
        <security:expression-handler ref = "methodSecurityExpressionHandler"/>
    </security:global-method-security>
</beans>

Written by kienerj

May 22, 2013 at 08:37

Posted in Chemistry, Java, Programming

Tagged with ,

Creating a Framework for Chemical Structure Search – Part 7

leave a comment »

Series Overview

This is Part 7 – Service Layer of the “Creating a Framework for Chemical Structure Search“-Series.

Previous posts:

Follow-ups:

Introduction

In this article I will introduce the service layer of MoleculeDatabaseFramework. The service layer is responsible for transaction support and security.

Service for ChemicalStructure Entity

This service manages entities of type ChemicalStructure. This service is provided by the framework and should be used as-is. Any access of ChemicalStructures should be through this service. ChemicalStructureService contains the logic that make ChemicalStructures “immutable”. Quote from Part 5 of the series:

A ChemicalStructure is unique and immutable and managed by the framework. Users operate on ChemicalCompounds and not ChemicalStructures directly. Unique means if a new ChemicalCompound is saved, the framework checks if the ChemicalStructures in it already exist and if yes re-uses them. Immutable means that if a ChemicalCompound is updated and one of the ChemicalStructures has changed the framework will automatically check if the updated ChemicalStructure already exist and use it or create a new ChemicalStructure. The old one will remain unchanged!

In case a ChemicalStructure actually needs to be updated and the change should affect all ChemicalCompounds containing it the service has a separate method updateExistingStructure(structure) which requires the current user to have the role update_ChemicalStructure when Spring Security is enabled. In general this method should be restricted to Admins.

Below the source code for the two mentioned methods. Note that for brevity argument checks and logging statements were removed:

public T save(T structure) {
       
	T result = structureRepository.findByStructureKey(structure.getStructureKey());

	if (result == null) {
		// clear id (and createdBy and created) so that a new row is inserted
		structure.reset();

		return structureRepository.save(structure);
	} else {
		return structureRepository.save(result);
	}
}

@Override
public T updateExistingStructure(T structure){

	T result = structureRepository.findOne(structure.getId());

	if (result == null){
		throw new IllegalArgumentException("Given ChemicalStructure does not exist. It can't be updated.");
	}        
	return structureRepository.save(structure);
}

Services for ChemicalCompound and Containable

The services for ChemicalCompound and Containable are very similar. They consist of an interface which contains the security annotations and an implementation containing the @Transactional annotations for declarative transactions. They also offer methods with optional loading of lazy collections.

When a entity is saved, the service automatically sets the correct ChemicalStructures by either selecting an existing one from the database or creating a new one.
Also before the entity is passed to Hibernate, the method preSave(entity); is executed. This method is empty in the provided abstract services like ChemicalCompoundServiceImpl but can be overridden in subclasses. As example one could set all non-nullable properties to a default or a sequence value if it is null.

Below the source code of the save(entity) method of ChemicalCompoundServiceImpl for clarification:

public final T save(T compound) {
	logger.entry(compound);
	Preconditions.checkNotNull(compound);
	preSave(compound);
	if (compound.getCompositions() != null) {
		for (ChemicalCompoundComposition composition : compound.getCompositions()) {
			ChemicalStructure structure = composition.getChemicalStructure();
			ChemicalStructure result = chemicalStructureService.save(structure);
			composition.setChemicalStructure(result);
		}
	}
	//...snipped...
}

You need to create a service interface and an implementation for every ChemicalCompound and Containable implementation the application uses. The services must implement the getRepository(), checkUniqueness() and getExistingCompound() methods.

getRepository() must return the Spring-Data repository responsible for saving the entity of the same type as the current service is for.

checkUniqueness() must return if an entity is unique (does not violate any unique constraints) and if it is not unique it must return a Mapping of the violated constraint(all field names of constraint) and the offending value.

getExistingCompound() or getExistingContainable() respectively is called during import of SD-Files. The method must use the data from the SD-File (SdfRecord) to check if the current compound that is being imported already exists in the database. If it already exists it must return it, else it must return null.

Below an Example of such a Service implementation for RegistrationCompound entity:

RegistrationCompoundService UML

Note that Java Generics are not shown in above diagram hence in source code:

public interface RegistrationCompoundService extends ChemicalCompoundService<RegistrationCompound> {
	//...snipped...
}

public class RegistrationCompoundServiceImpl extends ChemicalCompoundServiceImpl<RegistrationCompound>
        implements RegistrationCompoundService {
	//...snipped...
}

Please see the MoleculeDatabaseFramework Tutorial for further information on how to implement such services.

ChemicalCompoundContainerService

This service manages entities of type ChemicalCompoundContainer. The main difference to services for ChemicalCompound and Containable is that an application should only have 1 implementation of ChemicalCompoundContainer and hence only 1 such service. The service can be used out-of-the-box or in some cases must be extended as example when the ChemicalCompoundContainer implementation adds additional unique constraints, checkUniqueness() and getExistingContainer() must be overridden.

Also ChemicalCompoundContainerService has some special considerations in terms of the Spring-Security integration.

Please see the MoleculeDatabaseFramework Tutorial for further information on how to implement such a service.

Written by kienerj

May 8, 2013 at 08:06

Java Command-Line Applications and Regular Expression Arguments

leave a comment »

Introduction

I needed to create a simple tool to split pdfs into multiple documents where the splitting is defined by a certain text appearing on a page. Or said otherwise the occurrence of the specific text (regex) marks the start of a new document.

The issue

The application seemed to work correctly…until I actually used it from the command-line. It was obvious something is wrong with the regex and in fact I realized that newline character \n was an actual backslash + n in the string or "\\n" written as a Java String. I googled and found that this expected behavior and it does make sense. The solution is simple. Just replace it with an actual newline:

String regex = args[1];
regex = regex.replace("\\r", "\r"); // for Windows
regex = regex.replace("\\n", "\n");

Written by kienerj

May 7, 2013 at 14:23

Posted in Java, Programming

Tagged with ,

Creating a Framework for Chemical Structure Search – Part 6

leave a comment »

Series Overview

This is Part 6 – Data Access Layer of the “Creating a Framework for Chemical Structure Search“-Series.

Previous posts:

Follow-ups:

Introduction

In the previous article I introduced the entity model of MoleculeDatabaseFramework. This article will explain the Data Access Layer which uses Spring-Data-JPA with Hibernate and how the Chemical Structure Search methods of the Bingo PostgreSQL Cartridge are exposed to Hibernate and QueryDSL.

How Spring-Data JPA works

Basic functionality

I quote from Spring-Data website:

Spring Data JPA aims to significantly improve the implementation of data access layers by reducing the effort to the amount that’s actually needed. As a developer you write your repository interfaces, including custom finder methods, and Spring will provide the implementation automatically.

You create a new interface that extends from generic interfaces provided by Spring-Data and represents the repository for an entity. There are different kinds of repository interfaces but the repositories in MoleculeDatabaseFramework all extend JpaRepository. JpaRepository provides CRUD-methods and some retrieval methods for your entity.

Repositories in MoleculeDatabaseFramework also extend QueryDslPredicateExecutor. This adds findOne(predicate) and findAll(predicate) methods. Predicates are basically type-safe WHERE-Clauses.

Custom query methods

Besides the provided methods you can add your custom search methods by following the findBy-method conventions of Spring Data JPA or by annotating a method with @Query were the value of the annotation is either a JPQL Query or native SQL.

Custom Queries providing your own method implementation

In case you have a very complex query that can’t be automatically created by Spring-Data, you can create them yourself.

1. Create Custom Query Interface

To achieve this you need to first create an interface containing the desired query method(s) and annotate it with @NoRepositoryBean:

@NoRepositoryBean
public interface ChemicalStructureSearchRepository<T> {

    Page<T> findByChemicalStructure(String structureData,
            StructureSearchType searchType,
            Pageable pageable, Predicate predicate,
            String searchOptions,
            PathBuilder<T> pathBuilder);


    Page<T> findBySimilarStructure(String structureData,
            SimilarityType similarityType,
            Double lowerBound, Double upperBound,
            Pageable pageable, Predicate predicate,
            PathBuilder<T> pathBuilder);
}

This is the Source Code of ChemicalStructureSearchRepository minus JavaDoc comments.

2. Create a repository extending Custom Query interface

As an example below the Source Code for ChemicalCompoundRepository which extends ChemicalStructureSearchRepository:

@Repository
@Transactional(propagation = Propagation.MANDATORY)
public interface ChemicalCompoundRepository<T extends ChemicalCompound>
        extends ChemicalStructureSearchRepository<T>, JpaRepository<T, Long>,
        QueryDslPredicateExecutor<T> {
    
    List<T> findByCompositionsPkChemicalStructureId(Long structureId);
    
    T findByCas(String cas);

    @Query("select c from Containable c where c.chemicalCompound = ?1")
    List<Containable> getContainablesByCompound(ChemicalCompound compound);
}

3. Create an implementation of your repository

The convention is that the implementation is named after the repository with “Impl” appended, in this case ChemicalCompoundRepositoryImpl. This implementation must only implement your custom methods in this case defined in ChemicalStructureSearchRepository.

public class ChemicalCompoundRepositoryImpl<T extends ChemicalCompound>
        implements ChemicalStructureSearchRepository<T> {

	//...fields and constructors snipped...

    @Cacheable(STRUCTURE_QUERY_CACHE)
    @Override
    public Page<T> findByChemicalStructure(String structureData,
            StructureSearchType searchType, Pageable pageable,
            Predicate predicate, String searchOptions,
            PathBuilder<T> compoundPathBuilder) {
			
			//...implementation snipped...
    }


    @Cacheable(STRUCTURE_QUERY_CACHE)
    @Override
    public Page<T> findBySimilarStructure(String structureData,
            SimilarityType similarityType, Double lowerBound, Double upperBound,
            Pageable pageable, Predicate predicate,
            PathBuilder<T> compoundPathBuilder) {
			
			//...implementation snipped...
    }
}

Below an UML Class Diagram that shows the relationships of ChemicalCompoundRepository:

ChemicalCompoundRepository UML

Spring-Data automatically detects the repository implementation and combines all provided and all your custom search methods into one object which you use by calling them from ChemicalCompoundRepository.


Page<T> page = getRepository().findByChemicalStructure(structureData, searchType,
                pageable, predicate, searchOptions, pathBuilder);

Using the Repositories

MoleculeDatabaseFramework provides generic repositories for all entities in the entity model.

Source Code for all Repositories

To make use of a chemical structure search enabled repository you need to extend it using your specific entity implementation and optionally add your custom find methods:

@Repository
public interface RegistrationCompoundRepository extends ChemicalCompoundRepository<RegistrationCompound> {

    List<RegistrationCompound> findByRegNumberStartingWith(String regNumber);

}

That’s it!

You can find further information on how to implement entities and repositories in the MoleculeDatabaseFramework Tutorial as this article is meant to show the inner workings of the framework and not how to use it.

Exposing Bingo PostgreSQL Cartridge Methods

This is done by using a custom dialect extending Hibernates PostgreSQL82Dialect:

public class BingoPostgreSQLDialect extends PostgreSQL82Dialect {

    public BingoPostgreSQLDialect() {
         registerFunction("issubstructure", new SQLFunctionTemplate(
                 StandardBasicTypes.BOOLEAN, "?1  @ (?2, ?3)::bingo.sub"));
         registerFunction("isexactstructure", new SQLFunctionTemplate(
                 StandardBasicTypes.BOOLEAN, "?1  @ (?2, ?3)::bingo.exact"));
         registerFunction("matchessmarts", new SQLFunctionTemplate(
                 StandardBasicTypes.BOOLEAN, "?1  @ (?2, ?3)::bingo.smarts"));
         registerFunction("matchesformula", new SQLFunctionTemplate(
                 StandardBasicTypes.BOOLEAN, "?1  @ (?2, ?3)::bingo.gross"));
         registerFunction("issimilarstructure", new SQLFunctionTemplate(
                 StandardBasicTypes.BOOLEAN, "?1  @ (?2, ?3, ?4, ?5)::bingo.sim"));
         registerFunction("hasmassbetween", new SQLFunctionTemplate(
                 StandardBasicTypes.BOOLEAN, "?1 > ?2::bingo.mass AND ?1 < ?3::bingo.mass"));         
    }
}

And as a usage example a source code snippet from ChemicalCompoundRepositoryImpl:

public Page<T> findByChemicalStructure(String structureData,
            StructureSearchType searchType, Pageable pageable,
            Predicate predicate, String searchOptions,
            PathBuilder<T> compoundPathBuilder) {
			
	//...snipped...
			
	BooleanExpression matchesStructureQuery; // this is a Predicate!

	switch (searchType) {
		case EXACT:
			matchesStructureQuery = BooleanTemplate.create(
					"isExactStructure({0},{1},{2}) = true",
					structure.structureData,
					ConstantImpl.create(structureData),
					ConstantImpl.create(searchOptions));
			break;
		case SUBSTRUCTURE:
			matchesStructureQuery = BooleanTemplate.create(
					"isSubstructure({0},{1},{2}) = true",
					structure.structureData,
					ConstantImpl.create(structureData),
					ConstantImpl.create(searchOptions));
			break;
		//...snipped other cases
	}

	baseQuery = baseQuery.from(compoundPathBuilder)
			.innerJoin(compound.compositions, composition)
			.innerJoin(composition.pk.chemicalStructure, structure)
			.where(matchesStructureQuery.and(predicate));
	//...snipped...
}

Full Source Code for ChemicalCompoundRepositoryImpl

The next Part will focus on the Service Layer. The Service Layer controls transactions and security.

Written by kienerj

May 2, 2013 at 07:51