siark.com blog

November 12, 2010

The siark.com Gallery – Part 2

Part two of creating the siark.com gallery involves implementing the leaf and non-leaf types of gallery. To do this it’s necessary to add the concept of a parent and child relationship within the gallery.

The gallery domain class.

package com.siark.igallery.domain;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "gallery")
public class Gallery extends DomainBase {
	
	private static final long serialVersionUID = -7236265616573470929L;
	private String title;
	private Gallery parent;
	private List<Gallery> children = new ArrayList<Gallery>();
	boolean leaf = false;

	/**
	 *
	 */
	public Gallery(String title) {
		this.title = title;
	}

	/**
	 *
	 */
	public Gallery() {
	}

	/**
	 * Returns the display name of the gallery.
	 * 
	 * @return title the display name of the gallery
	 */
	@Column(name = "title")
	public String getTitle() {
		return title;
	}

	/**
	 * Sets the display name of the gallery.
	 * 
	 * @param title the display name of the gallery
	 */
	public void setTitle(String title) {
		this.title = title;
	}
	
	/**
	 * Returns the gallery that is the parent to this gallery.
	 * A gallery has only one parent.
	 * 
	 * @return the gallery that is this galleries parent
	 */
	@ManyToOne
	@JoinColumn(name="parent_fk")
	public Gallery getParent() {
		return this.parent;
	}
	
	/**
	 * Sets this galleries parent.
	 * 
	 * @param the parent gallery
	 */
	public void setParent(Gallery parent) {
		this.parent = parent;
	}
	
	/**
	 * If this gallery is a non-leaf gallery it can have zero or more child galleries.
	 * 
	 * @return a list of this galleries children
	 */
	@OneToMany
	@JoinColumn(name="parent_fk")
	public List<Gallery> getChildren() {
		return children;
	}
	
	/**
	 * Child galleries can only be added to this gallery if this gallery is a non-leaf gallery.
	 * 
	 * @param the list of this galleries child galleries
	 */
	public void setChildren(List<Gallery> children) throws GalleryException {
		if (!this.leaf || children.isEmpty() || (children == null)) this.children = children;
		else throw new GalleryException();
	}
	
	/**
	 * 
	 */
	@Column(name="leaf")
	public boolean isLeaf() {
		return leaf;
	}

	/**
	 * The value of leaf can only be set to true if there are no children.
	 * @param leaf
	 */
	public void setLeaf(boolean leaf) {
		this.leaf = leaf;
	}

	/**
	 *
	 */
	@Override
	public String toString() {
		StringBuffer buffer = new StringBuffer();
		buffer.append(super.toString());
		buffer.append("Title: " + this.title + "; ");
		return buffer.toString();
	}
	
	/**
	 * 
	 */
	@Override
	public boolean equals(Object o) {
		if (o == this) return true;
		if (!(o instanceof Gallery)) return false;
		if (getClass() != o.getClass()) return false;
		Gallery gallery = (Gallery) o;
		if ((this.id == gallery.getId())
			&& (this.title == null) ? (gallery.getTitle() == null) : gallery.getTitle().equals(this.title)) {
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * 
	 */
	@Override
	public int hashCode() {
		int result = 17;
		result = 31 * result + this.id;
		result = 31 * result + (this.title == null ? 0 : this.title.hashCode());
		return result;
	}
}

The dao interface is modified to include some methods to access the parent and the children.

package com.siark.igallery.repository;

import java.util.List;
import com.siark.igallery.domain.Gallery;

public interface GalleryDao {

	public void persistGallery(Gallery gallery);
	public List<Gallery> getAllNonLeafGalleries();
	public List<Gallery> getAllLeafGalleries();
	public List<Gallery> getAllGalleries();
	public List <Gallery> getGalleriesByParent(Gallery parent);
	public Gallery getGalleryById(int id);
	public void delete(int id);
}
package com.siark.igallery.repository;

import java.util.List;

import javax.inject.Inject;
import javax.inject.Named;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.SessionFactory;

import com.siark.igallery.domain.Gallery;

@Named("GalleryDao")
public class HibernateGalleryDao implements GalleryDao {

	protected final Log logger = LogFactory.getLog(getClass());
	private SessionFactory sessionFactory;
	
	/**
	 * Save a new gallery or update an existing gallery.
	 * 
	 * @param gallery a new or existing gallery
	 */
	public void persistGallery(Gallery gallery) {
		this.sessionFactory.getCurrentSession()
			.saveOrUpdate(gallery);
	}
	
	/**
	 * Return all the non-leaf galleries.
	 * 
	 * @return a list of the non-leaf galleries
	 */
	@SuppressWarnings("unchecked")
	public List<Gallery> getAllNonLeafGalleries() {
		return this.sessionFactory.getCurrentSession()
			.createQuery("from Gallery as gallery where leaf = false")
			.list();
	}
	
	/**
	 * Return all the leaf galleries.
	 * 
	 * @return a list of the leaf galleries
	 */
	@SuppressWarnings("unchecked")
	public List<Gallery> getAllLeafGalleries() {
		return this.sessionFactory.getCurrentSession()
		.createQuery("from Gallery as gallery where leaf = true")
		.list();
	}
	
	/**
	 * Return all of the galleries including the root gallery.
	 * 
	 * @return a list of all the galleries
	 */
	@SuppressWarnings("unchecked")
	public List<Gallery> getAllGalleries() {
		return this.sessionFactory.getCurrentSession()
			.createQuery("from Gallery")
			.list();
	}
	
	/**
	 * Return all the child galleries of a parent gallery.
	 * 
	 * @return a list of child galleries
	 */
	@SuppressWarnings("unchecked")
	public List<Gallery> getGalleriesByParent(Gallery parent) {
		return this.sessionFactory.getCurrentSession()
		.createQuery("from Gallery as gallery where parent = :parent")
		.setEntity("parent", parent)
		.list();
	}
	
	/**
	 * Return the gallery with a specific id or null if a gallery with that id does not exist.
	 * 
	 * @param id the id of the gallery to find
	 * @return a gallery with the id specified or null
	 */
	public Gallery getGalleryById(int id) {
		return (Gallery) this.sessionFactory.getCurrentSession()
			.createQuery("from Gallery as gallery where gallery.id = :id")
			.setInteger("id", id)
			.uniqueResult();
	}
	
	/**
	 * Delete the gallery with a specific id.
	 * 
	 * @param id the id of the gallery to delete
	 */
	public void delete(int id) {
		this.sessionFactory.getCurrentSession()
			.createQuery("delete from Gallery as gallery where gallery.id = :id")
			.setInteger("id", id);
	}
	
	@Inject
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
}

The service is also modified to include the methods to access the parent and children.

package com.siark.igallery.service;

import java.util.List;

import com.siark.igallery.domain.Gallery;

public interface GalleryService {
	
	public void persistGallery(Gallery gallery);
	public List<Gallery> getAllNonLeafGalleries();
	public List<Gallery> getAllLeafGalleries();
	public List<Gallery> getGalleriesByParent(Gallery parent);
	public List<Gallery> getAllGalleries();
	public Gallery getRootGallery();
	public Gallery getGalleryById(int id);
	public void delete(int id);
}
package com.siark.igallery.service;

import java.util.List;

import javax.inject.Inject;
import javax.inject.Named;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.siark.igallery.domain.Gallery;
import com.siark.igallery.repository.GalleryDao;

@Named("GalleryService")
public class GalleryServiceImpl implements GalleryService {
	
	protected final Log logger = LogFactory.getLog(getClass());

	@Inject
	@Named("GalleryDao")
	private GalleryDao galleryDao;
	
	/**
	 * Save a new gallery or update an existing gallery.
	 * 
	 * @param gallery a new or existing gallery
	 */
	public void persistGallery(Gallery gallery) {
		galleryDao.persistGallery(gallery);
	}
	
	/**
	 * Return all the non-leaf galleries.
	 * 
	 * @return a list of the non-leaf galleries
	 */
	public List<Gallery> getAllNonLeafGalleries() {
		return galleryDao.getAllNonLeafGalleries();
	}
	
	/**
	 * Return all the leaf galleries.
	 * 
	 * @return a list of the leaf galleries
	 */
	public List<Gallery> getAllLeafGalleries() {
		return galleryDao.getAllLeafGalleries();
	}
	
	/**
	 * Return all of the galleries including the root gallery.
	 * 
	 * @return a list of all the galleries
	 */
	public List<Gallery> getAllGalleries() {
		return galleryDao.getAllGalleries();
	}
	
	/**
	 * Return all the child galleries of a parent gallery.
	 * 
	 * @return a list of child galleries
	 */
	public List<Gallery> getGalleriesByParent(Gallery parent) {
		return galleryDao.getGalleriesByParent(parent);
	}
	
	/**
	 * Return the root gallery.
	 * 
	 * @return the root gallery
	 */
	public Gallery getRootGallery() {
		return galleryDao.getGalleryById(1);
	}
	
	/**
	 * Return the gallery with a specific id or null if a gallery with that id does not exist.
	 * 
	 * @param id the id of the gallery to find
	 * @return a gallery with the id specified or null
	 */
	public Gallery getGalleryById(int id) {
		return galleryDao.getGalleryById(id);
	}
	
	/**
	 * Delete the gallery with a specific id. The root gallery can not be deleted.
	 * 
	 * @param id the id of the gallery to delete
	 */
	public void delete(int id) {
		if (id > 1) galleryDao.delete(id);
	}
	
	public void setGalleryDao(GalleryDao galleryDao) {
		this.galleryDao = galleryDao;
	}
	
	public GalleryDao getGalleryDao() {
		return galleryDao;
	}
}

The gallery controller remains unchanged, but the home page menu is now populated using the children of the root gallery.

<?xml version="1.0" encoding="ISO-8859-1" ?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" 
		xmlns:c="http://java.sun.com/jsp/jstl/core"
		xmlns:fmt="http://java.sun.com/jsp/jstl/fmt"
		version="2.0">
	<fmt:setBundle basename="Messages" />
    <jsp:directive.page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1" />
    <jsp:text>
        <![CDATA[ <?xml version="1.0" encoding="ISO-8859-1" ?> ]]>
    </jsp:text>
    <jsp:text>
        <![CDATA[ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> ]]>
    </jsp:text>
	<html xmlns="http://www.w3.org/1999/xhtml">
		<head>
			<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
			<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/styles/base.css" />
			<link rel="stylesheet" type="text/css" href="${pageContext.request.contextPath}/styles/home.css" />
			<title><fmt:message key="home.title" /></title>
		</head>
		<body>
			<div class="container">
				<div id="header" class="bottom-line">
					<div id="logo">
						<a href="#">siark.com</a>
					</div>
				</div>
				<div id="top-menu">
					<div class="menu">
						<ul>
							<li>
								<a href="#"><fmt:message key="menu.gallery" /></a>
								<ul>
									<c:forEach items="${gallery.children}" var="item">
										<li>
											<jsp:element name="a">
												<jsp:attribute name="href">${pageContext.request.contextPath}/gallery/view.html?id=<c:out value="${item.id}" /></jsp:attribute>
												<jsp:body><c:out value="${item.title}" /></jsp:body>
											</jsp:element>
										</li>
									</c:forEach>
								</ul>
							</li>
	  						<li><a href="${pageContext.request.contextPath}/about.html"><fmt:message key="menu.about" /></a></li>
	  						<li><a href="#"><fmt:message key="menu.contact" /></a></li>
	  						<li class="right"><a href="${pageContext.request.contextPath}/gallery/admin/list.html"><fmt:message key="menu.admin" /></a></li>
	  					</ul>
	  				</div>
				</div>
				<div id="content">
					<div id="home-image">
						<div style="position:relative; top:79px; left:0px;">
							<img class="border" src="images/MG-100228-30-Edit.jpg" width="474" height="316" />
						</div>
					</div>
				</div>
				<div id="bottom-menu">
					<div class="menu">
						<ul>
							<li><a href="#"><fmt:message key="menu.news" /></a></li>
	  						<li><a href="#"><fmt:message key="menu.reviews" /></a></li>
	  						<li><a href="#"><fmt:message key="menu.tutorials" /></a></li>
	  						<li><a href="#"><fmt:message key="menu.videos" /></a></li>
	  					</ul>
	  				</div>
				</div>
				<div id="footer" class="top-line">
					<div id="copyright">all content © siark ltd</div>
				</div>
			</div>
		</body>
	</html>
</jsp:root>

In order for the JSP page to be able to access the children of the root gallery without incurring a lazy loading exception, the Open Session in View pattern is used. Spring makes it easy to use this pattern and all that is required is to add an interceptor to the mvc-config.xml file.

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

	<!-- Configures the @Controller programming model -->
	<mvc:annotation-driven />

	<!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory -->
	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/jsp/"/>
		<property name="suffix" value=".jsp"/>
	</bean>
	
	<mvc:interceptors>
		<bean class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
			<property name="sessionFactory">
				<ref bean="sessionFactory" />
			</property>
			<property name="flushModeName">
				<value>FLUSH_AUTO</value>
			</property>
		</bean>
	</mvc:interceptors>
</beans>

Note: The flush mode is set to FLUSH_AUTO as there is no transaction management at the moment.

Create a free website or blog at WordPress.com.