Author: rhauch
Date: 2008-09-25 13:58:08 -0400 (Thu, 25 Sep 2008)
New Revision: 541
Modified:
trunk/docs/reference/src/main/docbook/en-US/content/mimetypes.xml
trunk/docs/reference/src/main/docbook/en-US/content/testing.xml
trunk/docs/reference/src/main/docbook/en-US/custom.dtd
Log:
DNA-71 Document development tools and environment
https://jira.jboss.org/jira/browse/DNA-71
Added more content to the Reference Guide.
Modified: trunk/docs/reference/src/main/docbook/en-US/content/mimetypes.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/mimetypes.xml 2008-09-24 21:49:27
UTC (rev 540)
+++ trunk/docs/reference/src/main/docbook/en-US/content/mimetypes.xml 2008-09-25 17:58:08
UTC (rev 541)
@@ -28,17 +28,175 @@
]>
<chapter id="mimetypes">
<title>MIME types</title>
- <para></para>
+ <para>
+ JBoss DNA often needs the ability to determine the MIME type for some binary content.
When uploading content into
+ a repository, we may want to add the MIME type as metadata. Or, we may want to make
some processing decisions
+ based upon the MIME type. So, JBoss DNA created a small pluggable framework for
determining the MIME type by using
+ the name of the file (e.g., extensions) and/or by reading the actual content.
Technically, the framework
+ delegates this to one or more extensions. And we've provided one extension that
does a very good job at
+ determining the MIME type from a large variety of file types. But if that isn't
sufficient, you can always
+ incorporate your own detector into JBoss DNA.
+ </para>
+ <para>
+ To use this system, you simply invoke a static method and supply the name of the
content (e.g., the name of the file, with the extension)
+ and the &InputStream; to the actual binary content:
+ </para>
+ <programlisting>&MimeType;.of(name,content)</programlisting>
+ <para>
+ The result is a &String; containing the <ulink
url="http://www.iana.org/assignments/media-types/">MIME type</ulink>
+ (e.g., "text/plain") or null if the MIME type cannot be determined. Note
that the name or &InputStream; may be
+ null, making this a very versatile utility.
+ </para>
<sect1 id="detectors">
<title>JBoss DNA MIME type detectors</title>
- <para></para>
+ <para>
+ The principle component in this framework is the concept of a <emphasis
role="strong">detector</emphasis>.
+ A detector attempts to determine the MIME type using the name of the content (e.g.,
the file name)
+ and the actual content itself. If the detector is able to determine the MIME type, it
simply returns
+ it as a string. If not, it merely returns null. Note, however, that a detector must
be thread-safe.
+ </para>
+ <para>
+ Here is the interface:
+ </para>
+ <programlisting>
+package org.jboss.dna.graph.mimetype;
+@ThreadSafe
+public interface &MimeTypeDetector; {
+
+ /**
+ * Returns the MIME-type of a data source, using its supplied content and/or
+ * its supplied name, depending upon the implementation. If the MIME-type
+ * cannot be determined, either a "default" MIME-type or
<code>null</code> may
+ * be returned, where the former will prevent earlier registered MIME-type
+ * detectors from being consulted.
+ *
+ * @param name The name of the data source; may be <code>null</code>.
+ * @param content The content of the data source; may be
<code>null</code>.
+ * @return The MIME-type of the data source, or optionally
<code>null</code>
+ * if the MIME-type could not be determined.
+ * @throws &IOException; If an error occurs reading the supplied content.
+ */
+ &String; mimeTypeOf( &String; name,
+ &InputStream; content ) throws &IOException;;
+}</programlisting>
+ <para>
+ Detectors can be added to the &MimeType; class using the
<code>addDetector(&MimeTypeDetectorConfig; config)</code>
+ method, where the &MimeTypeDetectorConfig; defines the name of the detector class,
the name of the
+ <link linkend="classloaders">class loader</link>, a name, and a
description. It is also possible
+ to set the &ClassLoaderFactory; that the &MimeType; singleton will use.
+ </para>
+ <para>
+ We'll next look at the MIME type detectors that are provided out by JBoss DNA out
of the box, and how to write your own.
+ </para>
<sect2 id="dna-mimetype-detector-aperture">
<title>Aperture MIME type detector</title>
- <para></para>
+ <para>
+ The &ApertureMimeTypeDetector; class is an implementation of
&MimeTypeDetector; that uses the
+ <ulink
url="http://aperture.sourceforge.net/">Aperture</ulink>
open-source library, which
+ is a very capable utility for determining the MIME type for a wide range of file
types,
+ using both the file name and the actual content.
+ </para>
</sect2>
</sect1>
<sect1 id="custom-detectors">
<title>Writing custom detectors</title>
- <para></para>
+ <para>
+ Creating a custom detector involves the following steps:
+ <itemizedlist>
+ <listitem>
+ <para>Create a Maven 2 project for your detector;</para>
+ </listitem>
+ <listitem>
+ <para>Implement the &MimeTypeDetector; interface with your own
implementation, and create unit tests to verify
+ the functionality and expected behavior;</para>
+ </listitem>
+ <listitem>
+ <para>Add a &MimeTypeDetectorConfig; to the &MimeType; class in your
application
+ as described <link linkend="detectors">earlier</link>;
and</para>
+ </listitem>
+ <listitem>
+ <para>Deploy the JAR file with your implementation (as well as any
dependencies), and make them available to JBoss DNA
+ in your application.</para>
+ </listitem>
+ </itemizedlist>
+ It's that simple.
+ </para>
+ <sect2 id="custom_detector_project">
+ <title>Creating the Maven 2 project</title>
+ <para>The first step is to create the Maven 2 project that you can use to
compile your code and build the JARs.
+ Maven 2 automates a lot of the work, and since you're already <link
linkend="maven">set up to use Maven</link>,
+ using Maven for your project will save you a lot of time and effort. Of course, you
don't have to use Maven 2, but then you'll
+ have to get the required libraries and manage the compiling and building process
yourself.</para>
+ <note>
+ <para>JBoss DNA may provide in the future a Maven archetype for creating
detector projects. If you'd find this useful
+ and would like to help create it, please <link
linkend="preface">join the community</link>.</para>
+ </note>
+ <note>
+ <para>
+ The <emphasis
role="strong">dna-mimetype-detector-aperture</emphasis> project is a
small, self-contained detector implementation that
+ that you can use to help you get going. Starting with this project's source
and modifying it to suit your needs
+ may be the easiest way to get started.
+ See the subversion repository:
+ <ulink
url="&Subversion;trunk/extensions/dna-mimetype-detector-aperture/">&Subversion;trunk/sequencers/dna-mimetype-detector-aperture/</ulink>
+ </para>
+ </note>
+ <para>You can create your Maven project any way you'd like. For examples,
see the <ulink
url="http://maven.apache.org/guides/getting-started/index.html#How_d...
2 documentation</ulink>.
+ Once you've done that, just add the dependencies in your project's
<code>pom.xml</code> dependencies section:</para>
+ <programlisting role="XML"><![CDATA[<dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-common</artifactId>
+ <version>0.1</version>
+</dependency>
+<dependency>
+ <groupId>org.jboss.dna</groupId>
+ <artifactId>dna-graph</artifactId>
+ <version>0.1</version>
+</dependency>
+<dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+</dependency>
+]]></programlisting>
+ <para>These are minimum dependencies required for compiling a detector. Of
course, you'll have to add
+ other dependencies that your sequencer needs.</para>
+ <para>As for testing, you probably will want to add more dependencies, such as
those listed here:</para>
+ <programlisting role="XML"><![CDATA[<dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.4</version>
+ <scope>test</scope>
+</dependency>
+<dependency>
+ <groupId>org.hamcrest</groupId>
+ <artifactId>hamcrest-library</artifactId>
+ <version>1.1</version>
+ <scope>test</scope>
+</dependency>
+<!-- Logging with Log4J -->
+<dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.4.3</version>
+ <scope>test</scope>
+</dependency>
+<dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.14</version>
+ <scope>test</scope>
+</dependency>
+]]></programlisting>
+ <para>
+ After you've created the project, simply implement the &MimeTypeDetector;
interface. And testing should be
+ quite straightforward, MIME type detectors don't require any other components.
In your tests,
+ simply instantiate your &MimeTypeDetector; implementation, supply various
combinations of names and/or &InputStream;s,
+ and verify the output is what you expect.
+ </para>
+ <para>
+ To use in your application, create a &MimeTypeDetectorConfig; object with the
name, description, and class information
+ for your detector, and add to the &MimeType; class using the
<code>addDetector(&MimeTypeDetectorConfig; config)</code> method.
+ Then, just use the &MimeType; class.
+ </para>
+ </sect2>
</sect1>
</chapter>
Modified: trunk/docs/reference/src/main/docbook/en-US/content/testing.xml
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/content/testing.xml 2008-09-24 21:49:27
UTC (rev 540)
+++ trunk/docs/reference/src/main/docbook/en-US/content/testing.xml 2008-09-25 17:58:08
UTC (rev 541)
@@ -28,13 +28,103 @@
]>
<chapter id="testing">
<title>Testing</title>
- <para></para>
+ <para>
+ The JBoss DNA project uses automated testing to verify that the software is doing what
it's supposed to
+ and not doing what it shouldn't do. These automated tests are run continuously and
also act as regression tests,
+ ensuring that we known if any problems we find and fix reappear later. All of our
tests are executed as part of
+ our <link linkend="maven">Maven</link> build process, and the
entire build process (including the tests)
+ is automatically run using <link linkend="hudson">Hudson</link>
continuous integration system.
+ </para>
<sect1 id="unit-tests">
<title>Unit tests</title>
- <para></para>
+ <para>
+ <emphasis role="strong">Unit tests</emphasis> verify the
behavior of a single class (or small set of classes) in isolation
+ from other classes.
+ We use the JUnit 4.4 testing framework, which has significant improvements over
earlier versions and makes
+ it very easy to quickly write unit tests with little extra code. We also frequently
use the Mockito library
+ to help create mock implementations of other classes that are not under test but are
used in the tests.
+ </para>
+ <para>
+ Unit tests should generally run quickly and should not require large assemblies of
components. Additionally,
+ they may rely upon the file resources included in the project, but these tests should
require no external resources
+ (like databases or servers). Note that our unit tests are run during the
"test" phase of the standard
+ <ulink
url="http://maven.apache.org/guides/introduction/introduction-to-the...
lifecycle</ulink>.
+ This means that they are executed against the raw .class files created during
complication.
+ </para>
+ <para>
+ Developers are expected to run all of the JBoss DNA unit tests in their local
environment before committing changes to SVN.
+ So, if you're a developer and you've made changes to your local copy of the
source, you can run those tests that are
+ related to your changes using your IDE or with Maven (or any other mechanism). But
before you commit your changes,
+ you are expected to run a full Maven build using <code>mvn clean
install</code> (in the "trunk/" directory).
+ Please do <emphasis>not</emphasis> rely upon continuous integration to run
all of the tests for you - the CI
+ system is there to catch the occasional mistakes and to also run the <link
linkend="integration-tests">integration tests</link>.
+ </para>
</sect1>
<sect1 id="integration-tests">
<title>Integration tests</title>
- <para></para>
+ <para>
+ While <link linkend="unit-tests">unit tests</link> test
individual classes in (relative) isolation, the purpose of
+ <emphasis role="strong">integration tests</emphasis> are to
verify that assemblies of classes and components are
+ behaving correctly. These assemblies are often the same ones that end users will
actually use. In fact,
+ integration tests are executed during the "integration-test" phase of the
standard
+ <ulink
url="http://maven.apache.org/guides/introduction/introduction-to-the...
lifecycle</ulink>,
+ meaning they are executed against the packaged JARs and artifacts of the project.
+ </para>
+ <para>
+ Integration tests also use the JUnit 4.4 framework, so they are again easy to write
and follow the same pattern
+ as unit tests. However, because they're working with larger assemblies of
components, they often will take longer
+ to set up, longer to run, and longer to tear down. They also may require initializing
"external resources", like
+ databases or servers.
+ </para>
+ <para>
+ Note, that while external resources may be required, care should be taken to minimize
these dependencies and to
+ ensure that most (if not all) integration tests may be run by anyone who downloads the
source code. This means
+ that these external resources should be available and set up within the tests. For
example, use in-memory databases
+ where possible. Or, if a database is required, use an open-source database (e.g.,
MySQL or PostgreSQL). And when
+ these external resources are not available, it should be obvious from the test class
names and/or test method names
+ that it involved an external resource (e.g.,
"<code>MySqlConnectorIntegrationTest.shouldFindNodeStoredInDatabase()</code>").
+ </para>
</sect1>
+ <sect1 id="writing-tests">
+ <title>Writing tests</title>
+ <para>
+ As mentioned in <link linkend="methodology">the
introduction</link>, the JBoss DNA project doesn't follow any one methodology
+ or process. Instead, we simply have a goal that as much code as possible is tested to
ensure it behaves as expected.
+ Do we expect 100% of the code is covered by automated tests? No, but we do want to
test as much as we can.
+ Maybe a simple JavaBean class doesn't need many tests, but any class with
non-trivial logic should be tested.
+ </para>
+ <para>
+ We do encourage writing tests either before or while you write the code. Again,
we're not blindly following a methodology.
+ Instead, there's a very practical reason: writing the tests early on helps you
write classes that are testable.
+ If you wait until after the class (or classes) are done, you'll probably find that
it's not easy to test all
+ of the logic (especially the complicated logic).
+ </para>
+ <para>
+ Another suggestion is to write tests so that they specify and verify the behavior that
is expected from a class or component.
+ One challenge developers often have is knowing what they should even test and what the
tests should look like.
+ This is where <emphasis role="strong"><ulink
url="http://behaviour-driven.org/">Behavior-driven development
(BDD)</ulink></emphasis>
+ helps out. If you think about what a class' behaviors are supposed to be (e.g.,
requirements), simply capture those
+ requirements as test methods (with no implementations). For example, a test class for
sequencer
+ implementation might have a test
method <code>shouldNotThrowAnErrorWhenTheSuppliedStreamIsNull() { }</code>.
Then, after you enumerate
+ all the requirements you can think of, go back and start implementing the test
methods.
+ </para>
+ <para>
+ If you look at the existing test cases, you'll find that the names of the unit and
integration tests in JBoss DNA
+ follow a naming style, where the test method names are readable sentences. Actually,
we try to name the test methods
+ <emphasis>and</emphasis> the test classes such that they form a
concisely-worded requirement. For example,
+ </para>
+ <programlisting>InMemorySequencerTest.shouldNotThrowAnErrorWhenTheSuppliedStreamIsNull()</programlisting>
+ <para>
+ is easily translated into a readable requirement:
+ </para>
+ <programlisting>InMemorySequencer should not throw an error when the supplied
stream is null.</programlisting>
+ <para>
+ In fact, at some point in the future, we'd like to process the source to
automatically generate a list of the behavior specifications
+ that are asserted by the tests.
+ </para>
+ <para>
+ But for now, we write tests - a lot of them. And by following a few simple
conventions and practices, we're able
+ to do it quickly and in a way that makes it easy to understand what the code is
supposed to do (or not do).
+ </para>
+ </sect1>
</chapter>
Modified: trunk/docs/reference/src/main/docbook/en-US/custom.dtd
===================================================================
--- trunk/docs/reference/src/main/docbook/en-US/custom.dtd 2008-09-24 21:49:27 UTC (rev
540)
+++ trunk/docs/reference/src/main/docbook/en-US/custom.dtd 2008-09-25 17:58:08 UTC (rev
541)
@@ -26,7 +26,9 @@
<!-- Types in JRE -->
+<!ENTITY String "<ulink
url='&Java;java/lang/String.html'><interface>String</interface></ulink>">
<!ENTITY InputStream "<ulink
url='&Java;java/io/InputStream.html'><interface>InputStream</interface></ulink>">
+<!ENTITY IOException "<ulink
url='&Java;java/io/IOException.html'><classname>IOException</classname></ulink>">
<!ENTITY ClassLoader "<ulink
url='&Java;java/lang/ClassLoader.html'><interface>ClassLoader</interface></ulink>">
<!ENTITY AccessControlContext "<ulink
url='&Java;java/security/AccessController.html'><classname>AccessControlContext</classname></ulink>">
<!ENTITY LoginContext "<ulink
url='&Java;javax/security/auth/login/LoginContext.html'><classname>LoginContext</classname></ulink>">
@@ -61,6 +63,7 @@
<!ENTITY RepositoryConnection "<ulink
url='&API;graph/connectors/RepositoryConnection.html'><interface>RepositoryConnection</interface></ulink>">
<!ENTITY StreamSequencer "<ulink
url='&API;graph/sequencers/StreamSequencer.html'><interface>StreamSequencer</interface></ulink>">
<!ENTITY SequencerOutput "<ulink
url='&API;graph/sequencers/SequencerOutput.html'><interface>SequencerOutput</interface></ulink>">
+<!ENTITY MimeTypeDetector "<ulink
url='&API;graph/mimetype/MimeTypeDetector.html'><interface>MimeTypeDetector</interface></ulink>">
<!-- Types in dna-repository -->
@@ -74,7 +77,10 @@
<!ENTITY SimpleSessionFactory "<ulink
url='&API;repository/util/SimpleSessionFactory.html'><classname>SimpleSessionFactory</classname></ulink>">
<!ENTITY JcrExecutionContext "<ulink
url='&API;repository/util/JcrExecutionContext.html'><interface>JcrExecutionContext</interface></ulink>">
<!ENTITY BasicJcrExecutionContext "<ulink
url='&API;repository/util/BasicJcrExecutionContext.html'><classname>BasicJcrExecutionContext</classname></ulink>">
+<!ENTITY MimeType "<ulink
url='&API;repository/mimetype/MimeType.html'><classname>MimeType</classname></ulink>">
+<!ENTITY MimeTypeDetectorConfig "<ulink
url='&API;repository/mimetype/MimeTypeDetectorConfig.html'><interface>MimeTypeDetectorConfig</interface></ulink>">
+
<!-- Types in dna-jcr -->
<!ENTITY JcrRepository "<ulink
url='&API;jcr/JcrRepository.html'><classname>JcrRepository</classname></ulink>">
@@ -87,4 +93,5 @@
<!ENTITY ImageMetadataSequencer "<ulink
url='&API;sequencer/image/ImageMetadataSequencer.html'><classname>ImageMetadataSequencer</classname></ulink>">
<!ENTITY ImageMetadata "<ulink
url='&API;sequencer/image/ImageMetadata.html'><classname>ImageMetadata</classname></ulink>">
<!ENTITY ImageSequencerI18n "<ulink
url='&API;sequencer/image/ImageSequencerI18n.html'><classname>ImageSequencerI18n</classname></ulink>">
+<!ENTITY ApertureMimeTypeDetector "<ulink
url='&API;mimetype/ApertureMimeTypeDetector.html'><classname>ApertureMimeTypeDetector</classname></ulink>">