Table of Contents
Objective: Create a new document type with its own unique meta-data. Understand the basics of Nuxeo projects' structure, build process, and deployment.
Minor things can become moments of great revelation when encountered for the first time. Margot Fonteyn, English ballerina ( 1919 - 1991 )
If you have any comments, questions, or general-purpose harassment you would like give us about this book, then please use the comment form at the bottom of each page! We promise that we will try to incorporate any feedback you give (minus the profanity, of course), will respond to your questions, and credit you appropriately.
Back in the first lesson, we explained that we would expect you to use Eclipse to compile Nuxeo programs and Maven to deploy them. While that was true, it was true in the sense that "Darth Vader betrayed and murdered Luke's father," that is, from a certain point of view. A more complete answer is that Eclipse and Maven have to be convinced to peacefully co-exist so that you can use them each for the purpose they are best suited-and that their duties substantially overlap. At various times, each will be used to accomplish the task of building a Nuxeo bundle, for example. Maven is quite particular about the layout of project files and Eclipse can handle almost any layout, so we will now discuss how to layout your files in the arrangement preferred by Maven.
You may be tempted to use one of the Eclipse plugins that allows Maven to be run from within Eclipse, such as m2eclipse. The authors have extensive experience with Maven, eclipse, and these plugins and have found them to consistently cause much more trouble than they are worth for a beginning developer on Nuxeo: trust us, you don't want to go there! An example difficulty with using Maven-in-Eclipse plugins is that the build and test classpaths for Nuxeo bundles are quite large and complex and, at best, the use of Maven for building will make your builds so slow that they cannot be done interactively; without the plugins, Eclipse caches enough information to do builds as you type without trouble, even on a computationally weak machine. At worst, Maven plugins can become confused about how to run your test harness and actively change (destroy) your Eclipse setup! Trust us, if you have a Maven plugin for eclipse in your eclipse this is a good time to remove it.
The set of directories that you should use when building a Nuxeo bundle, also referred to as a Nuxeo plugin, is shown in this listing of what happens when you check out the skeleton of lesson4 (explained below):
$ svn co http://svn.nuxeo.org/nuxeo/sandbox/iansmith/book/lesson-bundle
A lesson-bundle/src
A lesson-bundle/src/test
A lesson-bundle/src/test/java
A lesson-bundle/src/test/resources
A lesson-bundle/src/main
A lesson-bundle/src/main/java
A lesson-bundle/src/main/resources
A lesson-bundle/src/main/resources/META-INF
A lesson-bundle/src/main/resources/OSGI-INF
Briefly, we will discuss the purpose of the directories in
lesson-bundle above. The src directory and its children are the primary
focus of interest for developers. The top level division into
main and test subdirectories is to differentiate between
the bundle's implementation, in main,
and the code used to test the bundle in test. Each of these directories has two children,
java and resources, to distinguish between Java code and
all the other support files needed. Within the Java directories,
the usual Java convention applies, a production Java class with the
fully qualified name org.nuxeo.foo.MyClass found in the file src/main/java/org/nuxeo/foo/MyClass.java . Within
the main directory, you can see the
META-INF and OSGI-INF directories that were discussed in the
previous lesson. This layout is quite standardized for Maven
projects and although there are many more options possible for
Maven projects, this arrangement is instantly recognizable to
anyone with experience using Maven.
To make this project a bit easier to get started, we have
prepared a skeleton for you to start from, with all the directories
and files in the correct structure as explained above. We will make
a new subdirectory of /nuxeo called
/nuxeo/workspace to be used as the
Eclipse workspace for all the remaining projects. Retrieve the
project skeleton from Nuxeo's subversion repository and unpack the
skeleton to create the directory lesson-bundle that you will use in Eclipse as
your project.
iansmith@Photo /nuxeo $ mkdir workspace iansmith@Photo /nuxeo $ cd workspace iansmith@Photo /nuxeo/workspace $ mvn -Declipse.workspace=. eclipse:add-maven-repo iansmith@Photo /nuxeo/workspace $ svn export http://svn.nuxeo.org/nuxeo/sandbox/iansmith/book/lesson-bundle/ iansmith@Photo /nuxeo/workspace $ cd lesson-bundle iansmith@Photo /nuxeo/workspace/lesson-bundle $ ls -F pom.xml* src/
There is mvn
command in the listing above that initializes the Eclipse
workspace. The syntax provided is for the most common version of
the Eclipse support in Maven (version 2.4). This command simply
creates a single Eclipse variable M2_REPO. If you find that your version of Maven
does not support this command (it is currently deprecated, but
still available, in version 2.5 of the Eclipse support for Maven)
you may want to try using configure-workspace instead of
add-maven-repo.
This lesson and several upcoming lessons will be about building a new type of document, Upcoming which repesents an upcoming event as we explained in the first chapter to this book. For this lesson, our goal, roughly, is to be able to create this new type of document through the Nuxeo web user interface. An example of an Upcoming document would be a document that describes a concert that will occur at some point in the future. Obviously, there are a number of special types of meta-data associated with upcoming events, such as when they will occur and how much they cost to attend. We will be filling out the definition of this new document type as we proceed through the lessons.
Go ahead and use Maven to create our Eclipse project files (!) with a command like this:
iansmith@Photo /nuxeo/workspace/lesson-bundle
$ mvn eclipse:eclipse
Since you have never used Maven with Nuxeo before, or perhaps have never used it all before, do not be alarmed if Maven begins wildly downloading a great many things from the internet; instead, go get a cup of coffee-this will take a few minutes. It only happens the first time you use Maven with Nuxeo. When this completes, you should see a "build successful" message like this:
[INFO] Wrote settings to C:\nuxeo\workspace.lessons\lesson-bundle\.settings\org.eclipse.jdt.core.prefs [INFO] Wrote Eclipse project for "lesson-bundle" to c:\nuxeo\workspace.lessons\lesson-bundle. [INFO] [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 36 seconds [INFO] Finished at: Wed Jan 21 16:47:44 EST 2009 [INFO] Final Memory: 25M/45M [INFO] ------------------------------------------------------------------------
Note that the build above only took 36 seconds! If you don't see a message like that at the end of your mvn output, you probably have something wrong with either your internet connectivity or your Maven configuration.
To import the project into eclipse, start up eclipse and use
/nuxeo/workspace as the workspace.
Then you can use the File Menu's Import option, hereafter written
as File > Import,
and choose the General option from the dialog box that appears.
Choosing General will open up a few more choices and you should
select Existing Projects into Workspace. From here on, will write a
selection like this with square brackets around it to indicate a
dialog box and we use the plus sign to indicate a sub-choice and so
importing this existing project would be written as
[ General + Existing Projects into
Workspace ] and is shown graphically in this screen
shot:
After you click , you can use
the button next to the
choice to
choose the lesson-bundle directory
created above. Don't choose any of it's subdirectories. After you
click , you should see a
project layout like this in your Eclipse Package Explorer:
Some things may vary in your particular Eclipse. First, you may
have a slightly different JRE version than shown above. More
important, you must insure that the only two directories that
Eclipse should look in for source code are src/main/java and src/test/java. You can correct any errors, such
as those shown above, by using Project > Properties with
lesson-bundle selected as above, and then choosing Java Build Path
and the tab for Source. We write the last command of these as
Java Build Path ->>
Source. To remove a source directory, you should
click on it's name in the dialog and then click the button as is shown below:

We'll start by writing a manifest file for our bundle. Create
this file by selecting the directory src/main/resources/META-INF in the Package
Explorer and then use File > New
> File to create the new file. It must be named
MANIFEST.MF so it can be found by the
container. The contents of this file should be:
Manifest-Version: 1.0 Bundle-ManifestVersion: 1 Bundle-Name: lesson on first bundle, project Bundle-SymbolicName: org.nuxeo.book.upcoming;singleton:=true Bundle-Version: 0.0.1 Bundle-Vendor: your name Nuxeo-Require: org.nuxeo.ecm.core, org.nuxeo.ecm.core.schema Nuxeo-Component: OSGI-INF/schema-contrib.xml, OSGI-INF/doctype-contrib.xml, OSGI-INF/ui-contrib.xml
If you do not remember what some of these lines mean you can
check back with the previous lesson. The required bundles for this
project are the core ECM capabilities of Nuxeo and the schema
support from the core. [Definition: In Nuxeo,
a document schema is a set of properties
that are associated with a document.] A document can be, and
usually is, a composite of many schemas. We often say "associated"
or "attached" when referring to schemas and their relationship to
documents. Most documents have the dublincore schema attached to them. dublincore provides a number of basic properties that
most documents need, such as title,
creator, and dateCopyrighted. (If you would like to read more
about the dublin core meta-data initiative, you can find that
information at http://dublincore.org/.)
Since Nuxeo's repository and web user interface already understand
the dublincore schema, there is no reason
for us to duplicate any of these properties. Nuxeo developers
usually write a property and the schema that defined it using this
notation, dublincore:title or using
the schema's abbreviation like this dc:title, and we will do so in this book.
In a previous lesson on running the Nuxeo 5 server, we suggested some exercises for you to try with the Nuxeo EP Server's web user interface. When you were manipulating the properties of a document, you were actually changing properties of schemas that are shipped with Nuxeo, for example title property of the dublincore schema. Although as a user you think of the web interface as "being" the Nuxeo server, in reality the interface is just a view into in the underlying repository. Writing a program to change a property has exactly the same effect as changing it through the web interface.
Be careful about ordering with your contributions listed on the
Nuxeo-Component line above. They need
to remain in the order shown! There are dependencies between the
contributions: The schema contribution must come before
contributions that reference it, in this case the doctype
contribution, and similarly these a dependency on this ordering
between the doctype and the ui contribution. This is always true
with the Nuxeo-Component line: ordering in this line implies a
dependency and the order the contributions are made.
Another problem that can happen with manifest files is bad formatting. As shown above, you want to have "continued" lines indented by one space from their predecessors. More subtle is to leave a trailing comma at the end of the list of required bundles or the list contributions. If you do so, your bundle will not be loaded properly and you are likely to get an error saying in the log of JBoss/Nuxeo that the bundle cannot be resolved.
The manifest file above says that our bundle will be making
three contributions to extension points. The contributions will all
be found in the OSGI-INF directory of
the final bundle.
In the final bundle schema-contrib.xml will be located at
OSGI-INF/schema-contrib.xml but in
the Eclipse project it is located at src/main/resources/OSGI-INF/schema-contrib.xml.
As before, create this file using File > New > File with the
OSGI-INF directory selected and name
the file as shown in the manifest file. The ability to add your own
meta-data to documents is a key ingredient of the power of the
Nuxeo platform. The contribution is as follows:
<?xml version="1.0"?>
<component name="org.nuxeo.book.upcoming.schema">
<extension target="org.nuxeo.ecm.core.schema.TypeService" point="schema">
<schema name="upcoming" src="schemas/upcoming.xsd" prefix="up" />
</extension>
</component>
What is this, no meta-data definition? Not yet. This is a
contribution to the TypeService bundle at
the extension point schema. We have told
the TypeService about our new
schema, upcoming (with a lower case 'u' indicating it is a
schema) and we have told the extension point where to read the
definition, the file schemas/upcoming.xsd. This file name is relative
to the root directory of the bundle, so the path in the final
bundle would be schemas/upcoming.xsd
and in the Eclipse project src/main/resources/schemas/upcoming.xsd. The
final part of the schema tag
creates namespace for our
schema so we can refer to a property foo of our schema as up:foo (more on namespaces in just a moment).
To actually define the fields of meta-data for upcoming, create
the file src/main/resources/schemas/upcoming.xsd in
Eclipse and use this content:
<?xml version="1.0"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://nuxeo.org/schemas/upcoming/" xmlns:up="http://nuxeo.org/schemas/upcoming/"> <xs:element name="occursOn" type="xs:dateTime" /> <xs:element name="presenter" type="xs:string" /> </xs:schema>
If you have experience working with XML, you'll recognize this
as an XSD or XML Schema
Descriptor. Whether or not you have experience with XML, be sure to
note that this file is not a
contribution to an extension point! If it were a contribution, it
would have been referenced in the MANIFEST.MF file in the Nuxeo-Component line! The first tag, xs:schema is to define the XML namespace
used by our schema. We defined this in the schema contribution file
as "up" and it is good practice that they match (both use "up" in
our example files) and that targetNamespace attribute point to a
URL that uniquely identifies the schema. The critical nodes in this
file are the two xs:element
nodes that define our meta-data's field names, occursOn and presenter, and the data type of each of our new
fields.
So, we now are beginning to see how an Upcoming document type might be used! We can set the
date and time that the event occurs, upcoming:occursOn, and we can set who (or what
organization) is going to be presenting the event, upcoming:presenter. These values might be
something like 'Feb-2-2015-19:00:00' and 'the Rolling Stones',
respectively.
Create the doctype-contrib.xml
file the same way as our previous contribution to the schema extension point. Here is the content of
doctype-contrib.xml:
<?xml version="1.0"?>
<component name="org.nuxeo.book.upcoming.doctype">
<extension target="org.nuxeo.ecm.core.schema.TypeService" point="doctype">
<doctype name="Upcoming" extends="Document">
<schema name="common" />
<schema name="dublincore" />
<schema name="upcoming" />
<schema name="file" />
<schema name="uid" />
<facet name="Commentable" />
<facet name="Versionable" />
<facet name="Indexable" />
</doctype>
</extension>
</component>
At this point, all the details of this file are not critical,
but there are a couple of things to notice. First, the extension
point doctype in the Nuxeo-supplied
bundle TypeService is the same bundle as
in the previous section, but a different extension point. This
extension point is being advertised for creating new document types
and we are contributing the new type Upcoming to this extension point (we use an uppercase
'U' for the document type). This document type is a composite of a
number of different schemas, including the dublincore schema we discussed before. Another part
of the Upcoming document type is the schema upcoming that we defined just a moment ago (with the
lower case 'u'); this new schema is where we can add our own
meta-data to the document. The facets shown in this example
indicate to the extension point that we would like some of the
standard functionality for manipulating documents in the UI, such
as the ability to add comments and have many versions of the
document.
In some configurations of Eclipse, creating a new XML or XSD file causes Eclipse to try to use a "pretty" editor rather than just allowing you to edit the file's text. You can tell if you are in this state if, when you create a new XML file, you see something like this in your Eclipse editor.
The document is empty. Right mouse click here to insert content.
Although this type of "structural" editor is nice in some circumstances, it is important for these lessons that you edit the "raw" XML source code. You can always access this in eclipse by using the tabs at the bottom of the editor. Try clicking on the one labelled to edit text normally.
This contribution is one that is not strictly required to create
a new type of document with its own meta-data fields. This
contribution, though, is necessary if you want to have the
satisfaction of seeing your
new datatype through the web UI of Nuxeo. It should not come as a
surprise, after some thought, that a system as large and
configurable as Nuxeo's ECM solution will place some small burdens
on new document types to "play nicely" within the Nuxeo system. We
will contribute the minimal amount to the user interface that is
possible and still be able to see our Upcoming events. You should create this file in the
same way as the other contributions, in the OSGI-INF directory:
<?xml version="1.0"?>
<component name="org.nuxeo.book.upcoming.ui">
<extension target="org.nuxeo.ecm.platform.types.TypeService" point="types">
<type id="Upcoming">
<label>Upcoming Event</label>
<default-view>view_documents</default-view>
<layouts mode="any">
<layout>heading</layout>
<layout>file</layout>
</layouts>
</type>
<type id="Workspace">
<subtypes>
<type>Upcoming</type>
</subtypes>
</type>
</extension>
</component>
There are two "contributions" to the type extension point of the TypeService in this file. If you have been paying
close attention, you will have noticed that we have now used three
different extension points (types,
schema, and doctype) of the TypeService; no surpise, since our objective in this
lesson was to create a new document type! The two contributions in
the ui-contrib.xml declare two
different things. First, that the type (more directly, the
document type) Upcoming has some display properties such as a
textual label, "Upcoming Event." We will discuss views and layouts
in an upcoming lesson, but for now you can assume that we are
selecting some default output choices so that an Upcoming document will look like other file types you
have seen in the web UI of Nuxeo.
The latter declaration concerns the Workspace document type that you first encountered when you were exploring the Nuxeo UI in a previous lesson. In effect, this declaration says that an Upcoming document is a "subtype" of Workspace. The effect of this declaration is that workspaces can contain upcoming events as you view them on the web. This is an important property: based on this declaration about the type relationship between Upcoming and Workspace, an upcoming event cannot be seen, for example, within a Folder in the Nuxeo UI.
There is another file that must be placed in the OSGI-INF
directory, although it is not a contribution to any extension
point. This file must be named deployment-fragment.xml and it describes
activities that the container needs to perform when the bundle is
loaded. A deployment fragment might, for example, install various
files in directories so that they can be used by other
contributions or java code in the the bundle. For this simple
bundle, one need only declare that we are a module and part of the
larger (Nuxeo EP Server) application:
<?xml version="1.0"?>
<fragment>
<extension target="application#MODULE">
<module>
<java>${bundle.fileName}</java>
</module>
</extension>
</fragment>
This nomenclature is really confusing: We have bundles, components, plugins, extensions, and now modules. Why so many?
With all that we have covered in this section you should now
have eight six files in your Eclipse project. The MANIFEST.MF file is in the META-INF directory and points at three other
files, these three contributions to extension points are in
OSGI-INF and all end in -contrib.xml, the deployment fragment is also in
OSGI-INF, and the crucial file for all this work, upcoming.xsd, is alone in the schemas directory and referred to by the
schema-contrib.xml contribution. It
is worth noting that only the deployment-fragment.xml and MANIFEST.MF have strictly specified filenames in
the bundle by the Nuxeo infrastructure. These are specified because
these files these must be found without any help by Nuxeo as the
bundle is loaded. All the other files are found by reading the
filenames from other files.
Since this lesson requires no java code, you do not need to use Eclipse to compile your code code-or test it. We will return to the command line to build and install the bundle with Maven. To compile the files into a bundle:
iansmith@Photo /nuxeo/workspace/lesson-bundle
$ mvn clean install
This mvn command cleans up from any previous build and builds the resulting jar file into the target directory. As Maven runs, you should see Maven inform you that there are no java files to compile and no tests to run. (These come in a future lesson!) After doing its job you should see the usual Maven success message, something like this:
[INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 23 seconds [INFO] Finished at: Wed Jan 21 21:25:29 EST 2009 [INFO] Final Memory: 28M/50M [INFO] ------------------------------------------------------------------------
You can now copy the bundle into your installation of Nuxeo 5 EP
server and restart the server, as shown below. (If your server is
currently running, you should shut it down first using one of the
scripts in the bin directory of
NuxeoServer.)
[/nuxeo/workspace/lesson-bundle] $ cp target/lesson-bundle-0.0.1.jar /nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/plugins/ [/nuxeo/workspace/lesson-bundle] $ cd /nuxeo/tools/NuxeoEP5/NuxeoServer/ [/nuxeo/tools/NuxeoEP5/NuxeoServer] $ bin/run.sh
The first command above copies the output of the maven build
process, called lesson-bundle-0.0.1.jar, into the designated area
for "plugins" (a.k.a. user-written bundles) to the Nuxeo
system.
Once the server starts up (the 2nd and 3rd commands above), log in is Administrator and go to the section of the interface for Workspaces. If you do not have any workspaces, you should create one-the name doesn't matter-using the button. Click on any workspace and then click the button (its under the tab) and you should see some choices for document types like this:

Success! If you go ahead and try to create one of these documents you will not notice anything different from creating any other type of file. You will have to trust the authors that, in fact, there are some extra meta-data fields associated an Upcoming Event and that these can be changed and searched for. You will see these for yourself soon enough. We have yet to tell Nuxeo much about how we want the UI to look, we did not even specify an icon for the Upcoming Event type shown above, so it appears out of "alignment" with the other document types. Improving the UI to this new document type might make for an interesting lesson...
If you return to the listing of the workspace you created the upcoming event in, you will see the upcoming event listed in the contents of the workspace with the title you have supplied. You should see a display in the workspace content something like this:

At this point, you have created a new document type with new fields that are specific to your application! Don't worry, we'll fix the problem with the crowded display shortly. The strange display is caused because we made the programming error (!) of not teaching you yet how to include an icon for the type Upcoming.
Allow Upcoming documents to be created inside Folders as well as Workspaces. Verify that this works properly through the UI by creating a Folder inside a Workspace and then an Upcoming document in the Folder.
Add another meta-data field to the Upcoming document, the admissionPrice field. This field should be a floating point value.