4 Working with Oracle Team Productivity Center Connectors

This chapter describes how to develop connectors between Oracle Team Productivity Center and external data repositories, such as bug databases, feature tracking systems, and any other repository of data used by a team for development. It also describes how to work with Oracle Team Productivity Center connectors after you have created them. This includes error handling, adding help, packaging the connectors for distribution, and internationalization.

Oracle Team Productivity Center connectors provide a framework to integrate third-party repositories with JDeveloper. Standard work item interfaces allow third-party connectors to fetch data from their backend repositories and present them in a standard format. The declarative user interface approach gives connector writers the freedom to lay out UI controls in many flexible ways, without writing an extensive amount of code. JDeveloper then combines the data and UI elements at runtime, and presents repository objects in a coherent way that JDeveloper users already are familiar with.

This chapter includes the following sections:

4.1 About Working with Oracle Team Productivity Center Connectors

Developing your own connectors for Team Productivity Center begins with an understanding of connector architecture. The architecture of an Oracle Team Productivity Center connector is organized to provide three primary functions:

  • Data fetching from the work item repository served by the connector.

  • Runtime UI component tree generation inside the Team Productivity Center client.

  • Display of UI controls and data in work item editor that ties the repository data to UI components.

4.1.1 Fetching Data From the Repository

Each work item connector implements the WorkitemConnector interface, and optionally WorkitemAttachment interface if the repository this connector uses supports attachments. The WorkitemConnector interface specifies methods for end user logging into and out of the repository, basic Create, Read, Update and Delete (CRUD) operations on work items, and retrieving query results. Based on the capabilities of the backend repository, Connector writer determines what WorkitemConnector methods to implement to expose the backend repository functionalities. When implementing these selected methods, connector writers use the appropriate APIs (or Web services) available from the backend repository. After data is collected through the APIs, it needs to be converted to the work item data structure that the connector writer defines.

4.1.2 Generating the Component UI Tree

After the connector obtains the work item data from the repository, Oracle Team Productivity Center's declarative UI framework reads the work item UI definition defined by the connector writer and binds the data with their corresponding UI controls. The Oracle Productivity Center provides a metadata-driven UI framework in which connector writers can develop a work item UI layout XML file by using the pre-defined UI tags. Preferably, the connector writer authors the UI layout that conforms to JDeveloper look and feel, while maintaining the behaviors of its native application as much as possible. This way the end users will have the same experience when navigating the UI in JDeveloper as well as in its native application.

4.1.3 The Work Item Editor

When both work item data and its UI components tree are available, the WorkitemEditor, a special editor inside JDeveloper, binds the data to the UI controls and displays them inside the editor.

4.1.4 The Dynamic Work Item Model and UI

Oracle Team Productivity Center supports a dynamic work item model and UI at runtime. For certain repositories, the work item model and/or UI are determined by some work item instance field value(s) or a pre-defined condition. Oracle Team Productivity Center provides the flexibility to show a different UI layout at runtime by exposing methods in the WorkitemConnector interface.

4.1.5 How to Download Extension Connectors

The Oracle Team Productivity Center is provided by default with the Task Repository connector. All other connectors require that you download them from the JDeveloper Update Center, using the Check for Updates wizard.

To download a connector extension:

  1. Select Help > Check for Updates.

  2. In the Check for Updates wizard, select Search Update Centers.

  3. Make sure that the Open Source and Partner Extensions center is selected, and click Next.

  4. On the Updates page, scroll through the list and select the Oracle Team Productivity Center connectors that you wish to download, and then click Next.

  5. Click Finish.

Online help for each of these connectors will be available after you download and install them. You can also refer to the contents and structure of these connectors as samples while developing your own connector.

For more information, see the "How to Install Extensions with Check for Updates" section in the Oracle Fusion Middleware User Guide for Oracle JDeveloper.

4.1.6 Team Productivity Center Connector Execution Flow Example

To understand the way the preceding information fits together in practice, consider the following example using the JIRA repository:

You double-click on a work item that represents a query titled "My P1 Issues." JDeveloper opens the query, displays the query criteria and executes the query to show the results in a list. You can then double-click on a particular issue in the result list; JDeveloper opens a new work item editor and shows the selected issue's details. Here is the call sequence represented by this example:

  1. UI framework gets the query information from the TPC database for "My P1 Issues."

  2. UI framework finds the JIRA connector instance and calls the method getQueryResults on the JIRA connector and sends in the query criteria.

  3. JIRA connector returns a list of Work Item objects that match the JIRA work item object definition.

  4. TPC framework shows the list of work items in the results list of the query.

  5. When the user double clicks on particular work item, UI framework calls the getWorkitem() method on the JIRA connector and passes the issue ID.

  6. Inside the JIRA connector instance, getWorkitem() uses the JIRA SOAP interface to retrieve the issue data.

  7. When the SOAP interface returns the data, getWorkitem() converts it to a JIRA Workitem object.

  8. UI framework creates a work item editor.

  9. The work item editor now loads the issue UI page by calling getUIRegionName() and then generating the UI component tree.

  10. The work item editor then binds the data to their UI controls.

  11. The work item editor, through different renderers, displays the issue data and their associated UI controls.

4.1.7 How to Define Team Productivity Center Repository Data

In this example, you define the XML data objects to hold the various types of objects inside your repository. The name of this file must be specified in the connector.xml file as the modelFileName. You create this model file and put it in under your project in the src/META-INF folder.

You can use tags in workitem-object.xsd to describe work item data in this definition file. This file specifies the fields to expose in the Team Productivity Center, default columns to show in a query result list, and list of value definitions and the data source to use for getting their data.

workitem-object.xsd is located in the file almcommon-api.jar. This file, along with the Oracle Team Productivity CenterConnector Tag Guide tpctagdoc.zip, is distributed under the directory jdeveloper\jdev\extensions\oracle.teamproductivitycenter\doc.

Example 4-1 is an example work item definition file (SampleDef.xml).

Example 4-1 Sample Work Definition File

<?xml version="1.0" encoding="windows-1252"?>
<RepositoryModel resName="res" resFile="/META-INF/res/modelresource.xml">
        <WorkItem data-source="rpthead" id-def="TASKID" id-label="${res.TASK_ID}" label-def="TASKID"
                  name="${res.TASK_NAME}" type="Task" subject-def="DESC"
                  webURLHandler="oracle.sampleconnector.model.TaskWebReferenceImpl"
                  supportSearchByID = "true" 
                  xmlns="http://www.oracle.com/alm/" version="1.1.1.1">
                <Fields>
                        <Field name="TASKID" label="${res.TASK_ID}" type="number"
                               readOnly="true"/>
                        <Field name="DESC" label="${res.TASK_DESC}" required="true" 
                               maxLength="80" type="string"/>
                        <Field name="OWNER" label="${res.TASK_OWNER}"
                               defaultValue="" controlType="lov" type="string"
                               lovDef="owner_lov"/>
                        <Field name="STATUS" label="${res.TASK_STATUS}" type="number"
                               required="true" controlType="choice"
                               lovDef="statusLookUp"/>
                        <Field name="DUEDATE" label="${res.TASK_DUEDATE}" type="date"
                               readOnly="true"/>
                        <Field name="URL" label="${res.TASK_URL}" maxLength="255"
                               type="string"/>
                </Fields>
                <QueryListColumns>
                        <FieldRef name="TASKID"/>
                        <FieldRef name="DESC"/>
                        <FieldRef name="OWNER"/>
                        <FieldRef name="STATUS"/>
                        
                </QueryListColumns>
                <WebResource>
                        <URLDef name="URL" archorOn="label"/>
                        <URLDef name="TASKID" archorOn="field"/>
                </WebResource>
                <LovDefs>
                        <LovDef name="owner_lov" list-source="users">
                                <CriteriaMap>
                                        <Map listFieldRef="USERID"
                                             fieldRef="OWNER"/>
                                </CriteriaMap>
                                <FieldMap>
                                        <Map listFieldRef="USERNAME"
                                             fieldRef="OWNER"/>
                                </FieldMap>
                                <DisplayList>
                                        <FieldRef name="USERID"/>
                                        <FieldRef name="USERNAME"/>
                                </DisplayList>
                        </LovDef>
                        <LovDef name="statusLookUp" list-source="status">
                                <FieldMap>
                                        <Map listFieldRef="SID"
                                             fieldRef="STATUS"/>
                                </FieldMap>
                                <DisplayList>
                                        <FieldRef name="SID"/>
                                        <FieldRef name="SDESC"/>
                                </DisplayList>
                        </LovDef>
                </LovDefs>
                <DataSources>
                        <DataSource name="users" id-def="USERID">
                                <Field name="USERID" label="${res.USER_ID}"
                                       type="string"/>
                                <Field name="USERNAME" label="${res.USER_NAME}"
                                       type="string"/>
                        </DataSource>
                        <DataSource name="priority" id-def="PID">
                                <Field name="PID" type="number"/>
                                <Field name="PDESC" type="string"/>
                        </DataSource>
                        <DataSource name="status" id-def="SID">
                                <Field name="SID" type="number"/>
                                <Field name="SDESC" type="string"/>
                        </DataSource>
                </DataSources>
        </WorkItem>
</RepositoryModel>

Table 4-1 lists the tags used and their descriptions.

Table 4-1 Repository Data Configuration Tags

Configuration Tag Attributes Description

RepositoryModel

 

Encloses all types of work items used for this connector.

 

resName

Name of the resource bundle. It is used as a name space to identify runtime labels based on the symbols specified.For example, label="${res.ISSUE_PROJECT}" will be resolved in runtime to "Project" if EN is the current JDeveloper locale, if ISSUE_PROJECT is defined as "Project" in EN.

 

resFile

Path of the resource bundle file for the connector.

Workitem

data-source

Refers to backend repository source. It could be a database table.

 

id-def

Field use to uniquely identify a work item. In most cases, it is the work item's ID or NO.

 

subject-def

Field used as a Subject field during tagging a work item or creating relationship between work items.

 

Type

The work item's type or category. Since you can specify multiple work items with different type in the connector model definition file, the work item's type is used to construct a URL editor for the work item at runtime. The type is also showed in certain UI elements, like right mouse menu items in various work item's pages.

 

xmlns

XML name space.

 

version

Version of the model definition file.

Fields

 

Encloses all fields used for the repository object

Field

name

Name of the field.

 

label

Display label used for the field in various work item's pages, such as detail UI and query UI.

 

type

Data type of the field. Valid values are "number", "string", "date". Default = string.

 

required

If set to true, an asterisk (*) will show up before the field label to indicate the field is a required field. Default = false.

 

controlType

For information on which UI controls to use., see Section 4.2.5, "How to Present Data Declaratively with the Team Productivity Center UI."

 

lovDef

Name of an LOV definition to use if the controlType is "lov". See LovDefs.

 

readonly

If set to true, the corresponding control is grayed out and the field value is in read only mode. Default = false.

 

queryable

If set to true this field will appear inside the field combo box on the query form. Default = true.

 

maxLength

This sets the maximum characters that can be entered into the field.

LovDefs

 

Encloses all List of Value (LOV) definitions used for the repository fields.

LovDef

 

Definition of an LOV.

 

name

Name of the LOV.

 

list-source

Name of a data source to use for retrieving its data. See DataSource.

DataSources

 

Encloses all data sources used by LOVs.

DataSource

 

Definition of a data source.

 

name

Name of a data source.

 

id-def

Object type or table name in the backend repository.

QueryListColumns

 

List of default columns to show in the query result list.

WebResource

 

Section that describes the fields that are hyperlinked.

URLDef

 

A child of WebResource. Describes each field that can be a hyperlink.

 

name

The name of the field from the field list.

 

archorOn

Whether the underlined hyperlink should be on the label or the actual value. Valid values are "label" or "field". Default = field.


4.1.8 How to Add Listeners to the Connector

The workitem.properties file is what Team Productivity Center uses to store the listeners (java class to invoke when any event happens regarding work item). Edit this file to include specific listeners that your connector relies on for user input.

When building your connector extension, make sure the workitem.properties file is included in your connector bundle.

4.2 Creating Oracle Team Productivity Center Connectors

The Team Productivity Center connector begins as a JDeveloper extension project. It uses a configuration file (in XML) to store and manage parameters for creating the connector instance. The connector also defines the data used by the repository so that JDeveloper can interpret it, retrieves data from the repository, and uses the Team Productivity Center UI for presenting data within JDeveloper. The remaining sections provide more details on each task and show sample code for implementing the WorkItemConnector interface.

4.2.1 How to Create an Oracle Team Productivity Center Connector

Team Productivity Center connectors are created as JDeveloper extensions. This allows them to integrate with JDeveloper and also provides a framework for packaging and distributing the connector through the JDeveloper Check for Updates feature, once the connector development is completed. This provides a well-known mechanism for distributing connectors to your development team.

The following steps provide an overview of the process of creating an Oracle Team Productivity Center connector. Details of many of the procedures listed here are available in the Oracle® Fusion Middleware User Guide for Oracle JDeveloper.

To create an Oracle Team Productivity Center connector:

  1. Create an JDeveloper Extension Project to build the connector.: select File > New > All Features > Client Tier > Extension Development.

  2. Write the connector configuration XML file. You need to provide connector configuration parameters to be used by the Team Productivity Center installer. The parameters will be treated as seed data and entered into the Team Productivity Center database. They will be used at runtime when creating an instance of the connector.

    For more information, see Section 4.2.2, "How to Create an Oracle Team Productivity Center Connector Configuration File."

  3. Determine what object types will be exposed to Oracle Team Productivity Center. For example, the writer of an MS Project Server connector may decide to show task, project, and resource data, so there will be three object types.

  4. Write the repository object definition XML file. This file provides field details on each object type, default label, default UI control type to use, whether it is required, etc.

    For more information, see Section 4.1.7, "How to Define Team Productivity Center Repository Data."

  5. If you are using specific listeners, add them to the workitem.properties file and make sure that file is included in the connector bundle.

    For more information, see Section 4.1.8, "How to Add Listeners to the Connector."

  6. Write the connector UI layout XML file. This lets you lay out the UI by using UI tags provided by the Team Productivity Center declarative UI framework.

  7. Create a class that implements WorkItemConnector and (optionally) WorkItemAttachment interface methods. This class will use the appropriate APIs available from the backend repository to establish a connection, send and receive repository data, and convert the data to work item format that Team Productivity Center uses.

  8. Provide context-sensitive help files. The help file is loaded by the JDeveloper Help Center when the user presses F1 with the work item detail UI in focus.

    For more information, see Section 4.4.1, "How to Add Help to the Team Productivity Center Connector."

  9. Provide resource bundle files for multi-language support.

    For more information, see Section 4.5.4, "How to Generate the Connector Bundle File."

  10. Package the connector into the appropriate ZIP format for deployment.

The remaining sections provide more details on each task and show sample code for implementing the WorkItemConnector interface.

4.2.2 How to Create an Oracle Team Productivity Center Connector Configuration File

The connector configuration XML file contains the parameters used when creating a runtime connector instance. The parameters can be set at the team level or at the server level. Oracle Team Productivity Center Installer reads in this configuration file during installation and populates seed data to Team Productivity Center database tables.

The connector.xml file will need to be created so that you can add parameters for connector that the team leader or administrator can define values for.

To create the connector.xml file:

  1. Right-click on your extension project in the Application Navigator.

  2. Select New > XML > XML Document.

  3. Name this file connector.xml and save it under your project in the src/META-INF folder.

This configuration file uses tags defined the connector.xsd file, which is located in the almcommon-api.jar file. You can find this JAR file under your JDeveloper install folder: \jdeveloper\jdev\extensions\oracle.teamproductivitycenter\lib

Example 4-2 contains an example of a configuration file:

Example 4-2 Configuration file sample code

<?xml version="1.0" encoding="UTF-8"?>
<ConnectorDefinition xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                     xsi:schemaLocation="http://www.oracle.com/alm connector.xsd"
                     xmlns="http://www.oracle.com/alm/">
  <configuration id="Sample"
                 className="oracle.sampleconnector.model.SampleConnectorService"
                 repositoryType="Work Item"
                 uiFileName="/META-INF/SampleUI.xml"
                 modelFileName="/META-INF/SampleDef.xml"
                 version="1.0">
    <parameter>
      <name>SampleParam1</name>
      <defaultValue>Default value 1</defaultValue>
      <label>
        <locale>US</locale>
        <value>Sample Param 1</value>
      </label>
      <description>This is the sample admin param one</description>
      <accessLevel>ALM-Admin</accessLevel>
    </parameter>
    <parameter>
      <name>SampleParam2</name>
      <defaultValue>Default value 2</defaultValue>
      <label>
        <locale>US</locale>
        <value>Sample Param 2</value>
      </label>
      <description>This is the sample admin param two</description>
      <accessLevel>ALM-Admin</accessLevel>
    </parameter>
    <parameter>
      <name>SampleTeamParam</name>
      <defaultValue>Sample Team Param</defaultValue>
      <label>
        <locale>US</locale>
        <value>Sample Team Param</value>
      </label>
      <description>This is a sample team parameter</description>
      <accessLevel>Team-Admin</accessLevel>
    </parameter>
  </configuration>
</ConnectorDefinition>

Table 4-2 lists the tags used and their descriptions.

Table 4-2 Tags used in connector.xml

Configuration Tag Attributes Description

configuration

id

Name of the connector

 

className

Connector class to load when creating a connector instance during runtime.

 

uiFileName

Path to a file inside the connector jar file that contains the connector UI definitions

 

modelFileName

Path to a file inside the connector jar file that contains the connector model definitions

 

version

Current connector version. Any new/upgrade connector package should use a new version.

parameter

 

Specifies each of configurable parameters

name

 

Parameter name

label

 

Display text to use in the Team Administration UI (or Admin UI)

locale

 

Localization support

value

 

Value for the specified locale

description

 

A brief description of what this parameter does. It will be displayed in the Admin UI

accessLevel

 

ALM-Admin - indicates that this parameter can be configured only by a TPC Administrator in the Admin UI > Repositories tab

Team-Admin - indicates that this parameter can be configured by a Team Administrator in the Admin UI > Teams > Repositories tab


4.2.3 How to Use Customized Listeners and Managed Beans

Developers of connectors for Team Productivity Center can provide connector-specific functionalities by customizing the work item UI control behavior.

Team Productivity Center provides a connector level configuration file, tpc-config.xml, for registering all metadata resources. This file should be put under src/META-INF/ in the connector source code directory.

For details on the tags and attributes supported in the configuration file, see the Oracle Fusion Middleware Tag Reference for Oracle Team Productivity Center Connectors.

To write a custom managed bean:

When you write a connector for Team Productivity Center, you can write a customized managed bean for any value binding support, as shown in the following steps.

  1. Register a managed bean entry in the file tpc-config.xml, as shown in Example 4-3:

    Example 4-3 Register a Managed Bean Entry

      <managed-bean>
          <name>labelBean</name>
              <impl-class>oracle.alm.sample.resbean.LabelBean</impl-class>
              <lifecycle>page</lifecycle>
      </managed-bean>
    
  2. Implement the LabelBean, as shown inExample 4-4:

    Example 4-4 LabelBean Implementation

    public class LabelBean
    {
       public LabelBean(){}
       public String getLabel()
          {
               return _label;
              }
       public  void setLabel(String label)
        { 
              _label = label;
            }
       String _label = "test label";
    }
    
  3. Use the managed bean in either the work item definition metadata file (for a work item field, for example), or a label attribute for a UI control in the UI metadata file:

    label="${labelBean.label}"

To write a customized UI listener:

You can also write a customized UI listener and register it for a control in the work item UI metadata by performing the following steps:

  1. Register the listener in tpc-config.xml as shown in Example 4-5:

    Example 4-5 Registering the Listener

      <managed-bean>
        <name>opentask </name> 
        <impl-class>oracle.alm.sample.view.OpenTaskListener </impl-class>
        <lifecycle>page </lifecycle>
      </managed-bean>
    
  2. Implement OpenTaskListener class:

    Example 4-6 Implementing Class OpenTaskListener

    package oracle.alm.sample.view;
     
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
     
    import java.util.List;
     
    import oracle.alm.connector.data.WorkItem;
    import oracle.alm.view.application.ViewManager;
    import oracle.alm.view.context.AlmELContext;
    import oracle.alm.view.model.AlmDataTableModel;
    import oracle.alm.view.uicomponents.AlmComponent;
    import oracle.alm.view.uicomponents.AlmContextMenuComponent;
    import oracle.alm.view.uicomponents.AlmTableComponent;
    import oracle.alm.view.uicomponents.RenderingContext;
     
    public class OpenTaskListener
      implements ActionListener, AlmScope
    {
      public OpenTaskListener(RenderingContext rcontext, AlmComponent component)
      {
       super();
       _rcontext = rcontext;
       _component = component;
      }
      
      public void actionPerformed(ActionEvent e)
      {
        if (_component instanceof AlmContextMenuComponent)
        {
          AlmComponent parent = _component.getParent();
          if (parent instanceof AlmTableComponent)
          {
            AlmTableComponent tableComp = (AlmTableComponent) parent;
            List<Integer> rows = tableComp.getSelectedRows();
            if (rows != null)
            {
              ViewManager vmanger = ViewManager.getInstance(); 
              for (int row: rows)
              {
                AlmELContext elcontext = vmanger.getELContext(_rcontext);
                AlmDataTableModel dataModel = tableComp.getValue(elcontext);
                Object selectedValue = dataModel.getSelectedItem(row);
                if (selectedValue instanceof WorkItem) 
                {
                  String wiType = _rcontext.getCurrentWorkItemType();
                  String reposName = _rcontext.getCurrentReposName();
                  String reposId = _rcontext.getCurrentReposId(); 
                  vmanger.OpenWorkItemInEditor(((WorkItem) selectedValue),
                                               wiType, reposName, reposId);
                }
              }
            }
          }
        }
      }
      public void setRenderingContext(RenderingContext rc){_rcontext = rc};
      public RenderingContext getRenderingContext(){return _rcontext};
      public void setSourceComponent(AlmComponent component) {_component = component};
      public AlmComponent getSourceComponent() {return _component};
      private RenderingContext _rcontext;
      private AlmComponent _component;}
    
  3. Use the customized listener in the work item UI metadata:

    Example 4-7 Using customized listener in a work item

    <?xml version="1.0" encoding="windows-1252" ?>
    <regions resFile="/META-INF/res/uiresources.xml">  
    <region id="Default" helpTopicId="f1_connector_sample_htm">
        <formLayout columns="1" blockSize="10" fieldWidth="400">
          <inputText label="#{workitemmodel.labels.TASKID}" 
                 value="#{workitemmodel.values.TASKID}" readOnly="true"/>          
          <inputText label="#{workitemmodel.labels.DESC}"
                 value="#{workitemmodel.values.DESC}"/> 
          <listOfValues label="#{workitemmodel.labels.OWNER}" 
                 value="#{workitemmodel.values.OWNER}" 
                 source="OWNER" pprTargets="statusID"/>
          <comboBox label="#{workitemmodel.labels.STATUS}"
                 value="#{workitemmodel.values.STATUS}"
                 valueSet="#{workitemmodel.listItems.STATUS}"
                 readOnly="true" id="statusID"/>
          <inputDate label="#{workitemmodel.labels.DUEDATE}"
                 value="#{workitemmodel.values.DUEDATE}"/>
          <inputText label="#{workitemmodel.labels.URL}" 
                 value="#{workitemmodel.values.URL}"/> 
        </formLayout>
        <panelLayout>
          <action text="Open Task" actionListener="${opentask}"/>
        </panelLayout>
      </region>
    </regions>
    

To customize context menu action:

You can add customized menu items when the user clicks the right mouse button on the query result table. Perform the following steps:

  1. Register the listener in tpc-config.xml and specify the menu item details:

    Example 4-8 Register the Listener, With Details

      <managed-bean>
      <name>savetask</name>
      <impl-class>oracle.alm.sample.model.SaveTaskListener</impl-class>
      <lifecycle>page</lifecycle>
      </managed-bean>
      <contextMenuDef>
      <menuItemDef label="Save" listenerRef="savetask"/>
      </contextMenuDef>
    
  2. Implement SaveTaskListener class:

    Example 4-9 Implementing class SaveTaskListener

    package oracle.alm.sample.model;
     
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.List;
    import javax.swing.JOptionPane;
    import oracle.alm.connector.data.WorkItem;
    import oracle.alm.view.application.ViewManager;
    import oracle.alm.view.context.AlmELContext;
    import oracle.alm.view.model.AlmDataTableModel;
    import oracle.alm.view.uicomponents.AlmComponent;
    import oracle.alm.view.uicomponents.AlmContextMenuComponent;
    import oracle.alm.view.uicomponents.AlmTableComponent;
    import oracle.alm.view.uicomponents.RenderingContext;
     
    public class SaveTaskListener implements ActionListener, AlmScope
    {
      public SaveTaskListener(RenderingContext rcontext, AlmComponent component)
      {
       super();
       if (component instanceof AlmContextMenuComponent)  
             _almComponent = (AlmContextMenuComponent) component;  
                     _renderingContext = rcontext;
       }
       
       public void actionPerformed(ActionEvent e)
       {
        ViewManager vmgr = ViewManager.getInstance();
            
            //First get the corresponding AlmTableComponent
            AlmComponent parent = _almComponent.getParent();
            if (parent instanceof AlmTableComponent)
            {
               AlmTableComponent tableComp = (AlmTableComponent) parent;
            //Then call public API on tableComp to get selected rows
            List&l;Integer> rows = tableComp.getSelectedRows();
            
            if (rows != null)
             {
              int row = rows.size();
              String cs = "";
              if (row == 1)
              { 
                //show the ID and subject of the selected item
                    //Then get the selected value object throw the tableComp's UI model.
                    ViewManager vmanger = ViewManager.getInstance(); 
                    AlmELContext elcontext = vmanger.getELContext(_renderingContext);
                    AlmDataTableModel dataModel = tableComp.getValue(elcontext);
                    Object selectedValue = dataModel.getSelectedItem(row);
                    if (selectedValue instanceof WorkItem)
                    {
                         cs = "Save Task listener: work item ";
                             WorkItem wi = (WorkItem)selectedValue;
                             cs += wi.getRowKey() + " with subject \'";
                             cs += wi.getSubject() + "\' has been selected.";
                    }
              }
              else if (row > 1)
              {
                //show the number of rows selected
                    cs = "Save Task listener: " + Integer.toString(row) + " rows selected";
                    }
                    JOptionPane.showMessageDialog(vmgr.getIDEMain(), cs);
              }
            }
      }
    public void setRenderingContext(RenderingContext rc){_ renderingContext = rc};
    public RenderingContext getRenderingContext(){return _ renderingContext };
    public void setSourceComponent(AlmComponent component) {_almComponent = component};
    public AlmComponent getSourceComponent() {return _almComponent };
     
    AlmContextMenuComponent _almComponent;
    RenderingContext _renderingContext;
    }
    

4.2.4 How to Access Connector Data Through a Firewall

If the connector needs to use the HTTP protocol to fetch data through a firewall that JDeveloper is running behind, the following special modifications are required.

  1. In JDeveloper, select Tools > Preferences.

  2. In the Preferences dialog, open the Web Browser and Proxy node.

  3. Check the Use Proxy check box and enter the values for Host Name, Port, and Exceptions.

  4. The connector writer needs to set the proxy configuration for its HttpClient inside the connector code where it needs to fetch data (for example, inside the getQueryResult() API).

    Example 4-10 Set Proxy Configuration Inside Connector Code

      HttpClient httpclient = new HttpClient();
      String proxyHost = System.getProperty("http.proxyHost");
      String proxyPort = System.getProperty("http.proxyPort");
      Boolean useProxy = null;
     
      if (proxyHost != null && !proxyHost.isEmpty()&&
          proxyPort != null && !proxyPort.isEmpty())
      {
        String proxyExceptions = System.getProperty("http.nonProxyHosts");
        useProxy = (proxyExceptions == null);
        if (!useProxy)
        {
          String host = "";
          try
          {
            URL url = new URL(getServerURL());
            host = url.getHost();
            useProxy = true;
          }
          catch (Exception e)
          {
            e.printStackTrace();
          }
     
          proxyExceptions = proxyExceptions.replace("*", ".*");
          useProxy = (Pattern.matches(proxyExceptions, host) == false);
        }
      }
     
      if (useProxy != null && useProxy.equals(Boolean.TRUE))
            httpclient.getHostConfiguration().setProxy(proxyHost, Integer.parseInt(proxyPort));
    

4.2.5 How to Present Data Declaratively with the Team Productivity Center UI

Oracle Team Productivity Center has a framework that supports declarative UI for any connector. Connector writers can use the UI tags defined in workitem-ui.xsd to lay out the work item UI. Basic UI elements like input text, radio buttons, combo box, checkbox, pick list or List-Of-Values (LOV), are all supported.

This step defines the XML data objects to hold the UI definition in order to show your repository objects to the user. The name of this file must be specified in the connector.xml file as the uiFileName. You can create this UI file and put it in under your project in the src/META-INF folder.

workitem-ui.xsd is located in the file almcommon-api.jar.

By using the pre-defined controlType defaults in the model definition, the UI can be laid out easily by simply using a formLayout component that automatically picks up the control tags from the model. This section shows several examples of how this can be done.

Example 4-11 Simple Method for Displaying Work Item UI Page

<?xml version="1.0" encoding="windows-1252" ?>
<regions resFile="/META-INF/res/uiresources.xml">
  <region name="Easy" helpTopicId="f1_connector_sample_htm">
    <formLayout value="${workitemmodel}" columns="1" blockSize="10"/>
  </region>
</regions>

Table 4-3 UI tags used in preceding example

UI Tag Attributes Description

Regions

 

Encapsulation of all UI regions used

 

resFile

Specifies the resource bundle file to use for multi language support

Region

 

One page layout identified by its name attribute

 

helpTopicId

Tells JDeveloper which help file name to use (from within the connector jar file)

formLayout

value

It has value of "${workitemmodel}", which will be resolved at runtime to an appropriate connector model.

 

columns

This sets the number of columns to lay out the form into.

 

blockSize

This means after every blockSize rows a line separator will be added

 

rowToSpan

Tells which row(s) from the model will span to the entire row of the page. If it is "1, 3, 5" then the 1st, 3rd, and 5th rows will span the entire row of the page.


To show a UI page using an explicit layout:

This example shows the same UI as in Example 4-11, but uses an explicit layout instead. This is necessary if you have multiple UI views of the same data model. For example, you would like only a subset of the fields to be visible when creating a new instance of an object but as soon as it is saved, all the fields become visible.

Example 4-12 Explicit Layout for UI page

<?xml version="1.0" encoding="windows-1252" ?>
<regions resFile="/META-INF/res/uiresources.xml">
  <region name="Default" helpTopicId="f1_connector_sample_htm">
    <formLayout columns="1" blockSize="10" >
        <inputText label="#{workitemmodel.labels.TASKID}" 
                   value="#{workitemmodel.values.TASKID}" 
                   readOnly="true"/>
        <inputText label="#{workitemmodel.labels.DESC}" 
                   value="#{workitemmodel.values.DESC}"/>
        <listOfValues label="#{workitemmodel.labels.OWNER}" 
                   value="#{workitemmodel.values.OWNER}"
                   srcAttr="OWNER"
                   lovDef="#{workitemmodel.lovDefs.OWNER}"/>
  <comboxBox label="#{workitemmodel.labels.STATUS}" 
                   value="#{workitemmodel.values.STATUS}"
                   valueSet="#{workitemmodel.listItems.STATUS}"/>      
  <inputDate label="#{workitemmodel.labels.DUEDATE}" 
                   value="#{workitemmodel.values.DUEDATE}"/>
        <inputText label="#{workitemmodel.labels.URL}" 
                   value="#{workitemmodel.values.URL}"/>
    </formLayout>
  </region>
</regions>

Table 4-4 Control types

UI Tag Attributes Description

inputText

label

Field label to show in the UI

 

value

Runtime field value

 

required

Determines if it is required.

 

readOnly

Determines if the data can be edited

inputDate

label

Field label to show in the UI

 

value

Runtime field value

 

required

Determines if it is required.

 

readOnly

Determines if the data can be edited

comboBox

label

Field label to show in the UI

 

value

Runtime field value

 

required

Determines if it is required.

 

readOnly

Determines if the data can be edited

checkBox

label

Field label to show in the UI

 

value

Runtime field value

 

required

Determines if it is required.

 

readOnly

Determines if the data can be edited

radio

label

Field label to show in the UI

 

value

Runtime field value

 

required

Determines if it is required.

 

readOnly

Determines if the data can be edited

 

valueSet

Defines where to get the list of values.

listOfValues

label

Field label to show in the UI

 

value

Runtime field value

 

required

Determines if it is required.

 

readOnly

Determines if the data can be edited

 

srcAttr

Defines the source field to use

 

lovDef

Defines the lovDef of the source field

textEditor

label

Field label to show in the UI

 

value

Runtime field value

 

required

Determines if it is required.

 

readOnly

Determines if the data can be edited

 

rows

Number of rows to show

 

required

Determines if it is required.

list

label

Field label to show in the UI

 

value

Runtime field value

 

valueSet

Defines where to get the list of values.


To lay out more complicated UI using panels:

You can also lay out controls using panels for more complicated UI layouts. Panels have the property of being horizontal or vertical. Panels can also be nested.

Example 4-13 Control layout using panels

<?xml version="1.0" encoding="windows-1252" ?>
<regions resFile="/META-INF/res/uiresources.xml">
  <region name="Default" helpTopicId="f1_connector_sample_htm">
                <panelLayout layout=”horizontal”>
    <formLayout columns="1" blockSize="10" >
        <inputText label="#{workitemmodel.labels.TASKID}" 
                   value="#{workitemmodel.values.TASKID}" 
                   readOnly="true"/>
        <inputText label="#{workitemmodel.labels.DESC}" 
                   value="#{workitemmodel.values.DESC}"/>
        <listOfValues label="#{workitemmodel.labels.OWNER}" 
                   value="#{workitemmodel.values.OWNER}"
                   srcAttr="OWNER"
                   lovDef="#{workitemmodel.lovDefs.OWNER}"/>
  <comboxBox label="#{workitemmodel.labels.STATUS}" 
                   value="#{workitemmodel.values.STATUS}"
                   valueSet="#{workitemmodel.listItems.STATUS}"/>      
  <inputDate label="#{workitemmodel.labels.DUEDATE}" 
                   value="#{workitemmodel.values.DUEDATE}"/>
        <inputText label="#{workitemmodel.labels.URL}" 
                   value="#{workitemmodel.values.URL}"/>
    </formLayout>
         <textEditor value="#{workitemmodel.values.BIGDESC}"/>
  </region>
</regions>

Table 4-5 UI tags used in panel example

UI Tag Attribute Description

panelLayout

layout

Specifies the layout direction of the grouping controls. Valid values are vertical and horizontal.


4.2.6 How to Retrieve Data from an Oracle Team Productivity Center Repository

After the model and UI layouts for different work item types are defined, the next step is to implement the methods on the WorkItemConnector interface, and the methods on WorkItemAttachment interface (if the connector supports attachments). This topic provides details on these methods.

Before you can implement these methods, you need to add the location of the Team Productivity Center JAR files to your project so you can pick up the appropriate classes for the WorkItemConnector and WorkItemAttachment interfaces.

To add the location of Team Productivity Center JAR files to your project:

  1. Double-click on your extension project, and then select Project Properties > Libraries and Classpath.

  2. On the right side, select Add JAR/Directory.

  3. Navigate to where you installed JDeveloper. Under the JDev/Extensions/oracle.teamproductivitycenter/lib folder, locate the file almcommon-ip.jar and include that.

4.2.6.1 Implementing the WorkItemConnector Interface

Now that the JAR is added, you can implement the interfaces for the WorkitemConnector.

To implement the interface:

  1. Select File > New.

  2. Select General > Java > Java Class.

  3. In the Create Java Class wizard, enter your class and package name.

  4. In the Optional Attributes section, click the plus to implement an interface.

  5. In the Class and Package Browser, select the Hierarchy tab and then find the following class: oracle/alm/connector/WorkItemConnector. If you intend to implement the WorkItemAttachment interface, select that also using the CTRL key.

  6. Click OK.

This will provide you with a skeleton file that has all the methods that you must implement.

Table 4-6 Method Summary

API
Description

void

init(Map sessionContext)

Initializes the connector instance on the client side, and builds the connector's physical connection parameters for its corresponding repository

void

login(Map sessionContext, String userID, String password)

Establishes a user connection between the connector instance on the client side and the backend repository

void

logout(Map sessionContext)

Disconnect the user from the backend repository. State can be saved using the data hash structure.

Void

setWorkItemDefs(Map sesion, Map<String, WorkItemDef> wiDefs)

Framework constructs the runtime data structures for the work item types defined in the connector model definition

List<WorkItem>

getQueryResult(Map sessionContext, String wiType, QueryInfo query)

Retrieves the query result set that satisfies the query criteria defined by QueryInfo

WorkItem

getWorkItem(Map sessionContext, String wiType, WorkItem workItem)

Retrieves a specific work item by its type and unique identifier

void

updateWorkItem(Map sessionContext, String wiType, WorkItem workItem)

Updates an existing work item by its type and unique identifier

void

createWorkItem(Map sessionContext, String wiType, WorkItem workItem)

Creates a new work item on its backend repository for the specified type

 

deleteWorkItem(Map sessionContext, String wiType, WorkItem workItem)

Deletes a work item from its backend repository

List<Row>

getLOVQueryResult(Map sessionContext, QueryInfo query, String fieldName)

Retrieves the value set for a predefined LOV (List of Value)

boolean

IsAttachmentSupported (Map sessionContext, WorkItem wi)

Determines if attachment is supported for the specified work item. If yes, the work item model needs to implement the WorkItemAttachment interface.

String

getUIRegionName(Map sessionContext, String wiType, WorkItem wi)

Retrieves the region name defined in the connector UI XML

boolean

hasDynamicUI(Map session)

If the connector supports dynamic UI, returns true

String

getDynamicUI(Map session, String currentUI)

Retrieves the new work item UI definition XML string

boolean

hasDynamicModel(Map session)

If the connector supports dynamic model, returns true

String

getDynamicModel (Map session, String currentModel)

Retrieves the new work item model definition XML string


4.2.7 How to Refresh Work Item Detail Based on Custom Actions

In certain scenarios, the work item detail page needs to be refreshed to a new layout based on some custom action in the existing layout. For example, users may make a new value selection from a combo box, or a date change from a date time picker, or just simply clicking a button in the page.

When a task is shown in its detail editor, there is a "Status" combination box in its base UI:

Figure 4-1 Status combination box in UI

Status combination box in UI

When the value of the status is changed from New to In-Progress, a new layout is shown with a rich text control that lets the user provide information on the status progress.

Figure 4-2 New rich text control for status UI

New rich text control for status UI

When the user finishes editing the work item and clicks Submit, the confirmation page shows with success or failure message.

Figure 4-3 Confirmation page after using rich text control

Confirmation page after using rich text control

To show the updated task detail page, click Return to Home.

To implement the functionality:

  1. Decide which UI control to use as the action source to trigger dynamic UI change, and which listener to control the UI interaction.

  2. Define new UI regions in the work item UI layout meta data file.

  3. Implement the corresponding listener in managed bean.

  4. Implement API getUIRegionName() to return different UI region based on different condition.

  5. Register the managed bean in the connector's tpc-config.xml file.

  6. Use the bean in the UI metadata through EL expression.

The following sections provide more detail using the sample connector.

4.2.7.1 Decide UI control and listener attribute

The sample connector uses the combination box control for the "status" field as the action source. It also uses the PopupMenuListener on the combo box control to listen to the selection change and to do dynamic update UI work. It also uses the Submit button to navigate between the task detail page and the confirmation page layout.

The configuration detail is in the SampleDef.xml file. Note in the following example how the status combination box and submit action are defined with their corresponding attribute name and value pairs.

Example 4-14 UI control and listener attribute selection

<?xml version="1.0" encoding="windows-1252" ?>
    <region id="Homepage">
        <formLayout columns="1" blockSize="10" fieldWidth="400" labelWidth="60">
            <inputText label="#{workitemmodel.labels.PARENT_TASKID}" 
                              value="#{workitemmodel.values.PARENT_TASKID}" readOnly="true"/>            
            <inputText label="#{workitemmodel.labels.TASKID}" 
                              value="#{workitemmodel.values.TASKID}" readOnly="true"/>            
            <inputText label="#{workitemmodel.labels.DESC}" 
                               value="#{workitemmodel.values.DESC}"/>
            <listOfValues label="#{workitemmodel.labels.OWNER}" 
                                   value="#{workitemmodel.values.OWNER}" source="OWNER" 
                                   pprTargets="statusID"/>
            <comboBox label="#{workitemmodel.labels.STATUS}" 
                   value="#{workitemmodel.values.STATUS}" id="statusID" 
                   valueSet="#{workitemmodel.listItems.STATUS}" readOnly="true"                          
                   popupMenuListener="#{mainBean.statusListener}"/>
            <inputDate label="#{workitemmodel.labels.DUEDATE}" 
                               value="#{workitemmodel.values.DUEDATE}"/>
            <inputText label="#{workitemmodel.labels.URL}"  
                              value="#{workitemmodel.values.URL}"/>
           <panelLayout>
   <action text="Submit" actionCommand="gotoc                 actionListener="${dynamicBean.actionListener}"/>onfirmpage" 
           </panelLayout>
        </formLayout>        
        <separator/>        
    </region>

4.2.7.2 Define New Regions in UI Metadata File

In addition to the default HomePage region, this code creates two new regions: region "Demo" (shown when status is changed to "in-progress") and region "confirmation" (shown when the user clicks Submit).

Example 4-15 New region definition

<region id="Demo" helpTopicId="f1_connector_sample_htm">
     <formLayout columns="1" blockSize="10" fieldWidth="400" labelWidth="60">
            <inputText label="#{workitemmodel.labels.PARENT_TASKID}" 
                            value="#{workitemmodel.values.PARENT_TASKID}" readOnly="true"/>            
            <inputText label="#{workitemmodel.labels.TASKID}" 
                            value="#{workitemmodel.values.TASKID}" readOnly="true"/>            
            <inputText label="#{workitemmodel.labels.DESC}" value="#{workitemmodel.values.DESC}"/>
            <listOfValues label="#{workitemmodel.labels.OWNER}" 
                                pprTargets="statusID" value="#{workitemmodel.values.OWNER}" source="OWNER"/>
            <comboBox label="#{workitemmodel.labels.STATUS}" 
                                 value="#{workitemmodel.values.STATUS}" 
                                 popupMenuListener="#{mainBean.statusListener}"
                                 valueSet="#{workitemmodel.listItems.STATUS}" readOnly="true" 
                                 id="statusID"/>
            <inputDate label="#{workitemmodel.labels.DUEDATE}" 
                               value="#{workitemmodel.values.DUEDATE}"/>
            <inputText label="#{workitemmodel.labels.URL}" value="#{workitemmodel.values.URL}"/>
            <textEditor label="#{workitemmodel.labels.STATUS_REPORT}" 
                                value="#{workitemmodel.values.STATUS_REPORT}" contentType="html"/>            
            <panelLayout>
                  <action text="Submit" actionCommand="gotoconfirmpage" 
                            actionListener="${dynamicBean.actionListener}"/>
            </panelLayout>
        </formLayout>   
</region>

<region id="confirmation">
     <panelLayout layout="vertical">
        <inputText value="Task has been updated successfully." readOnly="true"/>
        <action text="Return to Home" actionCommand="gotohomepage" 
                               actionListener="${dynamicBean.actionListener}"/>
      </panelLayout>
    </region>

4.2.7.3 How to Implement a Corresponding Listener in a Managed Bean

The listener object on the status combo box (popupMenuListener) is implemented in HomePageBean.java as follows:

Example 4-16 Implementing a listener in a managed bean

  public PopupMenuListener getStatusListener()
  {
    if (statusListener == null)
    {
      statusListener = new PopupMenuListener()
        {
          public void popupMenuWillBecomeInvisible(PopupMenuEvent e)
          {
            JComboBox src = (JComboBox) e.getSource();   
            Object[] selected = (Object[])src.getSelectedItem();
            if(selected == null)
              return;

            String value = (String)selected[1];
            if (value != null && value.contains("Progress"))
            {
               _rcontext.getConnectorParams().put("navigatorpage", "D");
            }
            else
              _rcontext.getConnectorParams().put("navigatorpage", "H");
            //we just need to refresh the current page;
            ViewManager vm = ViewManager.getInstance();
            if(vm != null)
              vm.refreshWorkItemDetailUI(_rcontext);
          }
          public void popupMenuCanceled(PopupMenuEvent e)
          {
          }
          public void popupMenuWillBecomeVisible(PopupMenuEvent e)
          {
          }
        };
    }
    return statusListener;
  }

The listener object on the Submit button (actionListener) is implemented in the DynamicRegionBean as follows:

Example 4-17 Implementing listener on Submit button

  public ActionListener getActionListener()
  {
    if (actionListener == null)
    {
      actionListener = new ActionListener()
        {
          public void actionPerformed(ActionEvent event)
          {
            String command = event.getActionCommand();
            ViewManager vm = ViewManager.getInstance();
            if (command != null && command.equals("gotohomepage"))
            {
              _rcontext.getConnectorParams().put("navigatorpage", "H");
            }
            else if (command != null && command.equals("gotowelcomepage"))
            {
              _rcontext.getConnectorParams().put("navigatorpage", "W");
            }
            else if (command != null && command.equals("gotodemopage"))
            {
              _rcontext.getConnectorParams().put("navigatorpage", "D");
            }

            vm.refreshWorkItemDetailUI(_rcontext);
          }
        };
    }

4.2.7.4 Guideline for implementing the managed bean

All managed beans should implement the AlmScope interface. Oracle Team Productivity Center uses AlmScope to synchronize the renderingContext and the corresponding AlmComponent for the UI control that uses the managed bean.

There are two ways to pass information from connector Managed Bean layer so it can be used in other connector classes:

  • Through RenderingContext

    Parameter name value pairs can be put at the connector session level. To review the code shown in the previous example:

    Example 4-18 Parameter name value pairs at connector session level

    _rcontext.getConnectorParams().put("navigatorpage", "H");
    

    This information can be retrieved inside other connector classes as shown here:

    Example 4-19 Retrieving information inside other connector classes

    Map params = (Map) session.get(WorkItemConnector.SESSION_PARAMS_KEY);
    
  • Through the current work item object

    The current work item object can be accessed through the ViewManager class:

    Example 4-20 Accessing work item through ViewManager class

    public   WorkItem getCurrentWorkItem(RenderingContext rcontext);
    

    Inside the managed bean class, you can modify the work item's submit values. Then other connector classes can use it to process logic based on different field values.

Use ViewManager APIs to refresh the work item detail page.

Example 4-21 Refreshing the work item detail page

public void refreshWorkItemDetailUI(RenderingContext rcontext);

This API triggers the call to getUIRegionName(), which returns new region name based on connector parameter or work item field values. For example, the sample connector uses a parameter to return a new region name:

Example 4-22 Using a parameter to return a new region name

  public String getUIRegionName(Map session, String wiType, WorkItem workItem)
    throws ALMException
  {
    String region = "";

    Map params = (Map) 
session.get(WorkItemConnector.SESSION_PARAMS_KEY);
    if (params != null)
    {
      Object val = params.get("navigatorpage");
      if (val == null || val.equals("H"))
        region = "Homepage";
      else if (val != null && val.equals("W"))
        region = "Confirmation";
      else if (val != null && val.equals("D"))
        region = "Demo";
    }

    return region;
  }

4.2.7.5 Register the Bean class in tpc-config.xml

Register the managed bean DynamicRegionBean with the name UIBean inside the file tpc-config.xml as follows:

Example 4-23 Registering the bean class in tpc-config.xml

<?xml version="1.0" encoding="windows-1252" ?>
<!-- TPC Configuration file -->
<tpc-config version="11.1.1.1.0" xmlns="http://fusion.oracle.com/tpc">
  <managed-bean>
    <name>mainBean</name>
    <impl-class>oracle.sampleconnector.view.mbean.HomePageBean</impl-class>
    <lifecycle>page</lifecycle>
  </managed-bean>
  <managed-bean>
    <name>dynamicBean</name>
    <impl-class>oracle.sampleconnector.view.mbean.DynamicRegionBean</impl-class>
    <lifecycle>page</lifecycle>
  </managed-bean>
  <managed-bean>
    <name>compBean</name>
    <impl-class>oracle.sampleconnector.view.mbean.ComponentBean</impl-class>
    <lifecycle>page</lifecycle>
  </managed-bean>
</tpc-config>

4.2.8 How to Open a New Editor Inside JDeveloper

On a work item detail page, the connector writer can create a link that, when clicked, opens a new Team Productivity Center-specific editor. For example, a Bugzilla bug has a field "Depends On," which may hold a bug number for another bug. The Bugzilla connector writer can create a link on the label. When clicked, a new editor opens up inside JDeveloper showing the details of that bug.

Team Productivity Center uses alm as the resource protocol and supports these URL formats:

  • Work item

    alm:/reposName/workitemType/workitemId.wid

  • Team query

    alm:/reposName/workitemType/Team Queries/queryName.wiq

  • User query

    alm:/reposName/workitemType/My Queries/queryName.wiq

  • Generic page

    alm:/path/filename.tpcx?repository=reposName&…..

Note that for a generic page, the connector writer needs to do the following:

  1. Put UI page files directly under the /META-INF/pages folder in the connector source code tree. This is because /META-INF/pages is set as the default DOC_HOME in the TPC framework.

  2. Attach repository=reposName as a parameter to the URL.

For example, if the URL used in the sample connector is alm:/component/component.tpcx?repository=SampleConnector&component=inputDate, then there should be a component.xml file under the /META-INF/pages/component folder.

To open a new editor:

Using these URLs, there are two different ways to open a Team Productivity Center-specific editor:

  1. Use OpenTPCPageInEditor () API on ViewManager:

    Example 4-24 Using the OpenTPCPageInEditor() API

    ViewManager vm = ViewManager.getInstance();
    vm.OpenTPCPageInEditor("/component/component.tpcx?
    repository=SampleConnector&component=inputDate");
    

    Similarly, this will open a specific work item editor:

    Example 4-25 Opening a specific work item editor

    ViewManager.getInstance().OpenTPCPageInEditor
     ("reposName/workitemType/workitemId.wid");
    
  2. Use the WebResource tag

    Using the sample connector as an example, there is a field "Parent ID" where its value portion is a link. When clicked, the work item editor for the parent task opens up. To achieve this, follow these steps.

    • Use the WebResource tag to define the field that can generate the URL in connector definition file:

      Example 4-26

      <RepositoryModel resName="res" resFile="/META-INF/res/modelresource.xml">
        <WorkItem type="Task"    
                          webURLHandler="oracle.sampleconnector.SampleConnectorService">
          <Fields>
            <Field name="PARENT_TASKID" label="${res.PARENT_TASK_ID}" type="number"   
                      readOnly="true"/>
            <Field name="TASKID" label="${res.TASK_ID}" type="number" readOnly="true"/>
            <Field name="DESC" label="${res.TASK_DESC}" required="true"
                maxLength="80" type="string"/>
       ……
          <Fields/>
          <WebResource>
      <URLDef name="PARENT_TASKID" archorOn="label"/>
      ……
          </WebResource>
      ……
        <WorkItem/>
      <RepositoryModel/>
      

      The valid values for the attribute archorOn are "label" and "value". If the attribute value is "label" the field label becomes a hyperlink. Otherwise the value acts as a hyperlink.

    • Implement the getURL() API on WorkItemFieldFeature interface

      Class SampleConnectorService implements the method on this interface. The getURL() method constructs the URL for the parent task field.

      Example 4-27

        public URL getURL(Map session, String attrName, Object attrValue, WorkItem wi)
        {
          String urlString = "";
          if (attrName.equalsIgnoreCase("PARENT_TASKID"))
          {
            Integer taskid = (Integer) attrValue;
            String reposName = (String)session.get("repositoryName");
            String wiType = (String)session.get("wiType");
      
            if(reposName != null && wiType != null)
              urlString = "alm:/" + reposName + "/" + wiType + "/" + taskid + ".wid";
          }
      
          try
          {
            return new URL(urlString);
          }
          catch (MalformedURLException e)
          {
            System.out.println(e);
          }
          return null;
        }
      
    • In the connector definition file, find the work item section and put the class name as the value for attribute webURLHandler. See the sample code in the first bullet.

      When the value for anchorOn is set to "label", the UI metadata for the corresponding work item field should be set to an "input" field, such as inputText, inputDate, or ListOfValues.

      When the value for anchorOn is set to "value", the UI metadata for corresponding work item field should be set to read-only inputText.

4.2.9 How to Debug an Oracle Team Productivity Center Connector

Once you have developed your connector, you will want to be able to run your connector inside of the debugger during execution. This capability is built into your project already.

To run your connector inside the JDeveloper debugger:

  • Right-click on your built/deployed project and select Debug Extension.

This launches another copy of JDeveloper from which you can open up Team Productivity Center and connect to an Oracle Team Productivity Center Server that has your connector defined. Then you can set breakpoints in your Java code and step through it while using watch windows for variables and use standard debugging utilities.

4.3 Handling Oracle Team Productivity Center Connector Errors

Once you have developed a connector for use with Oracle Team Productivity Center, there are a number of tasks left to perform. One important task is to handle errors that occur while using the connector. Oracle Team Productivity Center has two ways of propagating errors and messages to the client; they are described here.

You may choose to include help files with your connector, to provide assistance for your team members in using the connector you have developed. You can then view your help in the JDeveloper online help browser or in an external help viewer.

In addition, you will need to package your Oracle Team Productivity Center connector so that it can be downloaded by other team members. This includes compressing the connector into a JAR file and a bundle file. Furthermore, any help files you have created for the connector need to be included in the JAR file.

Oracle Team Productivity Center provides two ways to propagate errors and messages to the Team Productivity Center client:

  • through ALMException used on interface methods

  • through ALMMessage used to queue to ALMMessageFactory

All interface methods throw ALMException when something serious happens inside a connector. You can put an appropriate warning or message with the runtime instance of ALMException. The client framework will show to it the end user.

Example 4-28 Error handling

 try
 {
    connector.hasDynamicUI(session);
    }
 catch(ALMException e) 
 {
    setLastError(e);
 }

You can also use the classes provided in package oracle.alm.common.message to propagate error messages to the client. Two classes are defined in this package.

Table 4-7 Class Summary

AlmMessage

AlmMessageFactory

Manages the connection to the backend repository.


AlmMessageFactory is the class for message registration and access through Team Productivity Center. Use this class and AlmMessage to log any messages to be reported to the client through the UI framework.

AlmMessageFactory is implemented as a singleton. To get an AlmMessageFactory, call:

AlmMessageFactory msgFactory = AlmMessageFactory.getInstance()

To add a message, call AlmMessageFactory.addMessage() by passing the messageID and the associated message string.

4.4 Adding Help to an Oracle Team Productivity Center Connector

You can add custom help files, including context-sensitive help, to an Oracle Team Productivity Center connector. Your users can then access any information they need to help with the operation of setup of your connector.

There are two ways to display connector specific help pages to the users of your connector. The first approach is to show these help pages inside JDeveloper Help Center. The second approach is to show these pages in their own frame on the client's desktop or in a Web browser.

Extensive help is available for the writer of help for a JDeveloper extension, such as the Team Productivity Center connector, in the Developing Help Extensions topic.

4.4.1 How to Add Help to the Team Productivity Center Connector

You can write and display connector-specific help inside the JDeveloper Help Center for your users to refer to. If you implement JDeveloper help as an JDeveloper Help extension, your users will be able to access this help by pressing the F1 key while viewing a dialog in your connector.

To include help for a Team Productivity Center connector:

  1. Provide F1 help files in HTML format for each page that shows in JDeveloper. They should be located in a folder /Help inside the packaged connector JAR file.

  2. Create a new JDeveloper extension that only contains these help files.

  3. Add the connector help ID to the connector UI definition XML file.

    Example 4-29 Connector help ID

      <region name=”Edit” helpTopicId="f1_connector_htm" >
        <formLayout value="${workitemmodel}" 
                    columns="2" 
                    blockSize="6" 
                    id="wiFormId" 
                    rowToSpan="1"/>
      </region>
    

4.4.2 How to View Team Productivity Center Connector Help in an External Viewer

You may choose to present the help for your connector in an external viewer, such as the user's default Web browser or a PDF viewer.

To present connector help in an external viewer:

  1. Provide F1 help files in HTML format for each page that shows. They should be located in a folder called /Help in the packaged connector JAR file.

  2. Create a new JDeveloper extension that only contains these help files.

  3. Add a Help button in the work item detail UI. This can be done by adding a toolbar and one help button on this toolbar in the connector UI definition XML file:

    Example 4-30 Adding a Help button to a toolbar

    <region name=”Edit”>
      <toolbar title="Actions">
        <action text="Help" 
           actionCommand="showHelp"
           icon="HELP"
           actionListener="${showHelp}"/>
      <toolbar/>
      <formLayout value="${workitemmodel}" 
                    columns="2" 
                    blockSize="6" 
                  id="wiFormId" 
                    rowToSpan="1"/>
    </region>
    
  4. Implement the listener object class.

4.5 Packaging Connectors

The final phase of preparing an Oracle Team Productivity Center connector is to package it in JAR files for installation as a JDeveloper extension. This allows you to install the connector on the Team Productivity Center server so that your team members can connect to the repository to which this connector applies.

4.5.1 How to Package Connectors

In order to install your connector onto the server, and so it can be installed as an extension into JDeveloper, it must be packaged correctly. There are three pieces to the packaging:

  1. The JAR file that will contain your connector and all of its required files.

  2. A separate JAR file containing your help files and their required files.

  3. A bundle in ZIP format that will contain the two previous JAR files plus a bundle.xml file to describe how JDeveloper can install this as an extension.

You can create deployment profiles inside of your project to generate all of these files for you.

Before you create any deployment profiles, ensure you have built the project successfully and all output files have been created in the correct directories.

4.5.2 How to Generate the Connector JAR File

The connector JAR file contains all the components of your connector that will be included in the extension dedicated to your connector.

To generate the connector JAR file:

  1. Double-click on your project in the Application Navigator and select Project Properties > Deployment.

  2. Click New.

  3. Select JAR File as your archive type, and then enter a name for your JAR file. Typically this is Connector<your connector name>.JAR

  4. In the Edit JAR Deployment Profile Properties dialog, select Filters. Select all files in the META-INF directory (except Bundle.xml, to be defined soon) and all the files in your package directory.

  5. Click OK.

To test your connector JAR deployment, right-click on your project and select Deploy > <your deploy profile> > to JAR File.

4.5.3 How to Generate the Connector Help JAR File

The Help JAR file will contain everything needed to include Help with your connector extension. JDeveloper extension tools provide an integrated process for generating connector Help JAR files.

To generate a connector Help JAR file:

  1. Double-click on your project in the Application Navigator and select Project Properties > Deployment.

  2. Click New.

  3. Select JAR File as your archive type, and then enter a name for your help JAR file. Typically this is Connector<your connector name>Help.JAR

  4. In the Edit JAR Deployment Profile Properties dialog, select Filters. Select all the help-related files or the directory those are stored in. Deselect all other files.

  5. Click OK.

To test your connector JAR deployment, right-click on your project and select Deploy > <your help deploy profile> > to JAR File.

4.5.4 How to Generate the Connector Bundle File

When the connector JAR file is constructed, you can then prepare to deploy it by generating a bundle file. This is a ZIP file, which you can use to install the connector extension.

To generate a connector bundle file:

  1. Double-click on your project and select Project Properties > Deployment.

  2. Click New.

  3. Select JAR File as your archive type.

  4. Uncheck Include Manifest.

  5. Enter a name for your bundle ZIP file.

    This is typically located in a Bundle folder at the same level as your Deploy folder, and called Connector<your connector name>Bundle.ZIP. Be sure to name it .ZIP instead of .JAR.

  6. In the Edit JAR Deployment Profile Properties dialog, expand the Project Output node, then select Filters.

  7. Rename this to file group to JAR Output. Change the Target Directory in Archive to: oracle.teamproductivitycenter/connectors/<your connector name>. There should be no .JAR at the end. This is the path inside of the ZIP file to extract this file to

    Note:

    The installers are case-sensitive, so make sure the case is correct for your file paths.
  8. Go to the Contributors node under the JAR Output file group. Click Add and add the location where your connector JAR and help JAR files are generated.

  9. Go to the Filters node under the JAR Output file group. Select the connector and connector help JAR files you already generated

  10. Select the File Groups node and click New. Create a new file group called Bundle Output.

  11. Go to the Filters node under the Bundle Output file group and deselect everything except for your bundle.xml file. Make sure the Target Directory in Archive edit box is blank.

  12. Go to the Profile Dependencies node and add the connector and the help deploy profiles as dependencies.

  13. Click OK.

To test your connector bundle ZIP deployment, right-click on your project and select Deploy > <your bundle profile> > to JAR File. This creates a new ZIP file that contains your connector JAR, the help JAR and the bundle.xml file.

4.5.5 How to Define Dependencies in the Connector Bundle File

The bundle.xml file describes what is in an extension and what its dependencies are. It also holds the version information and info about the author.

Example 4-31 Connector bundle file bundle.xml

<update-bundle version="1.0"
    xmlns="http://xmlns.oracle.com/jdeveloper/updatebundle"
    xmlns:u="http://xmlns.oracle.com/jdeveloper/update">
 
  <u:update id="oracle.teamproductivitycenter.sampleconnector">
    <u:name>Oracle Sample Connector</u:name>
    <u:version>1.0</u:version>
    <u:author>Oracle Corporation</u:author>
    <u:author-url>http://www.oracle.com</u:author-url>
    
    <u:description>
      Sample connector for Oracle Team Productivity Center
    </u:description>
 
    <u:requirements>
      <u:requires-extension id="oracle.jdeveloper"
        minVersion="11.1.1.1.00"
        maxVersion="11.1.1.1.99" /> 
      <u:requires-extension id="oracle.teamproductivitycenter"
        minVersion="11.1.1.1.00"
        maxVersion="11.1.1.1.99" /> 
    </u:requirements>
  </u:update>
</update-bundle>

All Team Productivity Center connectors have dependencies on both JDeveloper and Team Productivity Center. These should always be included.

4.6 Team Productivity Center Connector Internationalization

Oracle Team Productivity Center provides support for connectors to show appropriate UI based on the running JDeveloper locale. As seen in the work item UI and model definition XML files, a resource file can be used to store localized strings. For example, if JDeveloper is running in JPN locale, the user may want to see connector detail page in the same locale. To support this, you can create language-specific resource bundle files. Example 4-32 is an example for the modelresource.xml:

Example 4-32 Internationalization file modelresource.xml

<?xml version="1.0" encoding="ISO8859-1" ?>
<resources xmlns="http://xmlns.oracle.com/bali/rts/tpc" package="company.bugzilla.res">
  <resource key="MSG_SAVEBUG_TITLE">BugDB: Save A Bug</resource>
  <resource key="MSG_NEWBUG_TITLE">BugDB: Create A Bug</resource>
  <resource key="MSG_BUGAPI_ERROR">Bug API Error: </resource>
  <resource key="DESCRIPTION">Description</resource>
  <resource key="BUG_NAME">Bug </resource>
  <resource key="BUG_NO">Bug Number</resource>
  <resource key="BUG_BASEBUG_NO">Base Bug No</resource>
  <resource key="BUG_STATUS">Status</resource>
  <resource key="BUG_SUBJECT">Subject</resource>  
  <resource key="BUG_PRODUCT">Product</resource>
  <resource key="BUG_PRIORITY">Severity</resource>  
  <resource key="BUG_COMPONENT">Component</resource>
  <resource key="BUG_SUBCOMPONENT">Sub Component</resource>
  <resource key="BUG_ASSIGNEE">Assigned</resource>
</resources>

And here is an example of the file uiresource.xml:

Example 4-33 Internationalization file uiresource.xml

<?xml version="1.0" encoding="ISO8859-1" ?>
<resources xmlns="http://xmlns.oracle.com/bali/rts/tpc"
           package="company.bugzilla.res">
  <resource key="COMMMENTS">Comments</resource>
  <resource key="ADD_COMMENTS">Add Comments</resource>
  <resource key="UPDATE_COMMENTS">Update Comments</resource>
</resources>

If JDeveloper is running in Japanese, the framework looks for resource bundle files named modelresource_jp.xml and uiresource_jp.xml to find and display labels in Japanese. You can create these files and put them in a central location. Store these resource bundle files under the folder META_INF\res in the connector jar file.