Alfresco Developer Guide
上QQ阅读APP看书,第一时间看更新

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:

  1. Create an extension directory. In the Eclipse client-extensions project, under |config|alfresco, create a new folder called extension if you do not already have one. As discussed in Chapter 2, the extension directory keeps your customizations separate from Alfresco's code.
  2. 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>
  3. 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 called scModel.xml (this name matches the value specified in the someco-model-context.xml file).
  4. 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>
  5. 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>
  6. Be sure to close the model tag so the XML is valid.
        </model>
  7. 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 the build.xml file you used in the exercises for the previous chapter.
  8. Run ant deploy.
  9. 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

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:

  1. Edit the scModel.xml file in config|alfresco|extension. Replace the sc: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>
  2. 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>
  3. Save the model file.
  4. Run ant deploy.
  5. 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.