Archive for the ‘UI toolkits’ Category

In order to implement the changes made to the livesite toolkit, it must be built.

At the root of the livesite customer toolkit in local/config/lib/content_center/livesite_customer_src, you will find a script build.sh. all you need to do is execute this script and it will take care of compiling your classes, merge configuration files for the sitepublisher application.

It may be that your classpath may need to be updated. The easiest way I have found is to modify the classpath before executing the script, as explained here.

Advertisements

if you look closely, the pages header in livesite only contain the title, keywords and description meta tags. If you want to add you own, such as <meta http-equiv=”content-type” content=”text/html; charset=utf-8″ />, then you have to modify the layouts a bit. Here is how it is done.

in /local/config/lib/content_center/livesite_customer_src/, you will find the toolkit for modifying the sitepublisher application. In there lies a configuration file for the layouts, in etc/conf/livesite_customer/pagetype-config.xml.

This defines the custom page types and layouts allowed in them. for example, to define a custom page type “acme custom html” the following xml would be required:

<page-types>
<page-type id=”acme_custom_html>
  <name>acme custom html</name>
 <output>
<doctype>
  <document-root>html</document-root>
  <doctype-public>-//W3C//DTD XHTML 1.0 Transitional//EN</doctype-public>
  </doctype>
  <method>xml</method>
  <content-type>text/html</content-type>
  <omit-xml-declaration>true</omit-xml-declaration>
  </output>
     <allowed-layouts>
          <layout refid=”acme-layout />
    </allowed-layouts>
  </page-type>
  </page-types>
 <layouts>
<layout id=”acme-layout”>
      <name>Acme layout</name>
      <stylesheet>com/interwoven/xsl/runtime/acme-layout.xsl</stylesheet>
      <class>com.interwoven.livesite.layout.impl.NoLayout</class>
    </layout>
</layouts>
 
This will add the page type, its id is unique (if you specify an id that already exists in /httpd/webapps/content_center/WEB-INF/classes/com/interwoven/livesite/pagetype-config.xml, you will be able to modify the default page types) and the users will know it as “acme custom html”.
 
This page allows 1 layout (think of a layout as an “composition” of your components on the page) named “acme-layout”. This layout is actually an xsl file on the classpath of the web application and therefore resides in web/WEB-INF/classes/com/interwoven/xsl/runtime/ under the name acme-layout.xsl. The class is used to calculate and make sense of the components positions to process them on the page, if need be.
All you need to do to add the meta tag in the header is to modify the xsl file with the <meta http-equiv=”content-type” content=”text/html; charset=utf-8″ /> content.
 
After you have modified the stylesheet to your liking, the livesite toolkit must be built. I’ve explained it here.
 
There is however a little omission by the build script that does not copy the xsl to all the appropriate places. As you know, the toolkit files are normally copied and merged with the existing equivalent files in the web application. So if you edit an xsl file in … it is copied to the the relevant folder httpd/webapps/content_center/WEB-INF/classes/com/interwoven/xsl/runtime/. This step seems to have been omitted by the script and needs to be also done for the iw-preview web application.
 
cp local/config/lib/content_center/livesite_customer_src/web/WEB-INF/classes/com/interwoven/xsl/runtime/*.xsl httpd/webapps/content_center/WEB-INF/classes/com/interwoven/xsl/runtime/ 
 

cp local/config/lib/content_center/livesite_customer_src/web/WEB-INF/classes/com/interwoven/xsl/runtime/*.xsl httpd/webapps/iw-preview/WEB-INF/classes/com/interwoven/xsl/runtime/ 
 
You may need to restart the user interface with iwreset -ui afterwards.

This is a 4 step process.

  1. We need to define a custom operation that points to the workflow, 
  2. We use the operation in the menu so that users can do the invoking.
  3. We make the toolkit so that teamsite accepts our new operation
  4. We grant people the right to use our operation

 Defining a custom operation

In the teamsite/local/config/lib/content_center/customer_src/etc/conf/customer folder, the file userops_custom.xml is the one we want to modify.

<custom-operations>
<operation description="Calls the workflow to create a new intranet site" display-name="New Site (Intranet)" id="acme.newsite.intranet" />
</custom-operations>

The id must be unique throughout the system. The operation itself does not do anything, it is used later to find who’s allowed to use the action before the action is checked from the link.

Modifying the menu

In order to modify a menu, you need to find where to place it. For that, navigate to the application folder teamsite/httpd/webapps/content_center/WEB-INF/conf/ccpro and view the file ui_common.xml

In this example, we want to create a link below the File > New Site menu option. Looking at the link when we hover over it gives us the “iw.livesite.ccpro.create_site” command. Now we know that, we can find the file this menu has been created in with this little script:

command="iw.livesite.ccpro.create_site"
for file in `find teamsite/local/config/lib/content_center/reference/etc/conf/ -name ui*.xml 2>/dev/null`
 do
  echo ${file}
  cat ${file} | grep ${command}
 done

Open the file given as containing the command (and therefore the link using it) and find the command again.
We need to customise our customisation file called ui_custom.xml with the containing element (and all its parent hierarchy to the action list).

<iwov-ui>
    <action-list id="iw.ccpro.filesys.menubar">
        <menu id="iw.ccpro.file.menu">
        </menu>
    </action>
</iwov-ui>

We need to insert a menu item, below the link to create a new site.

<iwov-ui>
    <action-list id="iw.ccpro.filesys.menubar">
        <menu id="iw.ccpro.file.menu">
            <iwov-insert-after id="iw.livesite.ccpro.file_menu.create_site.link">
                 <link id="acme.file.newsite.intranet"
                        label="New Site (Intranet)"
                        description="Creates a new intranet site"
                        url="/iw-cc/command/iw.ccpro.new_job?iw_template_file=intranet_new_site&amp;iw_template_name=intranet_new_site&amp;workflowType.flag=true"
                        target="_blank"
                        operationID="acme.newsite.intranet"/>
            </iwov-insert-after>
        </menu>
    </action>
</iwov-ui>

Making the toolkit

Navigate to teamsite/local/config/lib/content_center/customer_src and issue the following command as root

./make_toolkit.sh

Granting rights

 Now we’ve done all the hard work, All we need to do is give the operation to one of the roles. For example, admin. On the administration tab, select the manage roles and expand the custom operations part for the admin role.

In order to find the class behind a command, get the command id (e.g. iw.teamsite.create_group), initialise a variable named command with this value:

command="iw.teamsite.create_group"

And run the following code on it:

 for file in `find /apps/interwoven/teamsite/httpd/webapps/content_center/WEB-INF/conf -name commands.xml 2>/dev/null`
 do
  echo ${file}
  cat ${file} | grep ${command}
 done

Totally undocumented anywhere, you can also navigate to the following url and search for the text of the command: http://teamsite.acme.com/iw-cc/base/support/show_command_desc.jsp

If you want to create a new URLExternalTask class, here’s a skeleton that can be re-used. It allows you to run an test the class before having to rebuild the toolkits, therefore reducing the interferences (and also the build times). It also lets you control the workflow when errors have been intercepted and redirect the flow to an error handling task.

/*
 * Author: Laurent Picquet
 */
package com.acme.workflow;

import com.interwoven.cssdk.access.CSAuthenticationException;
import com.interwoven.cssdk.common.CSClient;
import com.interwoven.cssdk.common.CSException;
import com.interwoven.cssdk.common.CSRemoteException;
import com.interwoven.cssdk.factory.CSLocalFactory;
import com.interwoven.cssdk.filesys.CSFile;
import com.interwoven.cssdk.filesys.CSVPath;
import com.interwoven.cssdk.workflow.CSExternalTask;
import com.interwoven.cssdk.workflow.CSURLExternalTask;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Laurent Picquet
 */
public class SkeletonTask implements CSURLExternalTask {

 private CSClient client = null;
 private CSExternalTask task = null;
 private CSFile[] attachedCSFiles=new CSFile[0];
 private StringBuilder executionLog = null;
 private String transitionLinkName = "";
 private static String KEY_ONSUCCESS_TASK_VARIABLE = "onSucess";
 private static String KEY_ONFAILURE_TASK_VARIABLE = "onFailure";

 public void execute(CSClient client, CSExternalTask task, Hashtable params) throws CSException {
 this.client = client;
 this.task=task;
 attachedCSFiles=task.getArea().getFiles(task.getFiles());
 try {
 execute();
 transitionLinkName = task.getVariable(KEY_ONSUCCESS_TASK_VARIABLE);
 } catch (Exception e) {
 transitionLinkName = task.getVariable(KEY_ONFAILURE_TASK_VARIABLE);
 e.printStackTrace();
 } finally {
 if (transitionLinkName == null) {
 transitionLinkName = "";
 }
 task.chooseTransition(transitionLinkName, executionLog.toString());
 }
 }

 private void execute() {
 executionLog = new StringBuilder();
 executionLog.append("SkeletonTask begin execute\r\n");
 /* do the work here. */
 executionLog.append("SkeletonTask end execute\r\n");
 }

 public static void main(String args[]) throws CSException {
 String configFilePath = "/apps/interwoven/teamsite/cssdk/cssdk.cfg";
 Properties localProperties = new Properties();
 localProperties.setProperty("cssdk.cfg.path", configFilePath);
 CSLocalFactory csLocalFactory = (CSLocalFactory) CSLocalFactory.getFactory(localProperties);
 SkeletonTask task = new SkeletonTask();
 try {
 task.client = csLocalFactory.getClientForCurrentUser(Locale.ENGLISH, "SkeletonTask", "localhost");
 } catch (CSAuthenticationException ex) {
 Logger.getLogger(SkeletonTask.class.getName()).log(Level.SEVERE, null, ex);
 } catch (CSRemoteException ex) {
 Logger.getLogger(SkeletonTask.class.getName()).log(Level.SEVERE, null, ex);
 } catch (CSException ex) {
 Logger.getLogger(SkeletonTask.class.getName()).log(Level.SEVERE, null, ex);
 }

 if (task.client != null) {
 System.out.println("connected to TeamSite.");
 task.attachedCSFiles=new CSFile[1];
 task.attachedCSFiles[0]=task.client.getFile(new CSVPath("/default/main/acme/WORKAREA/acme/sites/acme/default.site"));
 task.execute();
 }
 }
}