You can add support that allows people to add tags to instances of your content type. People can also browse or search for your content type by tag. The content in this topic assumes you've implemented a manager class to locate content type instances based on their ID in the system.

Note: The code in this topic is from the Memo sample content type. You'll find the sample in the Jive public sample Subversion repository.

Note: The content type API is still a new feature that might change as developers provide feedback about it.

Here are the high-level steps. You'll find more about each in the sections below.

Provide Information About Tagging Support

Implement the TaggableTypeInfoProvider interface to describe your content type's tag handling strategy.

Signal Support for Tags

To tell the application that your content type should be taggable, your  implement the TaggableType interface.

Provide User Interface for Applying and Viewing Tags

Once you've connected your content type to the tagging subsystem through your object type and info provider classes, you can create user interface and logic for applying and viewing tags. Here are the pieces you'll probably need:

Supporting Applying and Editing Tags

To help make your content type consistent with other types in the application, you should have your type make tags available for adding and editing when the user is creating or editing the instance. To do this, you can implement the methods you need in the action class you use to handle instance creation.

For example, assume you have created an action class to create new instances of the content type. That class might include a way to capture a new instance's subject and body if it has them. For a taggable type, it will also include a way to capture and validate tags the user wants to save as part of the content, as well as a way to get popular tags from the community so that users can select from tags already in use.

To provide all of this, your action should implement the CreateEditTaggableTypeAction interface. It has methods for getting and setting tags, as well as for getting the list of popular tags. In the following example, code that's specific to things other than tags has been omitted to keep the example simpler. (Note that this assumes you're configuring Struts to be aware of your action. For more on that, see the topic on how to support content type instance creation.)

public class CreateMemoAction extends JiveActionSupport implements CreateEditTaggableTypeAction {

    private List<String> popularTags;
    private String tags;
    private Set<String> validatedTags = new HashSet<String>();
    private TagActionUtil tagActionUtil;
    private MemoManager memoManager;

    /**
     * Called by Spring to inject a MemoManager instance.
     *
     * @param memoManager The MemoManager.
     */
    public final void setMemoManager(MemoManager memoManager) {
        this.memoManager = memoManager;
    }

    /**
     * Called by Spring to inject the TagActionUtil instance.
     *
     * @param tagActionUtil A TagActionUtil instance.
     */
    public final void setTagActionUtil(TagActionUtil tagActionUtil) {
        this.tagActionUtil = tagActionUtil;
    }

    /**
     * Validates content data to ensure that information needed for creating the memo is present.
     * For example, if the memo's subject or body aren't present, then the UI will display an
     * error message so that the user knows what to do before creating or saving.
     *
     * This method is called automatically by Struts before the execute method is called.
     */

    public void validate() {

    // Code for subject and body omitted.

        // If there are tags, validate them before saving. If invalid tags are found, catch the
        // resulting exception and display and error for the user.
        if (!StringUtils.isBlank(tags)) {
            try {
                validatedTags = tagActionUtil.getValidTags(tags);
            }
            catch (InvalidPropertyException ipe) {
                switch(ipe.getError()) {
                    case length:
                        addFieldError("tags",
                                getText("memo.create.error.tag.length",

                                    new String[] {ipe.getProperty().toString()}));
                        break;
                    default:
                        addFieldError("tags",
                                getText("memo.create.error.tag.unknown",

                                    new String[] {ipe.getProperty().toString()}));
                        break;
                }
            }
        }
    }

    /**
     * Called by Struts to execute the action, creating the memo from content entered by the user.
     *
     * @return The Struts response.
     */
    @Override
    public String execute() {

        if ( !StringUtils.isEmpty( cancel ) ) {
            refererURL = JiveResourceResolver.getJiveObjectURL( container, false );
            return "cancel";
        }

        Memo memo;

        try {
            // Create a memo instance from valid data entered by the user.
            memo = memoManager.createMemo(container, subject, body);
        }
        catch (RejectedException e) {
            log.error("Memo " + subject + " rejected for create", e);
            return UNAUTHORIZED;
        }

        // Save the memo's validated tags.
        tagActionUtil.saveTags(memo, validatedTags);      

        // The URL that will be used to redirect to a view of this memo after the action
        // executes.
        refererURL = "/view-memo.jspa?memoID=" + memo.getID();
      
        return SUCCESS;
    }

    /**
     * Sets tags entered by the user.
     *
     * @param The space-separated list of tags.
     */
    public void setTags(String tags) {
        this.tags = tags;
    }
  
    /**
     * Gets tags saved for the memo instance.
     *
     * @return The space-separated list of tags.
     */
    public String getTags() {
        return tags;
    }

    /**
     * Get the popular tags for the community from the application.
     *
     * @return The list of popular tags.
     */
    public Iterable<String> getPopularTags() {
        if (popularTags == null) {

            popularTags = tagActionUtil.getPopularTags(getContainer(),

                JiveGlobals.getJiveIntProperty("memos.tags.populartags", 25));
        }
        return popularTags;
    }
}

The user interface is remarkably simple to create. Again, to be consistent with other content types in the UI, you can import that tag-related UI that's used by the rest of the application. You do that by including tag-macros.ftl, which has the code for displaying the tag entry form and for displaying the list of tags associated with the document when viewing it. The FreeMarker code in the included file will use values from your action class to display the tag-related UI.

For example, for UI to edit tags, include tag-macros.ftl with the include statement in the following example.

<!-- Insert this line near the top of your FTL file. -->
<#include "/template/global/include/tag-macros.ftl" />

<!-- Insert this code where the tag entry form and list of popular tags should be displayed. -->
<@editTags/>

In a similar way, you can add UI for displaying tags when your content is begin viewed by including the tag-macros.ftl file in your  FTL file for viewing UI. You'd use a different macro, of course, as shown in the following snippet.

<!-- Insert this line near the top of the FTL file. -->

<#include "/template/global/include/tag-macros.ftl" />

<!-- Insert this code where the list of tags should be displayed. -->

<@viewTags contentObject=memo />