Now we had a pretty complete application. It was time to put it to the test.
Before we opened the gates we needed to add some movie data. So we wrote a small class for populating the database which could be called from our controller. To make it safe to call several times we added index lookups to check for existing entries. A simple /populate endpoint for the controller that called it would be enough for now.
Example 10.1. Populating the database - Controller
@Service public class DatabasePopulator { @Autowired GraphDatabaseContext ctx; @Autowired CineastsRepository repository; @Transactional public List<Movie> populateDatabase() { Actor tomHanks = new Actor("1", "Tom Hanks").persist(); Movie forestGump = new Movie("1", "Forrest Gump").persist(); tomHanks.playedIn(forestGump,"Forrest"); return asList(forestGump); } } @Controller public class MovieController { private DatabasePopulator populator; @Autowired public MovieController(DatabasePopulator populator) { this.populator = populator; } @RequestMapping(value = "/populate", method = RequestMethod.GET) public String populateDatabase(Model model) { Collection<Movie> movies = populator.populateDatabase(); model.addAttribute("movies",movies); return "/movies/list"; } }
Example 10.2. Populating the database - JSP
<%@ page session="false" %> <%@ taglib uri="http://www.springframework.org/tags" prefix="s" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <c:choose> <c:when test="${not empty movie}"> <h2>${movie.title}</h2> <c:if test="${not empty movie.roles}"> <ul> <c:forEach items="${movie.roles}" var="role"> <li> <a href="/actors/${role.actor.id}"><c:out value="${role.actor.name}" /> as <c:out value="${role.name}" /></a><br/> </li> </c:forEach> </ul> </c:if> </c:when> <c:otherwise> No Movie with id ${id} found! </c:otherwise> </c:choose>
Accessing the URI showed the single added movie on screen.
Being the geeks we are, we also wanted to inspect the raw data in the database. Reading the Neo4j docs, there were a couple of different ways of going about this.
First we tried Neoclipse, an Eclipse RCP application/plugin that opens an existing graph store and visualizes its content. After getting an exception about concurrent access, we learned that we have to use Neoclipse in read-only mode when our webapp was still running. Good to know.
For console junkies there was also a shell that was able to connect to a running Neo4j instance (if it was started with enable_remote_shell=true), or directly open an existing graph store.
The shell was very similar to a standard Bash shell. We were able to cd
to
between the nodes, and ls
the relationships and properties. There were also
more advanced commands for indexing and traversals.
Example 10.4. Neo4j Shell usage
neo4j-sh[readonly] (0)$ help Available commands: index dbinfo ls rm alias set eval mv gsh env rmrel mkrel trav help pwd paths ... man cd Use man <command> for info about each command. neo4j-sh[readonly] (0)$ index --cd -g User login micha neo4j-sh[readonly] (Micha,1)$ ls *__type__ =[org.neo4j.cineasts.domain.User] *login =[micha] *name =[Micha] *roles =[ROLE_ADMIN,ROLE_USER] (me) --[FRIEND]-> (Olliver,2) (me) --[RATED]-> (The Matrix,3) neo4j-sh[readonly] (Micha,1)$ ls 2 *__type__ =[org.neo4j.cineasts.domain.User] *login =[ollie] *name =[Olliver] *roles =[ROLE_USER] (Olliver,2) <-[FRIEND]-- (me) neo4j-sh[readonly] (Micha,1)$ cd 3 neo4j-sh[readonly] (The Matrix,3)$ ls *__type__ =[org.neo4j.cineasts.domain.Movie] *description =[Neo is a young software engineer and part-time hacker who is singled ...] *genre =[Action] *homepage =[http://whatisthematrix.warnerbros.com/] ... *studio =[Warner Bros. Pictures] *tagline =[Welcome to the Real World.] *title =[The Matrix] *trailer =[http://www.youtube.com/watch?v=UM5yepZ21pI] *version =[324] (me) <-[ACTS_IN]-- (Marc Aden,19) (me) <-[ACTS_IN]-- (David Aston,18) ... (me) <-[ACTS_IN]-- (Keanu Reeves,6) (me) <-[DIRECTED]-- (Andy Wachowski,5) (me) <-[DIRECTED]-- (Lana Wachowski,4) (me) <-[RATED]-- (Micha,1)