| <html><head> |
| <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
| <title xmlns:d="http://docbook.org/ns/docbook">Chapter 9. Converting to Web Application</title><link rel="stylesheet" type="text/css" href="css/cayenne-doc.css"><meta xmlns:d="http://docbook.org/ns/docbook" name="keywords" content="Cayenne 3.1 documentation"><meta xmlns:d="http://docbook.org/ns/docbook" name="description" content="User documentation for Apache Cayenne version 3.1"><link rel="home" href="index.html" title="Getting Started with Cayenne"><link rel="up" href="getting-started-part4.html" title="Part IV. Converting to Web Application"><link rel="prev" href="getting-started-part4.html" title="Part IV. Converting to Web Application"><script xmlns:d="http://docbook.org/ns/docbook" type="text/javascript"> |
| var _gaq = _gaq || []; |
| _gaq.push(['_setAccount', 'UA-7036673-1']); |
| _gaq.push(['_trackPageview']); |
| (function() { |
| var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; |
| ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; |
| var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); |
| })(); |
| </script></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div xmlns:d="http://docbook.org/ns/docbook" class="navheader"><table width="100%" summary="Navigation header"><tr><th class="versioninfo">v.3.1 (3.1)</th><th align="center">Chapter 9. Converting to Web Application</th><th></th></tr><tr><td width="20%" align="left"><a accesskey="p" href="getting-started-part4.html">Prev</a> </td><th width="60%" align="center"><a accesskey="u" href="getting-started-part4.html">Part IV. Converting to Web Application</a></th><td width="20%" align="right"> </td></tr></table><hr></div><div class="chapter" title="Chapter 9. Converting to Web Application"><div class="titlepage"><div><div><h2 class="title"><a name="d0e493"></a>Chapter 9. Converting to Web Application</h2></div></div></div><div class="toc"><p><b>Table of Contents</b></p><dl><dt><span class="section"><a href="ch09.html#converting-to-webapp">Converting Tutorial to a Web Application</a></span></dt><dt><span class="section"><a href="ch09.html#running-webapp">Running Web Application</a></span></dt></dl></div><p>This chapter shows how to work with Cayenne in a web application.</p><div class="section" title="Converting Tutorial to a Web Application"><div class="titlepage"><div><div><h2 class="title"><a name="converting-to-webapp"></a>Converting Tutorial to a Web Application</h2></div></div></div><p>The web part of the web application tutorial is done in JSP, which is the least common |
| denominator of the Java web technologies, and is intentionally simplistic from the UI |
| perspective, to concentrate on Cayenne integration aspect, rather than the interface. A |
| typical Cayenne web application works like this:</p><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p>Cayenne configuiration is loaded when an application context is started, using |
| a special servlet filter.</p></li><li class="listitem"><p>User requests are intercepted by the filter, and the DataContext is bound to |
| the request thread, so the application can access it easily from |
| anywhere.</p></li><li class="listitem"><p>The same DataContext instance is reused within a single user session; |
| different sessions use different DataContexts (and therefore different sets of |
| objects). <span class="italic">The context can be scoped differently |
| depending on the app specifics. For the tutorial we'll be using a |
| session-scoped context.</span></p></li></ul></div><p>So let's convert the tutorial that we created to a web application:</p><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p>In Eclipse under "tutorial" project folder create a new folder |
| "src/main/webapp/WEB-INF".</p></li><li class="listitem"><p>Under "WEB-INF" create a new file "web.xml" (a standard web app descriptor): </p><p> |
| <span class="bold"><strong>web.xml</strong></span> |
| </p><pre class="programlisting"><?xml version="1.0" encoding="utf-8"?> |
| <!DOCTYPE web-app |
| PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" |
| "http://java.sun.com/dtd/web-app_2_3.dtd"> |
| <web-app> |
| <display-name>Cayenne Tutorial</display-name> |
| |
| <!-- This filter bootstraps ServerRuntime and then provides each request thread |
| with a session-bound DataContext. Note that the name of the filter is important, |
| as it points it to the right named configuration file. |
| --> |
| <filter> |
| <filter-name>cayenne-project</filter-name> |
| <filter-class>org.apache.cayenne.configuration.web.CayenneFilter</filter-class> |
| </filter> |
| <filter-mapping> |
| <filter-name>cayenne-project</filter-name> |
| <url-pattern>/*</url-pattern> |
| </filter-mapping> |
| <welcome-file-list> |
| <welcome-file>index.jsp</welcome-file> |
| </welcome-file-list> |
| </web-app></pre></li><li class="listitem"><p>Create the artist browser page src/main/webapp/index.jsp file with the |
| following contents: </p><p><span class="bold"><strong>webapp/index.jsp</strong></span> |
| </p><pre class="programlisting"><%@ page language="java" contentType="text/html" %> |
| <%@ page import="org.example.cayenne.persistent.*" %> |
| <%@ page import="org.apache.cayenne.*" %> |
| <%@ page import="org.apache.cayenne.query.*" %> |
| <%@ page import="org.apache.cayenne.exp.*" %> |
| <%@ page import="java.util.*" %> |
| |
| <% |
| SelectQuery query = new SelectQuery(Artist.class); |
| query.addOrdering(Artist.NAME_PROPERTY, SortOrder.ASCENDING); |
| |
| ObjectContext context = BaseContext.getThreadObjectContext(); |
| List<Artist> artists = context.performQuery(query); |
| %> |
| <html> |
| <head> |
| <title>Main</title> |
| </head> |
| <body> |
| <h2>Artists:</h2> |
| |
| <% if(artists.isEmpty()) {%> |
| <p>No artists found</p> |
| <% } else { |
| for(Artist a : artists) { |
| %> |
| <p><a href="detail.jsp?id=<%=Cayenne.intPKForObject(a)%>"> <%=a.getName()%> </a></p> |
| <% |
| } |
| } %> |
| <hr> |
| <p><a href="detail.jsp">Create new artist...</a></p> |
| </body> |
| </html> </pre></li><li class="listitem"><p>Create the artist editor page src/main/webapp/detail.jsp with the following |
| content: </p><p><span class="bold"><strong>webapp/detail.jsp</strong></span> |
| </p><pre class="programlisting"><%@ page language="java" contentType="text/html" %> |
| <%@ page import="org.example.cayenne.persistent.*" %> |
| <%@ page import="org.apache.cayenne.*" %> |
| <%@ page import="java.util.*" %> |
| <%@ page import="java.text.*" %> |
| |
| <% |
| ObjectContext context = BaseContext.getThreadObjectContext(); |
| String id = request.getParameter("id"); |
| |
| // find artist for id |
| Artist artist = null; |
| if(id != null && id.trim().length() > 0) { |
| artist = Cayenne.objectForPK(context, Artist.class, Integer.parseInt(id)); |
| } |
| |
| if("POST".equals(request.getMethod())) { |
| // if no id is saved in the hidden field, we are dealing with |
| // create new artist request |
| if(artist == null) { |
| artist = context.newObject(Artist.class); |
| } |
| |
| // note that in a real application we would so dome validation ... |
| // here we just hope the input is correct |
| artist.setName(request.getParameter("name")); |
| artist.setDateOfBirthString(request.getParameter("dateOfBirth")); |
| |
| context.commitChanges(); |
| |
| response.sendRedirect("index.jsp"); |
| } |
| |
| if(artist == null) { |
| // create transient artist for the form response rendering |
| artist = new Artist(); |
| } |
| |
| String name = artist.getName() == null ? "" : artist.getName(); |
| String dob = artist.getDateOfBirth() == null |
| ? "" : new SimpleDateFormat("yyyyMMdd").format(artist.getDateOfBirth()); |
| %> |
| <html> |
| <head> |
| <title>Artist Details</title> |
| </head> |
| <body> |
| <h2>Artists Details</h2> |
| <form name="EditArtist" action="detail.jsp" method="POST"> |
| <input type="hidden" name="id" value="<%= id != null ? id : "" %>" /> |
| <table border="0"> |
| <tr> |
| <td>Name:</td> |
| <td><input type="text" name="name" value="<%= name %>"/></td> |
| </tr> |
| <tr> |
| <td>Date of Birth (yyyyMMdd):</td> |
| <td><input type="text" name="dateOfBirth" value="<%= dob %>"/></td> |
| </tr> |
| <tr> |
| <td></td> |
| <td align="right"><input type="submit" value="Save" /></td> |
| </tr> |
| </table> |
| </form> |
| </body> |
| </html></pre></li></ul></div></div><div class="section" title="Running Web Application"><div class="titlepage"><div><div><h2 class="title"><a name="running-webapp"></a>Running Web Application</h2></div></div></div><p>To run the web application we'll use "maven-jetty-plugin". To activate it, let's add |
| the following piece of code to the "pom.xml" file, following the "dependencies" section |
| and save the POM:</p><pre class="programlisting"><build> |
| <plugins> |
| <plugin> |
| <groupId>org.mortbay.jetty</groupId> |
| <artifactId>maven-jetty-plugin</artifactId> |
| <version>6.1.22</version> |
| </plugin> |
| </plugins> |
| </build></pre><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p>Go to "Run > Run Configurations..." menu, select "Maven Build", right click |
| and select "New"</p></li><li class="listitem"><p>Make sure you fill "Name", "Base directory" and "Goals" fields as shown on the |
| screenshot:</p><p><span class="inlinemediaobject"><img src="images/eclipse-mvnrun.png"></span></p></li></ul></div><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p>Click "Apply" and "Run". On the first execution it may take a few minutes for |
| Jetty plugin to download all dependencies, but eventually you'll see the logs |
| like this:</p><pre class="programlisting">[INFO] Scanning for projects... |
| [INFO] |
| [INFO] ------------------------------------------------------------------------ |
| [INFO] Building tutorial 0.0.1-SNAPSHOT |
| [INFO] ------------------------------------------------------------------------ |
| ... |
| [INFO] Configuring Jetty for project: tutorial |
| [INFO] Webapp source directory = /.../tutorial/src/main/webapp |
| [INFO] Reload Mechanic: automatic |
| [INFO] Classes = /.../tutorial/target/classes |
| [INFO] Context path = /tutorial |
| [INFO] Tmp directory = determined at runtime |
| [INFO] Web defaults = org/mortbay/jetty/webapp/webdefault.xml |
| [INFO] Web overrides = none |
| [INFO] web.xml file = /.../tutorial/src/main/webapp/WEB-INF/web.xml |
| [INFO] Webapp directory = /.../tutorial/src/main/webapp |
| [INFO] Starting jetty 6.1.22 ... |
| INFO::jetty-6.1.22 |
| INFO::No Transaction manager found - if your webapp requires one, please configure one. |
| INFO::Started SelectChannelConnector@0.0.0.0:8080 |
| [INFO] Started Jetty Server</pre></li></ul></div><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p>So the Jetty container just started.</p></li><li class="listitem"><p>Now go to <span class="italic">http://localhost:8080/tutorial/</span> |
| URL. You should see "No artists found message" in the web browser and |
| the following output in the Eclipse console:</p><pre class="programlisting">INFO: Loading XML configuration resource from file:/.../tutorial/target/classes/cayenne-project.xml |
| INFO: loading user name and password. |
| INFO: Created connection pool: jdbc:derby:memory:testdb;create=true |
| Driver class: org.apache.derby.jdbc.EmbeddedDriver |
| Min. connections in the pool: 1 |
| Max. connections in the pool: 1 |
| INFO: Opening connection: jdbc:derby:memory:testdb;create=true |
| Login: null |
| Password: ******* |
| INFO: +++ Connecting: SUCCESS. |
| INFO: Detected and installed adapter: org.apache.cayenne.dba.derby.DerbyAdapter |
| INFO: --- transaction started. |
| INFO: No schema detected, will create mapped tables |
| INFO: CREATE TABLE GALLERY (ID INTEGER NOT NULL, NAME VARCHAR (200), PRIMARY KEY (ID)) |
| INFO: CREATE TABLE ARTIST (DATE_OF_BIRTH DATE, ID INTEGER NOT NULL, NAME VARCHAR (200), PRIMARY KEY (ID)) |
| INFO: CREATE TABLE PAINTING (ARTIST_ID INTEGER, GALLERY_ID INTEGER, ID INTEGER NOT NULL, |
| NAME VARCHAR (200), PRIMARY KEY (ID)) |
| INFO: ALTER TABLE PAINTING ADD FOREIGN KEY (ARTIST_ID) REFERENCES ARTIST (ID) |
| INFO: ALTER TABLE PAINTING ADD FOREIGN KEY (GALLERY_ID) REFERENCES GALLERY (ID) |
| INFO: CREATE TABLE AUTO_PK_SUPPORT ( |
| TABLE_NAME CHAR(100) NOT NULL, NEXT_ID BIGINT NOT NULL, PRIMARY KEY(TABLE_NAME)) |
| INFO: DELETE FROM AUTO_PK_SUPPORT WHERE TABLE_NAME IN ('ARTIST', 'GALLERY', 'PAINTING') |
| INFO: INSERT INTO AUTO_PK_SUPPORT (TABLE_NAME, NEXT_ID) VALUES ('ARTIST', 200) |
| INFO: INSERT INTO AUTO_PK_SUPPORT (TABLE_NAME, NEXT_ID) VALUES ('GALLERY', 200) |
| INFO: INSERT INTO AUTO_PK_SUPPORT (TABLE_NAME, NEXT_ID) VALUES ('PAINTING', 200) |
| INFO: SELECT t0.DATE_OF_BIRTH, t0.NAME, t0.ID FROM ARTIST t0 ORDER BY t0.NAME - prepared in 43 ms. |
| INFO: === returned 0 rows. - took 56 ms. |
| INFO: +++ transaction committed.</pre></li></ul></div><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p>You can click on "Create new artist" link to create artists. Existing artists |
| can be edited by clicking on their name:</p><p><span class="inlinemediaobject"><img src="images/firefox-webapp.png"></span></p></li></ul></div><p>You are done with the tutorial!</p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="getting-started-part4.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="getting-started-part4.html">Up</a></td><td width="40%" align="right"> </td></tr><tr><td width="40%" align="left" valign="top">Part IV. Converting to Web Application </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> </td></tr></table></div></body></html> |