
Defining SomeCo's Content Model
Recall from Chapter 1 that SomeCo is rolling out Alfresco across the organization. Each department has its own type of content to work with and different requirements for how it works with that content. SomeCo could just start uploading content into Alfresco. That would be better than nothing, but it relegates Alfresco to lowly file server status, doesn't take advantage of the full power of the platform, and makes for a really boring (and short) book. SomeCo would be better off formalizing the different types of content it works with by extending the Alfresco content model to make it SomeCo-specific.
Step-by-Step: Starting the Custom Content Model with Custom Types
Let's start small and build the model up over successive examples. First, let's create a custom content type for Whitepapers, which are a type of marketing document. This is going to involve creating a content model file, which is expressed as XML, and then telling Alfresco where to find it using a Spring bean configuration file.
To start the content model, follow these steps:
- Create an extension directory. In the Eclipse client-extensions project, under
|
config|alfresco
, create a new folder calledextension
if you do not already have one. As discussed in Chapter 2, the extension directory keeps your customizations separate from Alfresco's code. - Create a custom model context file. A custom model context file is a Spring bean configuration file. Spring bean configuration files were also discussed in Chapter 2. Create the file in the extension directory and call it
someco-model-context.xml
. Add the following:<?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' ' http://www.springframework.org/dtd/spring-beans.dtd'> <beans> <!-- Registration of new models --> <bean id="someco.dictionaryBootstrap" parent="dictionaryModelBootstrap" depends-on="dictionaryBootstrap"> <property name="models"> <list> <value>alfresco/extension/model/scModel.xml</value> </list> </property> </bean> </beans>
- Create a model file that implements the custom content model. The extension directory is going to fill up over time, so create a new directory under extension called
model
. Create a new XML file in the model directory calledscModel.xml
(this name matches the value specified in thesomeco-model-context.xml
file). - Add the following XML that is used to describe the model, import other models that this model extends, and declare the model's namespace:
<?xml version="1.0" encoding="UTF-8"?> <!-- Definition of new Model --> <model name="sc:somecomodel" xmlns="http://www.alfresco.org/model/dictionary/1.0"> <!-- Optional meta-data about the model --> <description>Someco Model</description> <author>Optaros</author> <version>1.0</version> <!-- Imports are required to allow references to definitions in other models --> <imports> <!-- Import Alfresco Dictionary Definitions --> <import uri="http://www.alfresco.org/model/dictionary/1.0" prefix="d" /> <!-- Import Alfresco Content Domain Model Definitions --> <import uri="http://www.alfresco.org/model/content/1.0" prefix="cm" /> </imports> <!-- Introduction of new namespaces defined by this model --> <namespaces> <namespace uri="http://www.someco.com/model/content/1.0" prefix="sc" /> </namespaces>
- Next, add the types. A Whitepaper is a type of marketing document that, in turn, is only one of several types of content SomeCo deals with. It's a hierarchy. That hierarchy will be reflected in the model. Add this XML to the model file below the "namespaces" element:
<types> <!-- Enterprise-wide generic document type --> <type name="sc:doc"> <title>Someco Document</title> <parent>cm:content</parent> </type> <type name="sc:marketingDoc"> <title>Someco Marketing Document</title> <parent>sc:doc</parent> </type> <type name="sc:whitepaper"> <title>Someco Whitepaper</title> <parent>sc:marketingDoc</parent> </type> </types>
- Be sure to close the model tag so the XML is valid.
</model>
- The final step is to deploy the changes and then restart Tomcat so that Alfresco will load the custom model. Copy the
build.xml
file from the source code that accompanies this chapter into the root of your Eclipse project, replacing thebuild.xml
file you used in the exercises for the previous chapter. - Run
ant
deploy
. - Restart Tomcat.
Watch the log during the restart. You should see no errors related to loading the custom model. If there is a problem, the message usually looks something like "Could not import bootstrap model".
With this change in place, the repository is now capable of telling the difference between a generic piece of content and SomeCo-specific pieces of content such as marketing documents and Whitepapers.
Types are like types or classes in the object-oriented world. They can be used to model business objects, they have properties, and they can inherit from a parent type. "Content", "Person", and "Folder" are three important types defined out of the box. Custom types are limited only by your imagination and business requirements. Examples include things such as "Expense Report", "Medical Record", "Movie", "Song", and "Comment".
Did you notice the names of the types you created in the example? Names are made unique across the repository by using a namespace specific to the model. The namespace has an abbreviation. The model you created for SomeCo defines a custom model, which declares a namespace with the URI of http://www.someco.com/model/content/1.0 and a prefix of "sc". Any type defined as a part of the model will have a name prefixed with "sc:". Using namespaces in this way helps to prevent name collisions when content models are shared across repositories.
Step-by-Step: Adding Properties to Types
The Marketing department thinks in terms of marketing campaigns. In fact, they want to be able to search by a specific campaign and find all of the content tied to a particular campaign. Not to hurt the Marketing team's feelings, but the HR, Sales, and Operations teams couldn't care less about campaigns.
You are going to address this by adding a property to the sc:marketingDoc
type to capture the marketing campaigns the document is related to. You could make this property a text field. But letting users enter a campaign as free-form text is a recipe for disaster if you care about getting valid search results later because of the potential for misspelling the campaign name. Plus, SomeCo wants to let each document be associated with multiple campaigns, which compounds the free-form text entry problem. So, for this particular property it makes sense to constrain its values to a list of valid campaigns.
To allow the Marketing team to "tag" a piece of content with one or more campaigns selected from a list of valid campaign names, update the model by following these steps:
- Edit the
scModel.xml
file in config|alfresco|extension. Replace thesc:marketingDoc
type definition with the following:<type name="sc:marketingDoc"> <title>Someco Marketing Document</title> <parent>sc:doc</parent> <properties> <property name="sc:campaign"> <type>d:text</type> <multiple>true</multiple> <constraints> <constraint ref="sc:campaignList" /> </constraints> </property> </properties> </type>
- Now, define the campaign list constraint. Between the "namespaces" and "types" elements, add a new "constraints" element as follows:
<constraints> <constraint name="sc:campaignList" type="LIST"> <parameter name="allowedValues"> <list> <value>Application Syndication</value> <value>Private Event Retailing</value> <value>Social Shopping</value> </list> </parameter> </constraint> </constraints>
- Save the
model
file. - Run
ant deploy
. - Restart Tomcat.
Again, Tomcat should start cleanly with no complaints about the content model.
Properties and Property Types
Properties are pieces of metadata associated with a particular type. In the previous example, the property was the marketing campaign. The properties of a SomeCo Expense Report might include things such as "Employee Name", "Date submitted", "Project", "Client", "Expense Report Number", "Total amount", and "Currency". The Expense Report might also include a "content" property to hold the actual expense report file (maybe it is a PDF or an Excel spreadsheet, for example).
Note
You may be wondering about the sc:whitepaper
type. Does anything special need to happen to make sure whitepapers can be tied to campaigns as well? Nope! In Alfresco, content types inherit the properties of their parent. The sc:whitepaper
type will automatically have an sc:campaign
property. In fact, it will have all sorts of properties inherited from its ancestor types. The file name, content property, and creation date are three important examples.
Property types (or data types) describe the fundamental types of data the repository will use to store properties. The data type of the sc:campaign
property is d:text
. Other examples include things such as dates, floats, Booleans, and content that is the property type of the property used to store content in a node. Because these data types literally are fundamental, they are pretty much the same for everyone. So they are defined for you out of the box. Even though these data types are defined out of the box, if you wanted to change the Alfresco data type "text" so that it maps to your own custom class rather than java.lang.String
, you could.
Constraints
Constraints can optionally be used to restrict the values that Alfresco will store in a property. In the following example, the sc:campaign
property used a LIST constraint. There are three other types of constraints available: REGEX, MINMAX, and LENGTH. REGEX is used to make sure that a property value matches a regular expression pattern. MINMAX provides a numeric range for a property value. LENGTH sets a restriction on the length of a string.
Constraints can be defined once and reused across a model. For example, out of the box, Alfresco makes available a constraint named cm:filename
that defines a regular expression constraint for file names. If a property in a custom type needs to restrict values to those matching the filename pattern, the custom model doesn't have to define the constraint again. It simply refers to the cm:filename
constraint.