D2 Lockbox & VirtualBox

D2 Lockbox can be a real PITA to install but it surely is even more PITA when it is installed in a VM. Thing is that even if you have a properly installed D2 Lockbox it will stop functioning after each VM reboot.

It took me long hours to notice what is wrong, I was changing the setup, double checking it with the documentation a few times and everything seemed just fine…Funny enough after changing the setup I was doing a reboot – “just in case” 🙂

So, the lesson I have learnt is that  VirtualBox VM should not be restarted after Lockbox was configured. It is better to use “VM Pause” otherwise D2.lockbox file will have to be re-generated.

 

 

Documentum D2: How to display a dialog from a D2-Plugin?

Sometimes it is useful to display some message to the user from the code running on the server side (in D2-Plugin). At the first sight there doesn’t seem to be a way to do this but thanks to Dariusz R. (thanks!) who has decompiled half of D2 code 🙂 we have learned that it is actually possible. And it is also extremely simple:

The trick is to use D2fsExceptionManager.throwD2SilentException(D2fsContext context, String eventName, String messageToPublish) exception with appropriate event name and message, for example:


D2fsExceptionManager.throwD2SilentException(context, "D2_ACTION_DISPLAY_DIALOG", "DIALOG_NAME==VeryImportantDialog!!CHANNEL_EVENT==D2_ACTION_DISPLAY_DIALOG");

That’s all! Try it for yourself.

Customizing Documentum D2

I have been working on customization of D2 for the last 1.5 years and I think that I am in a good position to share some knowledge I managed to gather. I am going to start a series of blog posts explaining some less obvious tricks that I find useful.

So, lets start with customizing D2 menus…

There are two ways of doing it, one way involves using D2-Config, you can simply click on “Go to…/D2 Menu” and then configure order of menu items, change their conditions etc.
This is fine, but this is not always the best way of doing it. For example, what if you would like to add more advanced conditions which are not available in vanilla D2? Or what if you would like to dynamically create menu items? This simply can’t be done by using just the D2-Config. In more advanced projects it is often better to have the menus customized via XML in a D2 plugin than in D2-Config, this also allows better control of changes (as all files are in VCS some sort).

Okay, enough introduction, lets see some example. Lets assume that we would like to add a static D2 menu that will open some dialog.
In order to achieve this goal it is good to understand how D2 plugins work. At the moment lets only focus on a typical plugin folder structure:

blog-d2-plugin-tree

The menu layout XML file is stored in src/main/resources/xml/menu, so lets create a file MenuContextDelta.xml there with following content:


<?xml version="1.0" encoding="utf-8"?>
<delta>
    <insert position-after="menuContextEdit">
        <menuitem id="menuContextSampleStatic">
            <dynamic-action
                    class="com.emc.d2fs.dctm.ui.dynamicactions.actions.ShowDialog"
                    dialog="SampleDialog"/>
        </menuitem>
    </insert>
</delta>

The name of this file is important, it is a ‘delta’ file containing differences that merged with the base MenuContext.xml (that is stored in D2FS4DCTM-WEB-4.5.jar) will produce the final MenuContext.xml.

What the XML code does is pretty simple, we define a new menu item, that will be inserted after menuContextEdit menu item (that is ‘Edit’) in the Context menu (this is implied by name of the MenuContextDelta.xml file). When clicked, the new menu item will show dialog named ‘SampleDialog’.

Now, what if we would like to have a dynamic menu item? Lets say the requirement is to list available custom actions e.g “Publish to system A”, “Publish to system B” etc. when the menu is selected.

In order to implement it we need two files: first one adds the main menu item that contains reference to the second file (please note src=”PublishSubmenu”), second one points to the Java class that will generate available submenu options based on the current document selection (as available publishing systems depend on the selected document):

File: MenuContextDelta.xml


<?xml version="1.0" encoding="utf-8"?>
<delta>
    <insert position-after="menuContextEdit">
        <menuitem id="menuContextSampleSubmenu" src="PublishSubmenu">
        </menuitem>
    </insert>
</delta>

File: PublishSubmenu.xml


<?xml version="1.0" encoding="utf-8"?>
<delta>
    <dynamic-menuitem id="submenuPublish" class="com.metasys.d2.menu.PublishMenu">
    </dynamic-menuitem>
</delta>

And finally the Java class that will create submenu items:


package com.metasys.d2.menu;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.documentum.fc.client.IDfSysObject;
import com.emc.common.java.xml.XmlNode;
import com.emc.d2fs.dctm.ui.dynamicactions.actions.ShowDialog;
import com.emc.d2fs.dctm.web.services.D2fsContext;
import com.emc.d2fs.utils.AttributeUtils;

/**
 * Created by kbryd on 11/01/2015.
 */
public class PublishMenu extends SimpleDynamicMenu {

  public XmlNode getXmlMenuItem(D2fsContext context) throws Exception {
    XmlNode result = new XmlNode();
    IDfSysObject sysObject = (IDfSysObject)context.getFirstObject();
    AvailablePublishingSystemsModel model = PublishingUtils.getSystems(context.getSession(), sysObject);
    List<String> configNames = model.getSystemsAsList();

    for(int i = 0; i < configNames.size(); i++) {
      String configName = configNames.get(i);
      String label = configName;
      XmlNode node = result.appendChildNode("menuitem");
      node.setAttribute("id", "genid_" + i);
      node.setAttribute("label", label);

      Map<String, Object> attributes = new HashMap();
      attributes.put("DIALOG_NAME", "ConfirmPublishDialog");
      attributes.put("DIALOG_LIST_PARAM",
          "target_system" + AttributeUtils.SEPARATOR_VALUE + "label" + AttributeUtils.SEPARATOR_VALUE
              + "oam_id");
      attributes.put("target_system", configName);
      node.setAttribute("action", new ShowDialog().getAction(context, attributes));
    }
    return result;
  }
}

There is one small interesting thing going on there…I pass the target_system name to the dialog so it can be displayed as part of the confirmation message:


      Map<String, Object> attributes = new HashMap();
      attributes.put("DIALOG_NAME", "ConfirmPublishDialog");
      attributes.put("DIALOG_LIST_PARAM",
          "target_system" + AttributeUtils.SEPARATOR_VALUE + "label" + AttributeUtils.SEPARATOR_VALUE
              + "oam_id");
      attributes.put("target_system", configName);
      node.setAttribute("action", new ShowDialog().getAction(context, attributes));

Merely adding the value to the attributes Map is not enough to pass the value to the dialog. It is also important to add that attribute name to the DIALOG_LIST_PARAM value. Then in the dialog buildDialog method you can access the parameter value like this:


  @Override
  public XmlNode buildDialog(D2fsContext context, List<Attribute> attributes) throws Exception {
    XmlNode configDialog = XmlUtil.loadFromURL(context.getXmlDialogFile()).getRootXmlNode();

    DialogProcessor dialogProcessor = new DialogProcessor(context, configDialog);
    dialogProcessor.setLabelsBundle(context.getDialogBundle());
    Map<String, String> defaultValues = new HashMap<>();
    defaultValues.put("target_system", context.getParameterParser().getStringParameter("target_system"));
    dialogProcessor.setDefaultValues(defaultValues);

    XmlNode dialogNode = dialogProcessor.getDialog();
    return dialogNode;
  }

Nice thing about default values in dialogs is that the values can be automatically used in *.properties files.

Lets have a look at a ConfirmPublishDialog layout XML:


<?xml version="1.0" encoding="utf-8"?>
<dialog id="ConfirmPublishDialog" width="410" height="200" resizable="true" buttons_right="false">
    <content>
        <comment id="confirmMessage" html_content="true" condition_visible="true"/>
    </content>
    <buttons>
        <button id="buttonOk" type="submit" action="validDialog()" />
        <button id="buttonCancel" type="reset" action="cancelDialog()" />
    </buttons>
</dialog>

The comment element has id ‘confirmMessage’. This id also points to the resource in ConfirmPublishDialog_en.properties in src/main/resources/strings/dialog/ConfirmPublishDialog.

And the promised trick is that you can use $value constructs there like this:


ConfirmPublishDialog=Publication
buttonOk=Publish
buttonCancel=Cancel
confirmMessage=Please confirm that you want to publish selected document to $value(target_system)

This saves some additional effort with passing the value down to the view.

I hope this was useful!