Integração com Hibernate
O NEO possui algumas facilidades para a utilização do Hibernate. Além da configuração simplificada ele também possui classes que facilitam ainda mais a utilização do Hibernate.
Configurando Hibernate
Existem duas formas de configurar o Hibernate. Através de uma configuração simplificada ou completa. Na forma simplificada a configuração é feita pelo NEO, na forma completa a configuração é feita via XML.
Configuração simplificada
A configuração simplificada está disponível apenas para os bancos de dados PostgreSQL, Oracle e Microsoft SQL Server. Para os outros bancos de dados a configuração deverá ser feita através do arquivo XML de configuração dos beans. Para utilizar configuração simplificada é necessário criar um arquivo chamado connection.properties e colocá-lo no diretório /WEB-INF/classes.
Dica: Se estiver utilizando uma IDE como o eclipse. É só colocar o arquivo na pasta dos fontes (geralmente src).
O arquivo connection.properties possui 5 parâmetros: Através desse arquivo a configuração pode ser feita através de jndi ou jdbc.
Para JNDI é necessária a configuração do parâmetro jndi.
Para JDBC é necessária a configuração dos parâmetros driver, url, username e password.
Se as duas configurações forem informadas. Em ambientes J2EE a configuração JNDI será utilizada. Em ambientes J2SE a configuração via JDBC será utilizada.
Exemplo de arquivo com JNDI informado:
jndi=java:/dataSourceJndiName
Exemplo de arquivo com o JDBC informado:
driver=org.postgresql.Driver
url=jdbc:postgresql://localhost/mydb
username=postgres
password=
O NEO detecta a presença do arquivo connection.properties e faz automaticamente toda a configuração necessária para a conexão com o banco de dados e com o hibernate. Nenhum XML é necessário.
Configuração completa
Em determinadas situações uma configuração mais personalizada pode ser necessária. Nesse caso deve ser utilizada a configuração completa do Hibernate. Essa configuração deve ser feita através de XML.
Nesse XML devem ser declarados os beans: Já existem classes que implementam as interfaces necessárias para esses beans. A tabela abaixo mostra quais classes são recomendáveis para a configuração de cada bean, além das dependências.
Bean Classe Dependência
dataSource org.springframework.jdbc.datasource.DriverManagerDataSource
quando for utilizar a configuração através de JDBC
org.springframework.jndi.JndiObjectFactoryBean
quando for utilizar a configuração através de JNDI
-
sessionFactorybr.com.linkcom.neo.hibernate.AnnotationSessionFactoryBean dataSource
hibernateTemplateorg.springframework.orm.hibernate3.HibernateTemplate sessionFactory
hibernateTransactionManager org.springframework.orm.hibernate3.HibernateTransactionManager dataSource, sessionFactory
transactionTemplateorg.springframework.transaction.support.TransactionTemplatehibernateTransactionManager
Se algum bean não foi declarado mas as suas dependências foram, o NEO irá criar esse bean automaticamente. Exemplo: Se o dataSource for declarado mas o sessionFactory não for declarado o NEO irá criar um sessionFactory porque o dataSource de quem o sessionFactory depende foi informado.

Para efetuar a configuração desses beans deve ser utilizado o arquivo applicationConfig.xml que fica em /WEB-INF/. Exemplo:
[JSP]
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
	
	<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
		<property name="transactionManager">
			<ref bean="hibernateTransactionManager"/>
		</property>
	</bean>
	
	<bean id="hibernateTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		<property name="sessionFactory">
			<ref bean="sessionFactory" />
		</property>
	</bean>
	
	<bean id="hibernateTemplate"	class="org.springframework.orm.hibernate3.HibernateTemplate">
		<property name="sessionFactory">
			<ref bean="sessionFactory" />
		</property>
	</bean>
	
	<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
		<property name="jndiName">
			<value>java:/dataSourceJndiName</value>
		</property>
	</bean>
 
	<bean id="sessionFactory" class="br.com.linkcom.neo.hibernate.AnnotationSessionFactoryBean">
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
				<prop key="hibernate.show_sql">true</prop>
			</props>
		</property>
	</bean>

</beans>
No bloco do bean sessionFactory deve ser informado o dialeto do hibernate de acordo com o banco de dados utilizado.

Se desejar utilizar uma configuração via JDBC substitua o bloco do bean dataSource pelo seguinte:
[JSP]
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	<property name="driverClassName" value="org.postgresql.Driver"/>
	<property name="url" value="jdbc:postgresql://localhost/mydb"/>	
	<property name="username" value="postgres"/>				
	<property name="password" value=""/>				
</bean>
Importante: Não esqueça de copiar os arquivos JAR do NEO para a aplicação.
Configurando beans no Hibernate
Os beans do Hibernate são configurados utilizando Hibernate Annotations. Hibernate Annotations é um framework do Hibernate que permite que as informações sobre o mapeamento dos beans seja feita via Annotations ao invés de XML. Em um ambiente apenas com o Hibernate Annotations além das anotações dos beans é necessário configurar em algum lugar (geralmente um XML) quais são os beans anotados e que devem ser gerenciados pelo Hibernate. No NEO essa configuração do XML não é necessária, ele irá detectar a presença dos beans e fazer o registro automático. Só é necessário criar a classe e fazer a anotação que o bean será registrado no Hibernate. Veja o exemplo:
package teste;

import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class Aluno {

	private Integer id;
	private String nome;
	
	@Id
	public Integer getId() {
		return id;
	}
	public String getNome() {
		return nome;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
}
Importante: Para uma classe ser registrada pelo neo ela deve estar dentro de /WEB-INF/classes. As classes dentro de arquivos JAR não são registradas.
Qualquer anotação do Hibernate Annotations é suportada pelo NEO. Para uma melhor utilização do Hibernate Annotations veja a documentação no site do Hibernate.
Para uma melhor utilização do Hibernate Annotations no NEO alguns padrões devem ser seguidos. Veja os exemplos de mapeamento abaixo:
package teste;

import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;

@Entity
@SequenceGenerator(name = "sq_aluno", sequenceName = "sq_aluno")
public class Aluno {

	private Integer id;
	private String nome;
	private List<Matricula> matriculas;

	@Id
	@GeneratedValue(strategy=GenerationType.AUTO, generator="sq_aluno")
	public Integer getId() {
		return id;
	}
	
	@OneToMany(mappedBy="aluno")
	public List<Matricula> getMatriculas() {
		return matriculas;
	}

	public String getNome() {
		return nome;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
	public void setMatriculas(List<Matricula> matriculas) {
		this.matriculas = matriculas;
	}
}

package teste;

import java.sql.Date;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;

@Entity
@SequenceGenerator(name = "sq_matricula", sequenceName = "sq_matricula")
public class Matricula {

	private Integer id;
	private Aluno aluno;
	private Date data;
	
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO, generator="sq_matricula")
	public Integer getId() {
		return id;
	}
	
	@ManyToOne(fetch=FetchType.LAZY)
	public Aluno getAluno() {
		return aluno;
	}
	public Date getData() {
		return data;
	}

	public void setAluno(Aluno aluno) {
		this.aluno = aluno;
	}
	public void setData(Date data) {
		this.data = data;
	}
	public void setId(Integer id) {
		this.id = id;
	}
}

QueryBuilder
Construir queries de aplicações do mundo real não é muito trivial. Geralmente é utilizada a concatenação de strings junto com blocos if para determinar se determinada condição deve ser adicionada na query de acordo com os parâmetros passados. Além de gastar tempo montando o algorítmo de criação das queries o código não fica organizado e de difícil manutenção. Para evitar o problema da criação de queries o NEO possui a classe QueryBuilder.
Para utilizar o query builder é necessária ter uma referência para hibernateTemplate. Veja o exemplo:
package teste;

import org.springframework.orm.hibernate3.HibernateTemplate;

import br.com.linkcom.neo.bean.annotation.Bean;

@Bean
public class ExecutaQuery {

	private HibernateTemplate hibernateTemplate;
	
	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}
	
}
Importante: Sempre utilize o HibernateTemplate do pacote org.springframework.orm.hibernate3
Criamos um bean ExecutaQuery e registramos utilizando @Bean. Criamos um atributo hibernateTemplate e um setter. Qualquer método que criarmos agora no ExecutaQuery possuirá uma referência para hibernateTemplate e então poderemos criar um QueryBuilder.
Vamos criar um método para retornar todos beans aluno que criamos anteriormente:
package teste;

import java.util.List;

import org.springframework.orm.hibernate3.HibernateTemplate;

import br.com.linkcom.neo.bean.annotation.Bean;
import br.com.linkcom.neo.persistence.QueryBuilder;

@Bean
public class ExecutaQuery {

	private HibernateTemplate hibernateTemplate;
	
	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}
	
	public List<Aluno> findAll(){
		return new QueryBuilder<Aluno>(hibernateTemplate)
					.from(Aluno.class)
					.list();
	}
}

O queryBuilder pode ser parametrizado por um tipo genérico. O queryBuilder também permite que apenas determinados campos sejam especificados na cláusula select. Exemplo:
new QueryBuilder<Aluno>(hibernateTemplate)
					.select("aluno.nome")
					.from(Aluno.class)
					.list();
Nesse caso os beans aluno retornados irão conter apenas o campo nome. Isso permite que apenas os dados necessários sejam carregados. Quando os campos são determinados na cláusula do select o tipo de retorno sempre será o mesmo da classe definida pelo método from.
O Hibernate não tem suporte para buscar apenas determinados campos do banco e mapear como objeto. O NEO faz a tradução do resultado da query para os beans necessários. Se desejar cancelar o tradutor do NEO utilize o método setUseTranslator(false). Sempre que existir o carater '.' (ponto) no select, o NEO irá utilizar o tradutor próprio. Nós demais casos ele irá retornar o resultado do Hibernate.
O QueryBuilder constrói queries do Hibernate (HQL) então os joins e wheres são especificados da mesma forma que o hibernate. Exemplo:
return new QueryBuilder<Aluno>(hibernateTemplate)
			.from(Matricula.class)
			.leftOuterJoin("matricula.aluno")
			.list();
Nesse exemplo fizemos uma query from Matricula e com join em aluno. Também seria possível definir um alias para o join:
return new QueryBuilder<Aluno>(hibernateTemplate)
			.from(Matricula.class)
			.leftOuterJoin("matricula.aluno aluno")
			.list();
A query montada pelo exemplo acima seria "from Matricula matricula left outer join matricula.aluno aluno". Existem outros métodos para diferentes tipos de join no QueryBuilder.
O QueryBuilder tem um suporte especial para cláusulas where. Exemplo:
public List<Aluno> findByNome(String nome){
	return new QueryBuilder<Aluno>(hibernateTemplate)
				.from(Aluno.class)
				.where("aluno.nome = ?", nome)
				.list();
}
Nesse exemplo será montada uma query da seguinte forma: "from Aluno aluno where aluno.nome = ?" e será passado como parâmetro o campo nome. Se o nome for nulo o QueryBuilder elimina essa condição da query: "from Aluno aluno"

É possível utilizar várias condições no mesmo queryBuilder, o NEO manipula a query sempre que um determinado parametro for null.
É possível criar parenteses com os métodos openParentheses() e closeParentheses() e também utilizar a cláusula or para separar as condições:
.from(NotaFiscal.class)
.leftOuterJoin("notaFiscal.cliente cliente")
.where("cliente.nome = ?", nomeCliente)
.or()
.openParentheses()
    .where("notaFiscal.data < ?", data)
	.where("notaFiscal.numero > ?", numero)
.closeParentheses()
.list()
Existem alguns métodos especiais no QueryBuilder para facilitar a construção de cláusulas where. Exemplo:
.whereLike("aluno.nome", nome)
Note que nos métodos especiais não deve ser colocada a interrogação '?'. Esse código equivale a escrever:
.where("aluno.nome like ?", "%" + nome + "%");
Os QueryBuilder possui métodos equivalentes as cláusulas do HQL o que facilita o entendimento.
SaveOrUpdateStrategy
Assim como existe uma classe auxiliar para executar queries, existe também uma classe para salvar informações no banco de dados. Essa classe é a SaveOrUpdateStrategy que também trabalha em cima do hibernate. Com ela é possível definir várias atividades a ser executadas em determinado bean e executá-las dentro de uma transação.
Para salvar um objeto no banco de dados:
Aluno aluno = ...;
new SaveOrUpdateStrategy(hibernateTemplate, aluno)
		.saveEntity()
		.execute();
Com o saveOrUpdateManaged também é possível salvar coleções de dados do bean. Veja o exemplo:
new SaveOrUpdateStrategy(hibernateTemplate, aluno)
	.saveEntity()
	.saveOrUpdateManaged("matriculas")
	.execute();
Nesse caso, o bean aluno será salvo, assim como os itens da propriedade matriculas. Podem ser salvas quantas coleções forem necessárias. Para isso é só chamar o método saveOrUpdateManaged para cada propriedade. O método saveEntity deve ser chamado apenas uma vez, e antes de salvar as coleções. Para cada coleção o SaveOrUpdateStrategy insere os itens novos, atualiza os itens que já estavam no banco e remove do banco os itens que não estão na lista. Esse tipo de comportamento é bastante utilizado em telas do tipo mestre/detalhe. As tarefas de salvar o bean e as coleções serão executadas dentro de uma transação.
TransactionTemplate
O transactionTemplate é uma classe que possibilita a utilização de transações de uma forma simples e eficiente. Sem a necessidade de blocos try, catch, finally.
Para utilizar o transactionTemplate utilize a injeção de dependencia. Exemplo:
import org.springframework.transaction.support.TransactionTemplate;

import br.com.linkcom.neo.bean.annotation.Bean;


@Bean
public class Operador {

	private TransactionTemplate transactionTemplate;
	
	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}
	
	public void calcular(){
		[bloco de código que deve estar dentro de uma transação]
	}
}
Depois de configurado o bean, basta utilizar o método execute do transactionTemplate conforme o modelo:
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import br.com.linkcom.neo.bean.annotation.Bean;


@Bean
public class Operador {

	private TransactionTemplate transactionTemplate;
	
	public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
		this.transactionTemplate = transactionTemplate;
	}
	
	public void calcular(){
		transactionTemplate.execute(new TransactionCallback(){

			public Object doInTransaction(TransactionStatus status) {
				[bloco de código que deve estar dentro de uma transação]
				return null;
			}}
		);
	}
}
O código será executado dentro de uma transação. O método execute recebe como parâmetro um TransactionCallback que foi representado no exemplo por uma classe anonima. A classe TransactionCallback possui um método doInTransaction, dentro desse método deve ser colocado o código a ser executado dentro da transação. O método doInTransaction pode retornar algum valor se necessário (caso contrário é só retornar null). Mais informações sobre o TransactionTemplate podem ser encontradas na documentação do Spring.
GenericDAO
DAO é um design pattern bem simples e amplamente utilizado no desenvolvimento de aplicações. Esse design pattern consiste em uma classe que possui todas as chamadas de acesso a banco para determinada entidade. Todas as queries ficam dentro dos DAOs proporcionando uma melhor organização da aplicação. Veja um exemplo de DAO:
package teste;

import java.util.List;

import org.springframework.orm.hibernate3.HibernateTemplate;

import br.com.linkcom.neo.bean.annotation.Bean;
import br.com.linkcom.neo.persistence.QueryBuilder;
import br.com.linkcom.neo.persistence.SaveOrUpdateStrategy;

@Bean
public class AlunoDAO {

	HibernateTemplate hibernateTemplate;
	
	public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
		this.hibernateTemplate = hibernateTemplate;
	}
	
	public void save(Aluno aluno){
		new SaveOrUpdateStrategy(hibernateTemplate, aluno)
				.saveEntity()
				.execute();	
	}
	
	public Aluno load(Integer id){
		return new QueryBuilder<Aluno>(hibernateTemplate)
					.from(Aluno.class)
					.idEq(id)
					.unique();
	}
	
	public List<Aluno> findAll(){
		return new QueryBuilder<Aluno>(hibernateTemplate)
					.from(Aluno.class)
					.list();
	}
	
	public void delete(Aluno aluno){
		hibernateTemplate.delete(aluno);
	}
}

Importante: O NEO em vários lugares utiliza padrões de nomeclatura para configurar a aplicação. Nos DAOs sempre utilize [nome do bean]DAO. Para o bean Aluno, AlunoDAO. Para o bean Matricula, MatriculaDAO.
Esse é um DAO simples que possui os métodos save, load, findAll e delete. Sempre que a aplicação precisar de acessar algum dado relativo a aluno é só pedir para o AlunoDAO. Como o DAO é muito comum, o NEO possui uma implementação padrão. Para implementar o DAO do NEO basta extender GenericDAO. Exemplo:
package teste;

import br.com.linkcom.neo.persistence.GenericDAO;

public class AlunoDAO extends GenericDAO<Aluno> {

}
Não é necessário escrever nenhum algorítmo e nem anotar a classe com @Bean. Esse DAO vem com os métodos mais comuns implementados. Veja um exemplo de utilização esse DAO:
package teste;

import java.util.List;

import br.com.linkcom.neo.bean.annotation.Bean;

@Bean
public class GerenciaAluno {

	AlunoDAO alunoDAO;
	
	public void setAlunoDAO(AlunoDAO alunoDAO) {
		this.alunoDAO = alunoDAO;
	}
	
	public void executar(){
		Aluno novoAluno = new Aluno();
		novoAluno.setNome("aluno teste");
		
		alunoDAO.saveOrUpdate(novoAluno);
		
		List<Aluno> all = alunoDAO.findAll();
		for (Aluno aluno : all) {
			System.out.println(aluno.getNome());
		}
	}
}

O GenericDAO além dos métodos saveOrUpdate e finAll mostrados, possui métodos para deletar e carregar beans. É possível adquirir uma referência para o HibernateTemplate, JdbcTemplate e TransactionTemplate com os métodos getHibernateTemplate(), getJdbcTemplate(), getTransactionTemplate() respectivamente. O GenericDAO também possui os métodos query() que cria um QueryBuilder com a cláusula from já configurada para a classe do DAO em questão. E também possui o método save(...) que recebe um bean como parâmetro, esse método cria um saveOrUpdateStrategy com a operação saveEntity já configurada. Veja um exemplo do uso desses métodos:
package teste;

import java.util.List;

import br.com.linkcom.neo.persistence.GenericDAO;

public class AlunoDAO  extends GenericDAO<Aluno>{
	
	public List<Aluno> find(){
		return query().list();
	}
	
	public void saveAluno(Aluno aluno){
		save(aluno).execute();
	}

}
Esse exemplo serve apenas para demonstrar a utilização do método save e query.
O GenericDAO também possui outros métodos que facilitam a criação de cruds e de combos. Portanto para utilizar toda a potencialidade do NEO é recomendável criar DAOs que estendam GenericDAO.
Configurando o cache do hibernate.
O NEO traz também a possibilidade de integrar com o cache que é fornecido pelo hibernate, o cache de segundo nível e também o cache de querys.
Caso o seu data-source tenha sido configurado pelo connection.properties adicione o seguinte trecho ao arquivo applicationConfig.xml:
[JSP]
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">

	<bean name="config"	class="br.com.linkcom.sined.util.config.NeoConfig" autowire="autodetect">
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
				<prop key="hibernate.cache.use_query_cache">true</prop>
			</props>
		</property>
	</bean>
Caso o seu datasource foi configurado manualmente pelo spring, adicione as seguintes linhas:
[JSP]
	<bean id="sessionFactory" class="br.com.linkcom.neo.hibernate.AnnotationSessionFactoryBean">
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>
				<prop key="hibernate.cache.use_query_cache">true</prop>
			</props>
		</property>
Com isso o NEO já está preparado para suportar o cache.
Utilizando o cache para as query's
No QueryBuilder, está disponível o método useCache, que deve ser usado da seguinte maneira:
	new QueryBuilder<Bean> queryBuilder = new QueryBuilder<Bean>(getHibernateTemplate());
				.useCache(true)
				.from(Bean.class)
				.unique();
A partir desse momento, o neo repassará ao hibernate que o resultado deverá ficar em cache.
Importante: Todas as consultas de combo por padrão vem com cache desabilitado, caso queira habilitar o cache para o combo, anote a entidade do mesmo com a annotation @org.hibernate.annotations.Cache. Ver utilização no seguinte link: http://www.hibernate.org/hib_docs/annotations/reference/en/html_single/#d0e2867