Skip to content
Browse files

Java from nothing, adding persistence added

Also added euler problem 3 solution
  • Loading branch information...
1 parent 5358aa4 commit cbcaf4737b86437d4e227af54921ec0e78c7c95c @credmp committed Mar 16, 2013
Showing with 569 additions and 0 deletions.
  1. +43 −0 _posts/2013-03-13-Project-Euler-Problem-3.md
  2. +526 −0 _posts/2013-03-16-java-adding-persistence.md
View
43 _posts/2013-03-13-Project-Euler-Problem-3.md
@@ -0,0 +1,43 @@
+---
+tags: [Erlang, Project Euler]
+title: "Project Euler Problem 3"
+image: /assets/post_images/Puzzle.JPG
+image_credit: Unknown
+layout: post
+---
+
+Problem
+-------
+
+The prime factors of 13195 are 5, 7, 13 and 29.
+
+What is the largest prime factor of the number 600851475143 ?
+
+Solution
+--------
+
+{% highlight erlang %}
+-module(problem3).
+-export([main/0]).
+
+solve(N) ->
+ solve(N, 2, []).
+
+solve(N, CurDiv,Acc) ->
+ if
+ CurDiv > N div 2 ->
+ N;
+ true ->
+ if
+ N rem CurDiv == 0 ->
+ io:format("[~p] ", [CurDiv]),
+ solve(N div CurDiv, CurDiv, Acc ++ [CurDiv]);
+ true ->
+ solve(N, CurDiv + 1, Acc)
+ end
+ end.
+
+main() ->
+ io:format("Problem 3~n"),
+ solve(600851475143).
+{% endhighlight %}
View
526 _posts/2013-03-16-java-adding-persistence.md
@@ -0,0 +1,526 @@
+---
+tags: [Java]
+title: "Java; adding persistence"
+series: developing a Java application
+image: /assets/post_images/java_from_nothing/2.persistence.png
+layout: post
+---
+{% include JB/setup %}
+{% include series.html %}
+
+
+# Lets store some stuff
+
+In the [first article](/2013/01/Java-starting-at-nothing) we started
+our project to create a simple movie database. We will be using a lot
+of cool stuff along the way and in this article we will explore
+persistence.
+
+My aim was to keep it simple, but persistence is anything but simple.
+Sure, you can just create a JDBC connection and do stuff, but that
+doesn't give you the tools to use the rich and powerful world that I
+want to show you.
+
+So, if the first article was a beginners introduction to a project,
+then this will be a step up into some of the complexities of
+persistence.
+
+At a high level we will be using only a few things:
+
+ - A postgres database
+ - If you are on a Mac I highly recommend [PostgresApp](http://postgresapp.com)
+ - Hibernate as an Object-Relational Mapping tool
+ - Spring to connect everything and its testing support
+ - DBUnit to do some testing
+
+One can write books on each of these subjects and people of course
+have. I will not go into full depth on each, but I will get you up and
+running with them.
+
+The sources for this article are available on [Github](https://github.com/credmp/java-from-nothing/tree/02_adding_persistence).
+
+## Pull in some dependencies
+
+The first thing we will do is enhance our **pom.xml** file to include
+the dependencies we require for our project. Keeping with good form we
+will first introduce the properties and after that we will update the
+dependencies.
+
+{% highlight xml %}
+ <org.dbunit.version>2.4.8</org.dbunit.version>
+ <logback-version>1.0.7</logback-version>
+ <hibernate-version>4.1.8.Final</hibernate-version>
+ <cglib.version>2.2.2</cglib.version>
+ <commons-dbcp.version>1.4</commons-dbcp.version>
+ <postgresql.version>9.1-901.jdbc4</postgresql.version>
+{% endhighlight %}
+
+Following we will add each dependency to the **dependencies** list. In
+total we will add 12 new dependencies. To save you some reading here
+you can find the full [pom.xml on Github](https://github.com/credmp/java-from-nothing/blob/02_adding_persistence/pom.xml)
+
+## Logging with logback
+
+You might wander about the *logback* dependency. I use logback for
+logging, it is a quite powerful framework which makes dealing with
+logging quite easy. I introduce it to the project now as the
+**Hibernate** and **Spring** output can be quite overwhelming.
+
+The configuration for logback can be found in **src/test/resources/logback.xml**
+and is as follows:
+
+{% highlight xml %}
+<?xml version='1.0' encoding='UTF-8'?>
+<configuration>
+ <appender name='CONSOLE' class='ch.qos.logback.core.ConsoleAppender'>
+ <encoder>
+ <pattern>%d %5p | %t | %-55logger{55} %L | %m %n</pattern>
+ </encoder>
+ </appender>
+
+ <logger name='org.springframework'>
+ <level value='INFO' />
+ </logger>
+ <logger name='org.hibernate'>
+ <level value='INFO' />
+ </logger>
+ <logger name='org.dbunit'>
+ <level value='INFO' />
+ </logger>
+
+ <root>
+ <level value='DEBUG' />
+ <appender-ref ref='CONSOLE' />
+ </root>
+</configuration>
+{% endhighlight %}
+
+Basically this file configures all the logging we need. It sets up a
+[PatternLayout](http://logback.qos.ch/manual/layouts.html) so that we
+can get some nicely organized data on the screen.
+
+Next we will reduced the logging from **Spring**, **Hibernate** and
+**DBUnit** by setting their level to *INFO*. This means we will only
+get information at the *INFO* level or more severe.
+
+The rest of the code, including our own will use the level set in the
+*root* element, in this case *DEBUG*.
+
+# Annotations all over the place
+
+In the good old days we would now start writing code that maps objects
+to databases and create a million and one data access objects
+(**DAO**). At this point in our project we will not do this. We will
+use the **javax.persistence** [annotations](http://docs.oracle.com/javaee/5/api/javax/persistence/package-summary.html)
+
+We will be using 6 annotations for our project, namely @Entity,
+@Column, @Id, @GeneratedValue, @Version and @OneToOne.
+
+## @Entity
+
+In order for the system to know that it should at least be able to
+persist an object its class needs to be annotation with @Entity.
+
+A class annotated with @Entity will be transferred to the database as
+a **table**. So our Actor class will become an Actor table in our database.
+
+[JavaDoc](http://docs.oracle.com/javaee/5/api/javax/persistence/Entity.html)
+
+## @Column
+
+(Almost) every attribute that you wish to store in the database as a
+column has to be annotated with @Column.
+
+This will create a column with the name of the property of which the
+values are **non-unique** and its value is **nullable**. The column
+will be included in **insert** and **update** statements and its **type**
+will be deduced from the inferred type.
+
+For a string the default **length** of 255 is used and for decimal
+value the **precision** and **scale** are set to 0.
+
+For our version field, discussed later, we will need to set a default
+value. This is not possible by using annotations alone so we need to
+provide the SQL based definition of the column in **columnDefinition**.
+
+[JavaDoc](http://docs.oracle.com/javaee/5/api/javax/persistence/Column.html)
+
+## @Id
+
+The @Id annotation indicates that the property is the primary key for
+the table.
+
+The magic for this column happens in @GeneratedValue.
+
+[JavaDoc](http://docs.oracle.com/javaee/5/api/javax/persistence/Id.html)
+
+## @GeneratedValue
+
+The @GeneratedValue tells the primary key how it is to be generated.
+By passing a **generator** and a **strategy** the database can create
+its internal objects accordingly.
+
+Not all databases support all the possible values. There is a nice
+overview on
+[wikibooks](http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing)
+on the subject.
+
+In our application we will be using **GenerationType.IDENTITY** as
+this is portable between MySQL and PostgreSQL.
+
+[JavaDoc](http://docs.oracle.com/javaee/5/api/javax/persistence/GeneratedValue.html)
+
+## @Version
+
+The @Version annotation allows us to use **optimistic locking**. This
+technique prevents a lot of locks, and thus waiting code, on the
+database by introducing a field, **version**, which will change value
+with each update.
+
+When our code performs an update it will check if the **version**
+field changed value in the meantime. If it changed then our statement
+will fail and we will need to deal with the error accordingly.
+
+The subject of optimistic locking is thoroughly explained on [wikipedia](http://en.wikipedia.org/wiki/Optimistic_concurrency_control).
+
+[JavaDoc](http://docs.oracle.com/javaee/5/api/javax/persistence/Version.html)
+
+## @OneToOne
+
+As the name suggests the @OneToOne annotation maps one object to
+another. For instance; a piece of **Trivia** belongs to an **Actor**.
+
+The other way around, @ManyToOne and @OneToMany, also exists, but we
+will not touch them, yet.
+
+The @OneToOne annotation is not **Lazy**, this means that when we
+retrieve a **Trivia** object it will also retrieve the **Actor**. This
+behaviour can be changed, however for these mappings it doesn't make sense.
+
+[JavaDoc](http://docs.oracle.com/javaee/5/api/javax/persistence/OneToOne.html)
+
+## The annotated classes
+
+Following the explanation from about we will annotate our classes. You
+can see the code for all the classes on
+[Github](https://github.com/credmp/java-from-nothing/tree/02_adding_persistence/src/main/java/org/credmp/fromnothing/model).
+As an example of the simple annotations, lets take a look at the Actor class.
+
+{% highlight java %}
+@Entity
+public class Actor {
+ @Id
+ @GeneratedValue(strategy=GenerationType.IDENTITY)
+ private long id;
+ @Column(nullable=false)
+ private String firstName;
+ @Column(nullable=true)
+ private String lastName;
+ @Column(nullable=true)
+ private String nickName;
+ @Column(nullable=true)
+ private Date birthDate;
+ @Column(nullable=true)
+ private Date dateOfDeath;
+ @Column(nullable=true)
+ private String credit;
+ @Version
+ @Column(columnDefinition="bigint not null default 0")
+ private long version;
+{% endhighlight %}
+
+And if we take a look at the **Trivia** class we see almost the same
+code, except for the @OneToOne annotation.
+
+{% highlight java %}
+@Entity
+public class Trivia {
+ @Id
+ @GeneratedValue(strategy=GenerationType.IDENTITY)
+ private long id;
+ @OneToOne
+ private Actor actor;
+ @Column
+ private String text;
+ @Version
+ @Column(columnDefinition="bigint not null default 0")
+ private long version;
+{% endhighlight %}
+
+# Testing
+
+Phew, we annotated all our classes... now what? Well, we will write
+some testcode to use these annotations. We will create a database,
+fill it with some data and then perform several tests on it.
+
+In regards of testing this is called **Integration Testing**. The upside
+of it is that you get a good feel for the accuracy of your code on a
+grand scale, the downside is that it can take quite some time to run
+the test.
+
+As a result we will split our testing cycle between **Unit Tests** and
+**Integration Tests**. Maven will gladly help us here.
+
+## Create a database
+
+But first things first, lets create a database to use for testing. As
+we are using **Postgres** for this application I highly recommend to
+use [pgAdmin3](http://www.pgadmin.org) for the job.
+
+First create a new **Login Role** with the username **yourusername**
+and the password **yourpassword**. You can pick anything you like, as
+long as your remember it.
+
+Then, under **localhost**, create a new database called
+**fromnothing_test** and assign ownership to **yourusername**.
+
+It is important to use a seperate database for testing as we will
+destroy the entire thing every chance we get to ensure our code is
+working correctly on the latest schema generated by **Hibernate**.
+
+## DBUnit and extensions
+
+I will continue to build up the information you need in order to fully
+understand the integration test we will be creating at the end. The
+next piece of information we need is [DBUnit](http://www.dbunit.org).
+
+DBUnit is a tool which allows you to populate your database with a set
+of known data on which you can create tests. This allows you to have
+predictable outcomes every single time.
+
+There are 2 annotations in the project
+[CleanInsertTestExecutionListener](https://github.com/credmp/java-from-nothing/blob/02_adding_persistence/src/test/java/org/credmp/dbunit/CleanInsertTestExecutionListener.java)
+and
+[DataSetLocation](https://github.com/credmp/java-from-nothing/blob/02_adding_persistence/src/test/java/org/credmp/dbunit/DataSetLocation.java).
+
+The first, the CleanInsertTestExecutionListener, ensures that before
+every testmethod runs the database is brought back to a known state.
+In our case it will clean out all the data and reimport our basic set
+of data.
+
+It knows where to get our data from the DataSetLocation. We will set
+this location to **die-hard-set.xml** which will be sought for in the
+classpath. The XML file itself is available on [Github](https://github.com/credmp/java-from-nothing/blob/02_adding_persistence/src/test/resources/die-hard-set.xml).
+
+As we are creating tests in Maven there is a location where we can
+store files that are needed on the classpath. This location is
+**src/test/resources**.
+
+## Telling hibernate what to do
+
+Next we will instruct hibernate what to do for us. This is actually a
+two-fold process. First we will create an XML file call
+**hibernate.cfg.xml** which is located in the resources directory and
+thus available on the classpath.
+
+This file lists all the classes that we want our hibernate system to
+look at for annotations.
+
+{% highlight xml %}
+<?xml version='1.0' encoding='utf-8'?>
+<!DOCTYPE hibernate-configuration PUBLIC
+"-//Hibernate/Hibernate Configuration DTD//EN"
+"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
+
+<hibernate-configuration>
+
+ <session-factory>
+ <mapping class="org.credmp.fromnothing.model.Actor" />
+ <mapping class="org.credmp.fromnothing.model.Movie" />
+ <mapping class="org.credmp.fromnothing.model.MovieCredits" />
+ <mapping class="org.credmp.fromnothing.model.Trivia" />
+ <mapping class="org.credmp.fromnothing.model.Quote" />
+ <mapping class="org.credmp.fromnothing.model.Biography" />
+ </session-factory>
+
+</hibernate-configuration>
+{% endhighlight %}
+
+The second part of the configuration will happen in **Spring**.
+
+## Testing with Spring
+
+**Spring** is a key component in our application. Its **Inversion Of
+Control**, IOC, mechanism allows us to define the existance of our objects
+and the IOC mechanism will connect all the objects.
+
+This prevents us from having the hardcode the relationship of objects.
+
+When we look at the class definition for our test you will see all the
+annotations coming together and a few new ones as well.
+
+{% highlight java %}
+@RunWith(SpringJUnit4ClassRunner.class)
+@ContextConfiguration
+@DataSetLocation("die-hard-set.xml")
+@TestExecutionListeners({DependencyInjectionTestExecutionListener.class,
+ CleanInsertTestExecutionListener.class,
+ TransactionalTestExecutionListener.class})
+@TransactionConfiguration(transactionManager="transactionManager",
+ defaultRollback = true)
+@Transactional
+public class PersistenceTestIT {
+{% endhighlight %}
+
+The @RunWith annotation tells **JUnit** to use the SpringJUnit2ClassRunner
+class, this allows for several **Spring** centric features to be used.
+
+The @ContextConfiguration without any parameters creates an IOC
+container and expects to find an XML file on the classpath at the same
+location as the class with a name derived from the classname itself.
+
+In our case it expects to find
+**org/credmp/fromnothing/PersistenceTestIT-context.xml** on the
+classpath, so we create this file in the resources directory with a
+few subdirectories for org, credmp and fromnothing.
+
+The other annotations are related to the *Transactional* support of
+**Spring**. Basically each test method becomes a transaction in the
+database and all actions executed in them will be rolled back.
+
+The entire XML file is quite large, so it is best viewed on
+[Github](https://github.com/credmp/java-from-nothing/blob/02_adding_persistence/src/test/resources/org/credmp/fromnothing/PersistenceTestIT-context.xml).
+Lets take a look at the most interesting parts:
+
+Configure the system to read the JDBC connection properties from [jdbc.properties](https://github.com/credmp/java-from-nothing/blob/02_adding_persistence/src/test/resources/jdbc.properties).
+
+{% highlight xml %}
+<bean id="propertyConfigurer"
+ class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
+ p:location="jdbc.properties" />
+{% endhighlight %}
+
+For the **Spring** and **Hibernate** integration we will need a
+datasource, for which I choose to use the implementation form
+**commons-dbcp**.
+
+We wil configure **Spring**'s implementation of a **SessionFactory**
+for **Hibernate**. This object connects the datasource,
+hibernate.cfg.xml and the second stage of hibernate configuration.
+
+Here we tell hibernate which dialect to use, to show us the SQL it
+uses and to recreate the schema each time we run the integration
+tests.
+
+And finally we setup a **Transaction Manager** to deal with database
+transactions.
+
+{% highlight xml %}
+<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
+ p:driverClassName="${jdbc.driverClassName}"
+ p:url="${jdbc.databaseurl}"
+ p:username="${jdbc.username}"
+ p:password="${jdbc.password}" />
+
+<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
+ <property name="dataSource" ref="dataSource" />
+ <property name="configLocation">
+ <value>classpath:hibernate.cfg.xml</value>
+ </property>
+ <property name="hibernateProperties">
+ <props>
+ <prop key="hibernate.dialect">${jdbc.dialect}</prop>
+ <prop key="hibernate.show_sql">true</prop>
+ <prop key="hibernate.hbm2ddl.auto">create</prop>
+ </props>
+ </property>
+</bean>
+
+<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
+ <property name="sessionFactory" ref="sessionFactory"/>
+</bean>
+{% endhighlight %}
+
+In the integration test itself we have 1 object which is actually
+directly injected from the IOC; the sessionFactory.
+
+{% highlight java %}
+@Autowired
+private SessionFactory sessionFactory;
+{% endhighlight %}
+
+## Maven failsafe
+
+In order to run the integration tests apart from our normal unit tests
+we need to enable this in the maven configuration file. This is done
+by using the maven-failsafe-plugin.
+
+{% highlight xml %}
+<plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>2.12.4</version>
+ <executions>
+ <execution>
+ <id>integration-test</id>
+ <goals>
+ <goal>integration-test</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>verify</id>
+ <goals>
+ <goal>verify</goal>
+ </goals>
+ </execution>
+ </executions>
+</plugin>
+{% endhighlight %}
+
+Whenever you now want to run your integration tests all you need to do
+is run **mvn verify**.
+
+Maven distinguishes integration tests from normal tests by the last
+part of the filename, namely **IT.java**. So in our case we will create
+a class called **PersistenceTestIT**.
+
+## The integration test
+
+One last special thing about the integration test, as least when using
+postgresql is to reset the sequences after we load the dataset. This
+is one in an method annotated with the *@Before* annotation so that
+they are run before any of the tests are done.
+
+{% highlight java %}
+getSession()
+.createSQLQuery("SELECT setval('actor_id_seq', (SELECT MAX(id) FROM actor))")
+.list();
+{% endhighlight %}
+
+You are now all setup, all you need to do is to create some testcases.
+I have illustrated several below.
+
+{% highlight java %}
+Actor actor = new Actor();
+actor.setFirstName("Arnold");
+actor.setLastName("Schwarzenegger");
+actor.setNickName("Arnie");
+Date date1 = new SimpleDateFormat("MM/dd/yy").parse("06/30/47");
+actor.setBirthDate(date1);
+
+getSession().save(actor);
+{% endhighlight %}
+
+{% highlight java %}
+Query query = getSession().createQuery("from Actor where nickname=:nickname");
+query.setParameter("nickname", "Arnie");
+
+Actor arnie = (Actor) query.uniqueResult();
+{% endhighlight %}
+
+{% highlight java %}
+getSession().delete(actor);
+Actor arnie3 = (Actor) query.uniqueResult();
+assertEquals("Arnie should no longer exist!", null, arnie3);
+{% endhighlight %}
+
+## Conclusion
+
+We have written a pretty impressive set of code at this point; we have
+a data model, we added annotations, configured persistence and lastly
+we did a full integration test on it as well.
+
+As always the code is fully available on
+[Github](https://github.com/credmp/java-from-nothing/tree/02_adding_persistence)
+for your viewing pleasure.
+

0 comments on commit cbcaf47

Please sign in to comment.
Something went wrong with that request. Please try again.