Showing posts with label In Memory. Show all posts
Showing posts with label In Memory. Show all posts

Tuesday, 2 April 2013

Creating A Customized Spring User & Persistence

This post explains how to create a customized Spring user and persistence mechanism for authentication. The code is available at GitHub in the Spring-MVC-Customized-User directory.

Things To Take Into Consideration

Before creating a customized user, we need to remind what a user is in Spring. We know from here that a user is an implementation of the UserDetails interface. Spring security also requires a loading mechanism, as an implementation of the UserDetailsService interface. To keep this example simple, we are not going to implement login/logout or other security features.

The UserDetails interface is a bit incomplete in order to define a user in a real application. It defines getters and no setters. It is not a big deal, but the real pain is that the username (a string) is considered as 'the' key. Most software developers will prefer a long id.

To solve these issues, we define a PracticalUser interface:
public interface PracticalUserDetails
        extends UserDetails, CredentialsContainer {

    long getId();

    void setPassword(String password);

    void setAccountExpired(boolean b);

    void setAccountLocked(boolean b);

    void setCredentialsExpired(boolean b);

    void setEnabled(boolean b);

    void setAuthorities(
        Collection<? extends GrantedAuthority> authorities);

}
Typically, one would use JPA annotations on the implementation bean and save it in a database in a real application. However, for this example, the DAO will register users in an in-memory map as described further.

The UserDetailsService interface does not provide a get user per name or id, which is necessary for an administrator (for example). More, it does not allow to retrieve all existing users' id and name, or to update or insert users, or even to delete them.

Therefore, we create a PracticalUserDetailsService interface to solve these issues:
public interface PracticalUserDetailsService
        extends UserDetailsService {

    Set<PracticalUserDetailsDAO.UserIdentifiers> getUsers();

    void deleteUser(long id);

    void upsertUser(PracticalUserDetails user);

    PracticalUserDetails getUser(long id);

    PracticalUserDetails getUser(String username);

}
The corresponding implementation is called PracticalUserDetailsServiceInMemory for this example.

In-Memory DAO

To keep this example simple, we define a simple PracticalUserDetailsDAO:
public interface PracticalUserDetailsDAO<U extends PracticalUserDetails> {

    void create(U user);

    boolean contains(U user);

    U read(String username);

    U read(long id);

    void update(U user);

    void delete(String username);

    void delete(long id);

    interface UserIdentifiers {
        long getId();
        String getUsername();
    }

    Set<UserIdentifiers> getUsers();

}
We also define a special user id and name identifier interface to retrieve the set of existing user data, without returning all users. Our implementation of PracticalUserDetailsDAO is PracticalUserDetailsDAOInMemory.

In a real implementation, using a JPA Repository is more appropriate.

Configuration

In the security.xml file, we define our practical user detail service (it will be registered in the authentication manager) and the in-memory DAO bean:
<beans:beans xmlns="http://www.springframework.org/schema/security"
  xmlns:beans="http://www.springframework.org/schema/beans"
  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.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <http auto-config="true">
    </http>

    <authentication-manager alias="authenticationManager">
        <authentication-provider user-service-ref='practicalUserDetailsServiceInMemory' />
    </authentication-manager>

    <beans:bean id="pud"
        class="com.jverstry.DAO.PracticalUserDetailsDAOInMemory">
    </beans:bean>

</beans:beans>

The JSP Pages

We use two pages. The main page displays registered users (together with a delete link) and registration form:


The second page is displayed when the Create User button is clicked to check the name and the password:


The Controller

The controller is used to check the username and password:
@Controller
public class MyController {

    @Autowired
    private PracticalUserDetailsServiceInMemory pudm;

    @RequestMapping(value = "/")
    public ModelAndView index() {

        ModelAndView result = new ModelAndView("index");

        result.addObject("users", this.pudm.getUsers());

        return result;

    }

    @RequestMapping(value = "/delete/{id}")
    public String delete(@PathVariable(value="id") String id) {

        this.pudm.deleteUser(Long.parseLong(id));

        return "redirect:/";

    }

    @RequestMapping(value = "/create")
    @SuppressWarnings("AssignmentToMethodParameter")
    public ModelAndView add(
            @RequestParam(value="name")
            String name,
            @RequestParam(value="password")
            String password) {

        name = StringUtils.replace(name, " ", "");
        password = StringUtils.replace(password, " ", "");

        String errorMsg = "";

        if ( name.length() == 0 ) {
            errorMsg += "Name is empty ";
        }

        if ( password.length() == 0 ) {
            errorMsg += "Password is empty ";
        }

        if ( errorMsg.isEmpty() ) {
            this.pudm.upsertUser(new PracticalUserDetailsImpl(name, password));
        }

        ModelAndView result = new ModelAndView("create");

        result.addObject("errorMsg", errorMsg);
        result.addObject("username", name);

        return result;

    }

}

Running The Example

One can run it using the maven tomcat:run goal. Then, browse:

  http://localhost:9191/spring-mvc-customized-user/

More Spring related posts here.

Execute Spring ACL SQL Script In Memory

This post describes how to execute the Spring ACL script to create ACL tables in an in-memory HSQL database instance. The code is available at GitHub in the Execute-ACL-SQL-Scripts-In-Memory directory.

In-Memory DataSource

We are using a configuration classe implementing the DisposableBean interface to shut down the created HSQL embedded database nicely.
@Configuration
public class InMemoryDataSource implements DisposableBean {

    private EmbeddedDatabase ed;

    @Bean(name="hsqlInMemory")
    public EmbeddedDatabase hsqlInMemory() {

        if ( this.ed == null ) {

            EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();

            this.ed = builder.setType(EmbeddedDatabaseType.HSQL)
                .addScript("aclSchema.sql").build();

        }

        return this.ed;

    }

    @Override
    public void destroy() {

        if ( this.ed != null ) {
            this.ed.shutdown();
        }

    }

}
When creating the database, we also have the aclSchema.sql script executed. It must be located at the root of the resource directory:


The content of the script is taken from the Spring documentation appendix.

Checking Table Creation

We extract the list table of tables in the controller. Technically speaking, we should do this at the service/DAO level, but for the sake of this example, we'll keep it simple:
@Controller
public class MyController {

    @Autowired
    EmbeddedDatabase hsqlInMemory;

    @RequestMapping(value = "/")
    public ModelAndView home() {

        ModelAndView result = new ModelAndView("index");

        ArrayList<String> tables = new ArrayList<String>();

        JdbcTemplate tplate = new JdbcTemplate(hsqlInMemory);

        SqlRowSet retr = tplate.queryForRowSet(
            "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES");

        while (retr.next()) {
            tables.add(retr.getString(1));
        }

        result.addObject("tables", tables);

        return result;

    }

}

Running The Example

One can run it using the maven tomcat:run goal. Then, browse:

  http://localhost:8585/execute-acl-sql-scripts-in-memory/

We find the tables we have created:


More Spring related posts here.

Thursday, 7 March 2013

Spring JpaRepository Example (In-Memory)

This post describes a simple Spring JpaRepository example using an in memory HSQL database. The code example is available from GitHub in the Spring-JpaRepository directory. It is based on the Spring-MVC-With-Annotations example and information available here.

JPA Repository

We implement a dummy bean for this example:
@Entity
@AutoProperty
public class SomeItem {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long Id;

    private String someText;

    /* ...Setters & Getters */

}
and the corresponding JpaRepository:
@Transactional
public interface SomeItemRepository
        extends JpaRepository<SomeItem, Long> {

}

Service & Controller

Next, we implement a service where our repository will be injected. We also populate the repository with dummy data:
@Service
@Repository
public class SomeItemService {

    @Autowired
    private SomeItemRepository someItemRepository;

    @PostConstruct
    @Transactional
    public void populate() {

        SomeItem si = new SomeItem();
        si.setSomeText("aaa");
        someItemRepository.saveAndFlush(si);

        si = new SomeItem();
        si.setSomeText("bbb");
        someItemRepository.saveAndFlush(si);

        si = new SomeItem();
        si.setSomeText("ccc");
        someItemRepository.saveAndFlush(si);

    }

    @Transactional(readOnly=true)
    public List<SomeItem> getAll() {

        return someItemRepository.findAll();

    }

    @SuppressWarnings("AssignmentToMethodParameter")
    @Transactional
    public SomeItem saveAndFlush(SomeItem si) {

        if ( si != null ) {
            si = someItemRepository.saveAndFlush(si);
        }

        return si;

    }

    @Transactional
    public void delete(long id) {

        someItemRepository.delete(id);

    }

}
and a controller:
@Controller
public class MyController {

    @Autowired
    private SomeItemService someItemService;

    @RequestMapping(value = "/")
    public ModelAndView index() {

        ModelAndView result = new ModelAndView("index");
        result.addObject("items", this.someItemService.getAll());

        return result;

    }

    @RequestMapping(value = "/delete/{id}")
    public String delete(
        @PathVariable(value="id") String id) {

        this.someItemService.delete(Long.parseLong(id));

        return "redirect:/";

    }

    @RequestMapping(value = "/create")
    @SuppressWarnings("AssignmentToMethodParameter")
    public String add() {

        SomeItem si = new SomeItem();
        si.setSomeText("Time is: " + System.currentTimeMillis());

        this.someItemService.saveAndFlush(si);

        return "redirect:/";

    }

}

JPA Configuration

On top of creating an entity manager based on an in-memeory instance of HSQL database, we enable JPA repositories with the @EnableJpaRepositories annotation:
@Configuration
@EnableJpaRepositories(basePackages={"com.jverstry"})
@EnableTransactionManagement
public class JpaConfig implements DisposableBean {

    private EmbeddedDatabase ed;

    @Bean(name="hsqlInMemory")
    public EmbeddedDatabase hsqlInMemory() {

        if ( this.ed == null ) {
            EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
            this.ed = builder.setType(EmbeddedDatabaseType.HSQL).build();
        }

        return this.ed;

    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(){

        LocalContainerEntityManagerFactoryBean lcemfb
            = new LocalContainerEntityManagerFactoryBean();

        lcemfb.setDataSource(this.hsqlInMemory());
        lcemfb.setPackagesToScan(new String[] {"com.jverstry"});

        lcemfb.setPersistenceUnitName("MyPU");

        HibernateJpaVendorAdapter va = new HibernateJpaVendorAdapter();
        lcemfb.setJpaVendorAdapter(va);

        Properties ps = new Properties();
        ps.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
        ps.put("hibernate.hbm2ddl.auto", "create");
        lcemfb.setJpaProperties(ps);

        lcemfb.afterPropertiesSet();

        return lcemfb;

    }

    @Bean
    public PlatformTransactionManager transactionManager(){

        JpaTransactionManager tm = new JpaTransactionManager();

        tm.setEntityManagerFactory(
            this.entityManagerFactory().getObject() );

        return tm;

    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
        return new PersistenceExceptionTranslationPostProcessor();
    }

    @Override
    public void destroy() {

        if ( this.ed != null ) {
            this.ed.shutdown();
        }

    }

}

The JSP Page

We create a simple page to list existing items with a delete link, and the possibility to create new items:

 Running The Example

One can run it using the maven tomcat:run goal. Then, browse:

  http://localhost:9191/spring-jparepository/

More Spring related posts here.