<?xml version="1.0" encoding="UTF-8"?>
<!--
  ~ ModeShape (http://www.modeshape.org)
  ~
  ~ See the COPYRIGHT.txt file distributed with this work for information
  ~ regarding copyright ownership.  Some portions may be licensed
  ~ to Red Hat, Inc. under one or more contributor license agreements.
  ~ See the AUTHORS.txt file in the distribution for a full listing of 
  ~ individual contributors.
  ~
  ~ ModeShape is free software. Unless otherwise indicated, all code in ModeShape
  ~ is licensed to you under the terms of the GNU Lesser General Public License as
  ~ published by the Free Software Foundation; either version 2.1 of
  ~ the License, or (at your option) any later version.
  ~
  ~ ModeShape is distributed in the hope that it will be useful,
  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  ~ or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
  ~ for more details.
  ~
  ~ You should have received a copy of the GNU Lesser General Public License
  ~ along with this distribution; if not, write to:
  ~ Free Software Foundation, Inc.
  ~ 51 Franklin Street, Fifth Floor
  ~ Boston, MA  02110-1301  USA
  -->
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % CustomDTD SYSTEM "../custom.dtd">
%CustomDTD;
]>
<chapter id="repository_example">
	<title>The Repository Example</title>
	<para>
		<link linkend="downloading_and_building">Chapter 4</link> walked through the process of downloading and building the examples,
		while the <link linkend="sequencer_example">previous chapter</link> showed how to run the sequencer example and walked
		through the code.  In this chapter, we'll run the repository example and walk through that example code to see what
		it's doing.
	</para>
	<sect1 id="running_repository_example">
		<title>Running the repository example</title>
		<para>The repository example consists of a client application that sets up three ModeShape repositories (named "Cars", "Airplanes", and "UFOs") and 
			a federated repository ("Vehicles") that dynamically federates the information from the other three repositories.
			The client application allows you to interactively navigate each of these repositories just as you would navigate the
			directory structure on a file system.</para>
		<para>This collection of repositories is shown in the following figure:
	  	<figure id="example-repositories">
				<title>Repositories used in the example client</title>
				<graphic align="center" scale="60" fileref="example-repositories.png"/>
			</figure>
			The "Cars" repository is an in-memory repository (using the In-Memory repository connector), the "Aircraft" repository is a JPA repository
			(using an in-memory HSQL database using the JPA repository connector), and the "UFOs" repository is
			a file system repository (using the File System repository connector). The federated "Vehicles" repository
			content is federated from the other repositories and cached into the "Cache" repository.  This is shown in the following figure: 
	  	<figure id="example-federated-repository">
				<title>Vehicles repository content is federated from the Cars, Airplanes, UFOs, and Configuration repositories</title>
				<graphic align="center" scale="60" fileref="example-federated-repository.png"/>
			</figure>
	  </para>
		<para>
      To run the client application, go to the <code>examples/repository/target/modeshape-example-repositories-basic.dir/</code>
      directory and type <code>./run.sh</code>. You should see the command-line client and its menus in your terminal:
      <figure id="example-repositories-client">
				<title>Example Client</title>
				<graphic align="center" scale="60" fileref="example-repositories-client.png"/>
			</figure>
      From this menu, you can see the list of repositories, select one, and navigate through that repository in a manner similar
      to a *nix command-line shell (although the client itself uses the JCR API to interact with the repositories).
      Here are some of the commands you can use:</para>
			<table frame='all'>
				<title>Repository client commands to navigate a repository</title>
				<tgroup cols='2' align='left' colsep='1' rowsep='1'>
		      <colspec colname='c1' colwidth="1*"/>
		      <colspec colname='c2' colwidth="1*"/>
					<thead>
						<row><entry>Command</entry><entry>Description</entry></row>
					</thead>
					<tbody>
						<row><entry>pwd</entry><entry>Print the path of the current node (e.g., the "working directory")</entry></row>
						<row><entry>ls [<emphasis>path</emphasis>]</entry><entry>List the children and properties of the node at the supplied path,
						     where "<emphasis>path</emphasis>" can be any relative path or absolute path.  If "<emphasis>path</emphasis>" is not supplied,
						     the current working node's path is used.</entry></row>
						<row><entry>cd <emphasis>path</emphasis></entry><entry>Change to the specified node, where "<emphasis>path</emphasis>"
						     can be any relative path or absolute path.  For example, "<code>cd alpha</code>" changes the current node to be a child named
						     "<code>alpha</code>"; "<code>cd ..</code>" changes the current node to the parent node; "<code>cd /a/b</code>" changes 
						     the current node to be the "<code>/a/b</code>" node.</entry></row>
						<row><entry>exit</entry><entry>Exit this repository and return the list of repositories.</entry></row>
					</tbody>
				</tgroup>
			</table>
			<note>
				<para>
					The first time you access any repository, the application is automatically logging you in to ModeShape's JAAS-based security
					system.  To make the application easier to use, it always logs in with the "jsmith" as the username and "secret" as the
					password.  This matches what is configured in the "jaas.conf.xml" and "users.properties" files.  If you want to confirm
					that the security feature is working, change the password in <code>target/modeshape-example-repositories-basic.dir/users.properties</code> to
					something else and re-run the application.  After you select a repository and try to view a directory with 'ls', you
					will get a LoginException!
				</para>
			</note>
			<para>If you were to select the "Cars" repository and use some of the commands, you should see something similar to: 
	      <figure id="example-repositories-navigating">
					<title>Navigating the Cars repository</title>
					<graphic align="center" scale="60" fileref="example-repositories-navigating.png"/>
				</figure>
			</para>
			<para>You can also choose to navigate the "Vehicles" repository, which projects the "Cars" repository content under the
				<code>/Vehicles/Cars</code> node, the "Airplanes" content under the <code>/Vehicles/Airplanes</code> branch,
				the "UFOs" content under the <code>/Vehicles/UFOs</code> branch,
				and the "Configuration" content under <code>/modeshape:system</code>.
			</para>
			<para>Try using the client to walk the different repositories.  And while this is a contrived application, it does demonstrate
				the use of ModeShape to federate repositories and provide access through JCR.</para>
  </sect1>
	<sect1 id="connectors">
		<title>ModeShape connectors</title>
		<para>As mentioned in the <link linkend="introduction">Introduction</link>, one of the capabilities of ModeShape is to provide access through 
			<ulink url="http://www.jcp.org/en/jsr/detail?id=170">JCR</ulink> to different kinds of repositories and storage systems.
			Your applications work with the JCR API, but through ModeShape you're able to accesses the content from where the information
			exists - not just a single purpose-built repository.  This is fundamentally what makes ModeShape different.</para>
		<para>How does ModeShape do this?  At the heart of ModeShape and it's JCR implementation is a simple connector
			system that is designed around creating and accessing graphs.  The ModeShape JCR implementation actually just sits on
			top of a single repository source, which it uses to access of the repositories content.
			<figure id="modeshapejcr-and-connector">
				<title>ModeShape's JCR implementation delegates to a repository connector</title>
				<graphic align="center" scale="100" fileref="modeshapejcr-and-connector.png"/>
			</figure>
			That single repository connector could access:
		</para>
 		<itemizedlist>
			<listitem>
				<para>a transient, in-memory repository</para>
			</listitem>
			<listitem>
				<para>an Infinispan data grid that acts as an extremely scalable, highly-available store for repository content</para>
			</listitem>
			<listitem>
				<para>a JBoss Cache instance that acts as a clustered and replicated store for repository content</para>
			</listitem>
			<listitem>
				<para>a JDBC database used as a store for repository content</para>
			</listitem>
			<listitem>
				<para>a repository that accesses existing JDBC databases to project the schema structure as read-only repository content</para>
			</listitem>
			<listitem>
				<para>a repository that accesses a file systems to present the files and directory structure as (updatable) repository content</para>
			</listitem>
			<listitem>
				<para>a repository that accesses an SVN repository to present the files and directory structure as (updatable) repository content</para>
			</listitem>
			<listitem>
				<para>a federated repository that presents a unified, updatable view of the content in multiple other systems (which are accessed via connectors)</para>
			</listitem>
		</itemizedlist>
		<para>
			<figure id="modeshape-connectors">
				<title>ModeShape can put JCR on top of multiple kinds of systems</title>
				<graphic align="center" scale="100" fileref="modeshape-connectors.png"/>
			</figure>
	  	And the ModeShape project has plans to create other connectors, too.  For instance, we're going to build a connector 
	    to other JCR repositories.  And another to access existing databases so that some or all of the existing data (in whatever structure)
	    can be accessed through JCR.  Of course, if we don't have a connector to suit your needs, you can write your own.
			<figure id="modeshape-connectors-future">
				<title>Future ModeShape connectors</title>
				<graphic align="center" scale="100" fileref="modeshape-connectors-future.png"/>
			</figure>
		</para>
		<note>
			<para>You might be thinking that these connectors are interesting, but what do they really provide?  Is it really useful
			  to use JCR to access a relational database rather than JDBC?  Or, why access the files on a file system when there 
			  are already mechanisms to do that?</para>
		  <para>Maybe putting JCR on top of a single system (like a JDBC database) isn't that interesting. What
			  <emphasis>is</emphasis> interesting, though, is accessing the information in multiple systems <emphasis>as if all that information were
			  in a single JCR repository</emphasis>.  That's what the federated repository source is all about.  The ModeShape connector
				system just makes it possible to interact with all these systems in the same way.</para>
			<para>Think of it this way: with ModeShape, you can use JCR to get to the schemas of multiple relational databases <emphasis>and</emphasis> the schemas
			  defined by DDL files in your SVN repository <emphasis>and</emphasis> the schemas defined by logical models stored on your file system.
			</para>
		</note>
    <para>Before we go further, let's define some terminology regarding connectors.</para>
 		<itemizedlist>
			<listitem>
				<para>
					A <emphasis role="strong">connector</emphasis> is the runnable code packaged in one or more JAR files that
					contains implementations of several interfaces (described below).  A Java developer <emphasis>writes</emphasis>
					a connector to a type of source, such as a particular database management system, LDAP directory, source code
					management system, etc.  It is then packaged into one or more JAR files (including dependent JARs) and deployed
					for use in applications that use ModeShape repositories.
				</para>
			</listitem>
			<listitem>
				<para>
					The description of a particular source system (e.g., the "Customer" database, or the company LDAP system) 
					is called a <emphasis role="strong">repository source</emphasis>.  ModeShape defines a &RepositorySource; interface
					that defines methods describing the behavior and supported features and a method for establishing connections.
					A connector will have a class that implements this interface and that has JavaBean properties for
					all of the connector-specific properties required to fully describe an instance of the system.  Use of JavaBean
					properties is not required, but it is highly recommended, as it enables reflective configuration and administration.
					Applications that use ModeShape create an instance of the connector's &RepositorySource; implementation and set 
					the properties for the external source that the application wants to access with that connector.
				</para>
			</listitem>
			<listitem>
				<para>
					A repository source instance is then used to establish <emphasis role="strong">connections</emphasis> to
					that source.  A connector provides an implementation of the &RepositoryConnection; interface, which
					defines methods for interacting with the external system.  In particular, the <code>execute(...)</code> method
					takes an &ExecutionContext; instance and a &Request; object.  The &ExectuionContext; object defines the
					environment in which the processing is occurring, including information about the JAAS &Subject; and &LoginContext;.
					The &Request; object describes the requested operations on the content, with different concrete subclasses
					representing each type of activity.  Examples of commands include (but not limited to) getting a node, moving a node, creating a node, 
					changing a node, and deleting a node.  And, if the repository source is able to participate in JTA/JTS distributed transactions, then the
					&RepositoryConnection; must implement the <code>getXaResource()</code> method by returning 
					a valid <code>javax.transaction.xa.XAResource</code> object that can be used by the transaction monitor.
				</para>
			</listitem>
		</itemizedlist>
		<para>As an example, consider that we want ModeShape to give us access through JCR to the schema information contained in a
			relational database.  We first have to develop a connector that allows us to interact with relational databases using JDBC.
			That connector would contain a &JdbcMetadataSource; Java class that implements &RepositorySource;,
			and that has all of the various JavaBean properties for setting the name of the driver class, URL, username, password,
			and other properties.  If we add a JavaBean property defining the JNDI name, our connector could look in JNDI to find a JDBC
			<code>DataSource</code> instance, perhaps already configured to use connection pools.
		</para>
		<note>
			<para>
				Of course, before you develop a connector, you should probably check the
				<ulink url="http://docs.jboss.org/modeshape/latest/manuals/reference/html/provied-connectors-part.html">list of connectors</ulink> ModeShape already provides out of the box.
				With this latest release, ModeShape already includes this JDBC metadata connector!  And we're always interested in new
				connectors and new contributors, so please consider developing your custom connector as part of ModeShape.
			</para>
		</note>
		<para>So with this very high-level summary, let's dive a little deeper and look at the repository example.</para>
	</sect1>
	<sect1 id="example_repository_application_review">
		<title>Reviewing the example repository application</title>
		<para>Recall that the example repository application consists of a client application that sets up a repository service and the
			repositories defined in a configuration repository, allowing the user to pick a repository and interactively navigate
			the selected repository.  Several repositories are set up, including several standalone repositories and one federated repository
			that dynamically federates the content from the other repositories.</para>
		<para>
      The example is comprised of 2 classes and 1 interface, located in the <code>src/main/java</code> directory:</para>
    <programlisting><![CDATA[
  org/modeshape/example/repositories/ConsoleInput.java
                                    /RepositoryClient.java
                                    /UserInterface.java
  ]]></programlisting>
		<para><code>RepositoryClient</code> is the class that contains the main application. It uses an instance of the
      <code>UserInterface</code> interface to  methods that will be called at runtime to obtain information about the
      files that are imported into the standalone repositories and the JAAS <code>CallbackHandler</code> implementation
      that will be used by JAAS to collect the authentication information.  Finally, the <code>ConsoleInput</code>
			is an implementation of this that creates a text user interface,	allowing the user to operate the client from the command-line.  
			We can easily create a graphical implementation of <code>UserInterface</code> at a later date, or we can also create a mock 
			implementation for testing purposes that simulates a user entering data. This allows us to check the behavior of the client 
			automatically using conventional JUnit test cases, as demonstrated by the code in the <code>src/test/java</code> directory:</para>
    <programlisting><![CDATA[
  org/modeshape/example/sequencers/RepositoryClientTest.java
                                  /RepositoryClientUsingJcrTest.java
  ]]></programlisting>
	<para>If we look at the <code>RepositoryClient</code> code, there are a handful of methods that encapsulate the various activities.</para>
	<note>
		<para>Some of the code samples included in this book have had some of the error handling and comments removed so that
			the code is more readable and concise.</para>
	</note>
	<para>The <code>main(String[] argv)</code> method is of course the method that is executed when the application is run.  This code
	  creates the ModeShape configuration by loading it from a file.
	</para>
	<programlisting language="JAVA" role="JAVA"><![CDATA[
// Set up the JAAS provider (IDTrust) and a policy file (which defines the "modeshape-jcr" login config name)
IDTrustConfiguration idtrustConfig = new IDTrustConfiguration();
try {
    idtrustConfig.config("security/jaas.conf.xml");
} catch (Exception ex) {
    throw new IllegalStateException(ex);
}

// Now configure the repository client component ...
RepositoryClient client = new RepositoryClient();
for (String arg : args) {
    arg = arg.trim();
    if (arg.equals("--api=jcr")) client.setApi(Api.JCR);
    if (arg.equals("--api=modeshape")) client.setApi(Api.ModeShape);
    if (arg.equals("--jaas")) client.setJaasContextName(JAAS_LOGIN_CONTEXT_NAME);
    if (arg.startsWith("--jaas=") && arg.length() > 7) client.setJaasContextName(arg.substring(7).trim());
}
// And have it use a ConsoleInput user interface ...
client.setUserInterface(new ConsoleInput(client, args));
 ]]></programlisting>
	<para>
		The first block sets up the JAAS provider to be the IDTrust library and a policy file that defines the "modeshape-jcr" JAAS configuration.
	</para>
	<para>
		The second block of code instantiates the <code>RepositoryClient</code> and passes in some options determined from the command-line.
		It then sets the user interface (which then executes its behavior, which we'll see below).
	</para>
	<para>
		The <code>startRepositories()</code> method builds the <code>JcrEngine</code> component from the configuration, starts the engine,
		and obtains the JCR <code>javax.jcr.Repository</code> instance that the client will use.  Note that the client has not yet
		obtained a <code>javax.jcr.Session</code> instance, since this will be done each time the client needs to access content from
		the repository. (This is actually a common practice according to the JCR specification, since Sessions are lightweight.)
   </para>
	<programlisting language="JAVA" role="JAVA"><![CDATA[
public void startRepositories() throws IOException, SAXException {
    if (engine != null) return; // already started

    // Load the configuration from a file, as provided by the user interface ...
    JcrConfiguration configuration = new JcrConfiguration();
    configuration.loadFrom(userInterface.getRepositoryConfiguration());

    // Now create the JCR engine ...
    engine = configuration.build();
    engine.start();

    ...

    // For this example, we're using a couple of in-memory repositories (including one for the 
    // configuration repository). Normally, these would exist already and would simply be accessed. 
    // But in this example, we're going to populate these repositories here by importing from files. 
    // First do the configuration repository ...
    String location = this.userInterface.getLocationOfRepositoryFiles();

    // Now import the content for the two in-memory repositories ...
    Graph cars = engine.getGraph("Cars");
    cars.importXmlFrom(location + "/cars.xml").into("/");
    Graph aircraft = engine.getGraph("Aircraft");
    aircraft.importXmlFrom(location + "/aircraft.xml").into("/");
}
 ]]></programlisting>
		<para>
			This method does a number of different things.  First, it checks to make sure the repositories are not already running; if so
			the method just returns.  Then, it creates a ModeShape <code>JcrConfiguration</code> instance and loads the configuration
			from a file provided by the user interface.
			It then creates the <code>JcrEngine</code> from the configuration and starts it.  Finally, it obtains the location of the
			content files from the user interface, and imports them into the "Cars" and "Aircraft" repositories.  Again, this is
			done to keep the example simple.
		</para>
		<para>
			The <code>shutdown()</code> method of the example then logs out and requests that the <code>JcrEngine</code> instance 
			shut down and, since that may take
		  a few moments (if there are any ongoing operations or enqueued activities) awaits for it to complete the shutdown.
	   </para>
		<programlisting language="JAVA" role="JAVA"><![CDATA[
public void shutdown() throws InterruptedException, LoginException {
    logout();
    if (engine == null) return;
    try {
        // Tell the engine to shut down, and then wait up to 5 seconds for it to complete...
        engine.shutdown();
        engine.awaitTermination(5, TimeUnit.SECONDS);
    } finally {
        engine = null;
    }
}
 ]]></programlisting>
		<para>
			A few of the other methods in the <code>RepositoryClient</code> class deal with the JAAS <code>LoginContext</code>.
			When needed, the client will authenticate the user (by asking the user interface for a callback handler that will be called
			when the authentication information is needed).  The resulting authenticated <code>LoginContext</code> is wrapped
			by a custom <code>javax.jcr.Credentials</code> implementation.  As long as the <code>Credentials</code> implementation
			has a <code>getLoginContext()</code> method that returns a <code>LoginContext</code> object, ModeShape's repository
			implementation will use that context to create the <code>javax.jcr.Session</code>.  (Of course, the <code>javax.jcr.SimpleCredentials</code>
			can also be used to create a Session, and ModeShape will then attempt to use JAAS to authenticate the user given by the credentials.)
		</para>
		<para>
			The <code>getNodeInfo(...)</code> method of the example is what is called when the properties and children of a particular node
			are requested by the user interface.  (In the console user interface, this happens when the user navigates the graph structure.)
			There are really two different behaviors to this method, depending upon whether the JCR API is to be used or whether
			the ModeShape Graph API is to be used.  The portion that uses JCR is shown below:
	   </para>
		<programlisting language="JAVA" role="JAVA"><![CDATA[
JcrRepository jcrRepository = engine.getRepository(sourceName);
Session session = null;
if (loginContext != null) {
    // Could also use SimpleCredentials(username,password) too
    Credentials credentials = new JaasCredentials(loginContext);
    session = jcrRepository.login(credentials);
} else {
    session = jcrRepository.login();
}
try {
    // Make the path relative to the root by removing the leading slash(es) ...
    pathToNode = pathToNode.replaceAll("^/+", "");
    // Get the node by path ...
    Node root = session.getRootNode();
    Node node = root;
    if (pathToNode.length() != 0) {
        if (!pathToNode.endsWith("]")) pathToNode = pathToNode + "[1]";
        node = pathToNode.equals("") ? root : root.getNode(pathToNode);
    }

    // Now populate the properties and children ...
    if (properties != null) {
        for (PropertyIterator iter = node.getProperties(); iter.hasNext();) {
            javax.jcr.Property property = iter.nextProperty();
            Object[] values = null;
            // Must call either 'getValue()' or 'getValues()' depending upon # of values
            if (property.getDefinition().isMultiple()) {
                Value[] jcrValues = property.getValues();
                values = new String[jcrValues.length];
                for (int i = 0; i < jcrValues.length; i++) {
                    values[i] = jcrValues[i].getString();
                }
            } else {
                values = new Object[] {property.getValue().getString()};
            }
            properties.put(property.getName(), values);
        }
    }
    if (children != null) {
        // Figure out which children need same-name sibling indexes ...
        Set<String> sameNameSiblings = new HashSet<String>();
        for (NodeIterator iter = node.getNodes(); iter.hasNext();) {
            javax.jcr.Node child = iter.nextNode();
            if (child.getIndex() > 1) sameNameSiblings.add(child.getName());
        }
        for (NodeIterator iter = node.getNodes(); iter.hasNext();) {
            javax.jcr.Node child = iter.nextNode();
            String name = child.getName();
            if (sameNameSiblings.contains(name)) name = name + "[" + child.getIndex() + "]";
            children.add(name);
        }
    }
} catch (javax.jcr.ItemNotFoundException e) {
    return false;
} catch (javax.jcr.PathNotFoundException e) {
    return false;
} finally {
    if (session != null) session.logout();
}
 ]]></programlisting>
		<para>
			This code is literally just using the standard JCR API.  First, it obtains a <code>javax.jcr.Session</code> instance
			(using the available <code>LoginContext</code>), finds the desired <code>javax.jcr.Node</code>, copies the
			properties and names of the children into collections supplied by the caller via method parameters, and
			finally logs out of the session.
		</para>
		<para>
			The ModeShape Graph API is actually an internal API used within the different components of ModeShape
			(including the connector and sequencer frameworks),	and provides low-level access to the exact same content.
			Though we do not recommend using this API in your client applications, if you need to write a connector
			or sequencer, you may need to know how to use the Graph API.  
			Here is the portion of the <code>getNodeInfo(...)</code> method that does the exact same operation as the JCR code
			shown above:
		</para>
		<programlisting language="JAVA" role="JAVA"><![CDATA[
// Use the ModeShape Graph API to read the properties and children of the node ...
ExecutionContext context = loginContext != null ? this.context.create(loginContext) : this.context;
Graph graph = engine.getGraph(context, sourceName);
graph.useWorkspace("default");
org.modeshape.graph.Node node = graph.getNodeAt(pathToNode);

if (properties != null) {
    // Now copy the properties into the map provided as a method parameter ...
    for (Property property : node.getProperties()) {
        String name = property.getName().getString(context.getNamespaceRegistry());
        properties.put(name, property.getValuesAsArray());
    }
}
if (children != null) {
    // And copy the names of the children into the list provided as a method parameter ...
    for (Location child : node.getChildren()) {
        String name = child.getPath().getLastSegment().getString(context.getNamespaceRegistry());
        children.add(name);
    }
}
 ]]></programlisting>
		<para>
			Note that this code is significantly shorter than the equivalent code based upon the JCR API.  
			This is in part because the Graph API doesn't have the notion of a stateful session.  But some of it also is simply
			because the Graph API design requires less code to do the same kinds of operations.
		</para>
		<para>None of the other methods in the <code>RepositoryClient</code> really do anything with ModeShape or JCR 
		  <emphasis>per se</emphasis>. Instead, they really facilitate interaction with the user interface.
		</para>
		<para>If we look at the <code>ConsoleInput</code> constructor, it starts the repository and a thread 
			for the user interface. At this point, the constructor returns, but the main application continues under the user interface thread.  
			When the user requests to quit, the user interface thread also shuts down the JCR repository.</para>
    <programlisting language="JAVA" role="JAVA"><![CDATA[
public ConsoleInput( SequencerClient client ) {
  try {
      client.startRepositories();

      System.out.println(getMenu());
      Thread eventThread = new Thread(new Runnable() {
          private boolean quit = false;
          public void run() {
              try {
                  while (!quit) {
                      // Display the prompt and process the requested operation ...
                  }
              } finally {
                  try {
                      // Terminate ...
                      client.shutdown();
                  } catch (Exception err) {
                      System.out.println("Error shutting down repository: " 
                                         + err.getLocalizedMessage());
                      err.printStackTrace(System.err);
                  }
              }
          }
      });
      eventThread.start();
  } catch (Exception err) {
      System.out.println("Error: " + err.getLocalizedMessage());
      err.printStackTrace(System.err);
  }
}
  ]]></programlisting>
		<para>At this point, we've reviewed all of the interesting code in the example application related to ModeShape.  However, feel free
    to play with the application, trying different things.
    </para>
	</sect1>
	<sect1 id="repository_example_whats_next">
		<title>What's next</title>
		<para>
			This chapter walked through running the repository example and looked at the example code.  This example allowed you to walk 
			through multiple repositories, including one whose content was federated from multiple other repositories.
			This was a very simplistic example that only took a few minutes to run.
		</para>
		<para>
			In the <link linkend="conclusion">next chapter</link> we'll wrap up by summarizing what we've learned about ModeShape
			and provide information about where you can find out more about ModeShape.
		</para>
	</sect1>
</chapter>
