New Alfresco tutorial on working with a custom content model

UPDATE (2012): I’ve recently published a second edition of this tutorial that updates the original with Alfresco Share and CMIS.

UPDATE (2014): I’ve moved the tutorial and the source code to GitHub. The HTML version of the tutorial is here. It has been updated for Maven and AMPs.

I’ve written a new article (with sample files) that talks about how to extend Alfresco with your own content model and how to work with content that leverages that model via the Web Services API. All of the examples are written in Java but I do include one in PHP just for grins.

Most of the code is based on the Alfresco SDK Web Services sample code, but I’ve tweaked it here and there and I break it down into smaller chunks with commentary. I also think it is good to have one example to follow that takes you from designing the content model to implementing it to writing code that might leverage it.

More about the Alfresco Developer Series.

114 comments

  1. Hitesh Lad says:

    Good background on the content operations. I look forward on learning how to attach custom behavior to custom models.

    FYI, it looks like CML is Content Manipulation Language. CML (Content Manipulation Language) provides a set of simple statements for updating a Repository.

    Source:
    http://wiki.alfresco.com/wiki/CML

  2. Sean Hanford says:

    I’ve been looking for an article that covers this topic for the past week! Thank you so much for taking the time to explain it beginning to end.

    Very grateful!

  3. Yannick Schutz says:

    Great article,

    I’ve been looking for informations about the overrides part of type. Is it possible to have some infos? I try to override the cm:name property for a folder to have only a list of names possible…

  4. Antonio D. says:

    Jeff, i’ve read all your articles about Alfresco.

    I’ve a question for you, though.
    I think Alfresco is the product that is narrow my needs. My Docs are all modules with fields that different users have to fill.
    So it would be great to have a “form editor” to replicate the modules and customize Alfresco in this manner :
    1.First user fills his fields and than the documents move to the “next” space.
    2.Second User “read” what the first users wrote and fills his fields. And so on.
    3.At the end, the documents will be transformed in pdf to the final space.

    So, my question is not how to do this. But, from your experience, my question is : Is possible to do this with a CMS ?

    When i saw to create content, all the CMS i analyzed came up with a “wizard” not very user friendly explictly with not skilled users.

    Many thanks and excuse me for this answer : as you certainly noted i’m new to this exciting piece of software.

  5. jpotts says:

    Antonio,

    You could do what you are describing with a CMS, but it sounds like it might be more appropriate for an electronic forms application or a custom web application with workflow or business process management.

    I’m working on an article on advanced workflow that might shed some light on how you would do this within a CMS.

    Jeff

  6. Antonio D. says:

    Jeff,

    I’ve followed your suggestion and after googling a little i’ve found something i look for : cuteflow, for example.
    This product is very near what i mean. Though, it doesn’t seem a “CMS” strictly speaking.

    The question is : in a lot of situation we have to deal with “modules” where fields have to be filled by users with different jobs to do.

    In a ideal world, it would be beatiful to have a visual editor where copy the paper module. Then specify type fields and permission on them. After this, the CMS functions ( Alfresco is very good in this ) : create in one space, workflow to another space and final archiving.

    These are my needs, and so i have put my interest in CMS : but i see that the “documents” in CMS are “as is”, i mean with metadata all is possibly but with the “content” of the documents nothing to do, the content is “entire” : Yes, in Alfresco there is FreeMarker, but it’s a presentation template : indeed what i think would be useful is a scripting language to “write” content.
    Let me explain better : the first user starts the document viewing the electronic version of the paper module. Once he fills the proper fields, this document goes to the space of the second user. This user, after log in, has to view the tasks assigned to him, and after read the document and done the job to do, fills the proper fields. And so on. At the end, the complete document ( and correctly filled ) with a transformation in pdf goes to a repository.
    A situation like this is the management of ISO9000 modules.

    How do you think about this ?
    I mean, when they thought about CMS, especially those JCR complaint, didn’t they considered this kinds of documents ?
    CMS are only for web content management and Alfresco is trying to consider management of “internal” document ?

  7. jpotts says:

    Yes, I see what you are saying. There are several ways you could handle this. First, you could create “content-less” objects in which there is no file being managed–all of the data resides in properties on the object. You could route the object through a workflow and then based on where the document is in the process you could show or hide different sets of properties as you describe.

    Another option would be to use a workflow to collect the information throughout the process and then in a final step in the workflow you essentially serialize the data to an XML document and place it in the repository.

    A third option would be to use the concept of “compound documents” in which one “parent” document is actually made up of multiple child documents. In your case each child document is a chunk of XML created during a process. When you “publish” the document you could then assemble the single document out of the children and convert it to PDF.

    Hope this helps.

    Jeff

  8. ftesei says:

    Hi Jeff,
    your article on Working on Custom Content Type eventually clarify me
    on the topic after a long inefficient googling.
    A really valuable article.
    So I’d like to know your advise on this topic either.
    I’d like to setup a simple Content Model such as a parent Content with two
    child associations or a parent Content with a bunch of peer associations.
    I’d like too that my simple work-flow action on the parent Content move the
    child/peer associated documents too.
    Simple work flow I’ve implemented on main Content seem to move just it, not the associated stuff.
    There is no Alfresco simple work flow function out of the box to perform this task.
    What is your suggestion to move the structured document as a whole ?
    Is it an advanced work-flow the best way to get the desired result ?

    Thanks again to sweep fog away from my CMS comprehension

    federico

    P.S

    I beg your pardon asking a speculation on this strange behaviour testing “Working with Custom Content Type” sample you

    provided on ecmarchitect.com on June 07
    My setup is JBoss 4.2 GA Java 1.5 with Alfresco 2.1 + WCM and I’ve experienced
    unexpected behaviour.
    I’ve unzip on extension directory but I’ve and even if the startup log is clean
    when I log as admin and try
    I mean:

    – I can choose the custom type just in case of ‘create’ content but not in the case of ‘add’ content.
    – I can’t see the aspect properties added on the property sheet except the Related document one

  9. Thomas says:

    The examples should be runnable through the commandline, however when imported in Eclipse it cannot find the imported packages. Which is why I imported the examples in the first place. How do you do that?

    Thanks!

  10. Ken Walker says:

    I also found the article to be very helpful. Thanks! I have a question though, which I’m hoping you might be able to shed some light on for me. I’d like to be able to have a 1-to-many relationship from a content type to an aspect with several properties. For example, I created a custom aspect to store the first name, last name, and role of a person and I’d like to be able to link one document to several people, such as plaintiff, defendant, etc. Is this possible? What would be the way to go about doing this? I know there is a tag which can be added to a specific property, but I want the entire aspect to have this attribute, rather than each individual property.

  11. jpotts says:

    @Thomas,

    First, note that the command-line examples are limited to the Java web services examples. You may have already realized that but I wanted to clarify it.The rest of the code examples in the articles require customizations to be deployed to an Alfresco instance.

    Next, if you’re working with the project in Eclipse, you’ll need to import the Alfresco SDK projects. Instructions for how to do that are on the Alfresco wiki.

    If you already have the Alfresco SDK projects imported, double-check that the content-article project has the SDK AlfrescoEmbedded and SDK AlfrescoRemote projects in the build path.

    Finally, if you are using runExamples.sh, check the alf_sdk_home and alf_lib environment variables to make sure they point to your locally installed SDK.

    Hope that helps,

    Jeff

  12. jpotts says:

    @Ken,

    The aspect you describe would define a set of attributes for describing a person. If you had a content type that needed those attributes, the aspect would be a convenient way of assigning those attributes to the type.

    I don’t think this is what you’re going for, though. What it sounds like to me is that you have an object, let’s say it is a legalBrief. The legalBrief is related to one or more people or parties. If any given legalBrief had a fixed number of people associated with it, and if you didn’t need to use parties elsewhere in your system, you could make multiple attributes of legalBrief such as plaintiffFirstName, plaintiffLastName, defendantFirstName, defendantLastName. This doesn’t leave much room for changes over time.

    More likely, what you want to do is use associations. An association defines a relationship between objects in your repository. So you’d define your legalBrief object and you’d define your party object. You’d then define a peer association between legalBrief and party.

    It might make sense to associate legalBriefs with Parties and the Parties with People. That way, you could have a “defendent”, “plaintiff”, or other indicator on the party object and the person object could be more generic.

    The article discusses associations and has an example in the “relatedDocuments” association. The Data Dictionary Guide on the Alfresco wiki may also be of interest: http://wiki.alfresco.com/wiki/Data_Dictionary_Guide#Step_6:_Defining_Associations

    Hope this helps.

    Jeff

  13. Chandru says:

    Its a great article.I need one requirement .That is i am creating one folder space in the alfresco and I need to open my custom jsp instead if the default browse.jsp.can u help me for this situation?

  14. jpotts says:

    @Chandru,

    Assuming what you want to do is make sure that in every case where the old browse.jsp was opened it is replaced by opening your custom.jsp, what you need to do is implement a custom faces config file. You need to change all of the navigation rules that used to point to browse.jsp to point to your custom.jsp.

    Instructions for where to put your new faces config file are at:

    http://wiki.alfresco.com/wiki/Packaging_And_Deploying_Extensions#JSF_configuration_files

    Good luck!

    Jeff

  15. Chandru says:

    Thanks Jeff.
    The next question is how can I find that my action takes place for the folder which I had created.I need to change the “browse” to some other custom value. so that all other folder has their own navigation and my folder has its customized navigation.

  16. Ken Walker says:

    Jeff,
    Thanks for your response. I was thinking I needed to use associations somehow. But I’m still struggling to get it to work the way I would like. So are you saying that I would need to create a separate piece of content for the Party, which would define the name fields listed in the PeopleAspect as it’s properties so that I could then associate a document to that “content”? I’m confused on how to get it to work without having to have the individual Parties show up as “content”, since those aren’t really documents. When I added the assocation, in the web client when I add a new document, I see the “Associated People” association, but it’s just like the related documents one where there’s a single text field and a search button above the “Add to List” button. But I want to be able to just enter the name fields and click Add to List, rather than search for some previosly added Party “document”.

    Or is there some way to add the Parties to the database, but not as content, so I could then search for them and either create a new one if not found, or select one if found, and add to the list of associated people for a specific document?

    Does that make sense? Sorry if I completely confused you.

  17. Kapil Avasthi says:

    Hi Jeff,
    Its a very good aricle.I am developing one application in which there are majorly two requirements which are :
    1. Basically i want to make a add server in which users can upload their advertisement & can play/view them. Now my problem is that if i want to use Alfresco’s upload functionality I am not able to change the propeties for that uploaded file (i.e I am only able to upload the file but if i want to add some description, user information I am not able to do it) so how can i do it? if i have to develop it as out of box development, how can i do it? what will be the steps?
    2. My second requirement is for user creation, at user creation I want to add many more information with that like comapny id, company logo, date of birth of user etc, now for this do i have to make a new table? how to change in UI part?
    please give some reply, or some example code so that i can atleast start this, thanks in advance.

  18. debraj says:

    hey jeff,
    I am very new to alfresco. I am trying to put an expiry date to any type of content added.This expiry date can be set and modified by the user.When the content expires it needs to be deleted. Can you please give me some suggestions how to approach this

  19. jpotts says:

    debraj,

    This is a very “Records Management” thing to do. So, if you’d rather not do this with your own customizations you should check into the Alfresco Records Management add-on. The Records Management functionality is installed by applying an AMP to the out-of-the-box Alfresco WAR file. Scheduled destruction should be part of that functionality although I’ve never used it personally.

    If you still want to do it on your own, here’s what you’d do:
    – Add an expiration date property to a new aspect. The new aspect and expiration date property are added by extending the content model. Instructions for how to do that are in the content model tutorial.
    – Write something that will check for content that has an expiration date older than today and delete the content. That something could be server-side JavaScript that you run on a schedule or it could be an action that you write and then schedule through the action-scheduling mechanism.

    Jeff

  20. jpotts says:

    Sri,

    The content model article referenced in this post includes deployment instructions. If you have Java code that simply accesses the repository through the API, that code can go anywhere. If you have Java code that is tightly bound to the Alfresco web app (such as content type behavior) you should JAR it up and then put it in the classpath such as in the Alfresco webapp’s WEB-INF/lib directory.

    If that isn’t working for you reply with specific details of the problem you are having or try the Alfresco forums at http://forums.alfresco.com.

    Jeff

  21. krishnan says:

    I am new to alfersco so i need to know how to get the data from user and store in the repository and also to retreive it with detail code

  22. jpotts says:

    Krishnan,

    There are many ways to get the data from the user and into the store. You could write a custom application using whatever language is most appropriate for what you are trying to do and then post it to a web script which would then persist it to the repository. You could write a Java application that embedded the repository within it. You could use the web services API. You could use the JCR API. The same approaches can be used to retrieve the data.

    Without specifics, I can’t be of much help. My advice is to read the content model article as well as the Web Scripts article. That should get you pointed in the right direction. If you still have trouble, try the Alfresco forums at http://forums.alfresco.com and the examples on the wiki at http://wiki.alfresco.com.

    Hope that helps,

    Jeff

  23. Tony says:

    Hi Jeff,

    Good article and it works!

    I’m not sure if this is bug or feature when using custom content and properties whereby the properties in the parent type are not inherited by the children?

    My custom content model defines a couple extra properties that I’ve defined in my base type. The custom properties appear in the base type but not in its subtypes. Short of copying the property definitions to all the subtypes is there something wrong in my configuration or is this the correct behavior?

    Cheers

    Tony

  24. jpotts says:

    Tony,

    I believe what you are saying is that the properties of child types don’t automatically show up in the web client, even if you’ve configured the web client to show the properties of the parent type.

    I believe you have to update the property-sheet in the web-client-config-custom.xml specifically for every type. The properties are there, they just aren’t exposed.

    Note that what gets inherited is the *definition* of the types, not the property values. If what you are wanting to do is inherit property values you’ll have to write that yourself.

    Jeff

  25. Snig says:

    Hi Jeff

    I have read articles posted by you in this space, great articles and very useful ones. Thanks a lot for sharing these with us.

    I have a query, which is still unresolved after a long unsuccessful googling. Got a couple of posts in alfresco forums, but not final answer, alas.

    My requirement is to create a couple of functionalities which behave like a standard web application using RDMS. The other implementations mostly are possible by alfresco, but what I am not sure is how to “standard database operations” using alfresco. I don’t want to use custom content model as the number of records will be really large, and performance would be a hazard; there are some complex business rules also need to be applied which can be done most easily using standard SQL queries etc.

    Please Help.

    Thanks
    Snig.

  26. topher says:

    Hiya,

    I’ve tried your example with Alfresco Labs 3b and getting the property sheets to display the new aspects don’t appear to work. Everything else works fine, I can see the new types in creation, search, etc. And in the properties list, I see the related documents aspects in the web client UI – but not the webable or relatedProducts aspects.

    I just copied the example files without modification into the extension directory and restarted Tomcat.

    Any ideas?

  27. Prasad says:

    Good Article. But one thing how to customize if we have a drop downs in the properties. please provide the solution.

  28. jpotts says:

    Prasad,

    A dropdown is a controlled set of choices for a given property. Alfresco calls these constraints. There are several types of constraints out of the box and they include things like LIST, RANGE, MIN MAX, and REGEX. So if you wanted to have a property that showed a dropdown with Apple, Orange, and Banana, you’d create a LIST constraint with those values in your content model XML. When you configure the web client UI to show that property, the component renderer will automatically render itself as a dropdown. If you make the property multivalue, the property will automatically render itself using the multi-select component.

    You should be able to grep the out-of-the-box content models for examples of constraints.

    Also, there are a few examples available for doing dynamic list constraints. For example, maybe you want to populate the list from an arbitrary database query or maybe by running a Lucene query against the repository.

    Jeff

  29. Ryan says:

    Hi,
    Great article.
    Is there a way to have you custom content type hold attachments?

    That is, a user can create this content, with any file as attachment or add these later on.

    best regards,
    Ryan

  30. jpotts says:

    Ryan,

    Any content type that extends cm:content automatically can have a file associated with it because it has a content property.

    Generally, one object has one file attachment associated with it but that does not have to be the case.

    Jeff

  31. Ryan says:

    Hi,

    Thanks for the reply Jeff.
    I’m interested in the “not have to be the case” situation.

    I need a content type that can hold several files.
    Is is possible to create several properties of type cm:content, using them as placeholders for a known set of attachments?

    //Ryan

  32. jpotts says:

    @Ryan,

    I *believe* so but I’ve never tried it. Try extending cm:content with your own type and add a few d:content properties then give it a try. I wouldn’t be surprised if the web client UI has a problem with it so you might have to add your file attachments through API calls.

    Jeff

  33. sankari.p says:

    Hi,

    I am newbie to Alfresco..

    I am having Approve Space..Under this I am having two Folders Namely Deposit and Loan..And under Deposit space i am having sub spaces like Account_1,Account_2,Account_3.

    Approve
    |_ Deposit——>Account_1,Account_2,Account_3
    |_ Loan———>Account_1,Account_2,Account_3

    In Approve Space it contains so many documents..

    I have to enter Account Id (I added as Aspect property) in every document..

    And based on the account id i entered I have to move the document to
    EITHER Deposit.Alfresco1 Space OR Loan.Alfresco1 Space based on the Aspect property value …

    Please any help

  34. jpotts says:

    sankari.p,

    Here are a couple of options: You can either write a rule and have it check the account ID and then do a move or you can write a behavior and do the same thing.

    I would start with a rule. Put your logic in JavaScript–it will be easier/faster to code and you aren’t doing anything here that would require the Java API.

    Hope that helps. If you need further details, the friendly folks in the forums will likely be able to respond more quickly than I can.

    Jeff

  35. Madhu says:

    Hi Jeff,

    Great articles to come across with….

    Even I am trying since very long to find the result of my requirements, hope I get some solution here.

    I want the content to be managed by Alfresco but not building the whole project on Alfresco from the root. Alfresco should control the content of my site, the changes made to the content through Alfresco is to be saved in database(or any filesystem with a mime type that can be noticeable and retrieved) so that we can retrieve that content back and publish.

    Recently I found a java file from the alfresco source code which defines the storage of the content with a random numeral in .bin format.

    Now that I want to change this code so that I can define my storage path with an accessible mimetype and some filename which accomplishes my task of retrieving.

    My query is- how to integrate the changed code with the current working module and work as usual with the storage path as defined by ourselves.

    Is this possible? or can you suggest some other ways of doing this?

    Thanks,
    Madhu

  36. jpotts says:

    Madhu,

    It isn’t clear to me why you need to access the files directly on the file system. Alfresco’s data directory is not “public” so you should avoid touching those files directly. And really, you shouldn’t have to. There are all kinds of ways to get those files to your web site.

    You could:
    * Use rsync to copy the files by accessing the repository via CIFS
    * Connect to the repository through FTP or WebDAV
    * Query for and retireve the files using SOAP or REST
    * Use Alfresco WCM to manage the files and then deploy the files using the built-in ASR and FSR deployment mechanisms.

    Jeff

  37. Madhu says:

    HI Jeff,

    To be very specific, I am trying to understand how Alfresco works as “OpenDeploy of Interwoven”.

    Can I use Alfresco the way I use “Team Site” and “Live Site” of Interwoven. I have a little exposure to those modules of IW but we are now looking at an opensource solution.

    Madhu

  38. jpotts says:

    Alfresco WCM includes two deployment mechanisms. One is called a File System Receiver (FSR) which essentially copies web assets from Alfresco’s web store to any file system running the receiver process which is a small Spring application.

    The other is called an Alfresco Server Receiver (ASR) which is used to copy web assets and metadata from the Alfresco web store to another web store (on the same or different Alfresco server).

    Whether or not these are functionally equivalent to OpenDeploy, that’s up for someone else to determine. It’s been too long since I’ve worked with Interwoven to make that judgement.

    If you have used Documentum I’d say Alfresco FSR is like SCS. What would be great is if Alfresco’s deployer was as robust as Documentum’s SDS (originally an OEM of Marimba’s deployment mechanism). Although complex, SDS was able to treat a multi-node deployment as a single transaction, rolling back all destination nodes if one fails, which is something Alfresco’s ASR/FSR currently lacks.

    Jeff

  39. efrain says:

    Great article, but got one problem, i able to recreate your example with my own model, i create a simple work flow rule with 3 spaces Draft/Approved/Rejected. Draft is the initial space and i’m able to create the file into that space from SDK but my problem is that i cannot execute the action from the rule (Submit) from SDK, this rule basically move the document to the Approved space, i found in the SDK API the class ActionUtil for execute Actions and Scripts, but is not working for me, can you help?

    http://dev.alfresco.com/resource/docs/java/web-service-client/org/alfresco/webservice/util/ActionUtils.html

  40. efrain says:

    Here is part of the code:
    USAGE: java XcelWorkflowProcess

    Store storeRef = new Store(Constants.WORKSPACE_STORE, “SpacesStore”);
    Reference doc = new Reference(storeRef, getDocUuid(), null);

    System.out.println(“Found document:” + doc.getUuid());

    ActionUtils.executeAction(doc, getAction(), null);

    STACKTRACE:
    Found document:ac171c08-d98a-4022-90b0-bcf336d09225
    org.alfresco.webservice.util.WebServiceException: Unable to execute action
    org.alfresco.webservice.util.WebServiceException: Unable to execute action
    at org.alfresco.webservice.util.ActionUtils.executeAction(ActionUtils.java:105)
    at com.xcel.examples.XcelWorkflowProcess.executeAction(XcelWorkflowProcess.java:42)
    at com.xcel.examples.XcelWorkflowProcess.main(XcelWorkflowProcess.java:27)
    Caused by:

  41. efrain says:

    Ok, fist of all i was using a doc reference instead of a folder reference, even with a folder do not work for the action created, what i have to do is create a Script(JavaScript) and use ActionUtils.executeScript instead.

Comments are closed.