Model variables for all views in Thymeleaf 2.1 with Spring MVC

Recently I’ve stumbled upon quite common problem – how to inject a few variables to every Thymeleaf view in application. Of course there is @ModelParam annotation, I could use interceptor or @ControllerAdvice. All solutions are described on StackOverFlow (it is about controllers).

The problem was that I wanted to put Maven build information in that model (to show version and build time in footer). Therefore I did not need application-scope wiring, as build informations are available during Spring’s container startup. So I’ve found another solution dealing with model itself on the lower level – pure XML configuration. There is a special property in ThymeleafViewResolver that can be used – static variables. So code sample can look like this:

<bean id="thymeleafViewResolver" class="org.thymeleaf.spring4.view.ThymeleafViewResolver">
    <property name="templateEngine" ref="templateEngine" />
    <property name="characterEncoding" value="UTF-8" />
    <property name="staticVariables">
            <map>
                <entry key="myModelVariableIWantToSet" value="My model variable value" />
                <!-- All placeholders taken from context:property-placeholder tag can be used as value-->
            </map>
    </property>
</bean>

All defined variables are put into all Model instances that are linked to Thymeleaf views. If You are just serving plain JSON it does not go there – that can be expected behaviour or not! Be aware of that fact.

OneToMany relations with ordering in Grails – one form solution

The article was written during development. Therefore final solution differs from the code presented in the beginning of this post. If You want to see how working code looks like just check my Github.

It is quite common situation – we want two domain classes to share one form. In addition there is also oneToMany relation between them. And to make things a little bit harder we need to keep order of many side of the relationship – despite delete or create operations. With simple drag&drop functionality. Of course in Grails. Are You ready? Let’s go.

I started with solution described by ObjectPartners, but it got one big problem. It was using additional jQuery plugin, and therefore was doing some kind of ‘under the hood’ job, which was not suitable for my needs. So I have switched to plain jQuery and its plugins mainly due to main information source about this topic. My solution is fairly similar to described in omarello post, but if You do not need other form elements that inputs in your list and do not even think about sorting and ordering them, solution provided by by ObjectPartners will suffice.

Grails way of oneToMany

Before coding there is an important issue raised in comments section. Imports required for code snippets to work include:
import org.codehaus.groovy.grails.plugins.springsecurity.GrailsUserDetailsService
import org.springframework.security.core.authority.GrantedAuthorityImpl
import org.springframework.security.core.userdetails.UserDetails

We should start with two simple domain classes:

package com.wordpress.chlebik

class Article {

	String title
	ArticleType type
	boolean deleted

	static transients = [ 'deleted' ]

	static constraints = {
		title(size: 3..12, nullabe: false)
	}

	String toString() {
		title
	}

}

enum ArticleType {

	NEWS,
	STORY

}

package com.wordpress.chlebik

class Newspaper {

	String name
	List<Article> articles = []

	static hasMany = [articles: Article]

	static mapping = {
		articles cascade:"all-delete-orphan"
	  }

    static constraints = {
		name(nullable: false, blank: false, size: 3..16)
    }

	String toString() {
		name
	}
}

They are simple but provide several usefull features – like list of types in enum and constraints. They are important in this example, but for now we should just focus on simple relation. Newspaper consists of Articles – you should pay attention to the fact, that I have used not only belongsTo mapping, but directly declared that there is a List of Articles. Default Grails’ behaviour with oneToMany relations is to use Set. We want to maintain order fo our Articles so I used List.

If You run application with default data source settings – Grails will automatically create tables in memory (with h2 db engine). Just visit http://localhost:8080/YOURAPPNAME/dbconsole and see by yourself what is going on. We have two simple tables for domain classes and one join table – NEWSPAPER_ARTICLE. There are two columns with foreign keys and what is more important – there is articles_idx column, which is needed for keeping order of articles. And all that thanks to Grails’ db creation. Awesome.

We got model created, now it is time for web layer. Within Grails’ console issue a command:

generate-all com.wordpress.chlebik.Newspaper

and in a moment we have generated controller and views. Unfortunately they do not provide possibility to create new articles within newspaper but it gives us a solid code-base to proceed. First, we should create a newspaper with articles in it. I will not use form generated, as it lacks functionality we need. Nothing as simple as issuing this code on controller or bootstrap:

Newspaper n = new Newspaper(name: 'ChlebikZine')

Article a1 = new Article(title: 'Title1', type: ArticleType.NEWS)
Article a2 = new Article(title: 'Title2', type: ArticleType.NEWS)
Article a3 = new Article(title: 'Title3', type: ArticleType.STORY)
n.articles.add(a1)
n.articles.add(a2)
n.articles.add(a3)

n.save()

Edit and update existing domain class

After running the application we can visit http://localhost:8080/YOURAPPNAME/newspaper/show/1 to see how our newspaper is rendered (I’ve changed page source generated by Grails, eg. removed links to articles edition).

ChlebikZine

It is show action and it looks fine. To now we can switch to editing. I am interested in list with editable fields. Right now I also want to have delete link to remove existing records (we do not add new ones so far). So our _form.gsp should look like this.

<%@ page import="com.wordpress.chlebik.Newspaper" %>

<script type="text/javascript">

jQuery(document).ready( function() {

	$(document).on("click", ".deleteArticle",function(event) {	

		var tableBody = $('#articlesListTableBody');
		var rowToDelete = $(this).closest('tr');
		var rowId = rowToDelete.attr('rowId');		

		// This is for removing only already existing rows in DB.
		if( !$(rowToDelete).attr('newRow') ) {
			$(tableBody).append("<input type='hidden' name='articles[" + rowId + "].deleted' value='true' />");
		}

		$(rowToDelete).remove();
		return false;
	});

	$('.addNewArticle').click( function() {

	});

} );

</script>
<div class="fieldcontain ${hasErrors(bean: newspaperInstance, field: 'name', 'error')} required">
	<label for="name">
		<g:message code="newspaper.name.label" default="Name" />
		<span class="required-indicator">*</span>
	</label>
	<g:textField name="name" maxlength="16" required="" value="${newspaperInstance?.name}"/></div>
<div class="fieldcontain ${hasErrors(bean: newspaperInstance, field: 'articles', 'error')} ">
	<label for="articles">
		<g:message code="newspaper.articles.label" default="Articles" />

	</label>
<table id="articlesList">
<thead>
<tr>
<th>Title</th>
<th>Type</th>
<th>Delete</th>
</tr>
</thead>
<tbody id="articlesListTableBody">
		<g:each in="${newspaperInstance.articles}" var="article" status="i">
<tr rowId="${i}">
<td>
					<g:textField required="" name="articles[$i].title" value="${article.title}"/>
					<g:hiddenField name="articles[$i].id" id="articles[$i].id" value="${article.id}"/></td>
<td>
					<g:select value="${article.type}" name="articles[${i}].type" from="${com.wordpress.chlebik.ArticleType?.values()}" keys="${com.wordpress.chlebik.ArticleType.values()*.name()}" /></td>
<td>
					<a href="#" class="deleteArticle">Delete article</a></td>
</tr>
</g:each></tbody>
</table>
</div>

It is quite simple. Now here is a catch.

In Grails versions before 2.2.x UPDATE method was working differently than shown below. Solution given by ObjectPartners is working then but in newer versions it is not! Check out StackOverflow question. My solution was tested in Grails 2.4.3 with Groovy 2.3.6 and is mainly based on the solution given by Omarello. But it is just partly true. Keep reading to see what I’ve changed to make it work.

Therefore update method of the controller should like this:

 @Transactional
    def update(Newspaper newspaperInstance) {
        if (newspaperInstance == null) {
            notFound()
            return
        }

        if (newspaperInstance.hasErrors()) {
            respond newspaperInstance.errors, view:'edit'
            return
        }

		newspaperInstance.articles.eachWithIndex{ v,i ->
			if( params['articles[' + i + '].deleted'] == 'true' ) {
				v.deleted = true
			}
		}

		newspaperInstance.articles.removeAll{ it.deleted }
        newspaperInstance.save flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.updated.message', args: [message(code: 'Newspaper.label', default: 'Newspaper'), newspaperInstance.id])
                redirect newspaperInstance
            }
            '*'{ respond newspaperInstance, [status: OK] }
        }
    }

If you know better solution please let me know – it seems that wiring between form data/params is not transffering deleted property into created Newspaper entity. I’ve tried using:

newspaper.properties = params

With params filled with proper-named attributes for articles but it is not working! So I had to use additional iteration over all articles to set their deleted property. Again – if there is something I am doing wrong please let me know.

Now we should think about adding new articles to our newspaper. As You have seen it is quite simple – we just need to add inputs/selects to our table (in a view layer) with proper name attribute and that is all. Grails should do all the hard work. So after table we add simple link:

<a href="#" class="addNewArticle">Add new article</a>

And of course do not forget about Javascript.

$('.addNewArticle').click( function() {
		var allArticles = $("#articlesListTableBody tr[rowId]");
		var rowId = 0;			

		// This operation is performed to allow safe-delete of newly created (not saved in DB) articles
		if( allArticles.length ) {
			var maxId = 0;
        	allArticles.each(function() {
            	maxId = Math.max(maxId, parseInt($(this).attr('rowId')));
        	});
        	rowId = maxId+1;
		} 			

		$("#articlesListTableBody").append( '<tr newRow="true" rowId="' + rowId  + '">' +
		'<td><input type="text" required="" name="articles[' + rowId + '].title" value=""/></td>' +
                 '<td><select name="articles[' + rowId + '].type" >' +
        	'<g:each in="${com.wordpress.chlebik.ArticleType?.values()}" var="type">
<option value="${type}">${type}</option></g:each>
</select></td>
' +
									'
<td><a href="#" class="deleteArticle">Delete article</a></td>
</tr>
');

		return false;
	});

Nothing new here. We just add another row in our table. Pay attention to the fact, that there is newRow attribute in newly created row. Now it is clear why there was check for that attribute in delete function – if new article was not stored in DB, removal of it is not needed to be presented with deleted property set. You can play around with above solution – adding and deleting articles was never so easy. There is one thing to add – I resigned from cloning existing rows like it was presented in Omorello post. It is possbile when there are for sure rows in articles list and in my way – we can start with empty list so there is nothing to clone. Appending pure strings is maybe more low-level, but gives developer total control (which was compromised by using writetable-plugin).

Validate me

So far we did not checked two things – creation of totally new newspaper (that will come in a moment), ad validation (in facts it is about re-rendering of the view). Let’s have a look.

In generated views there is required attribute in inputs which are responsible for rendering domain class properties that have nullable : false in constraints. Newspaper name is one of them. Let’s see what will happen if we remove that attribute in GSP and submit empty newspaper name.

SaveSuccess

Apparently everything is all-right. Added article was successfully persisted in the DB. That is because our newspaper is separated from articles – constraint violation on newspaper do not stop persisting new article (because it is proper entity). Now let’s try to remove required attribute from article title and try to submit new article without it – sorry. We receive error message.

NPE

Do not ask me why and what does it mean. fortunately I know what helps – removing @Transactional annotation on our update method in controller!. If you remove it, form will re-render with proper error message. But try to submit form another time with new article empty title. It will give us error with finding deleted property in our code.

newspaperInstance.articles.removeAll{ it.deleted }

Somehow Grails managed to create new article which violates constraint (empty title) and is trying to save it! The cure for this is adding if statement in GSP that is listing all articles.

<g:each in="${newspaperInstance.articles}" var="article" status="i">
<tr rowId="${i}">
<td>
					<g:textField required="" name="articles[$i].title" value="${article.title}"/>
					<g:if test="${article.id}">
						<g:hiddenField name="articles[$i].id" id="articles[$i].id" value="${article.id}"/>
					</g:if></td>
<td>
					<g:select value="${article.type}" name="articles[${i}].type" from="${com.wordpress.chlebik.ArticleType?.values()}" keys="${com.wordpress.chlebik.ArticleType.values()*.name()}" /></td>
<td>
					<a href="#" class="deleteArticle">Delete article</a></td>
</tr>
</g:each>

This is the second time I do not know why Grails behaves like this – I understand that when there is no id attribute Grails will treat created domain class as new instance to persist. But how can it try to persist an entity which fails validation! Just to remember, generated update method has at the beginning:

if (newspaperInstance == null) {
      notFound()
      return
}

if (newspaperInstance.hasErrors()) {
     respond newspaperInstance.errors, view:'edit'
     return
}

Why this works for the first empty-title submit and fails at the second – I have no idea. Fortunately adding show-id logic in GSP helped.

But I want new newspaper

We started this topic from existing entity and editing it. It was easier that way to create clean code and show what is essential in oneToMany in one form. Right now we are going to create new newspaper and add some articles to it. There is already generated form and controller action. The truth is that – it works 😉 But only if we do not start to fool around validation again. To make long things short – there is a problem with treating newly added articles as new ones, not stored in DB (therefore they do not have id). _form.gsp must be modified in a section reponsobile for rendering article list (mainly safe-operator logic).

<table id="articlesList">
<thead>
<tr>
<th>Title</th>
<th>Type</th>
<th>Delete</th>
</tr>
</thead>
<tbody id="articlesListTableBody">
		<g:each in="${newspaperInstance.articles}" var="article" status="i">
<tr <g:if test="${!article?.id}">newRow="true"</g:if> rowId="${i}">
<td>
					<g:textField required="" name="articles[$i].title" value="${article?.title}"/>
					<g:if test="${article?.id}">
						<g:hiddenField name="articles[$i].id" id="articles[$i].id" value="${article?.id}"/>
					</g:if></td>
<td>
					<g:select value="${article?.type}" name="articles[${i}].type" from="${com.wordpress.chlebik.ArticleType?.values()}" keys="${com.wordpress.chlebik.ArticleType.values()*.name()}" /></td>
<td>
					<a href="#" class="deleteArticle">Delete article</a></td>
</tr>
</g:each></tbody>
</table>

Now we can do whatever we want with creation of new entity – try to break validation, add and delete articles, try to break articles’ validation, whatever You want. It just works 😉

Gimme more – I want to sort things out

Generally I did not expect sorting to work so easily and quickly. Of course You need to download/link jQeury UI with sortable. After that You must change _form.gsp to this:

<%@ page import="com.wordpress.chlebik.Newspaper" %>

<script type="text/javascript">

jQuery(document).ready( function() {

	$(document).on("click", ".deleteArticle",function(event) {	

		var tableBody = $('#articlesListTableBody');
		var rowToDelete = $(this).closest('tr');	

		// This is for removing only already existing rows in DB.
		if( !$(rowToDelete).attr('newRow') ) {
			var rowId = $(rowToDelete).attr('rowId')
			var articleId = $("input[name='articles[" + rowId + "].id']").val();
			$(tableBody).append("<input type='hidden' name='articles[" + articleId + "].deleted' value='true' />");
		}

		$(rowToDelete).remove();
		return false;
	});

	$('.addNewArticle').click( function() {
		var allArticles = $("#articlesListTableBody tr[rowId]");
		var rowId = 0;			

		// This operation is performed to allow safe-delete of newly created (not saved in DB) articles
		if( allArticles.length ) {
			var maxId = 0;
        	allArticles.each(function() {
            	maxId = Math.max(maxId, parseInt($(this).attr('rowId')));
        	});
        	rowId = maxId+1;
		} 			

		$("#articlesListTableBody").append( '<tr newRow="true" rowId="' + rowId  + '">' +
		'<td><input required="true" type="text"  name="articles[' + rowId + '].title" value=""/></td>' +
                '<td><select name="articles[' + rowId + '].type" >' +
		'<g:each in="${com.wordpress.chlebik.ArticleType?.values()}" var="type">
                  <option value="${type}">${type}</option>
                 </g:each></select></td>' +
                 '<td  class="moveRow"><a href="#" class="deleteArticle">Delete article</a></td>
                  <td class="moveRow">Move</td></tr>');

		return false;
	});

	 $('#articlesListTableBody').sortable({
	        stop: function (event, ui) {
	            updateNames($(this))
	        },
	        handle: '.moveRow',
	    });

	 function updateNames($tbody) {
		    $tbody.find('tr').each(function (idx) {
		        var $inp = $(this).find('input,select,textarea');
		        $(this).attr('rowId', idx);
		        $inp.each(function () {
		            this.name = this.name.replace(/(\[\d\])/, '[' + idx + ']');
		        })
		    });
	}

   } );

</script>
<div class="fieldcontain ${hasErrors(bean: newspaperInstance, field: 'name', 'error')} required">
	<label for="name">
		<g:message code="newspaper.name.label" default="Name" />
		<span class="required-indicator">*</span>
	</label>
	<g:textField name="name" required="" maxlength="16"  value="${newspaperInstance?.name}"/></div>
<div class="fieldcontain ${hasErrors(bean: newspaperInstance, field: 'articles', 'error')} ">
	<label for="articles">
		<g:message code="newspaper.articles.label" default="Articles" />

	</label>
<table id="articlesList">
<thead>
<tr>
<th>Title</th>
<th>Type</th>
<th>Delete</th>
<th>Move</th>
</tr>
</thead>
<tbody id="articlesListTableBody">
		<g:each in="${newspaperInstance.articles}" var="article" status="i">
<tr <g:if test="${!article?.id}">newRow="true"</g:if> rowId="${i}">
<td>
					<g:textField required="" name="articles[$i].title" value="${article?.title}"/>
					<g:if test="${article?.id}">
						<g:hiddenField id="" name="articles[$i].id" value="${article?.id}"/>
					</g:if></td>
<td>
					<g:select value="${article?.type}" name="articles[${i}].type" from="${com.wordpress.chlebik.ArticleType?.values()}" keys="${com.wordpress.chlebik.ArticleType.values()*.name()}" /></td>
<td>
					<a href="#" class="deleteArticle">Delete article</a></td>
<td class="moveRow">
					Move</td>
</tr>
</g:each></tbody>
</table>
<a href="#" class="addNewArticle">Add new article</a></div>

JavaScript code used in this example comes from StackOverflow question – it works just out-of-the-box. But there is a catch – only with already persisted entities. So create new newspaper, add several new articles, save them. After that edit newspaper switch order and save it again. It works like a charm.

The problems begin when removal of rows or changing order of not yet persisted rows – I receieved many different errors and logical errors. It took me about two hours – after that I was not sure what was the reason that it started working 😉 But it does – I definetly added refreshing input-indexes after row removal in Javascript (same action that is triggered when sorting ends). I’ve removed delete property completly – and it still works. Magic.

So here is view and controller.

<%@ page import="com.wordpress.chlebik.Newspaper" %>

<script type="text/javascript">

jQuery(document).ready( function() {

	$('#articlesListTableBody').sortable({
        stop: function (event, ui) {
            updateNames($(this))
        },
        handle: '.moveRow',
    });

 	function updateNames($tbody) {
	    $tbody.find('tr').each(function (idx) {
	        var $inp = $(this).find('input,select,textarea');
	        $(this).attr('rowId', idx);
	        $inp.each(function () {
	            this.name = this.name.replace(/(\[\d\])/, '[' + idx + ']');
	        })
	    });
	}

	$(document).on("click", ".deleteArticle",function(event) {	

		var tableBody = $('#articlesListTableBody');
		var rowToDelete = $(this).closest('tr');	

		$(rowToDelete).remove();
		updateNames(tableBody);
		return false;
	});

	$('.addNewArticle').click( function() {
		var allArticles = $("#articlesListTableBody tr[rowId]");
		var rowId = 0;			

		// This operation is performed to allow safe-delete of newly created (not saved in DB) articles
		if( allArticles.length ) {
		    var maxId = 0;
        	    allArticles.each(function() {
            	        maxId = Math.max(maxId, parseInt($(this).attr('rowId')));
        	    });
        	    rowId = maxId+1;
		} 			

		$("#articlesListTableBody").append( '<tr newRow="true" rowId="' + rowId  + '">' + 									
                 '<td><input required="true" type="text"  name="articles[' + rowId + '].title" value=""/></td>' +
                 '<td><select name="articles[' + rowId + '].type" >' +
		'<g:each in="${com.wordpress.chlebik.ArticleType?.values()}" var="type">
                 <option value="${type}">${type}</option></g:each></select></td>' +
		'<td  class="moveRow"><a href="#" class="deleteArticle">Delete article</a></td><td class="moveRow">Move</td></tr>');

		return false;
	});

} );

</script>
<div class="fieldcontain ${hasErrors(bean: newspaperInstance, field: 'name', 'error')} required">
	<label for="name">
		<g:message code="newspaper.name.label" default="Name" />
		<span class="required-indicator">*</span>
	</label>
	<g:textField name="name" required="" maxlength="16"  value="${newspaperInstance?.name}"/></div>
<div class="fieldcontain ${hasErrors(bean: newspaperInstance, field: 'articles', 'error')} ">
	<label for="articles">
		<g:message code="newspaper.articles.label" default="Articles" />

	</label>
<table id="articlesList">
<thead>
<tr>
<th>Title</th>
<th>Type</th>
<th>Delete</th>
<th>Move</th>
</tr>
</thead>
<tbody id="articlesListTableBody">
		<g:each in="${newspaperInstance.articles}" var="article" status="i">
<tr <g:if test="${!article?.id}">newRow="true"</g:if> rowId="${i}">
<td>
	<g:textField id="" required="" name="articles[$i].title" value="${article?.title}"/>
		<g:if test="${article?.id}">
			<g:hiddenField id="" name="articles[$i].id" value="${article?.id}"/>
		</g:if></td>
<td>
	<g:select value="${article?.type}" name="articles[${i}].type" from="${com.wordpress.chlebik.ArticleType?.values()}" keys="${com.wordpress.chlebik.ArticleType.values()*.name()}" /></td>
<td>
	<a href="#" class="deleteArticle">Delete article</a>
</td>
<td class="moveRow">Move</td>
</tr>
</g:each></tbody>
</table>
<a href="#" class="addNewArticle">Add new article</a></div>
 def update(Newspaper newspaperInstance) {

        if (newspaperInstance == null) {
            notFound()
            return
        }

        if (newspaperInstance.hasErrors()) {
            respond newspaperInstance.errors, view:'edit'
            return
        }

	newspaperInstance.articles.clear()
	newspaperInstance.properties = params

	newspaperInstance.save flush:true

        request.withFormat {
            form multipartForm {
                flash.message = message(code: 'default.updated.message', args: [message(code: 'Newspaper.label', default: 'Newspaper'), newspaperInstance.id])
                redirect newspaperInstance
            }
            '*'{ respond newspaperInstance, [status: OK] }
        }
    }

Almost finished

Looking back at all the trouble I had with figuring out the proper solution made me wonder – why do not use AJAX? This is fine idea but I wanted to deal with pure Grails’ form handling. Full source (with final solution) can be found on my Github. As I mentioned before – I have used Grails 2.4.3 with Groovy 2.3.6.

ENUM in Grails with i18n support

Enums are pretty usefull Java feature. However, developers often encounter problems with two things – reflecting enum in database and i18n. Database is often a easy thing – store enum value in character column or even in specialised column type (eg. in MySQL). Internationalization is a little bit harder but fortunately Grails makes it so easy. The goal of this tutorial is to show how Grails can present enum values in a view layer with translated values.

The key interface is MessageSourceResolvable  which comes of course from Spring. We can have simple enum like this:

 

enum WarriorLevel implements org.springframework.context.MessageSourceResolvable {

    BEGGINER, NOVICE, APPRENTICE, MASTER

    // Methods inherited from interface
    public Object[] getArguments() { [] as Object[] }
    public String[] getCodes() { [ name() ] }
    public String getDefaultMessage() { name() }
}

Nothing new except implementation of methods inherited from interface. They are very simple, just for demonstration purposes.
Another thing to be done are internationalization entries. Grails keeps them in i18n folder with separate files for every language that can be supported. I come from Poland therefore my filename is messages_pl.properties. For given enum entries look like that (prefix is just for clearance):

com.wordpress.chlebik.BEGGINER=nowy
com.wordpress.chlebik=nowicjusz
com.wordpress.chlebik=adept
com.wordpress.chlebik=mistrz

Now the only thing is to put everything in motion – in a view layer we naturally use Grails tags to create select element:

<g:select name="chlebikTest" from="${WarriorLevel?.values()}" keys="${WarriorLevel .values()*.name()}" value="${warrior?.level?.name()}" valueMessagePrefix="com.wordpress.chlebik" />

And that’s all folks. Here are some links about it:

Grails page (check out last entry)
Enum in Grails domain from StackOverflow
Enum in GSP view from StackOverflow

Incrementing Grails application version during WAR packaging

Grails comes with several predefined properties, which can be used in application or build process. One of them is application version. It can be found in application.properties file and the usual way is to change it manually. Of course we can find a plugin – version updater – that makes that via Grails console. But what about situation in which every WAR creation should trigger version update?

Quick fix for that can be seen below (it is based on the script I have found on this blog). It is a simple script which should be places in /scripts folder of our project in a file named _Events.groovy. During WAR creation this script will be read and executed. Of course logic presented is fairly simple and lacks some parameters validation but I will leave it up to the developer.


eventCreateWarStart = { warName, stagingDir ->
	
	Map<String,Integer> mappings = [ 'M' : 0, 'm' : 1, 'p' : 2 ]
	String versionParam = System.getProperty('version.update.position', 'M')
	def lastAppVersionNumberList = metadata.'app.version'.split('\\.')
			   
	
	println "*** Started customised version update of Grails app. Current version: ${metadata.'app.version'}"
				
	lastAppVersionNumberList[ mappings[versionParam] ] =        Integer.valueOf(lastAppVersionNumberList[mappings[versionParam]]) + 1
	
	metadata.'app.version' = lastAppVersionNumberList.join('.')
	metadata.persist() 
	
	println "*** Ended customised version update of Grails app. Current version: ${lastAppVersionNumberList.join('.')}"
}

Grails logging class names

I have recently dived into Grails’ logging features. It is simple mechanism but I stumbled upon a problem with class names. If You want to log behaviour in controllers, domains or services – You have to prefix class name with prefix grails.application. So when I tried to log my services i should have write something like this:

warn   'grails.app.services.com.wordpress.chlebik.MyClass'

Instead of:

warn   'com.wordpress.chlebik.MyClass'

The truth is that documentation shows that in code samples – next time – read the manual stupid 😉

LDAP Authentication and DB authorisation with Grails Spring Security

Recently I faced quite simple problem – allow application to authenticate users via LDAP but authorise them via database. It is a common solution – we make sure that only company’s users are logging into app, but there comes flexibility with ACL stored locally. In Grails it looked pretty simple until I started to integrate this solution into my application. It took me a while to put everything together so I decided to share it.

To make long things short – there is an offical documentation but IMHO, it should be tweaked a little to be more user-friendly. The most important thing to understand are sides and roles that take place in logging process. There is LDAP instance, where we send requests to authorise user. LDAP response must be transmitted to our app and full our users’ object. Meanwhile there is also roles read from database. In addition there is simple check – if logging user has no account in our app, we will create it with default roles.

My app uses simple domain classes provided by Spring Security (User, Role and UserRole). If You are not familiar with them I suggest reading official docs. First we create UserMappingDetails class, which is simple POJO that will store user data (login, password, account data) and authorities (roles that user has).

class ChlebikUserDetails extends GrailsUser {

   ChlebikUserDetails(String username, String password, boolean enabled,
                 boolean accountNonExpired, boolean credentialsNonExpired,
                 boolean accountNonLocked,
                 Collection<GrantedAuthority> authorities,
                 long id, String fullName) {
      super(username, password, enabled, accountNonExpired,
            credentialsNonExpired, accountNonLocked, authorities, id)      
   }
}

Next we create mapping class, which will translate LDAP response to our application user.

class ChlebikUserDetailsContextMapper implements UserDetailsContextMapper {

	private static final List NO_ROLES = [new SimpleGrantedAuthority(SpringSecurityUtils.NO_ROLE)]
		
	@Override
	@Transactional
	public ChlebikUserDetails mapUserFromContext(DirContextOperations ctx, String username, Collection<SimpleGrantedAuthority> authority) {
		
		User user = User.findByUsername(username)
		
		if(!user) {					
				// Create new user and save to the database                                
				user = new User()
				user.username = username				
				user.password = "123" // doesn't matter
				user.save(flush: true, failOnError: true)
									
				UserRole userRole = new UserRole()
				userRole.user = user
				userRole.role = Role.findByAuthority('USER') // Default role in my app
				userRole.save(flush: true, failOnError: true)			
		}
						 
		def authorities = user.getAuthorities().collect { new SimpleGrantedAuthority(it.authority) }		
		def userDetails = new ChlebikUserDetails(username, user.password, user.enabled, false,
					false, false, authorities, user.id, username)
		return userDetails
	}

	
	@Override
	public void mapUserToContext(UserDetails arg0, DirContextAdapter arg1) {}	
}

Ok, we are getting closer. Last class to create is service that will be called by Spring Security to retrieve our user when needed. It cannot be put in Grails’ service directory!!! Just place it in src/groovy

class PrePopulateUserDetailsService implements GrailsUserDetailsService  {
	
	Logger logger = Logger.getLogger(getClass())
	LdapUserDetailsService ldapUserDetailsService
	
	static final List NO_ROLES = [new SimpleGrantedAuthority(SpringSecurityUtils.NO_ROLE)]
	
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
		return loadUserByUsername(username, true)
	}
	
	@Override
	@Transactional	// Services in Grails are transactional by default but it is normal class so we put this annotation
	public UserDetails loadUserByUsername(String username, boolean loadRoles) throws UsernameNotFoundException, DataAccessException {
				
		User user = User.findByUsername(username)
		def authorities = user.getAuthorities().collect {new SimpleGrantedAuthority(it.authority)}
		
		return new ChlebikUserDetails(user.username, user.password, user.enabled,
			!user.accountExpired, !user.passwordExpired,
			!user.accountLocked, authorities ?: NO_ROLES, user.id,
			user.username)   
	}
}

That’s all. Of course we need to add some config to our application. First we visit configuration folder and spring subfolder. There in resources.groovy we put this (registering beans):

beans = {		
	ldapUserDetailsMapper(com.wordpress.chlebik.ChlebikUserDetailsContextMapper)
	userDetailsService(com.wordpress.chlebik.PrePopulateUserDetailsService)
}

And in out Config.groovy (or whatever user-defined config file You are using) we should have several config properties. I am putting them all (to allow Grails connect to LDAP).

grails.plugin.springsecurity.providerNames = ['rememberMeAuthenticationProvider', 'ldapAuthProvider', 'anonymousAuthenticationProvider']

// Probably better to keep this data in an external file for security reasons
grails.plugin.springsecurity.ldap.context.managerDn = ''
grails.plugin.springsecurity.ldap.context.managerPassword = ''
grails.plugin.springsecurity.ldap.context.server = ''

grails.plugin.springsecurity.ldap.authorities.ignorePartialResultException = true // typically needed for Active Directory
grails.plugin.springsecurity.ldap.search.base = 'CN=putwhatyoumust,O=putwhatyoumust'
grails.plugin.springsecurity.ldap.authenticator.dnPatterns=='uid={0},CN=putwhatyoumust,O=putwhatyoumust'
grails.plugin.springsecurity.ldap.search.filter="uid={0}" 
grails.plugin.springsecurity.ldap.search.searchSubtree = true
grails.plugin.springsecurity.ldap.auth.hideUserNotFoundExceptions = false

// These are crucial for LDAP/DB configuration
grails.plugin.springsecurity.ldap.mapper.userDetailsClass='com.wordpress.chlebik.ChlebikUserDetails'
grails.plugin.springsecurity.ldap.authorities.retrieveGroupRoles = false
grails.plugin.springsecurity.ldap.authorities.retrieveDatabaseRoles = true

And it magically works. Above code is the result of several hours on the web. Below I put all links that helped me a lot.

Grails passwords salted
Juan Vazquez GitHub
Most helpfull Nabble
Customizing authentication in your grails app
Official plugin page

Groovy 2.3.5 backward compatibility with Spock unit tests

In my new workplace there is a problem – corporate firewall, which is a common problem in IT world. Therefore update sites of Eclipse are blocked, which means quite a mess with dependencies and plugin management.

My main concern was Spock, which I have run using built-in Groovy in version 2.3.6, while tests and whole application was written in Grails 2.2.3 with Groovy a little bit older 😉 Finally it came to my attention that hated exception

Caused by: java.lang.ClassNotFoundException: org.codehaus.groovy.runtime.typehandling.ShortTypeHandling at java.net.URLClassLoader$1.run(URLClassLoader.java:372)

can be easily fixed in a way that Guillaume Laforge wrote. Just downloaded JAR, added to project’s classpath and there it is – my Spock test are working like charm.

Welcome back Grails

I started my journey with learning Java web-frameworks with Grails. That was really long time ago (around 2009) with Grails’ version 1.0.4. When I became full-time Java programmer I used Grails in several internal CRUD apps, but it was quick&dirty solution to provide basic functionality. My new job (I’ve just started) involves mainly programming with Groovy&Grails therefore I’ve decided to write a few posts about what is going on in Groovy&Grails world right now.

grails Before I start there is a big announcement. As Graeme Rocher posted on Twitter, new version of Grails (starting with number 3) will be totally new thing – based on Spring Boot and many projects around it. Therefore Grails being described here is going to retire in a predictable future. Just so You know.

The latest version of Grails which I am using is 2.4.3 with Groovy in version 2.3. In a following article I am gonna to point out some problems and interesting things I have discovered while ‘getting in touch’ with latest Grails.

Scaffolding

Scaffolding is often presented as one of the most ‘groovy’ thing in Grails. The ability to quickly prototype working application is powerful feature and it was a place where I started my revisit. And right at the beginning I have encountered an subtle problem. Reference documentation says that there is a possibility to run such code:

class UserController {
     static scaffold = true     
}

And it should work with existing User domain class. I have given it a try but I was unsuccessfull. Why? Grails complained about missing domain class. What have I done wrong? The problem is with packaging – I have never liked examples using default package. With Grails it is even more problematic as there are separate folders for controllers, domain classes and so on. Therefore as I created com.wordpress.chlebik.grails.tutorial package inside domain folder, framework could not resolve proper path. The solution is simple – just use full class name.

class UserController {
     static scaffold = com.wordpress.chlebik.grails.tutorial.User
}

It works like a charm. It is also possible to use such code to enable scaffolding for a given domain class even from controllers with different name:

class AdminController {
     static scaffold = com.wordpress.chlebik.grails.tutorial.User
}

In my opinion Grails scaffolding is even better than it was with feature called static scaffolding. Back in 2009 scaffolding was interesting, but it was done as a ‘runtime magic’. There was no way to interact with generated sources (or it was not so easy). Right now we have static scaffolding which is scaffolding but with generated sources. Imagine creating simple domain class like User

class User {

    static constraints = {}
	
    String       firsrName
    String       lastName	
    String       email	
	
}

Using Grails console or IDE support we can invoke command:

grails generate-all User

which creates separate views (I mean GSP files) and controller with implemented methods. What is more cool, are test classes (based on Spock specifications) generated as well with testing logic within! So if You are not familiar with unit-testing – it is a great place to learn how it is done.

Testing

A few years ago my knowledge about TDD was almost non-existent. It has changed since then, therefore I welcomed Grails’ testing support pretty great. As I mentioned above, we can be given out-of-the-box tests methods with logic in them. Of course it is not what TDD is about, but it makes a good start to make changes and go further. What is more interesting is use of mixins. They provide simple way to link tested class with tests itseslf. What is more cool is use of Spock testing framework. I have to admit I have a problem with finding which plugin/core functionality provides Spock as a dependency. There is Spock Grails Plugin but I do not see any dependencies to it in plain configuration files.

But enough of it – we have Spock at our service, so using it is very simple. Just like this:

@TestFor(UserController)
class UserControllerSpec extends Specification {

    def setup() {
    }

    def cleanup() {
    }

    void "test something"() {
    }
}

If You are trying to run above test it is possible You get initializationError. Test method must atually test something – leaving empty method body is not an option!

We are given several implicit objects like request, response, controller, view to support controller testing. We can use very straightforward annotation @Mock – which just instantiates in-memory GORM which mocks all ORM-related calls. There is also possiblity to run integration tests, and what is even more cool – even more plugin for functional tests. Back in time there was only Canoo available, now new solutions like Selenium and Geb are also an option. It is hard to write here all about testing in Grails. I am planning to wrote more in separate posts.

Config options

Config files are still very neat way to tail application to our needs. What is the most important change since I last worked with Grails is added BuildConfig.groovy file, which was designed to separate configuration of build process and application config itself. What is more fabulous is logging configuration – so many customizing possibilities! To keep things short I am planning also some kind of post about it, but there is a nice place to start.

Asset Pipeline Plugin

As a Java programmer I am not keeping up with latest changes in HTML&CSS&JavaScript community. There has been tremendous progress in that areas lately (not to mention HTML5, LESS&SASS, writing MVP apps in JavaScript). Therefore creators of Grails are trying to simplify several things so they have switched from resources-plugin to asset-pipeline-plugin.

With previous approach, all resources put in web-app folder were just laying there waiting for the programmer to use them. It was a matter of view layer to include or exclude used resources. Right now plugin has possibility to include or exclude portions of CSS or JavaScript used on certain page. Another cool thing is ability to automaticaly apply changes in resources code while in development mode. there is a great Youtube video about it.

Static compilation

Somewhere by the road to Groovy 2.0 and Java 7 appeared static compilation and invoke dynamic. To make long things short – in a situation where You do not need dynamic Groovy features, it is possible to disable them and gain boost on performance. There are is nice blog post worth mentioning.

Summary

As I walk through the latest reference documentation I constantly see something new. It is hard to put everything in one blog post therefore I am planning several additional articles about latest Grails and Groovy combo. Stay tuned.

Jak zarządzać bałaganem frameworków, czyli o narzędziu GVM

Z pewnością znacie ten ból, kiedy używa się jednego z frameworków czy języków JVM, których kolejne wersje wychodzą dość często i dobrze byłoby od czasu do czasu uaktualnić istniejące instalacje. Zazwyczaj kończymy z dużą ilością poinstalowanych wersji, w różnych miejscach i nie wiedząc do końca ile tego mamy i gdzie. Jeżeli nie jest to sytuacja Wam obca polecam zapoznanie się z bardzo fajnym narzędziem o nazwie GVM, które jest napisane w czystym bash-u, a do sprawnego działania potrzebuje tylko curl-a oraz unzip-a. Narzędzie to pozwala w bardzo wygodny sposób zarządzać wszystkimi zainstalowanymi wersjami najróżniejszych bibliotek – oto lista obecnie wspieranych:

  • Groovy
  • Grails
  • Griffon
  • Gradle
  • Groovyserv
  • Lazybones
  • vert.x
  • Crash
  • Glide
  • Gaiden
  • JBake
  • Springboot

Więcej informacji oraz sposoby użycia można znaleźć na oficjalnej stronie narzędzia.

Działający przykład JEE w akcji

Jakoś tak się złożyło, że poza servletami i JPA niespecjalnie miałem w życiu pobawić się w EJB i insze wynalazki. Fakt, że pojawił się kiedyś dawno Spring skutecznie zniechęcał do posiłkowania się JEE w codziennym developmencie. Jednakże sytuacja zmieniła się wraz z wydaniem wersji 6 Javy EE.

Szukając w sieci materiałów dla przygotowań do certyfikatu Java Persistence API Developer Certified Expert (tak tak, pierwsze wpisy z przygotowań już niedługo) znalazłem dość ciekawy tutorial, który umożliwia postawienie w pełni funkcjonalnej aplikacji, na której możnaby przećwiczyć mniej i bardziej zaawansowane tematy związane z tą certyfikacją.

JBoss to nazwa budząca respekt. Jako firma oferuje szeroki wachlarz produktów – począwszy od serwera aplikacyjnego skończywszy na IDE. Oferuje również strasznie fajny tutorial znajdujący się  dokładnie pod tym adresem. Obejmuje on instalację dedykowanego IDE oraz przedstawia JEE w akcji – mamy i usługi sieciowe, mamy JSF, mamy też podpięte Hibernate jako ORM. Nic tylko brać i działać. Jeśli ktoś potrzebuje zobaczyć jak może wyglądać sensowna appka bez miliona zależności w POMie to powyższy adres jest świetnym punktem wyjścia.

Tag g:select w Grails

Ostatnio miałem z Grailsami cokolwiek niefajną sytuację, a poszło o tag g:select. Zasadniczo nie wiem, co zawiniło – moje luźne podejście, brak dostatecznego przetestowania, czy mało przejrzysta dokumentacja. Pewnie wszystko po trochu.

Zacznijmy jednak od początku. Jak można się łatwo domyślić w GSP użycie tagu g:select ma docelowo doprowadzić do wyrenderowania znacznika <select>. Póki co wszystko jasne. Znaczącym ułatwieniem jest również fakt, iż znacznik ten może posiadać atrybut multiple, który pozwala użytkownikowi na wybranie nie jednego, ale kilkunastu elementów z listy. W moim przypadku były to kategorie – choć to rzecz bez znaczenia, grunt, iż etykietami były łańcuchy znaków, zaś przekazywanymi wartościami identyfikatory liczbowe (konkretnie wartości klucza głównego w bazie danych). Przyjmijmy taką oto sytuację:

<g:select name="kategorie" from="${kategorieList}" value="${wybranePoprzednioID}"
 optionKey="id" multiple="true" />

Na liście kategorii znajduje się kilkanaście obiektów, zaś identyfikatory wybrane z listy (po np. wadliwej walidacji i ponownym wyrenderowaniu formularza) znajdują się w zmiennej/kolekcji o nazwie ${wybranePoprzednioID}. Po stronie kontrolera działał taki oto pseudokod:

if( kategorie ) {
    kategorie.each {
       zapiszIDDoBazy( it )
    }
}

Kiedy wybierano na liście tylko jeden element wszystko było OK. Co więcej – kiedy na liście wybierano kilka elementów również wszystko było OK. Problem zaczął się w momencie, gdy aplikacja wylądowała na serwerze preprodukcyjnym. W czym problem? Otóż po wybraniu jednego elementu z listy okazywało się, że po ponownym wyświetleniu formularza (po udanym zapisie do bazy danych) zaznaczona kategoria nie pokrywała się z tą, którą wybrano przed zapisaniem. Ot zagwozdka. Przy wybieraniu dwóch lub więcej elementów – działało poprawnie. Szybki debug i oto co się okazało.

Kategorie w bazie danych znalazły się ‘ręcznie’. To znaczy, że zostały wprowadzone grubym klientem bezpośrednio do bazy danych i oczywiście sekwencja przydzieliła ładne identyfikatory startując od numeru 1 (z krokiem też o 1). Zatem mieliśmy bodajże 7 kategorii, spośród których można było wybierać, każda posiadająca identyfikator mniejszy niż 10. Wraz z przejściem na preprodukcję do pracy wzięli się nie tylko testerzy (ci przetestowali aplikację i wszystko było OK, nawet po dodaniu kategorii), ale również docelowi użytkownicy. A ci z kolei pododawali o wiele więcej kategorii do wyboru i tym samym identyfikatory rekordów zaczęły składać się z 2 cyfr. Co z tego wynika?

Otóż Groovy w konstrukcji each przechodzi po kolejnych elementach obiektu, na rzecz którego został wywołany. W przypadku kolekcji oznacza to przejście po wszystkich elementach, zaś w przypadku łańcuchów tekstowych – po każdym znaku w tymże łańcuchu! Przy wybraniu kilkunastu elementów wartość parametru była kolekcją – zatem iteracja szła dobrze. Przy zaznaczeniu kategorii ‘początkowych’, czyli takich, które miały identyfikatory mniejsze niż 10 również wszystko było OK. Problemem było wybranie 1 elementu o identyfikatorze np. 14Grails traktował wówczas parametr jako łańcuch tekstowy i wykonanie takiego kodu:

if( kategorie ) {
 kategorie.each {
println it
 }
}

Dla identyfikatora 14 dawało na wyjściu:


1
4

Czyli jako dwie oddzielne wartości. Widzicie już problem? W bazie danych istniały kategorie o takich identyfikatorach (1 oraz 4) zatem przy zapisie nie było mowy o wyrzuceniu wyjątku czy błędach – wszystko się zgadzało, kategorie istniały to Grails grzecznie je zapisał. Problem był taki, że to dane wejściowe nie były do końca tymi, na które liczyliśmy.  Czyli zamiast jednej kategorii o identyfikatorze 14 mieliśmy dwie kategorie o identyfikatorach oraz 4.  Typowy błąd logiczny – godzinka na debugowaniu w plecy.  Stąd ten wpis i mam nadzieję, że dzięki niemu zdarzy się uniknąć komuś takiej sytuacji 😉

Natywne zapytania SQL w Groovy i Grails

Grails jeśli chodzi o zabawy z bazą danych potrafi być bardzo wdzięczny. Niestety czasami potrzebujemy odpytać bazę w sposób, do którego magii Grails po prostu nie da się użyć. Tutaj z pomocą przychodzi sam Groovy.

Załóżmy, że potrzebujemy zapytania sumującego szereg wartości z tabeli. Posłużę się znów przykładem tabeli z wpisami na blogu. Przyjmijmy, że w wierszach trzymamy informacje o odsłonach danego wpisu, ale z podziałem na np. dni. Czyli mamy dzisiejsze odsłony, odsłony z wczoraj i odsłony od początku istnienia danego wpisu. Użycie Grailsów w tym przypadku nie bardzo się powiedzie zatem kod napiszemy w Groovym, korzystając z dobrodziejstw klasy groovy.sql.Sql.


 def dataSource

 String sqlAllCommand = "SELECT SUM(show_count_all) AS sca, SUM(show_count_yesterday) AS scy, SUM(show_count_today) AS sct FROM posts";
 groovy.sql.Sql sql = new groovy.sql.Sql( dataSource )

 sql.eachRow( sqlAllCommand, { row ->
			println row.sca + " " + row.scy + " " + row.sct
		} )

 sql.close()

Jak widać rzecz jest dość prosta. Jedyną rzeczą o której należy pamiętać jest skorzystanie z dependency injection dla otrzymania obiektu dataSource. Problemem niestety jest to, iż bezpośrednie posługiwanie się beanem dataSource może w perspektywie powodować wyczerpywanie się puli wątków na serwerze lub komunikatem w stylu dataSource is closed (pomimo teoretycznego zamykania połączenia odpowiednią metodą). Poszukując w internecie rozwiązania natknąłem się na rozwiązanie bazujące na Hibernate. Oto ono:

def sessionFactory

String sqlAllCommand = "SELECT SUM(show_count_all) AS sca, SUM(show_count_yesterday) AS scy, SUM(show_count_today) AS sct FROM posts";
groovy.sql.Sql sql = new groovy.sql.Sql( sessionFactory.currentSession.connection() )

 sql.eachRow( sqlAllCommand, { row ->
		println row.sca + " " + row.scy + " " + row.sct
		} )

W tym przypadku pozwalamy by to Hibernate grzecznie użyczył nam obiektu sesji, a po zakończeniu pracy bez jakiegokolwiek udziału z naszej strony zajmuje się połączeniem. Błędy dotyczące ilości połączeń znikają.

Kilkukrotne wykorzystanie kryteriów szukania w Grailsach

Podobnie jak w poprzednim wpisie pozostajemy dziś w obrębie współpracy Grails z Hibernate. Choć może by być bardziej konkretnym – z mechanizmem domknięć w Groovym.

Bardzo często występującą sytuacją jest stosowanie paginatorów do prezentacji wyników wyszukiwania lub po prostu wylistowania wszystkich danych z bazy. Ma to na celu ułatwienie nawigacji użytkownikowi, ale też odciążenie bazy i łącza (nie przesyłamy na raz olbrzymich zbiorów wyników). Grailsy posiadają bardzo praktyczny tag GSP, który generuje poprawne menu paginacji oraz obsługuje co trzeba. Warunkiem koniecznym dla poprawnego działania tego mechanizmu są:

  • skonfigurowanie paginatora – czyli podanie podstawowych danych jak zakres wyświetlanych stron, bieżącą stronę i tym podobne informacje
  • wyciągnięcie danych – wyniki, które mamy zaprezentować musimy w jakiś sposób otrzymać (lub po prostu strzelić po nie do bazy)
  • podać łączną ilość wierszy w zbiorze wynikowym – i tym właśnie się teraz zajmiemy

Posiłkując się przykładem z poprzedniego wpisu (artykuły preentowane na blogu) – załóżmy, iż łączna ilość tychże wynosi 166. W panelu zarządzania blogiem, albo też na głównej stronie prezentowanie listy ich wszystkich mija się z celem. Załóżmy zatem, iż potrzebujemy do wyświetlenia tylko 10 rekordów. Otrzymanie ich z bazy danych jest dość proste (w przypadku Grails wręcz banalne – wystarczy odpowiednio manipulować metodami listującymi). Jednakże wypadałoby otrzymać informację o magicznej liczbie 166 (łączna ilość wierszy). Tutaj ponownie Grails załatwia za nas całą robotę – metoda klasy domenowej o wdzięcznej nazwie count zwraca łączną liczbę rekordów. Co jednak zrobimy w przypadku jakiejkolwiek formy filtrowania wyników?

Załóżmy, że prezentowane posty możemy filtrować w zależności od ich statusu. Posty mogą być opublikowane, równie dobrze mogą być postami prywatnymi (do ich oglądania potrzebne są specjalne uprawnienia) – możliwych pomysłów jest wiele. Moglibyśmy zastosować dynamicznych finderów Grails – czyli wywołań metod na kształt:

def postList = Post.findByStatusLike("opublikowany")

Rozwiązanie to sprawdza się w przypadku prostych list. Jeżeli wpadniemy na pomysł by naszą listę filtrować na podstawie kilku różnych kryteriów (i do tego używając ich jednocześnie), możemy wpaść w kłopoty budując w naszym kontrolerze/serwisie rozbudowane konstrukcje warunków. Raczej nie tędy droga.

Odwołamy się zatem po raz kolejny do Hibernate wraz z jego mechanizmem kryteriów. Naturalną konsekwencją byłoby utworzenie obiektu kryteriów i następnie zaaplikować go do wywołania metod listujących oraz zliczających rekordy. Rzecz jest osiągalna – poniższy listing powie więcej niż tysiąc słów:


// Dwa 'kontenery' na kryteria
def listCriteria = Post.createCriteria()
def listCountCriteria = Post.createCriteria()

// Domyslne wartosci na podstawowe parametry paginatora
if( params.offset == null ) {
	params['offset'] = 0
}

if( params.max == null ) {
	params['max'] = 30
}

if( params.order == null ) {
	params['order'] = 'asc'
}

if( params.portalXX == null ) {
	params['portalXX'] = 'all'
}

def commonListCriteria = {

	// Wszystkie kryteria, ktorych zamierzamy uzyc do
	// wyciagniecia rekordow (okreslony status, daty)

   maxResults(params.max as Integer)
   firstResult(params.offset as Integer)

}

// Zwrocenie wynikow oraz zapytanie listujace
def postList = listCriteria.list(commonListCriteria)
def postCount = listCountCriteria.count(commonListCriteria)

Prezentowany kod wydaje się być niemożliwie prosty, jednakże by dojść do takiej jego postaci straciłem chyba ze 3 godziny. Jak widać ‘bazowe’ kryterium określa również takie kryteria jak maksymalna ilość rekordów na stronie oraz przesunięcie (offset), od którego należy wyciągnąć rekordy. Równie dobrze zwrócone posty mogą reprezentować 10tą stronę z łącznego zbioru wynikowego (przy params.offset = 10). Jednocześnie zastosowanie tych samych kryteriów dla metody zliczającej dalej zwróci poprawną łączną liczbę wierszy dla danych kryteriów (pomijając wartości paginacyjne).

Sortowanie po wyrażeniu SQL w Grails

Ostatnio mam okazję produkcyjnie pobawić się Grailsami. Co cieszy – zwłaszcza po niedawnych przygodach z prehistorycznym kodem, który prezentował ogromniaste kolce i strzykał na kilometr śmierdzącą śliną. Jednakże jak zwykle coś delikatnie było nie tak – stąd ten wpis.

Na pierwszy rzut oka sprawa jest dość prosta. Chcemy posortować zwracane z bazy danych rekordy za pomocą pewnego wyrażenia. Załóżmy, że mamy tabelę z listą postów na blogu. Tabelka zawiera tytuł, zajawkę, datę i wszystkie inne obowiązkowe w tym przypadku dane. Każdy rekord zawiera też informację o ilości odsłon danego postu, a także o ilości kliknięć na link do niego prowadzący z głównej strony bloga. Sprawa jest prosta:

SELECT * FROM posts 

Idźmy dalej. Może byłoby fajnie wyciągnąć posty o największym CTR (kliki do emisji)? Ok, lecimy:

SELECT * FROM posts ORDER BY main_page_click_count / emission_count DESC

Od strony logiki oraz kodu SQL sprawa jest niesamowicie prosta. Niestety w przypadku Grailsowego DSLa problem okazał się dość niebagatelny. Standardowe metody listujące ( list, findAll ) niestety nie przyjmują dla wyciągania/sortowania/grupowania wyrażeń – otrzymywałem błąd, iż dana właściwość nie istnieje w klasie domenowej. Próby stworzenia własności typu transient (nie zapisywanej w bazie danych) jako wyniku działania pewnej funkcji (w tym przypadku dzielenia dwóch innych własności) również nie zakończyła się powodzeniem.

Tutaj z pomocą przyszedł ‘spodni’ mechanizm frameworku, czyli konkretnie Hibernate. W tym ORMie mamy coś takiego jak kryteria. Sprawa zaczęła wyglądać na łatwiejszą, niestety, tylko wyglądać. Próba użycia restrykcji do klauzuli sortującej zakończyła się niepowodzeniem. Całe szczęście znalazłem w necie wpis o dokładnie tym samym zagadnieniu. Kod przeze mnie prezentowany bazuje na zamieszczonym przez autora ww. wpisu.

Musimy utworzyć oddzielną klasę, która będzie fizycznie odpowiedzialna za dodanie kawałka kodu SQL do naszego wynikowego zapytania. U mnie wygląda ona tak:

package com.wordpress.chlebik.hibernate.extension;

import org.hibernate.criterion.Order;
import org.hibernate.criterion.CriteriaQuery;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;


/**
 * Class extending Hibernate order by functionality to deal with
 * SQL-expression in order by  
 */
public class SortBySql extends Order {

    private static final long serialVersionUID = -6698545180750378282L;
    private String sqlFormula;
 
    /**
     * Constructor for Order.
     * @param sqlFormula an SQL formula that will be appended to the resulting SQL query
     */
    protected SortBySql(String sqlFormula) {
        super(sqlFormula, true);
        this.sqlFormula = sqlFormula;
    }
 
    public String toString() {
        return sqlFormula;
    }
 
    public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
        return sqlFormula;
    }
 
    /**
     * Custom order
     *
     * @param sqlFormula an SQL formula that will be appended to the resulting SQL query
     * @return Order
     */
    public static Order sqlFormula(String sqlFormula) {
        return new SortBySql(sqlFormula);
    }   
    
}

Klasę tę oraz metody wywołujemy w miejscu użycia kryteriów Hibernate. Dzięki sile domknięć kryteria można stworzyć oraz wywoływać w ten sposób:

 // To jest stworzenie obiektu kryteriow dla klasy domenowej 'Post'
 def listCriteria = Post.createCriteria()

 // To domkniecie, ktore przekazemy jako parametr do metody listujacej kryteriow
 def sortBySqlCriteria = {
           getInstance().addOrder( SortBySql.sqlFormula(" (main_page_click_count / emission_count) DESC ") )
 }
       
 // Wywolanie metod listujacych posty dla zadeklarowanych kryteriow          
def postList = listCriteria.list(sortBySqlCriteria) 

I w ten oto piękny sposób uzyskaliśmy zamierzony efekt. Zainteresowanych odsyłam do ww. wpisu. W tym przypadku (chodzi o CTR) należy również zwrócić uwagę na możliwy błąd dzielenia przez zero! Trzeba go obsłużyć na poziomie samej bazy danych – w moim przypadku było to Oracle i posiłkowałem się rozwiązaniami zaprezentowanymi w tym poście. Jednakże ostatecznie sprawa zakończyła się ustaleniem domyślnej wartości emisji nawiększą niż 0 i tym samym konieczność obsługi tego problemu można było pominąć.

Kilka sztuczek w Struts 1

W nowej pracy mam okazję na co dzień pracować z frameworkiem Struts. W moich dotychczasowych projektach nie miałem do tej pory okazji zapoznać się z tym frameworkiem, jednakże p0 kilku tygodniach pisania w nim kodu mam o nim jakieś tam pojęcie. Napotkałem po drodze kilka dość frustrujących “wpadek” i dlatego postanowiłem je opisać na blogu.

1. Tagi z dynamicznymi wartościami.

Podstawą internetu jest magiczny znacznik HTMLa o nazwie FORM. Zasadniczo dość często zdarza się, iż adres akcji, która zostanie wywołana jest zależny od przekazanego parametru. W Strustach zaleca się do takich operacji używanie tagu <bean:write> – w sumie można się z tym nawet zgodzić, problemem jest to, iż nie da się umieścić tego tagu wewnątrz treści innego tagu. Czyli takie coś nie przejdzie:

<html:form action="<bean:write [...] />"  ></html:form>

Wpisanie czegoś takiego do treści strony JSP spowoduje wyrzucenie wyjątku. O dziwo użycie składni skrypletowej ze znacznikami również nie zadziała;

<html:form action="<%=(String)request.getAtrtribute("cost")%>"  ></html:form>

Problem ten można obejść sposobem “niejavowym”. A mianowicie tak:

<html:form action='<%=(String)request.getAtrtribute("cost")%>'  ></html:form>

Widać różnicę? Zamieniamy po prostu cudzysłów na apostrof. I nagle dziwnym trafem wszystko działa.

2. Checkboxy w checkboxie czyli o tagu html:multibox

Załóżmy taką sytuację. Piszemy aplikację do rezerwacji pokoi w hotelu. Jako użytkownik wybieramy sobie kilka opcji spośród dostępnych w hotelu ( np. sejf w pokoju, wypożyczenie auta). I te informacje przechowujemy dla każdej rezerwacji. Z drugiej strony mamy rzecz jasna również wszystkie możliwe opcje – ich lista może być długa. I teraz – jak przy edycji/podglądzie formularza szybko i łatwo zaznaczyć na liście te, które użytkownik wybrał dla swojej rezerwacji?

Rzecz jasna możemy przeiterować po całej kolekcji ze wszystkimi opcjami i następnie iteracyjnie przechodzić po opcjach, które wybrał użytkownik. Jeśli obecnie przetwarzana wartość znajduje się pośród tych, które wybrał użytkownik renderujemy atrybut checked. Jednakże jest to troszeczkę nieefektywne i dlatego też twórcy Strutsa wymyślili tag o nazwie html:multibox. W skrócie – iterujemy po liście wszystkich możliwych opcji, ale zamiast porównywać cokolwiek (skrypletami choćby) wstawiamy do tej pętli ww. znacznik i powinno być dobrze. Dlaczego o tym piszę? Ano rzućmy okiem na dokumentację tagu:

Renders an HTML <input> element of type checkbox, whose “checked” status is initialized based on whether the specified value matches one of the elements of the underlying property’s array of current values.

Co pomyśli sobie programista? Świetnie – iterujemy po liście obiektów i potem do tagu wrzucamy drugą listę tego samego typu obiektów i jest OK. Czyli wystarczy dokonać trochę magii z przesłonięciem metod equals oraz hashCode i jesteśmy w domu. No i nie do końca…

Okazuje się (po 3h mojego rzucania mięsem przed komputerem), iż w tym przypadku jednym rozwiązaniem jest to, że obydwie kolekcje będą zawierały obiekty typu String!. Zapomnijcie o dobrach tego taga w przypadku własnych klas. Ostatecznie może wyglądać to tak:

<logic:iterate id="lancuch" name="BeanFormularza" property="listaLancuchow" >

         <html:multibox property="listaLancuchowDoZaznaczenia">
             <bean:write name="lancuch" />
        </html:multibox>

</logic:iterate>

3. Sprawdzanie parametrów żądania

Generalnie sprawa jest prosta. W akcji zapisujemy zmienną w obiekcie żądania i chcemy dobrać się do niej w widoku. Robimy tak:

request.setAttribute( "klucz", wartoscPodTymKluczem );

Wiadomo jednakże, iż czasami wartoscPodTymKluczem może przyjąć wartość NULL, albo co gorsza w ogóle nie zostać ustawiona (co może, choć nie do końca, znaczyć to samo co NULL). Dobrą praktyką byłoby tym samym sprawdzenie w widoku, czy aby interesująca nas zmienna nie jest właśnie NULLem. I tutaj mała niespodzianka w przypadku tagu logic:present. Tag ten sprawdza, czy podana zmienna istnieje. Jednakże należy uważać, gdyż dokumentacja może być myląca – przyzwyczajeni bowiem jesteśmy do tego, iż atrybuty name oraz property oznaczają to samo w każdym tagu – name zawiera nazwę beana, zaś property to konkretna własność obiektu (choć nie do końca, tak naprawdę liczy się istnienie metody dostępowej). Natomiast w przypadku atrybutów żądania jest odwrotnie! By powyższy przykład zadziałał z ww. tagiem musi to wyglądać następująco:

<logic:present name="klucz" >
  tutaj jest miejsce na nasz kod i wszystko inne jeśli wartość istnieje i nie jest pusta
</logic:present>

Zapominamy o property. Tak to ma wyglądać.

4. Podsumowanie
Duperelki, ale ileż potrafią napsuć zdrowia i dobrego samopoczucia. Rzecz jasna wszystko dotyczy frameworka Struts w wersji 1. Jak wygląda ten temat obecnie nie wiem i raczej niezbyt prędko będę miał okazję poznać drugą odsłonę tego frameworka. Jednakże komentarze na ten temat jak najmilej widziane.

SCJPTester wyświetla newsy – podstawy Springa w praktyce

Dziś przyszedł czas na coś większego. Mam nadzieję, że ilość kodu nie będzie odstraszająca. Ponieważ dziś zaimplementujemy coś z pomocą tandemu Spring + Hibernate. Konkretnie przebudujemy troszeczkę widok strony głównej po to, aby móc wyświetlić ostatnie informacje o aplikacji (podobną rzecz robiliśmy z ProgramBash). Jest to o tyle ciekawe, iż użyjemy Springa w całej jego krasie, stworzymy pierwszą tabelę w naszej bazie, nauczymy się czegoś więcej o kontrolerach, używaniu Hibernate poprzez klasy Springa, a ostatecznie troszeczkę podlejemy to sosem od FreeMarkera. Do dzieła.

Zaczniemy od bazy. Zainstalowałem ją jakiś czas temu, a do naszej aplikacji podpiąłem chwilkę później. W ten sposób wyposażeni możemy stworzyć pierwszą tabelę w bazie danych – konkretnie news:

CREATE TABLE news (
id serial PRIMARY KEY,
title varchar(127) NOT NULL,
content text NOT NULL,
data date NOT NULL
) WITHOUT OIDS ;

Co zaowocuje takim komunikatem:

NOTICE: CREATE TABLE will create implicit sequence "news_id_seq" for serial column "news.id"
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "news_pkey" for table "news"
Zapytanie zostało wykonane w 454 ms i nie zwróciło żadnych wyników.

Mówiąc krótko – została utworzona sekwencja, która została przypisana do kolumny z naszym kluczem głównym (ten też został zresztą utworzony jak widać). Mamy zatem tabelę, na której będziemy pracować – dodałem do niej też 2 rekordy, aby mieć jakieś dane do pracy. Zajmiemy się teraz samym Springiem. Na czym bowiem polega jego zajefajność? Otóż podstawą jest właśnie wstrzykiwanie zależności – mamy obiekt, którego składową jest inny obiekt. Konfigurujemy te 2 obiekty w pliku XML, a Spring zajmie się utworzeniem obiektu, jego przekazaniem i wszystkim po drodze. Jest to o tyle praktyczne, iż redukuje ilość kodu, który trzeba za każdym razem napisać. Deklarujemy po prostu, że potrzebujemy w danym obiekcie innego obiektu i viola – działa. Suchy opis jednakże niewiele znaczy, zatem lepiej przerobić rzecz w praktyce.

Zaczniemy od klasy domenowej dla naszego newsa. Dla tej i pozostałych klas domenowych utworzymy oddzielny pakiet com.wordpress.chlebik.domain. Kod wygląda tak:

package com.wordpress.chlebik.domain;

import java.io.Serializable;
import java.sql.Date;

/**
 * Klasa domenowa dla newsa w serwisie
 *
 * @author chlebik
 */
public class News implements Serializable {

 private    long      id;
 private    String   title;
 private    String   content;
 private    Date     data;

 /**
 * Konstruktor
 *
 * @author chlebik
 */
 public News() {}

 // Gettery
 public long getId() {
 return id;
 }

 public String getTitle() {
 return title;
 }

 public String getContent() {
 return content;
 }

 public Date getData() {
 return data;
 }

 // Settery
 public void setId( int id ) {
 this.id = id;
 }

 public void setTitle( String title ) {
 this.title = title;
 }

 public void setContent( String content ) {
 this.content = content;
 }

 public void setData( Date data ) {
 this.data = data;
 }

}

Nihil novi sub sole. Klasa jest prosta i sztampowa do bólu. Mapowanie:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.wordpress.chlebik.domain.News" table="news">
 <id column="id" name="id" type="int">
 <generator/>
 </id>
 <!--  zwykle kolumny -->
 <property column="content" name="content" type="string"/>
 <property column="title" name="title" type="string"/>
 <property column="data" name="data" type="date"/>
 </class>
</hibernate-mapping>

Należy pamiętać o dopisaniu mapowania do pliku konfiguracyjnego Hibernate. Teraz wypadałoby zaimplementować klasę dostępu do naszej klasy domenowej, czyli mówiąc krótko piszemy DAO. Rzecz jasna wychodzimy od interfejsu, który zdefiniuje kontrakt jaki chcemy by spełniały ew. klasy implementujące. Uwaga! Dla tych co nie wiedzą dlaczego używamy interfejsów ważne wskazanie – posiadając interfejs korzystamy przy ewentualnej pracy z polimorfizmu. Zatem nagłe przepisanie aplikacji z MySQLa na PostgreSQL i na odwrót nie stanowi problemu, gdyż ew. obiekty przekazujemy rzutując w górę na interfejs.

Rzecz jasna w przypadku newsów na stronie głównej problemu nie ma – będzie tam póki co jedna metoda, która będzie nam wyciągała nasze newsy w określonej ilości. Może i dla takiego zastosowania możnaby od razu sklepać klasę, ale ani to profesjonalne, ani nie wykształca dobrych zachowań. Zatem tworzymy prosty interfejs w pakiecie com.wordpress.chlebik.dao.interfaces.

package com.wordpress.chlebik.dao.interfaces;

import com.wordpress.chlebik.domain.News;
import java.util.List;

/**
 * Interfejs specyfikujacy kontrakt dla klas DAO newsow w serwisie
 *
 * @author chlebik
 */
public interface NewsDaoInterface {
 public List<News> getNews( int counter );
}

Interfejs mamy – teraz przyszedł czas na klasę go implementującą. I tutaj pierwszy styk Springa z Hibernate. Ten pierwszy posiada gotowe klasy, które służą obsłudze zapytań SQLa poprzez Hibernate. Oczywiście skorzystamy z tej możliwości, tym bardziej, że ułatwia to pisanie kodu. Jak bowiem wyglądałaby nasza klasa DAO? Zaimplementowalibyśmy metodę, w której wyciągalibyśmy sesję, potem ją zamykali, obsługa wyjątków, blech, coś brzydkiego, prawie jak JDBC. Zaczniemy od konfiguracji – musimy poinformować Springa, że używać będziemy Hibernate. Jednakże wprowadzimy pewien porządek, coby nie mieszać niepotrzebnie w dotychczasowym pliku konfiguracyjnym. Stworzymy oddzielny plik XMLa z konfiguracją bazy danych, a następnie zaimportujemy go do obecnie już istniejącego frontcontroller-servlet.xml. Nasz plik nazwiemy database-config.xml i wrzucamy do katalogu WEB-INF:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="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-2.5.xsd">

 <bean id="dataSource">

 <property name="driverClassName">
 <value>org.postgresql.Driver</value>
 </property>
 <property name="url">
 <value>jdbc:postgresql://88.198.31.169/chlebik</value>
 </property>

 <property name="username"><value>MOJ_USER</value></property>
 <property name="password"><value>MOJE_HASLO</value></property>
 </bean>

 <bean id="mySessionFactory">

 <property name="mappingResources">
 <list>
 <value>News.hbm.xml</value>
 </list>
 </property>

 <property name="hibernateProperties">
 <props>
 <prop key="hibernate.dialect">
 org.hibernate.dialect.PostgreSQLDialect
 </prop>
 </props>

 </property>
 <property name="dataSource">
 <ref bean="dataSource"/>
 </property>

 </bean>
</beans>

Zaś do pliku frontcontroller-servlet.xml dopisujemy taki kod (dotyczy bazy danych jak i naszego beana z newsami):

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

  <bean id="newsDao" class="com.wordpress.chlebik.dao.implementation.NewsDao">
        <property name="sessionFactory" ref="mySessionFactory" />
     </bean>

  <bean name="/index.html" class="com.wordpress.chlebik.controllers.IndexController">
       <property name="newsDao" ref="newsDao" />
  </bean>

Mamy pokonfigurowane stosowne beany by ogarnąć połączenie z bazą danych. W ten sposób wstępnie poinformowaliśmy Springa (zdefiniowaliśmy bean) o istnieniu fabryki sesji Hibernate. Ślicznie. Dzięki temu możemy teraz zastanowić się nad implementacją klasy DAO dla newsów. Mamy tutaj kilka możliwości:

  • HibernateDaoSupport – jest to klasa, którą powinny rozszerzać nasze klasy implementujące interfejs DAO konkretnej encji. Dzięki jej użyciu uzyskujemy o wiele łatwiejszy dostęp do sesji (po to właśnie skonfigurowaliśmy session factory), co prawda może to momentami być problematyczne ( o tym pewnie kiedy indziej napiszę ), dla obecnego przykładu powinno być OK.
  • HibernateDaoSupport wraz z obiektem pomocniczym HibernateTemplate – jest pokłosiem powyższego – również rozszerzamy klasę HibernateDaoSupport, ale za to odowłujemy się również do obiektu pomocniczego HibernateTemplate, co znacznie skraca kod.

Jako, że jedno wynika z drugiego pokażę obie implementacje. W wersji pierwszej po prostu rozszerzymy klasę HibernateDaoSupport:


package com.wordpress.chlebik.dao.implementation;

import com.wordpress.chlebik.dao.interfaces.NewsDaoInterface;
import com.wordpress.chlebik.domain.News;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

/**
 * Klasa DAO dla newsów
 *
 * @author chlebik
 */
public class NewsDao extends HibernateDaoSupport implements NewsDaoInterface {

 List<News> newsy;
 SessionFactory sessionFactory;

 /**
 * Bezargumentowy konstruktor
 */
 public NewsDao() {}

 /**
 * Wyciaga newsy w zadanej ilosci
 *
 * @param   int    counter
 * @return  List<News>
 */
 public List<News> getNews(int counter) {

 try {

 Session session = getSession();
 newsy = (List<News>)session.createQuery( "from News order by data desc limit " + counter ).list();
 releaseSession( session );
 return newsy;

 } catch ( Exception e ) {
 System.out.println( e.toString() );
 }

 return newsy;

 }

 public List<News> getNewsy()  {
 return newsy;
 }

 public void  setNewsy( List<News> lista )  {
 newsy = lista;
 }
}

Jak widać łatwiej dostać się do sesji, łatwiej ją uwolnić i w ogóle jest zawsze czysto, zawsze sucho i powiedzmy, że zazwyczaj pewnie. Jednakże kod ten można jeszcze bardziej uprościć i doprowadzić do takiej oto postaci (sama metoda getNews()):

public List<News> getNews(int counter) {
         return (List<News>) getHibernateTemplate().find( "from News order by data desc limit " + counter );
}

Obiekt pomocniczny HibernateTemplate udostępnia kilka najbardziej popularnych metod używanych przy pracach z bazami danych, dlatego też w tak prostych przypadkach jego użycie jest jak najbardziej wskazane. Po więcej informacji na temat tej klasy odsyłam do dokumentacji. Ja użyłem metody find, która jak widać wyciąga rekordy pasujące do zapytania. Uwaga! Używanie tego podejścia jest bardzo szybkie i przyjemne, ale automatycznie mocno skazuje nas na integrację ze Springiem. W przypadku gdybyśmy chcieli zmienić coś w samym kodzie aplikacji i ewentualnie przemigrować jego kawałek na inny framework mielibyśmy trochę roboty. Polecam odnośnik z jednego z komentarzy do tutoriala Darka Zonia ( mały link ).

Cóż nam teraz zostało? Sprawdzić czy w ogóle coś działa! Odwołamy się do istniejącego już kontrolera – IndexController. Tam w metodzie handleRequest do tej pory zwracaliśmy prostą instancję ModelandView. Na razie zostawimy ten temat sam sobie, natomiast stworzymy obiekt DAO i zobaczymy czy na pewno zwrócił to, co powinien zwrócić. Modyfikujemy zatem ww. metodę i dodajemy taki oto kod:


newsy = newsDao.getNews(MAIN_PAGE_NEWS_COUNTER);
System.out.println( "Zwroconych newsow " + newsy.size() );

Jak widać do kontrolera dodałem też stałą, która będzie nam wskazywała ile newsów pobrać na główną stronę. W codziennej praktyce rzeczy związane z konkretnym kontrolerem/akcją umieszczam najbliżej jak się da – do tego jako stałą. Jakoś tak bardziej to elegancko wygląda. Choć pewnie w komercyjnym projekcie dla zewnętrznego klienta takie rzeczy powinno się trzymać w zewnętrznym pliku, a konto łatwiejszego utrzymania. Uruchamiamy nasz projekt. I w konsoli wyskakuje krótkie:


Zwroconych newsow 2

Czyli coś poszło tak jak powinno 😉  Oczywiście kwestia jest teraz taka, że wypadałoby owe newsy przedstawić w odpowiedni sposób. Rzecz jasna wpierw trzeba listę z newsami przekazać do widoku. W kontrolerze zatem zamieniamy linijkę z instrukcją zwrotu obiektu ModelandView na następującą:


return new ModelAndView( "index", "newsList", newsy );

I po kilku zabawach z CSSem oraz z modyfikacją widoku:

  <#list newsList as News>
                  <div class="col">
                      <h4 style="color: #FFF2B3;">${News.title}</h4>
                      <h5>${News.data}</h5>
                      <p style="font-size: 10px; line-height: 1.2em;">${News.content}</p>

                  </div>
    </#list>

Znaczniki są dość samo-opisujące. Mamy zwykłą iterację po liście i ostateczny efekt wygląda w taki oto sposób:

SCJPTester w wersji HelloWorld!

Dzisiaj zrobimy coś poważniejszego. Konkretnie postaramy się sprawić, że nasz SCJPTester zaistnieje w sieci, a także sprawimy by owo zaistnienie było czymś więcej niż wyświetleniem zwykłej strony JSP z napisem “Hello World!”. Do roboty.

W tym momencie jednakże nie wiem od czego tak naprawdę zacząć. Może od samego Spring MVC, gdyż to w jego strukturze będziemy się poruszać. Już po nazwie widać, iż realizujemy wzorzec MVC, co jest bardzo dobre, ale co więcej – Spring MVC implenentuje również wzorzec Front Controllera, to znaczy, iż wszystkie żądania skierowane do aplikacji przechodzą przez jedno miejsce (niezależnie od requestu). Poniżej ładny schemat zaczerpnięty ze stron Spring MVC:

Jest mi to wszystko o tyle bliskie, że w codziennej pracy z PHP korzystam z tych samych wzorców. Podoba mi się to również z tego powodu, iż wiadomo gdzie przychodzi nasze żądanie, można z nim po drodze zrobić jeszcze wiele ciekawych rzeczy. O wiele bardziej to przejrzyste niż JSF. Lecimy dalej. Nasz front controller jest najzwyklejszym serwletem, który dziedziczy po klasie HttpServlet i jako taki powinien być zdefiniowany w pliku web.xml. Podstawowa konfiguracja wyglądałaby na przykład tak:


    <servlet>
        <servlet-name>frontcontroller</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>frontcontroller</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>

Domyślnie Spring MVC załaduje wszystkie ustawienia z pliku web.xml, jednakże przy każdym requeście (w powyższym przykładzie do zasobów kończących się na .html) zostanie uruchomiony serwlet o nazwie frontController. W tym momencie mechanizm ładujący spróbuje znaleźć w katalogu WEB-INF dodatkowy plik z konfiguracją, według wzoru:

[nazwa-serwletu]-servlet.xml

Dzięki czemu możemy mieć wyspecjalizowany plik kontekstu dla konkretnego typu żądań (np. do takich, które wymagają zwrotu nie HTMLa, ale np. pliku PDF). Generalnie w myśl mojego zamysłu aplikacja będzie posługiwała się rozszerzeniami *.html. Samych stron jakoś specjalnie wiele to nie będzie, dlatego też poprzestaniemy na opisowych nazwach “niby-routingu”, czyli np. login.html czy testuj.html. Request do konkretnego zasobu jest podpinany pod klasę kontrolera, która go obsłuży. Spring dostarcza szereg bazowych klas, które powinny być użyte do obsługi żądań (w sensie – należy po nich dziedziczyć). Dlatego też w pliku frontcontroller-servlet.xml pojawi się taki kod:

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

<beans xmlns="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-2.5.xsd">

  <!-- the application context definition for the springapp DispatcherServlet -->

  <bean name="/index.html" class="com.wordpress.chlebik.controllers.IndexController" />

</beans>

I teraz trzeba napisać nasz kontroler. Generalnie jego zadaniem będzie serwowanie zwykłej statycznej strony, zatem nie ma potrzeby korzystać z jakiś bardziej zaawansowanych klas Springa – zaimplementujemy po prostu interfejs Controller, który jest bazowym dla wszystkich klas kontrolerów. O innych klasach implementujących ten interfejs napiszę później przy tworzeniu bardziej zaawansowanej użyteczności:

package com.wordpress.chlebik.controllers;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

/**
 *  Klasa kontrolera dla strony glownej
 *
 * @author chlebik
 */
public class IndexController implements Controller {

 public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {

    return new ModelAndView("index.jsp");
  }

}

Na razie odnosimy się do prostej strony index.jsp, która została utworzona wraz z całym projektem. Jest ona też wpisana w pliku web.xml na liście plików powitalnych dla aplikacji. Po małych przeróbkach z mojej strony plik ten wygląda tak:


<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>SCJPTester</title>
    </head>
    <body>
        <h1>Bardziej rozbudowane Hello World!</h1>
    </body>
</html>

No i po uruchomieniu aplikacji widzimy taki ekran:

Rzecz jasna jest to domyślny start poprzez odwołanie się do domeny localhost:8084, sprawdźmy zaś, czy nasz kontroler daje sobie radę. Odwiedzamy adres localhost:8084/index.html i widok nam się nie zmienił – czyli jesteśmy w domu, kontroler działa. Jednakże jak na razie jest to dość słabe HelloWorld. Dorzucimy do tego przykładu ładny widok – czyli podepniemy FreeMakera wraz z całym layoutem. Na pewno będzie się przyjemniej z tym wszystkim pracowało.

Wpierw zatem trzeba się zatroszczyć o same źródła biblioteki FreeMarker. Odwiedzamy starego znajomego POM.xml i w zależnościach projektu dopisujemy:

 <dependency>
   <groupId>org.freemarker</groupId>
   <artifactId>freemarker</artifactId>
   <version>2.3.16</version>
 </dependency>

I dociągamy tę zależność. Kiedy FreeMarker pojawi się nam na liście bibliotek jesteśmy w domu. Tak w ogóle to zdecydowałem się na tę bibliotekę, gdyż jest ponoć bardzo podobna do Velocity (czyli poznaję prawie 2 rzeczy za cenę 1:) ), a do tego Spring posiada do tego wyprowadzenie (w sensie integracji widoku), ale do tego jeszcze dojdziemy. Co konkretnie robi FreeMarker? Organizuje nam widok – jest to w zasadzie system szablonów – czyli dzięki niemu stworzymy sobie cały layout strony, a także będziemy dzięki niemu operować w widoku na danych, które dostaniemy z modelu. Problem z FreeMarkerem jest taki, że w sieci jest masa tutoriali na temat jego połączenia ze Springiem, jednakże najczęściej na przykładzie 1 statycznej strony się kończy. Takie zaś rozwiązania były dobre przy HTMLu 3 jakieś 10 lat temu, jak nie lepiej. Dlatego też ja pokażę jak przygotować projekt do życia – czyli zbudujemy sobie cały layout, który będzie dynamicznie wypełniany w zależności od wywołanego zasobu. Do dzieła!

FreeMarker jest już w naszej bibliotece. Teraz należy poinformować Springa o jego istnieniu, a także ustawić, że wyświetlamy widok inaczej niż za pomocą czystych stron HTMLa. Zatem odwiedzamy web.xml i klepiemy tam takie coś:

<servlet>
    <servlet-name>freemarker</servlet-name>
    <servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class>

    <!-- FreemarkerServlet settings: -->
    <init-param>
      <param-name>TemplatePath</param-name>
      <param-value>/WEB-INF</param-value>
    </init-param>
    <init-param>
      <param-name>NoCache</param-name>
      <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>ContentType</param-name>
      <param-value>text/html</param-value>
    </init-param>

    <!-- FreeMarker settings: -->
    <init-param>
      <param-name>template_update_delay</param-name>
      <param-value>0</param-value>
    </init-param>
    <init-param>
      <param-name>default_encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>number_format</param-name>
      <param-value>0.##########</param-value>
    </init-param>

    <load-on-startup>1</load-on-startup>
  </servlet>

To na początek kilka podstawowych ustawień servletu FreeMarkera. Wartości są dość jasne – warto tylko zwrócić uwagę na parametr template_update_delay – ustawienie tam wartości 0 jest dobre dla środowiska developerskiego. Dla oddzielnych pików layoutu rzecz jasna utworzymy specjalny katalog w folderze WEB-INF, dzięki czemu nie da się otworzyć poszczególnych składowych w przeglądarce. Dla swojej aplikacji jak zawsze skorzystałem z darmowego szabloniku, który można podejrzeć w tym miejscu. Szablonik rzecz jasna posiada coś takiego jak nagłówek, menu, główną treść i content. Dlatego też naturalnie rozbijemy go na kilka oddzielnych części
i ładować potrzebne nam części. FreeMarker składuje szablony w plikach z rozszerzeniem *.ftl. Tworzymy katalog layout w folderze WEB-INF i wrzucamy tam plik layout.ftl:

<#macro scjptesterLayout>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
<html>
    <head>
        <title>SCJPTester</title>
        <meta http-equiv="Content-Language" content="Polish" />
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <link href="/css/main.css" rel="stylesheet" type="text/css" />
    </head>
    <body>
        <div id="header">
          <h1><a href="/index.html">SCJPTester</a></h1>
          <ul id="menu">
            <li class="active"><a href="/index.html">główna</a></li>
            <li><a href="/start.html">zarejestruj/zaloguj</a></li>
            <li><a href="#">demo</a></li>
            <li><a href="#">kontakt</a></li> 
          </ul>
        </div>
    
        
      <div class="wrap">

       <#nested />
          

        </div>
        <div id="footer">
          <p class="right">Design: <a href="http://www.solucija.com/">Luka Cvrk</a></p>
          <p>&copy; Nazwa 'SCJPTester' &middot; jest własnością Michała 'Chlebika' Piotrowskiego</p>
        </div>
    </body>
</html>
</#macro>

Jest to zwykły layout (na razie większość linków i menu są dość umowne), w którym jednakże widać kilka nowości. Pierwsza linijka kodu mówi już wiele – tworzymy własne makro, któremu nadajemy określoną nazwę. Całość HTMLa musi być zawarta w treści tegoż makra. W środku do tego, konkretnie w miejscu gdzie będziemy chcieli, aby wyświetlana zawartość zmieniała się w zależności od wybranego zasobu – wrzuciliśmy znacznik: #nested. W tym miejscy FreeMarker wrzuci nam stosowny widok. Pliki z obrazkami oraz CSSem należy wrzucić bezpośrednio do katalogu webapp, dzięki czemu będzie on dostępny z poziomu przeglądarki – bez tego nic ładnego nam się nie pokaże. W katalogu WEB-INF tworzymy także podkatalog views, gdzie będziemy składować poszczególne widoki dla konkretnych akcji. Taki podział wprowadza trochę czystości do widoków, od razu wiadomo gdzie i czego szukać. Teraz do tego musimy poddać edycji plik frontcontroller-servlet.xml i wrzucić tam taki oto kod (zwróć uwagę na zapisy o kodowaniu – mi zeszło na rozkminienie tego 2h):

<bean id="freemarkerConfig"
  class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer">
  <property name="templateLoaderPath"
   value="/WEB-INF" />

  <!-- To jest niemozliwie wrecz wazne - bez tego bedziemy mieli krzaki w widoku zamiast UTF-8  -->
 <property name="freemarkerSettings"> 
    <props>
         <prop key="default_encoding">UTF-8</prop>
    </props>
 </property>

 </bean>


 <bean id="viewResolver"
  class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver">
      <property name="cache" value="true" />
      <property name="prefix" value="/views/" />
      <property name="suffix" value=".ftl" />

      <!-- if you want to use the Spring FreeMarker macros, set this property to true -->
      <property name="exposeSpringMacroHelpers" value="true" />

       <!-- To jest niemozliwie wrecz wazne - bez tego bedziemy mieli krzaki w widoku zamiast UTF-8  -->
      <property name="contentType" value="text/html;charset=UTF-8"></property>

 </bean>

Powiadamiamy w ten sposób FreeMarkera gdzie ma szukać plików z szablonami, a także w jakim formacie się to odbędzie (określenia prefix i suffix dla ViewResolvera). W związku z takim określeniem reguł, kod w kontrolerze musimy zmienić na:

 public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {


    return new ModelAndView("index");
  }

Dzięki takiemu podejściu przy ewentualnej zmianie koncepcji widoku wystarczy, że zmienimy dane w pliku XML i możemy zmienić katalog, gdzie nasze pliki leżą, że o i ich rozszerzeniu nie wspomnę. Teraz na koniec wystarczy stworzyć plik index.ftl w katalogu views:

<#import "../layout/layout.ftl" as layout>
<@layout.scjptesterLayout>

  <div id="teaser">
      <div class="wrap">
       
        <div class="box">
          <h2>Witaj na stronach aplikacji <em title="SCJPTester">SCJPTester</em></h2>
          <p>Aplikacja ta powstała jako projekt edukacyjny Michała 'Chlebika' Piotrowskiego, w celu praktycznego poznania frameworka <strong>Spring</strong>, a także szeregu innych
          technologii. Projekt powstał niedawno zatem jego funkcjonalność jest na razie znikoma, jednakże stan ten zmienia się bardzo szybko. Więcej informacji na temat aplikacji
          moża znaleźć <a href="https://chlebik.wordpress.com">na blogu autora.</a></p>
        </div>
      </div>
    </div>


      <div class="col">
        <h3>Zarejestruj <span class="red"> się!</span></h3>
        <p>Bardzo szybki i prosty proces rejestracji pozwoli Ci od razu rozpocząć przygotowania do egzaminu.</p>
      </div>
      <div class="col">
        <h3>Kontroluj <span class="red">postępy</span></h3>
        <p>Dzięki panelowi statystyk będziesz mógł sprawdzić swoje postępy w nauce. Wyniki poprzednich testów zostaną zapisane i w każdej chwili można je przejrzeć.</p>
      </div>
      <div class="col last">
        <h3>Zgłaszaj <span class="red">własne pomysły</span></h3>
        <p>Jeżeli zaproponowane pytania nie są dla Ciebie wyzwaniem - stwórz swoje własne i podziel się nimi z innymi użytkownikami serwisu!</p>
      </div>



</@layout.scjptesterLayout>

I jesteśmy w domu. W pierwszej linijce importujemy nasz layout (wskazujemy konkretny plik) do konkretnej przestrzeni nazw, w tym przypadku layout. Niestety tak to wygląda, gdyż próby podpięcia automatycznego wgrywania pliku layoutu poprzez edycję web.xml nie powiodły się. Gdyby ktoś wiedział jak to osiągnąć byłbym wdzięczny. Uruchamiamy aplikację i przechodzimy pod adres http://localhost:8084/index.html i viola – mamy stronkę główną (poniosło mnie trochę przy marketingowych zwrotach, zatem wybaczcie :).

Teraz przyszedł czas na poprawienie naszej strony startowej. Należy przypomnieć, iż określiliśmy kontroler, który jest odpowiedzialny za obsługę żądań do zasobów kończących się na *.html. Jednakże wypadałoby zrobić coś z faktem, iż nasza główna strona będzie wyświetlana również w sytuacji, kiedy w pasku adresu wpiszemy tylko nazwę domeny. Tutaj w przypadku ProgramBash stosowałem zwykły plik HTML z redirectem. Jednakże nie jest to potrzebne. Do pliku web.xml dopisaliśmy regułę, iż wszystkie requesty kończące się na HTML są przechwytywane przez FreeMarkera. W takim razie w katalogu webapp tworzymy PUSTY plik index.html i dopisujemy go do listy plików powitalnych w web.xml

 <welcome-file-list>
        <welcome-file>index.html</welcome-file>
 </welcome-file-list> 

I teraz już bez konieczności zabaw w jakiekolwiek przenoszenie – wszystkie requesty, które pójdą na naszą domenę (jednakże te “całościowe” z prośbą o stronę główną) zostaną obsłużone w ten sam sposób co requesty przychodzące na adres http://domena.pl/index.html. Proste jak konstrukcja gwoździa, szkoda, że dopiero po tym jak się wyczyta o tym u wujka Google. To tyle na dziś – przyznam, że pomijając przygodę z kodowaniem stron w FreeMarkerze i nieudaną próbę podpięcia domyślnego layoutu poznawanie Springa jest całkiem przyjemne. Szybki rzut oka na klasy kontrolerów dostarczane wraz ze Springiem utwierdził mnie w przekonaniu, że ktoś wiedział co robi projektując te narzędzie.

Ostateczne dodanie wpisu w ProgramBash

Umilkło ostatnio na blogu, dopadła mnie mądrze pisząc “prokrastynacja”, a po polsku – nie chciało mi się jak cholera.

Jednakże poczucie obowiązku robi swoje – dziś ostatni odcinek w cyklu “dodajemy wpisy w ProgramBash“. Zasadniczo nie za wiele tutaj nowości – widok, walidacja, zapis do bazy. Pozwoliłem sobie nie przeklejać listingów niezbyt różniących się od tych z poprzedniego wpisu dotyczącego ProgramBash. Jedyne co wypada pokazać, to użycie kolejnego komponentu Richafaces, jakim jest komponent DataScroller. Jest to nie mniej i nie więcej, a paginator dla danych, które zamierzamy wyświetlić. Oto kod:

 <h:form id="topForm">

        <rich:datascroller align="left" for="topList" maxPages="20"
             reRender="sc2, topList" id="sc1" oncomplete="SyntaxHighlighter.highlight()" />
     
        <rich:dataTable width="755" id="topList" rows="2" columnClasses="col"
           value="#{entryBean.topList}" var="entry"> 
            
            <f:facet name="header">
                <rich:columnGroup>
                    <h:column>        
                    </h:column>
                </rich:columnGroup>
            </f:facet>

            <h:column>
                Punktów: <h:outputText value="#{entry.points}" /><br />
                Dodał: <h:outputText value="#{entry.author.nick}" /><br />
                W kategorii <strong><h:outputText value="#{entry.category}" /></strong> w dniu: <strong><h:outputText value="#{entry.adddate}" /></strong><br /><br />

                <pre class="brush: <h:outputText value='#{entry.category.shortname}' />">
                    <h:outputFormat value="#{entry.entry}" />
                </pre>


            </h:column>


        </rich:dataTable>
        <rich:datascroller align="left" for="topList" maxPages="20"
          id="sc2" reRender="sc1, topList"  oncomplete="SyntaxHighlighter.highlight()">
        </rich:datascroller>

      
    </h:form>

Umieszczony w odpowiednim widoku komponent ten zaczytuje ze stosownego beana ( entryBean ) wszystkie wpisy posortowane po ilości posiadanych punktów. Jest to o tyle hardkorowe, że w przypadku np. 100k wpisów mielibyśmy spore narzuty na wydajności bazy i całej aplikacji. Jednakże w środowisku produkcyjnym do takich rzeczy standardowo uzywałoby się jakiegoś cache. Na potrzeby edukacyjne nie ma problemu – możemy zostawić to tak jak jest.

Domyślnie zaś ilość wyświetlanych rekordów na stronę to 2 – nie jest to zbyt duża ilość, ale chodziło mi o pokazanie możliwości paginacji bez musu tworzenia testowych 30 wpisów. Na razie pozostanie to wszystko bez zmian. Należy także zwrócić uwagę na podpięcie formatowania kodu – służą do tego znaczniki pre wraz z odpowiednią klasą. Konkretna klasa jest reprezentowana przez nową składową encji EntryCategory – shortname. Uwaga! Należy zwrócić szczególną uwagę na atrybut oncomplete i wywołanie metody SyntaxHighlighter.highlight()! Bez tego po wgraniu nowej strony z kodem nie zostanie on sformatowany!!! Straciłem na to godzinę szukania i kombinowania.

Problem polega na tym, iż na moim lokalnym kompie rozwiązanie powyższe śmiga pięknie. Co więcej – niezależnie od tego, czy do dataScrollera wrzucę bezpośrednio atrybut page, czy też nie. Niezależnie również od tego czy trzymam tę wartość w beanie o zasięgu sesji, czy pojedynczego requestu. Wszystko jest OK. Zaś na VPSie – ZONK! Naciskając przyciski zmieniające stronę, podgląd odpowiedzi serwera wskazuje na to, iż aplikacja otrzymała AJAXem jak najbardziej kolejną stronę wyników. Niestety, nie jest to odzwierciedlane w oknie programu. Grzebię w tym już chyba od tygodnia i nic nie jestem w stanie na to poradzić mimo rozlicznych kombinacji. Jeśli ktoś miałby jakiś pomysł – będę wdzięczny.

Efekt końcowy wygląda mniej więcej tak:

Do tego niestety pomimo najszczerszych chęci przegrałem z SyntaxHighlighterem jeśli chodzi o formatowanie kodu, w którym znajduje się ENTER na końcu pierwszej linii. Dorzuca on sobie kilkanaście spacji na początku linii, co wygląda dziwnie (obrazek powyżej), ale co więcej – nie daje się usunąć choćby JSem!!! Prototype dostarczany razem z Richfaces wyrzuca mi błędami (np. jego funkcja remove oficjalnie nie istnieje), zaś próba podpięcia jQuery pod aplikację kończy się prawie śmiercią kliniczną Richfaces. Trudno, cóż począć.

To tyle na dziś – niewiele w sumie zostało rzeczy, które chciałbym do aplikacyjki dodać – na pewno ocenianie wpisów (AJAX), a także możliwość otrzymania danych poprzez webservice (to tak celem przećwiczenia takowych w Javie). Zatem do następnego razu.

PS. Nie lubię JSF.

Bardziej rozbudowany Hibernate, czyli dodajemy wpisy w ProgramBash

Po zabawach z rejestracją, uploadami plików i innymi sesyjnymi gadżetami przyszedł czas na trochę bardziej zorientowane na bazę rzeczy. Konkretnie chodzi oczywiście o użycie Hibernate i jego mechanizmu relacji. Do dzieła.

Podstawową rzeczą w serwisie będzie pojedynczy wpis. Upraszczając zagadnienie chodzi nam o wpis do bazy z pewną treścią, datą dodania, autorem, oceną (poprzez głosowanie innych użytkowników serwisu), a także by było ciekawiej przyporządkowanymi kategoriami. Mówiąc krótko mamy tutaj szereg relacji pomiędzy tabelami, no i samych tabel też trzeba będzie dorobić. Do tej pory (jak choćby w przypadku obiektu użytkownika), odwzorowania danych w bazie poprzez obiekt było proste. Mieliśmy zwykły obiekt z kilkoma własnościami – dopisaliśmy metody dostępowe i tyle. Podobną rzecz robiliśmy już przy okazji pisania HowToJava, jednakże tam relacje obsługiwał DSL z Grails, zatem rzecz była maksymalnie łatwa i uproszczona. W przypadku Hibernate rzecz jest trochę bardziej skomplikowana. Jednakże zanim weźmiemy się za kodowanie trzeba przedstawić kod SQLa, który posłuży nam do pracy. Do tej pory tabele były tworzone przez ORM, co wymagało nie raz ich poprawiania. Teraz damy Hibernate gotowe tabele do działania.

Istnieje już tabela reprezentująca użytkowników w serwisie. Użytkownicy dodają wpisy, które tym samym posiadają tylko 1 autora (wiele do jednego z perspektywy wpisu). Wpisy są również przypisane do jednej z kategorii (by było łatwiej wyszukiwać i segregować – relacja jeden do jednego). Tworzymy tabele:

-- Tabela dla wpisów
CREATE TABLE `entries` (
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`user_id` BIGINT NOT NULL ,
`category_id` BIGINT NOT NULL ,
`add_date` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
`content` TEXT NOT NULL ,
`points` INT NOT NULL ,
INDEX ( `user_id` )
) ENGINE = MYISAM ;

-- Tabela dla kategorii
CREATE TABLE `entry_categories` (
`id` BIGINT  NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`category` VARCHAR( 64 ) NOT NULL ,
PRIMARY KEY ( `id` )
) ENGINE = MYISAM ;


INSERT INTO `entry_categories` (`id`, `category`) VALUES
(1, 'Java'),
(2, 'MySQL'),
(3, 'PostgreSQL'),
(4, 'C#'),
(5, 'PHP'),
(6, 'Groovy'),
(7, 'Python'),
(8, 'Ruby'),
(9, 'RoR'),
(10, 'C++'),
(11, 'C'),
(12, 'Bash'),
(13, 'Life');

Teraz trochę teorii, gdyż zrozumienie relacji w Hibernate wcale nie jest takie proste. Kilka rzeczy, które wypadałoby wiedzieć:

  • relacje jednostronne i dwustronne – relację uznajemy za jednostronną, kiedy tylko jedna z encji ma pojęcie o istnieniu drugiej. Prosty przykład – mam akwarium i w nim rybki. Jestem ich właścicielem i powiedzmy, że posiadam zbiór obiektów rybek i wiem dokładnie, która jest która. Natomiast moje rybki ni cholery nie wiedzą skąd się wzięły, co je to zresztą obchodzi. Relacja dwustronna ma miejsce wówczas, gdy obydwie strony relacji wiedzą o sobie. Idealnym przykładem jest rodzic, który posiada kilkanaście dzieci. Doskonale zdaje sobie sprawę z ich istnienia, potrafi je jednoznacznie rozróżnić, ale także każde z dzieci ma informacje o swoich rodzicach (w sumie jest to relacja wiele-do-wielu).
  • właściciel relacji – posiłkując się przykładami powyżej należy w każdej relacji wskazać jej właściciela. Jest to ta encja, która ma prawo do ustawiania klucza głównego w tabeli po stronie “wiele”. Czyli w przykładzie z rodzicem i dziećmi to rodzic za każdym razem ustawia swoje ID w tabeli dzieci. W naszym przypadku to użytkownik będzie właścicielem relacji z wpisem.
  • kaskadowość – bardzo przydatna rzecz, a konkretniej zapis, który pozwala na wskazanie czy przy zapisywaniu właściciela relacji utrwaleniu w bazie danych mają również być poddane wszystkie zależne encje. Jest to o tyle wygodne, iż wystarczy dodać dzieci do rodzica, zapisać rodzica w bazie i viola – informacje o dzieciach również zostały zapisane.

Rozpatrzmy teraz nasz przykład. Zaczniemy od tej łatwiejszej części, czyli relacji pomiędzy wpisem, a kategorią do której jest przypisany. Kategoria jako taka istnieje, ale nie ma pojęcia do czego jest przypisywana (albo co do niej) i zasadniczo taki stan rzeczy wszystkich zadowala. Zatem będziemy mieli do czynienia z relacją jednostronną, której to właścicielem będzie wpis – bo właśnie w tej klasie będzie zapisana informacja o kategorii. Z drugiej strony mamy użytkownika, który może być autorem pewnej ilości wpisów. Zatem wypadałoby, aby użytkownik miał dostęp do swoich wpisów (by wyświetlić je np. na stronie użytkownika). Z drugiej strony kiedy wyświetlimy jeden konkretny wpis to dobrze byłoby też poznać jego autora – skoro umieścił fajnego loga, to pewnie innego jego wpisy są/mogą być równie ciekawe. Czyli wpis musi znać swojego autora. Tym samym od razu wiadomo, że jest to relacja dwustronna. Kto ma być właścicielem? Z zaprezentowanego schematu bazy danych łatwo wyczytać, iż będzie nim użytkownik. Obiekt uzytkownika wciąż wisi u nas w sesji – i kiedy będziemy dodawać wpis, będziemy tenże obiekt aktualizować, a dzięki konfiguracji zachowania kaskadowego automatycznie aktualizacji dokonamy w tabeli z wpisami.

Dość teorii na razie – rzućmy okiem na kod:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="hibernate.mappings">
  <class name="com.wordpress.chlebik.EntryCategory" table="entry_categories">
    <id column="id" name="id" type="long">
      <generator class="native"/>
    </id>
    <property column="category" name="category" type="string"/>
  </class>
</hibernate-mapping>

A oto i klasa Javy:

package com.wordpress.chlebik;

import java.io.Serializable;
import javax.persistence.Id;


/**
 * Klasa, ktora ma za zadanie byc beanem wystepujacym jako kategoria wpisu
 *
 * @author Michal Piotrowski
 */
public class EntryCategory implements Serializable {

    @Id
    private Long id;
    private String category;
    
    public EntryCategory() {  }

    public EntryCategory( String category ) {
        this.category = category;
    }

    @Override
    public String toString() {
        return category;
    }

    // Gettery
    public String getCategory()
    {
        return category;
    }
    
    protected Long getId()
    {
        return id;
    }

     // Settery - bardziej dla poprawnosci niz potrzeby
    public void setCategory( String category )
    {
        this.category = category;
    }

    protected void setId( Long id )
    {
        this.id = id;
    }
}


Rzecz już bardziej prosta być nie może. Mapowanie tej klasy jest póki co podobne do obecnego obiektu usera. Zajmijmy się teraz wpisem.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="hibernate.mappings">
  <class name="com.wordpress.chlebik.Entry" table="entries">
    <id column="id" name="id" type="long">
      <generator class="native"/>
    </id>

    <!-- relacja -->
    <many-to-one name="category" class="com.wordpress.chlebik.EntryCategory" column="category_id" />

    <!--  zwykle kolumny -->
    <property column="content" name="entry" type="string"/>
    <property column="points" name="points" type="integer"/>
    <property column="add_date" name="adddate" type="timestamp"/>
  </class>
</hibernate-mapping>

No i jej kod:

package com.wordpress.chlebik;

import java.io.Serializable;
import java.sql.Timestamp;
import javax.persistence.Id;


/**
 * Klasa, ktora ma za zadanie byc beanem wystepujacym jako wpis
 *
 * @author Michal Piotrowski
 */
public class Entry implements Serializable {

    @Id
    private Long id;
    private EntryCategory category;
    private Timestamp adddate;
    private String entry;
    private Integer points;

    /**
     * Bezargumentowy konstruktor
     */
    public Entry() {  }

    /**
     * Konstruktor z danymi
     *
     * @param id
     * @param adddate
     * @param entry
     * @param points
     * @param category
     */
    public Entry( Long id, Timestamp adddate, String entry, Integer points, EntryCategory category ) {
        this.id          =   id;
        this.category    =   category;
        this.adddate     =   adddate;
        this.entry       =   entry;
        this.points      =   points;
    }

    @Override
    public String toString() {
       return entry + "\n Kategoria: " + category.toString();
    }

    // Gettery
    public EntryCategory getCategory()  {
        return category;
    }
    
    public Long getId()  {
        return id;
    }

    public String getEntry()  {
        return entry;
    }

    public Timestamp getAdddate()  {
        return adddate;
    }

    public Integer getPoints()  {
        return points;
    }

     // Settery 
    public void setCategory( EntryCategory category )  {
        this.category = category;
    }

    public void setId( Long id )  {
        this.id = id;
    }

    public void setPoints( Integer points )  {
        this.points  = points;
    }

    public void setAdddate( Timestamp adddate ) {
        this.adddate = adddate;
    }

    public void setEntry( String entry ) {
        this.entry  =  entry;
    }

}

Nie zapomnijmy również dodać stosownych wpisów w pliku hibernate.cfg.xml:

    <mapping resource="/com/wordpress/chlebik/mapping/EntryCategory.hbm.xml"/>
    <mapping resource="/com/wordpress/chlebik/mapping/Entry.hbm.xml"/>

Encja Entry posiada ID kategorii, dzięki czemu wrzucając mapowanie do pliku konfiguracyjnego Hibernate bez problemu wie, co i skąd wyciągnąć. Jak widać w encjach nadpisałem metodę toString, dzięki czemu dodając do bazy danych przykładowy wpis mogłem po małej magii otrzymać w widoku takie oto cudo:

Od razu postanowiłem podpiąć formatowanie kodu, o którym pisałem niedawno. Zważywszy na edukacyjny charakter aplikacji,a tym samym małe obciążenie postanowiłem linkować do zewnętrznych źródeł. Podpięcie biblioteki, wrzucamy wyciągnięty z bazy kod i oto taki widok:

Ślicznie. Wróćmy jednakże do głównego wątku naszych rozważań. Nasz wpis posiada przypisaną kategorię. Posiada również autora, którym jest jeden z użytkowników w bazie danych. Zajmiemy się teraz stworzeniem odpowiedniego mapowania dla pokazania tej relacji. Jak napisałem powyżej jest to relacja dwustronna – wpis zna swojego autora, zaś użytkownik również jest świadom swoich wpisów.

W pliku Users.hbm.xml dopisujemy taki oto kod:

<set table="entries" name="entries">
         <key column="user_id"/>
         <one-to-many class="com.wordpress.chlebik.Entry" not-found="ignore" />
</set>

Mówi on tyle, że w przypadku obiektu User mamy dostęp do zbioru unikalnych wpisów, które są składowane w tabeli entries. Identyfikującym kluczem, który pozwoli wyciągnąć tylko te wpisy, które przynależą do naszego użytkownika jest kolumna user_id. No i ostatecznie obiekty, które będą w tej kolekcji są obiekty typu Entry. Rzecz dość czytelna. Oczywiście dopisujemy również metody dostępowe do tej kolekcji w klasie User!!!.

Z kolei by obiekt wpisu zdawał sobie sprawę z istnienia swego autora i mógł się do niego odwoływać należy do pliku Entry.hbm.xml dorzucić taką deklarację:

<many-to-one name="author" class="com.wordpress.chlebik.User" column="user_id"/>

W klasie Entry również trzeba dopisać metody dostępowe dla właściwości author. Uruchamiamy naszą aplikację i testowo gdzie nam wygodnie umieszczamy takie coś:

        try
        {
            org.hibernate.SessionFactory sessionFactory = com.wordpress.chlebik.util.ProgramBashUtil.getSessionFactory();
            Session session = sessionFactory.openSession();
            Entry wpis = (Entry) session.get( Entry.class, new Long(1) );
            return wpis;
        }
        catch( Exception e )
        { };

Używam metody get, gdyż nie rzuca ona wyjątku przy wyciąganiu obiektu z bazy tylko zwraca NULL w przypadku braku poszukiwanego rekordu. Akurat jego istnienia jestem pewny (wklepałem go ręcznie), ale dobrze jest wyrabiać sobie dobre nawyki. Zmodyfikowałem trochę metodę toString w klasie Entry i po uruchomieniu aplikacji pokazał się mym oczom taki widoczek:

Ślicznie. Od strony pojedynczego wpisu działa. Teraz testowo zamieniamy kod wyciągający pojedynczy wpis na taki oto kawałek:

 User author = (User) session.get( User.class, new Long(49) );
 return author;

Zaś w pliku Users.hbm.xml zmieniamy definicję na:

 <bag table="entries" name="entries" order-by="add_date">
         <key column="user_id"/>
         <one-to-many class="com.wordpress.chlebik.Entry" not-found="ignore" />
 </bag>

W widoku wrzuciłem taki kod dla spróbowania:

<rich:dataList var="elem" value="#{testowyBean.author.entries}">
    <h:outputText value="#{elem.entry}" />
</rich:dataList>

I pokazuje się nam piękna lista wpisów, które stworzył nasz użytkownik (na razie jego ID wklepane na sztywno, ale przerobienie tego to za chwilkę). Pytanie czemu użyłem znacznika bag, a nie np. Set lub List. Odpowiedź na to pytanie można znaleźć pod tym adresem – nie będę tworzył dodatkowego taga dla operacji, które powinny być oczywiste i powszechnie dostępne w widoku. Co do List dostawałem błąd parsowania XMLa – pomimo wklapania struktury znacznika prosto z dokumentacji Hibernate. Dopiero ww. konstrukcja z bag dała radę i posłusznie współpracuje ze znacznikiem rich:dataList.

Wpis trochę się zrobił rozwlekły zatem część widoku oraz samej logiki w następnym odcinku.

Formatowanie kodu w aplikacjach webowych w najprostszy mozliwy sposób

Przymierzając się wprowadzenia funkcjonalności dodawania wpisów w ProgramBash natknąłem się na problem wprowadzenia formatowania kodu. No i mały problem.

Domyślnie do aplikacji będzie można wklejać dowolny niemalże język programowania. Oczywiście pojawia się problem formatowania kodu źródłowego – zgodzimy się, iż czyste wskaźniki <pre> to nie jest dobre rozwiązanie. Oczywiście istnieje masa skryptów, które zajmują się tego typu konwersją, jednakże najcześciej są one napisane w PHP, zaś przepisywanie tego typu skryptów to benedyktyńska praca i niezbyt do tego rozwojowa. Java pod tym względem (dostępności takich skryptów) jest o wiele bardziej uboga. Jednakże okazuje się, iż istnieje inny sposób – można do tego typu zadań zaprząc JavaScript!. Jest to najzwyklejszy skrypt w tymże języku, dodane pliki stylowania kodu i viola – po wrzuceniu do skryptu łańcucha z kodem powinniśmy mieć pięknie sformatowany kod.

Narzędzie to nazywa się niezbyt oryginalnie SyntaxHighlighter, zaś jego strona domowa to wiki, gdzie znajdziemy wszystkie możliwe informacje. Na razie wygląda to bardzo obiecująco – jak tylko wezmę się za kolorowanie składni to na pewno skorzystam z tego skryptu.