Chapter 5. Your First Bundle: Upcoming [DRAFT]

Table of Contents

5.1. This is a DRAFT! Give your opinion!
5.2. The layout of a Nuxeo project
5.2.1. Downloading the example project skeleton
5.3. The objective: Upcoming
5.4. Getting the project into Eclipse
5.5. Creating the Upcoming document type
5.5.1. The manifest file
5.5.2. The contributions
5.5.3. The deployment fragment
5.6. Installing the bundle
5.6.1. Looking at the workspace
5.7. Exercises

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 )

5.1. This is a DRAFT! Give your opinion!

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.

5.2. The layout of a Nuxeo project

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.

Note

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.

5.2.1. Downloading the example project skeleton

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/ 

Note

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.

5.3. The objective: Upcoming

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.

5.4. Getting the project into Eclipse

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 Next, you can use the Browse button next to the Select Root Directory choice to choose the lesson-bundle directory created above. Don't choose any of it's subdirectories. After you click Finish, 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 Remove button as is shown below:

5.5. Creating the Upcoming document type

5.5.1. The manifest file

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.

Warning

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.

Warning

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.

5.5.2. The contributions

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.

5.5.2.1. schema-contrib.xml and upcoming.xsd

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.

5.5.2.2. doctype-contrib.xml

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.

Note

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 Source to edit text normally.

5.5.2.3. The UI contribution

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.

5.5.3. The deployment fragment

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.

5.6. Installing the bundle

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 Create a new workspace button. Click on any workspace and then click the New document button (its under the Content 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...

5.6.1. Looking at the workspace

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.

5.7. Exercises

  1. 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.

  2. Add another meta-data field to the Upcoming document, the admissionPrice field. This field should be a floating point value.