Agile Product Lifecycle Management
SDK Developer Guide - Using Agile APIs
January 2012
v9.3.1.2
Part No. E23880-01
SDK Developer Guide - Using Agile APIs
ii Agile Product Lifecycle Management
Oracle Copyright
Copyright © 1995, 2012, Oracle and/or its affiliates. All rights reserved.
This software and related documentation are provided under a license agreement containing
restrictions on use and disclosure and are protected by intellectual property laws. Except as
expressly permitted in your license agreement or allowed by law, you may not use, copy,
reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform, publish or
display any part, in any form, or by any means. Reverse engineering, disassembly, or decompilation
of this software, unless required by law for interoperability, is prohibited.
The information contained herein is subject to change without notice and is not warranted to be
error-free. If you find any errors, please report them to us in writing.
If this software or related documentation is delivered to the U.S. Government or anyone licensing it
on behalf of the U.S. Government, the following notice is applicable:
U.S. GOVERNMENT RIGHTS
Programs, software, databases, and related documentation and technical data delivered to U.S.
Government customers are "commercial computer software" or "commercial technical data"
pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental
regulations. As such, the use, duplication, disclosure, modification, and adaptation shall be subject
to the restrictions and license terms set forth in the applicable Government contract, and, to the
extent applicable by the terms of the Government contract, the additional rights set forth in FAR
52.227-19, Commercial Computer Software License (December 2007). Oracle USA, Inc., 500
Oracle Parkway, Redwood City, CA 94065.
This software is developed for general use in a variety of information management applications. It is
not developed or intended for use in any inherently dangerous applications, including applications
which may create a risk of personal injury. If you use this software in dangerous applications, then
you shall be responsible to take all appropriate fail-safe, backup, redundancy and other measures
to ensure the safe use of this software. Oracle Corporation and its affiliates disclaim any liability for
any damages caused by use of this software in dangerous applications.
Oracle and Java are registered trademarks of Oracle Corporation and/or its affiliates. Other names
may be trademarks of their respective owners.
This software and documentation may provide access to or information on content, products and
services from third parties. Oracle Corporation and its affiliates are not responsible for and
expressly disclaim all warranties of any kind with respect to third party content, products and
services. Oracle Corporation and its affiliates will not be responsible for any loss, costs, or damages
incurred due to your access to or use of third party content, products or services. The RMW product
includes software developed by the Visigoth Software Society.
v9.3.1.2 iii
CONTENTS
Oracle Copyright...................................................................................................................................ii
New in Release 9.3.1.2 .................................................................................................................... xvii
Introduction...................................................................................................................... 1
About this Guide...................................................................................................................................1
Agile APIs...........................................................................................................................................................................2
SDK Components.................................................................................................................................2
Client-Side Components.....................................................................................................................................................2
Server-Side Components...................................................................................................................................................3
SDK Architecture - Using Agile APIs....................................................................................................3
System Requirements..........................................................................................................................4
Java Requirements ..............................................................................................................................4
JVM Parameters for Preventing Out of Memory Exceptions..............................................................................................4
Agile SDK Installation Folders..............................................................................................................5
Checking Your Agile PLM System .......................................................................................................5
Agile PLM Business Objects ................................................................................................................5
Getting Started with Agile API ......................................................................................... 7
Agile API Overview...............................................................................................................................7
Types of Agile API Classes and Interfaces ........................................................................................................................7
Network Class Loading.......................................................................................................................................................8
Single-Threaded versus Multi-Threaded Applications........................................................................................................9
Packaging an Agile API Program.......................................................................................................................................9
Distributing Agile API Files.................................................................................................................................................9
Sample Programs...............................................................................................................................................................9
Starting an Agile API Program ...........................................................................................................10
Setting the Class Path for the Agile API Library...............................................................................................................10
Importing Agile API Classes.............................................................................................................................................10
Creating a Session and Logging In ..................................................................................................................................11
Creating a Session by Accessing a Password Protected URL.........................................................................................12
Creating a Session from an Agile Web Service................................................................................................................13
Creating a Session in a Cluster Environment...................................................................................................................13
SDK Developer Guide - Using Agile APIs
iv Agile Product Lifecycle Management
Loading and Creating Agile PLM Objects ..........................................................................................
14
Loading Objects ...............................................................................................................................................................15
Specifying Object Types......................................................................................................... 15
Specifying Object Parameters................................................................................................15
Loading Different Types of Objects........................................................................................16
Creating Objects...............................................................................................................................................................19
Working with Agile PLM Classes............................................................................................ 20
Creating Objects of User-Defined Subclasses....................................................................... 21
Using AutoNumbers ............................................................................................................... 22
Setting the Required Fields.................................................................................................... 23
Creating Different Types of Objects ....................................................................................... 25
Checking the State of Agile PLM Objects.........................................................................................................................29
Propagating Values to Related Objects............................................................................................................................30
Saving an Object to a New Object....................................................................................................................................30
Sharing an Object.............................................................................................................................................................31
Deleting and Undeleting Objects......................................................................................................................................32
Closing a Session.............................................................................................................................................................33
Creating and Loading Queries......................................................................................... 35
About Queries.....................................................................................................................................35
Creating a Query................................................................................................................................35
Saving a Query to a Folder ................................................................................................................36
Generating Ordered (sorted) or Unordered Query Results................................................................37
Specifying Query Attributes when Creating a Query..........................................................................37
Specifying Search Criteria..................................................................................................................38
Search Conditions............................................................................................................................................................39
Query Language Keywords..............................................................................................................................................39
Specifying Search Attributes ............................................................................................................................................40
Retrieving Searchable Attributes......................................................................................................................................41
Using Relational Operators ..............................................................................................................................................41
Using Unicode Escape Sequences........................................................................................42
Using Between, Not Between, In, and Not In Operators........................................................ 43
Using the Nested Criteria to Search for Values in Object Lists.............................................. 43
Using Criteria Selected from Criteria Library in SDK Queries................................................ 44
Using Relationships and Content in SDK Queries ................................................................. 45
Searching for Words or Phrases Contained in Attachments.................................................. 46
Creating a Parameterized Query......................................................................................................................................46
Formatting Dates in Query Criteria...................................................................................................................................47
Using Logical Operators...................................................................................................................................................48
Using Wildcard Characters with the Like Operator...........................................................................................................49
Using Parentheses in Search Criteria ..............................................................................................................................49
Setting Search Criteria for Lists Containing Large Number of Objects ............................................................................50
Contents
v9.3.1.2 v
Using SQL Syntax for Search Criteria................................................................................................
50
Using SQL Wildcards .......................................................................................................................................................52
Sorting Query Results Using SQL Syntax........................................................................................................................52
Setting Result Attributes for a Query..................................................................................................53
Specifying Result Attributes..............................................................................................................................................58
Retrieving CTO Originator Name.....................................................................................................................................59
Duplicate Results for Site-Related Objects and AMLs.....................................................................................................60
Working with Query Results...............................................................................................................60
Sorting Query Results ......................................................................................................................................................60
Query Result Datatypes ...................................................................................................................................................60
Managing Large Query Results........................................................................................................................................61
Query Performance..........................................................................................................................................................61
Creating a Where-Used Query...........................................................................................................61
Loading a Query.................................................................................................................................62
Deleting a Query.................................................................................................................................63
Simple Query Examples.....................................................................................................................63
Working with Tables....................................................................................................... 65
About Tables ......................................................................................................................................65
Retrieving a Table ..............................................................................................................................66
Accessing the New and Merged Relationships Tables......................................................................67
Accessing the Relationships Table...................................................................................................................................67
Accessing the Merged Tables..........................................................................................................................................67
Accessing the Merged Relationships.AffectedBy Table......................................................... 67
Accessing the Merged Relationships.Affects table ................................................................ 68
Accessing the Merged Relationships.References Table........................................................ 68
Working with Read-only Tables........................................................................................................................................69
Retrieving the Metadata of a Table....................................................................................................69
Adding Table Rows ............................................................................................................................69
Adding an Item to the BOM Table....................................................................................................................................70
Adding an Attachment to the Attachments Table.............................................................................................................70
Adding a Manufacturer Part to the Manufacturers Table..................................................................................................70
Adding an Item to the Affected Items Table .....................................................................................................................71
Adding a Task to the Schedule Table ..............................................................................................................................71
Adding and Updating Multiple Table Rows ........................................................................................72
Adding Multiple Team Members to the Team Table of a Project .....................................................................................72
Adding Multiple Items to the BOM Table..........................................................................................................................73
Updating Multiple BOM Rows...........................................................................................................................................74
Iterating Over Table Rows..................................................................................................................75
Updating Objects in Query Results with Multiple Page Tables ........................................................................................76
SDK Developer Guide - Using Agile APIs
vi Agile Product Lifecycle Management
Sorting Table Rows............................................................................................................................
76
Removing Table Rows .......................................................................................................................78
Retrieving the Referenced Object for a Row......................................................................................79
Checking Status Flags of a Row ........................................................................................................83
Working with Page 1, Page 2, and Page 3 ........................................................................................83
Redlining.............................................................................................................................................84
Removing Redline Changes...............................................................................................................86
Removing Redline Changes in Bulk Mode.......................................................................................................................87
Identifying Redlined Rows and Redlined Cells ..................................................................................87
Using ICell.getOldValue ...................................................................................................................................................88
Working with Data Cells ................................................................................................. 89
About Data Cells.................................................................................................................................89
Data Types .........................................................................................................................................89
Checking User's Discovery Privilege..................................................................................................90
Checking if the Cell is a Read-Only Cell ............................................................................................91
Getting Values....................................................................................................................................91
Understanding SDK Date Formats and User Preferences...............................................................................................93
Getting Values....................................................................................................................................93
Setting Values ....................................................................................................................................95
Catching Exceptions for Locked Objects..........................................................................................................................96
Getting and Setting List Values..........................................................................................................96
Getting and Setting Values for SingleList Cells................................................................................................................96
Getting and Setting Values for MultiList Cells ..................................................................................................................97
Getting and Setting Values for Cascading Lists...............................................................................................................98
Using Reference Designator Cells.....................................................................................................99
Working with Folders.................................................................................................... 101
About Folders .................................................................................................................................. 101
Using Level Separation Characters in Folder and Object Names..................................................................................102
Loading a Folder.............................................................................................................................. 103
Creating a Folder............................................................................................................................. 103
Setting the Folder Type................................................................................................................... 104
Adding and Removing Folder Elements.......................................................................................... 104
Adding Folder Elements.................................................................................................................................................105
Removing Folder Elements............................................................................................................................................105
Getting Folder Elements.................................................................................................................. 105
Deleting a Folder............................................................................................................................. 108
Contents
v9.3.1.2 vii
Working with Items, BOMs, and AMLs..........................................................................
109
Working with Items.......................................................................................................................... 109
Getting and Setting the Revision of an Item...................................................................................................................109
Changing the Incorporated Status of a Revision............................................................................................................111
Working with BOMs......................................................................................................................... 112
Adding an Item to a BOM...............................................................................................................................................112
Expanding a BOM ..........................................................................................................................................................113
Copying one BOM into another BOM.............................................................................................................................114
Creating BOM-Related Product Reports........................................................................................................................114
Redlining a BOM ............................................................................................................................................................116
Getting a Released Assembly Item...................................................................................... 117
Creating a Change Order ..................................................................................................... 117
Adding an Item to the Affected Items tab of a Change Order .............................................. 117
Modifying the Redline BOM Table........................................................................................ 118
Working with AMLs.......................................................................................................................... 119
Adding an Approved Manufacturer to the Manufacturers Table.....................................................................................119
Redlining an AML...........................................................................................................................................................120
Accessing PLM Metadata with APIName Field.............................................................. 123
About APIName Field...................................................................................................................... 123
Assigning Names to APIName Fields ............................................................................................. 124
APIName Validation Rules.............................................................................................................. 124
Accessing Metadata Using the APIName Field .............................................................................. 125
APIs that Support the APIName Field............................................................................................................................125
SDK APIs that Get the APIName Field...........................................................................................................................129
API Names of Root Administrator Nodes.......................................................................................................................130
API Name Examples ......................................................................................................................................................131
Subscribing to Agile PLM Objects ................................................................................. 137
About User Subscriptions................................................................................................................ 137
Subscription Events........................................................................................................................................................137
Subscribe Privilege.........................................................................................................................................................138
Subscription Notifications...............................................................................................................................................138
Sending Notifications with SDK............................................................................................138
Deleting Subscribed Objects..........................................................................................................................................139
Getting Subscriptions for an Object................................................................................................. 140
Modifying the Subscriptions for an Object....................................................................................... 141
Making Attributes Available for Subscription................................................................................... 142
Parent and Child Attributes.............................................................................................................................................143
Working with Subscription Tables ................................................................................................... 144
SDK Developer Guide - Using Agile APIs
viii Agile Product Lifecycle Management
Managing Manufacturing Sites .....................................................................................
147
About Manufacturing Sites .............................................................................................................. 147
Controlling Access to Sites.............................................................................................................. 147
Creating a Manufacturing Site......................................................................................................... 148
Loading a Manufacturing Site.......................................................................................................... 148
Retrieving the Sites Table for an Item............................................................................................. 149
Adding a Manufacturing Site to the Sites Table.............................................................................. 149
Selecting the Current Manufacturing Site for an Item ..................................................................... 150
Disabling a Site................................................................................................................................ 151
Working with Lists........................................................................................................ 153
About Lists....................................................................................................................................... 153
List Library......................................................................................................................................................................153
SingleList Lists ...............................................................................................................................................................154
Cascading Lists..............................................................................................................................................................155
MultiList Lists..................................................................................................................................................................156
Methods that Use IAgileList............................................................................................................................................156
Selecting a List Value...................................................................................................................... 157
Working with Lifecycle Phase Cells................................................................................................................................159
Working with Dynamic Lists............................................................................................................................................160
Enumerable and Non-Enumerable Lists .............................................................................. 160
Non-Enumerable PG&C Lists............................................................................................... 161
Selecting a List from the List Library............................................................................................... 161
Creating Custom Lists..................................................................................................................... 163
Creating a Simple List ....................................................................................................................................................163
Automatically Creating New Lists by Modifying Existing Lists........................................................................................164
Creating a Cascading List ..............................................................................................................................................165
Creating a Criteria-Based List ........................................................................................................................................168
Checking the Data Type of a List .................................................................................................... 169
Modifying a List................................................................................................................................ 170
Adding a Value to a List .................................................................................................................................................170
Making List Values Obsolete..........................................................................................................................................170
Setting the List Name and Description...........................................................................................................................171
Setting Level Names for a Cascading List......................................................................................................................171
Enabling or Disabling a List............................................................................................................................................172
Deleting a List.................................................................................................................................................................172
Modifying and Removing List Values .............................................................................................................................172
Printing Contents of IAgileList Objects............................................................................................ 174
Contents
v9.3.1.2 ix
Working with Attachments and File Folder Objects .....................................................
175
About Attachments and File Folders............................................................................................... 175
Working with File Folders................................................................................................................ 176
File Folder Classes and Subclasses ..............................................................................................................................176
File Folder Tables and Constants...................................................................................................................................177
Creating File Folder Objects...........................................................................................................................................177
Creating File Folder Objects by Adding Rows to Attachments Table.............................................................................180
Working with the Files Table of a File Folder .................................................................................................................180
Accessing Files in Agile PLM File Vault with IAttachmentFile........................................................................................181
Working with Attachments Table of an Object ................................................................................ 182
Checking In and Checking Out Files with ICheckoutable...............................................................................................183
Specifying the Revision of the Item................................................................................................................................183
Checking whether the Revision Is Incorporated.............................................................................................................184
Checking Out a File Folder.............................................................................................................. 185
Canceling a File Folder Checkout ................................................................................................... 185
Adding Files and URLs to the Attachments Table .......................................................................... 186
Deep Cloning Attachments and Files from One Object to Another................................................................................188
Specifying the File Folder Subclass When Adding Attachments....................................................................................189
Retrieving Attachment Files............................................................................................................................................190
Deleting Attachments and File Folders...........................................................................................................................191
Working with Thumbnails ...............................................................................................................................................191
Accessing Thumbnails.......................................................................................................... 191
Regenerating Thumbnails .................................................................................................... 192
Setting Master Thumbnails................................................................................................... 193
Replacing Thumbnails.......................................................................................................... 193
Sequencing Thumbnails....................................................................................................... 194
Generating Thumbnails while Adding Files to Attachments Tab..........................................194
Working with Design Objects..........................................................................................................................................195
Adding and Loading Design Objects..............................................................................................................................195
Managing Version Specific Relationships between Design Objects ..............................................................................195
Adding Relationships for Specific Versions of Design Objects............................................ 196
Removing Relationships for Specific Versions of Design Objects....................................... 196
Getting Relationships for Specific Versions of Design Objects............................................ 196
Editing Relationships for Specific Versions of Design Objects ........................................... 197
Purging Specific Versions of Design Objects.................................................................................................................197
Searching Design Object Deployments with Where-Used Queries................................................................................197
SDK Developer Guide - Using Agile APIs
x Agile Product Lifecycle Management
Importing and Exporting Data with SDK......................................................................
199
About Importing and Exporting Data............................................................................................... 199
Validating Import Data and Importing Data..................................................................................... 199
Validating Data and Importing Data with SDK................................................................................................................199
Exporting Data from the SDK.......................................................................................................... 202
Invoking SDK's Export Function.....................................................................................................................................202
Managing Workflow...................................................................................................... 205
About Workflow ............................................................................................................................... 205
The Change Control Process.........................................................................................................................................205
Dynamics of Workflow Functionality...............................................................................................................................206
How the Status of a Change Affects Workflow Functionality ...............................................206
How User Privileges Affect Workflow Functionality.............................................................. 206
Selecting a Workflow....................................................................................................................... 207
Adding and Removing Approvers.................................................................................................... 208
Setting the “Signoff User Dual Identification” Preference...............................................................................................209
Approving a Routable Object................................................................................................ 210
Rejecting a Routable Object................................................................................................. 211
Adding User Groups of Approvers and Users to Approve Routable Objects....................... 212
Approving a Routable Object by Users on behalf of “Transferred from Users” ................... 213
Adding Active Escalations for Current Users to a Approve Routable Object....................... 214
Specifying a Second Signature to Approve a Routable Object............................................ 215
Adding User ID as Second Signature to Approve a Routable Object..................................216
Approving or Rejecting Change ...................................................................................................... 217
Approving or Rejecting a Change Without Password..................................................................... 218
Commenting a Change ................................................................................................................... 219
Auditing a Change........................................................................................................................... 219
Changing the Workflow Status of an Object ................................................................................... 220
Sending an Agile Object to Selected Users .................................................................................... 223
Sending an Agile Object to User Groups ........................................................................................ 223
Managing and Tracking Quality .................................................................................... 225
About Quality Control ...................................................................................................................... 225
Quality-Related API Objects...........................................................................................................................................225
Quality-Related Roles and Privileges.............................................................................................................................226
Working with Customers ................................................................................................................. 226
About Customers............................................................................................................................................................226
Creating a Customer ......................................................................................................................................................226
Loading a Customer.......................................................................................................................................................227
Saving a Customer as Another Customer......................................................................................................................227
Contents
v9.3.1.2 xi
Working with Product Service Requests.........................................................................................
228
About Problem Reports..................................................................................................................................................228
About Nonconformance Reports....................................................................................................................................228
Creating a Product Service Request..............................................................................................................................228
Assigning a Product Service Request to a Quality Analyst............................................................................................229
Adding Affected Items to a Product Service Request.....................................................................................................229
Adding Related PSRs to a Product Service Request.....................................................................................................230
Working with Quality Change Requests.......................................................................................... 231
Creating a Quality Change Request...............................................................................................................................231
Assigning a Quality Change Request to a Quality Administrator ...................................................................................232
Saving a Quality Change Request as a Change............................................................................................................232
Using Workflow Features with PSRs and QCRs............................................................................. 233
Selecting Workflows for PSRs and QCRs......................................................................................................................233
Creating and Managing Projects................................................................................... 235
About Projects and Project Objects................................................................................................. 235
Differences in the Behavior of Project Objects................................................................................ 236
Creating Projects............................................................................................................................. 236
Adding Rules for PPM Objects........................................................................................................ 238
Loading Projects.............................................................................................................................. 239
Adding "FileFolder" to Project's Content Tab.................................................................................. 239
Using Project Templates ................................................................................................................. 241
Creating New Projects Using Templates........................................................................................................................241
Creating Projects and Changing Ownerships.................................................................................................................242
Saving Projects as Templates........................................................................................................................................243
Scheduling Projects......................................................................................................................... 244
Setting Start and End Timestamps for PPM Date Attributes .......................................................... 247
Working with Projects Baselines ..................................................................................................... 248
Delegating Ownership of a Projects to Another User...................................................................... 249
Adding Resources to a Projects Team............................................................................................ 249
Substituting Project Resources ....................................................................................................... 252
Locking or Unlocking Projects......................................................................................................... 253
Working with Discussions................................................................................................................ 253
Creating a Discussion.....................................................................................................................................................253
Replying to a Discussion................................................................................................................................................255
Joining a Discussion.......................................................................................................................................................257
Creating an Action Item..................................................................................................................................................258
SDK Developer Guide - Using Agile APIs
xii Agile Product Lifecycle Management
Working with Product Cost Management.....................................................................
261
Overview.......................................................................................................................................... 261
Working with Price Objects ............................................................................................................. 262
Loading a Price Object...................................................................................................................................................262
Adding Price Lines..........................................................................................................................................................263
Creating a Price Change Order......................................................................................................................................264
Creating a Price Object ..................................................................................................................................................265
Defaults................................................................................................................................. 265
Specifying Item Revision ......................................................................................................265
Creating a Published Price................................................................................................... 266
Working with Suppliers.................................................................................................................... 266
Loading a Supplier..........................................................................................................................................................266
Modifying Supplier Data .................................................................................................................................................267
Working with Sourcing Projects....................................................................................................... 268
Supported API Methods .................................................................................................................................................269
Loading an Existing Sourcing Project.............................................................................................................................269
Creating Sourcing Projects by Quantity Breaks .............................................................................................................270
Creating Sourcing Projects by Quantity Breaks and Price Periods................................................................................270
Accessing and Modifying Objects, Tables, and Attributes..............................................................................................271
Setting Cover Page Values for Sourcing Projects................................................................ 272
Understanding Nested Tables in PCM...........................................................................................................................273
Sourcing Projects' Parent Table and Nested Child Table Constants................................... 273
Accessing and Modifying Nested Tables in Sourcing Projects or RFQs ............................. 273
Accessing and Modifying the Status of Sourcing Project..................................................... 274
Managing Data in Sourcing Projects..............................................................................................................................274
Setting Quantity for Items in Sourcing Projects.................................................................... 274
Adding Items to Sourcing Projects with BOM Filters............................................................ 275
Performing Quantity Rollup in Sourcing Projects................................................................. 276
Performing Cost Rollup in Sourcing Projects .......................................................................277
Performing Price Lookup in Sourcing Projects..................................................................... 277
Generating the Assembly Cost Report for Sourcing Projects ..............................................282
Modifying the Target Price for Items in Sourcing Projects ................................................... 284
Setting the Best Response for Items in Sourcing Projects................................................... 285
Setting Partners in Sourcing Projects................................................................................... 286
Working with RFQs.........................................................................................................................................................288
Supported API Methods ....................................................................................................... 288
Creating RFQs for Sourcing Projects................................................................................... 289
Loading Existing RFQs......................................................................................................... 290
Loading RFQs from Sourcing Project's RFQ Table ............................................................. 290
Accessing and Modifying RFQ Objects, Tables, Nested Tables, and Attributes ................. 291
Performing Price Lookup in RFQs........................................................................................ 292
Working with RFQ Responses ............................................................................................. 293
Contents
v9.3.1.2 xiii
Managing Product Governance & Compliance..............................................................
295
About Agile Product Governance and Compliance......................................................................... 295
Agile PG&C Interfaces and Classes................................................................................................ 296
Agile PG&C Roles........................................................................................................................... 296
Creating Declarations, Specifications, and Substances ................................................................. 297
Creating Declarations.....................................................................................................................................................297
Creating Specifications...................................................................................................................................................298
Creating Substances....................................................................................................................... 299
Creating a Subpart .........................................................................................................................................................299
Creating a Substance Group..........................................................................................................................................300
Creating a Material.........................................................................................................................................................300
Creating a Substance.....................................................................................................................................................301
Adding Items, Manufacturer Parts, and Part Groups to Declarations............................................. 301
Adding Substances to Declarations ................................................................................................ 302
Structure of Bill of Substances .......................................................................................................................................303
Rules for Adding Substances.........................................................................................................................................304
Adding Subparts and Materials that Do Not Exist ..........................................................................................................304
Examples of Adding Substances....................................................................................................................................305
Adding Substances to Manufacturer Part Composition Table of Homogeneous Material
Declarations..........................................................................................................................
305
Adding Substances to Manufacturer Part Composition Table of Substance Declarations.. 307
Adding Substances to a Specification............................................................................................. 308
Adding Specifications to a Declaration............................................................................................ 309
Rules for Adding Specifications......................................................................................................................................309
Routing Declarations....................................................................................................................... 310
Completing a Declaration................................................................................................................ 312
Submitting Declarations to Compliance Managers ......................................................................... 312
Publishing a Declaration.................................................................................................................. 313
Getting and Setting Weight Values ................................................................................................. 313
Adding Substance Compositions for Manufacturer Parts ............................................................... 314
Rolling Up Compliance Data ........................................................................................................... 317
Understanding the IPGCRollup Interface.......................................................................................................................317
Passing the Date Parameter ................................................................................................ 317
Using the IPGCRollup Interface .....................................................................................................................................318
Rolling Up Assembled Data on Items...................................................................................318
Rolling Up Assembled Data on MPNs.................................................................................. 319
Setting Values in the Calculated Compliance Field for Item Objects................................... 320
Setting Values in the Calculated Compliance Field for Declaration Objects........................ 320
SDK Developer Guide - Using Agile APIs
xiv Agile Product Lifecycle Management
Handling Exceptions .....................................................................................................
323
About Exceptions............................................................................................................................. 323
Exception Constants ....................................................................................................................... 324
Getting Error Codes ........................................................................................................................ 324
Disabling and Enabling Error Codes with Bulk APIs....................................................................... 324
Getting Error Messages .................................................................................................................. 325
Disabling and Enabling Warning Messages.................................................................................... 326
Checking if APIException is Warning and not Error........................................................................ 327
Saving and Restoring State Enabled and Disabled Warnings........................................................ 327
Warnings on Deleting Objects Automatically Disabled by Agile API .............................................. 328
Performing Administrative Tasks.................................................................................. 329
About Agile PLM Administration...................................................................................................... 329
Privileges Required to Administer Agile PLM.................................................................................. 330
Administrative Interfaces................................................................................................................. 330
Getting an IAdmin Instance............................................................................................................. 331
Working with Nodes ........................................................................................................................ 331
Working with the Classes Node......................................................................................................................................336
Managing Agile PLM Classes ......................................................................................................... 336
Concrete and Abstract Classes......................................................................................................................................338
Referencing Classes ......................................................................................................................................................339
Identifying the Target Type of a Class............................................................................................................................340
Working with Attributes.................................................................................................................... 340
Referencing Attributes....................................................................................................................................................341
Retrieving Attributes.......................................................................................................................................................342
Retrieving Individual Attributes.......................................................................................................................................343
Editing the Property of an Attribute ................................................................................................................................343
Working with User-Defined Attributes.............................................................................................................................343
Working with Properties of Administrative Nodes ........................................................................... 344
Managing Users .............................................................................................................................. 345
Getting All Users.............................................................................................................................................................345
Creating a User - 9.3.1.2...............................................................................................................................................345
Creating Users and Requiring Password Modification at Login .....................................................................................346
Creating a Supplier User................................................................................................................................................347
Saving a User to a New User.........................................................................................................................................347
Checking for Expired Passwords....................................................................................................................................348
Configuring User Settings...............................................................................................................................................348
Resetting User Passwords.............................................................................................................................................349
Deleting a User...............................................................................................................................................................350
Contents
v9.3.1.2 xv
Managing User Groups ...................................................................................................................
350
Getting All User Groups..................................................................................................................................................350
Creating a User Group...................................................................................................................................................351
Adding a User Group to the User's User Group Table...................................................................................................352
Listing Users in a User Group ........................................................................................................................................353
Mapping Agile PLM Client Features to Agile API .......................................................... 355
Login Features................................................................................................................................. 355
General Features............................................................................................................................. 356
Search Features.............................................................................................................................. 356
Attachment Features....................................................................................................................... 357
Workflow Features .......................................................................................................................... 357
Manufacturing Site Features ........................................................................................................... 358
Folder Features ............................................................................................................................... 358
Projects Features ............................................................................................................................ 359
Administrative Features................................................................................................................... 359
Migrating Release 9.2.1 and Older Table Constants to Release 9.2.2 or Later ............ 361
Mapped Pre-Release 9.2.2 Table Constants to 9.2.2 Table Constants.......................................... 361
Removed Pre-Release 9.2.2 Table Constants................................................................................ 364
xvi Agile Product Lifecycle Management
Preface
Oracle's Agile PLM documentation set includes Adobe® Acrobat PDF files. The Oracle Technology
Network (OTN) Web site http://www.oracle.com/technetwork/documentation/agile-085940.html
contains the latest versions of the Agile PLM PDF files. You can view or download these manuals
from the Web site, or you can ask your Agile administrator if there is an Agile PLM Documentation
folder available on your network from which you can access the Agile PLM documentation (PDF)
files.
Note To read the PDF files, you must use the free Adobe Acrobat Reader version 9.0 or later.
This program can be downloaded from the Adobe Web site http://www.adobe.com.
The Oracle Technology Network (OTN) Web site
http://www.oracle.com/technetwork/documentation/agile-085940.html can be accessed through Help
> Manuals in both Agile Web Client and Agile Java Client. If you need additional assistance or
information, please contact My Oracle Support (
https://support.oracle.com) for assistance.
Note Before calling Oracle Support about a problem with an Agile PLM manual, please have
the full part number, which is located on the title page.
TTY Access to Oracle Support Services
Oracle provides dedicated Text Telephone (TTY) access to Oracle Support Services within the
United States of America 24 hours a day, 7 days a week. For TTY support, call 800.446.2398.
Outside the United States, call +1.407.458.2479.
Readme
Any last-minute information about Agile PLM can be found in the Readme file on the Oracle
Technology Network (OTN) Web site http://www.oracle.com/technetwork/documentation/agile-
085940.html.
Agile Training Aids
Go to the Oracle University Web page
http://www.oracle.com/education/chooser/selectcountry_new.html for more information on Agile
Training offerings.
Accessibility of Code Examples in Documentation
Screen readers may not always correctly read the code examples in this document. The
conventions for writing code require that closing braces should appear on an otherwise empty line;
however, some screen readers may not always read a line of text that consists solely of a bracket or
brace.
This documentation may contain links to Web sites of other companies or organizations that Oracle
does not own or control. Oracle neither evaluates nor makes any representations regarding the
accessibility of these Web sites.
v9.3.1.2 xvii
New in Release 9.3.1.2
There are no new features or enhancements to existing features in this release of the Agile SDK
APIs. Changes in this document include formatting modifications and changes made to some of the
code samples.
New in Release 9.3.1.1
The following new features and enhancements are implemented in this release:
à Adding "FileFolder" to the Content Tab of a Project – This release supports adding FileFolders to the
Content Tab of a Project using the IProgram API. See
Adding "FileFolder" to the Content Tab
of a Project on page 239.
à Adding Multiple Team members to a Project – The SDK supports using the Bulk APIs to add Multiple
Team members to a Project's Team Table. See
Adding Multiple Team Members to the Team
Table of a Project on page 72.
à The following entry is no longer applicable and is removed from Selecting a List from the List
Library on page 161.
"Cascading lists are only used for SingleList attributes and not for MultiList attributes"
New in Release 9.3.1 Rev 3
There are no new features or enhancements implemented in this release of the Agile SDK APIs.
Changes listed below only apply to this document.
Missing Content
The missing entries that appeared under "The Agile PLM system provides the following redline
tables" are restored in this revision of the Guide. See
Redlining on page 84.
Publishing Agile APIs and PLM Extensions in Separate Books
Starting with this release, the SDK Developer Guide which was published as a single book in
previous releases, is divided and published in two complimentary books as follows:
à SDK Developer Guide - Using Agile APIs – This book consists of the first twenty chapters of the
SDK Developer Guide Release 9.3.1 Rev 2 and applicable Appendices.
à SDK Developer Guide - Developing PLM Extensions – The contents of this book are the Process
Extensions, Web Services Extensions, Dashboard Management Extensions, and Event
Framework chapters of the SDK Developer Guide Release 9.3.1 Rev 2 and applicable
Appendices.
This change is necessary because the SDK Developer Guide which is posted on the Oracle
Technology Network (OTN), has more than 500 pages, and OTN rejects submissions that exceed
this page limit.
New in Release 9.3.1 Rev 2
The SDK_samples.zip file is moved from
http://www.oracle.com/technology/sample_code/products/agile/9.3/index.html
xviii Agile Product Lifecycle Management
to
https://codesamples.samplecode.oracle.com/servlets/tracking/id/S614.
Note Oracle recommends using Internet Explorer to access these sites.
New in Release 9.3.1
The following new features and enhancements are implemented in this release:
à Creating Agile sessions in cluster environments – The SDK exposes three new APIs to overcome
the proxy server URL issue during down time when creating an Agile session in a cluster
environment. See
Creating a Session in a Cluster Environment on page 13.
à Creating Criteria-based listsThe SDK supports creating, loading, and modifying Criteria-based
lists which are Dynamic lists defined by the criteria selected from the Agile Criteria library when
the lists are created. See
Creating a Criteria-Based List on page 168.
à Creating Users and Requiring Password Modification at Login – Using the SDK you can create and
configure a user with a temporary password, and require the new user to change his or her
password at login. See
Creating Users and Requiring Password Modification at Login on page
346.
à Checking for expired passwords – The text and example in Managing Users on page 345 that
checks for Agile API errors related to expired passwords is changed in this release. See
Checking for Expired Passwords on page 347.
à Approving or rejecting change without password – PLM's Java Client provides the option to approve
or reject a Change with or without typing a password. The SDK exposes the necessary APIs to
programmatically perform this function. See
Approving or Rejecting a Change Without
Password on page 218.
à Adding Items from Product Collaboration to Sourcing Projects – The Agile Web Client supports adding
PC Items to Sourcing Projects by applying the BOM filter to multiple attributes with different
operators from the UI. This release enhances the applicable APIs to perform this task using the
SDK. See
Adding Items to Sourcing Projects Using BOM Filters on page 275.
à Generating a project's Assembly Cost Report – The Agile Web Client supports generating Assembly
Cost Reports using the UI. In this release, the IProductReport.execute() API was
enhanced to perform this task using the SDK. See
Generating Assembly Cost Reports for
Sourcing Projects on page 282.
à Setting Start and End timestamps for PPM Date attributes – This release enables specifying the Start
and End times for PPM's Schedule, Estimated, and Actual Date attributes when creating or
editing scheduled PPM tasks. See
Setting Start and End Timestamps for PPM Date Attributes
on page
247.
à New Variant Management Interfaces – The following Variant Management specific interfaces are
implemented in com.agile.px package:
y IUniqueId
y IConfigurationGraph
y IConfigurationOption
y IModelOptionBOM
y IModelOptionBOMItem
à Working with Variant Management EventsThis release provides SDK support for Variant
v9.3.1.2 xix
Management Events. You can find the necessary background and procedural information in the
following sections of SDK Developer Guide Release 9.3.1 - Developing PLM Extensions.
y Event Information Objects – Lists the new Event Types and the corresponding Information
Object Interface (IVMEventObj) that enable supporting Variant Management using the
SDK
y Event Script Objects – Lists the new Event Types and the corresponding Script Object
Interface (IVMScriptObj) that enable supporting Variant Management using the SDK
y Working with Variant Management Actions – Describes working with Variant Management
Actions – Java PX and Variant Management Actions – Script PX
y Variant Management Configuration Graph Schema – Describes the structure of a Variant
Management XML graph schema
New in Release 9.3.0.2
The following new features and enhancements were implemented in this release:
à Checking for expired passwords – The example in Managing Users on page 345 that checks for
Agile API errors related to expired passwords is changed in this release. See
Checking for
Expired Passwords on page 347.
à Improving query performance for lists containing large number of objects – A new section that
shows how to set the search criteria to improve performance for lists containing a large number
of objects is added in this release. See
Setting Search Criteria for Lists Containing Large
Number of Objects on page 49.
à Deploying dependent/shared libraries in Weblogic server – Applicable procedures to deploy
the dependent JAR files are modified in this release. See Deploying the Dependent JAR Files
in SDK Developer Guide Release 9.3.0.2 - Developing PLM Extensions.
à Creating a Session and Logging In – A note describing JVM parameter settings when LDAP users
log in to Agile PLM running on Weblogic servers. See
Creating a Session and Logging In on
page
11.
New in Release 9.3.0.1 Rev 2
The SiteMinder and SAP portal references that appeared in Using Single Sign-On Cookies for
Client-Server are removed in this revision.
New in Release 9.3.0.1
New features and enhancements implemented in this release address using the SDK to create and
load queries and work with tables. These changes, summarized below, are documented in Chapter
3,
Creating and Loading Queries on page 35 and Chapter 4, Working with Tables on page 65.
à SDK support for workflow-related queries – This release supports using workflow attributes to
prepare queries that check the status of a workflow in the PLM process. See Specifying
Workflow Queries.
à SDK support to use the Nested Criteria to perform object list searches – This release provides an
enhancement in the behavior and performance of this feature. See
Using the Nested Criteria
to Search for Values in Object Lists on page 43.
à SDK support for Relationships/Content queries – As a result of enhancements made to the IQuery
interface, you can use the SDK to prepare queries listed below. For information and usage
xx Agile Product Lifecycle Management
examples, see
Using Relationships and Content in SDK Queries on page 45.
y An object's Relationships attribute
y A Program object's Content attribute
y A Transfer Order object's Selected Content attribute
à SDK support to query using criterion selected from PLM's Criteria Library – This feature was supported
in earlier releases of the SDK. In this release, the examples are modified. See
Using Criteria
Selected from Criteria Library in SDK Queries on page 44.
à SDK support for bulk removal of redline changes – A new interface called IRedlinedTable
supports this operation, See
Removing Redline Changes in Bulk Mode on page 86.
Note The PG&C constants and the relationships table functionality in AgileAPI.jar
Release 9.2.2 and subsequent releases of Agile PLM are incompatible with the ones in
the earlier versions of AgileAPI.jar.
v9.3.1.2 1
Chapter 1
Introduction
This chapter includes the following:
About this Guide.................................................................................................................................................. 1
SDK Components................................................................................................................................................2
SDK Architecture - Using Agile APIs................................................................................................................... 3
System Requirements ......................................................................................................................................... 4
Java Requirements..............................................................................................................................................4
Agile SDK Installation Folders............................................................................................................................. 5
Checking Your Agile PLM System....................................................................................................................... 5
Agile PLM Business Objects................................................................................................................................5
About this Guide
Oracle's Agile Software Development Kit (SDK) is a collection of Java application programming
interfaces (APIs), sample applications, and documentation that enable building custom applications
to access, or extend the functionalities of the Agile Application Server. Using the SDK, you can
create programs that extend the functionality of the Agile product lifecycle management system
(PLM) and can perform tasks against the PLM system.
The SDK enables the following operations:
à Integrate the Agile PLM system with enterprise resource planning (ERP) applications or other
custom applications
à Develop applications to process product data
à Perform batch operations against the Agile Application Server
à Extend the functionality of the Agile PLM system
This release marks the partition of the SDK Developer Guide which was published as a single book
prior to this release, into the following two books.
à SDK Developer Guide – Using the APIs – This component of the SDK Developer Guide provides
information to develop batch operations against the PLM Server, integrate PLM with other
applications, and process PLM data. This information is described and documented in this
book.
à SDK Developer Guide – Developing Extensions – This component of the SDK Developer Guide
provides background and procedural information to create additional PLM clients (extend Agile
PLM functionalities) and work with PLM Frameworks. This information is described and
documented in the SDK Developer Guide - Developing Extensions.
SDK Developer Guide - Using Agile APIs
2 Agile Product Lifecycle Management
Agile APIs
This component of the SDK Developer Guide provides referential and procedural information to get
started with the APIs and use the APIs to develop applications that programmtically perfrom batch
operations against the Agile Application Server to execute tasks such as:
à Querying PLM databases
à Loading data into PLM databases
à Importing and exporting data to and from Agile PLM
à Processing product data
à Interacting with PLM modules such as Product Cost Management, Product Portfolio
Management, and other modules
à Managing workflow
à Performing administrative functions
SDK Components
The Agile SDK has the following Client-side and sever-side components:
Client-Side Components
The contents of the Agile SDK Client-side components are:
Documentation
à SDK Developer Guide (this manual)
à API Reference files (these are the Javadoc generated HTML files that document the API
methods)
à Sample applications
Note The API HTML reference files and Sample applications are in the SDK_samples.zip
folder. This folder is found in the Oracle Agile PLM's Event and Web Services Samples
Web site
https://www.samplecode.oracle.com/tracker/tracking/linkid/prpl1004/remcurreport/true/te
mplate/IssueList.vm/action/Search?eventSubmit_doSelectquery=foo&go=224. For more
information and procedures to access its contents, contact your system administrator, or
refer to your PLM installation guide.
Installation
à Agile API library (AgileAPI.jar)
à Java Process Extensions API library (pxapi.jar)
à Apache Axis library (axis.jar)
Chapter 1: Introduction
v9.3.1.2 3
Server-Side Components
Oracle's Agile Application Server contains the following SDK server-side components:
à Agile API implementation classes
à Java and Scripting process extensions framework
à Web service extensions frameworks
SDK Architecture - Using Agile APIs
The SDK facilitates developing different types of programs to connect to the Agile Application
Server. If you are using only the Agile APIs, these programs connect directly to the server. If you
are developing Web service extensions (WSX), you can deploy them inside the Agile Application
Server container as Web Services. The Web server used for WSX is accessible from inside or
outside the company’s demilitarized computing zone (DMZ) or perimeter network. For information to
develop Web service extensions, refer to SDK Developer Guide - Developing PLM Extensions.
When the Agile PLM Client initiates a custom action, it either runs a program that is deployed on the
server, or connects to an external resource such as a URL or WSX. Java PX and Script PX
extensions can also use the Agile APIs. You can also develop extensions using APIs that are not
provided by Agile. For procedures and back ground information, refer to SDK Developer Guide -
Developing PLM Extensions.
Figure 1: Agile SDK architecture
SDK Developer Guide - Using Agile APIs
4 Agile Product Lifecycle Management
Note Agile API programs connect to the Agile Application Server using non-secure means.
Consequently, it is recommended that you run the Agile API programs only from within
the corporate firewall. Web service Clients, however, can connect to the server through
the corporate firewall using standard HTTP(S) technology.
System Requirements
For Agile SDK system requirements, refer to PLM Capacity Planning and Deployment Guide.
Java Requirements
The Agile API must be compatible with the version of Java that the application server supports. To
avoid problems, an Agile API Client must use the same version of Java that the connecting
application server is using. Oracle Application Server 10g must use Sun Java Runtime Environment
(JRE) 1.5.0_06 and Oracle WebLogic Server 10.3 must use Sun Java Runtime Environment (JRE)
1.6 for interoperability and 2007 Daylight Saving Time compliance.
The following table lists the recommended Java Runtime Environment (JRE) to use with Agile API
Clients on different application servers that Agile PLM supports.
Application Server Operating System Required Java Version for Agile API
clients
Oracle Application Server 10g Windows 2003 Sun JRE 1.5.0
Oracle WebLogic Server 10.3 Windows 2003 Sun JRE 1.6
JVM Parameters for Preventing Out of Memory Exceptions
To prevent out of memory errors, add the following Java Virtual Memory (JVM) parameter options in
the indicated locations.
Note This workaround is only applicable to single-threaded SDK programs.
à If the Client is a standalone SDK Client, add the JVM option as shown below:
java -Ddisable.agile.sessionID.generation=true pk.sample
à If the Client is a PX and out of memory occurs in Agile Server, add the JVM option in
<OAS_HOME>/opmn/conf/opmn.xml
<category id="start-parameters">
<data id="java-options" value="-Xrs -server -
XX:MaxPermSize=256M -ms1280M -mx1280M -XX:NewSize=256M -
XX:MaxNewSize=256M -XX:AppendRatio=3 -
Doracle.xdkjava.compatibility.version=10.1.0 -
Djava.security.policy=$ORACLE_HOME/j2ee/home/config/java2.policy -
Dagile.log.dir=$ORACLE_HOME/j2ee/home/log -
Dcom.sun.management.jmxremote -
Dcom.sun.management.jmxremote.port=9899 -
Dcom.sun.management.jmxremote.authenticate=false -
Chapter 1: Introduction
v9.3.1.2 5
Dcom.sun.management.jmxremote.ssl=false -Djava.awt.headless=true -
Dhttp.webdir.enable=false -Duser.timezone=GMT -
Ddisable.agile.sessionID.generation=true"/>
<data id="oc4j-options" value="-verbosity 10 -
userThreads"/>
</category>
à If the Client is a URL PX, add the following JVM option in the Server Start up (similar to
catalina.bat in Tomcat):
-Ddisable.agile.sessionID.generation=true
Agile SDK Installation Folders
The Agile SDK files use the following folder structure on your computer:
lib – The \agile_home\integration\sdk\lib folder contains the following libraries:
Important Do not include the axis.jar file and AgileAPI.jar file in the same classpath. The
SDK classpath does not support this setting and the SDK will not function properly.
à AgileAPI.jar – Agile API library, which contains Agile API classes and interfaces
à axis.jar – An Oracle-modified version of the Apache Axis library required for Web service
Clients
à pxapi.jar – PX API library, which contains interfaces used to develop custom autonumber
sources and custom actions
Checking Your Agile PLM System
Before trying to run the Agile SDK Clients on your Agile PLM system, make sure the system is
configured and working properly. In particular, make sure the HTTP ports for your application server
are set correctly. For more information, refer to the Agile PLM Installation Guide.
Agile PLM Business Objects
With any enterprise software system, you work with business objects to manage the company’s
data. The following table lists the Agile PLM business objects and their related Agile API interfaces.
Object Related Agile API Interface
Changes
IChange
Customers
ICustomer
Declarations
IDeclaration
Design
IDesign
Discussions
IDiscussion
File Folders
IFileFolder
SDK Developer Guide - Using Agile APIs
6 Agile Product Lifecycle Management
Object Related Agile API Interface
Items
IItem
Manufacturer parts
IManufacturerPart
Manufacturers
IManufacturer
Packages
IPackage
Part Groups (Commodity or Part Family)
ICommodity
Prices
IPrice
Product Service Request
IServiceRequest
Projects
IProgram
Sourcing Project
IProject
Quality Change Request
IQualityChangeRequest
Reports
IProductReport
Requests for Quote (RFQ)
IRequestForQuote
RFQ Responses
ISupplierResponse*
Sites
IManufacturingSite
Specifications
ISpecification
Substances
ISubstance
Suppliers
ISupplier
Transfer Order
ITransferOrder
User Groups
IUserGroup
Users
IUser
* Agile does not support the API interfaces in the current release of the software.
The business objects that you can view and actions that you can perform on these objects are
determined by the server components installed on your Agile Application Server and the roles, and
assigned privileges. Privilege levels can vary from field to field. In addition to Users and User
Groups, Agile PLM administrators work with administrative objects, such as administrative nodes
and Agile PLM classes.
Note Not all Agile PLM business objects are exposed in the Agile API. For example, some
Report objects are not accessible via the Agile API.
v9.3.1.2 7
Chapter 2
Getting Started with Agile API
This chapter includes the following:
Agile API Overview.............................................................................................................................................. 7
Starting an Agile API Program............................................................................................................................. 10
Loading and Creating Agile PLM Objects............................................................................................................ 14
Agile API Overview
This section provides an overview of the functionality provided by the Agile API. Topics covered
include:
à Types of Agile API classes and interfaces
à Loading Agile API classes
à How the Agile API is thread-safe
à Packaging your Agile API applications
à Finding the sample programs
Types of Agile API Classes and Interfaces
The Agile API contains several different classes and interfaces in the AgileAPI.jar library.
These files are further classified into the following groups according to functions that they support:
à Aggregate interfaces – These interfaces aggregate the applicable functional interfaces for a
particular object type. For example, the IItem interface extends IDataObject,
IRevisioned, IManufacturingSiteSelectable, IAttachmentContainer,
IHistoryManager, and IReferenced. Most SDK functionalities fall within these interfaces.
The Agile API’s underlying implementation classes, which are not exposed, implement these
interfaces.
à Functional Unit Interfaces – These interfaces hold units of functionality that are extended to other
interfaces. For example, IAttachmentContainer provides a convenient way to access the
attachments table for any object. Other interfaces in this group such as IChange and IItem
extend the IAttachmentContainer interface. IRoutable is another class that serves as a
functional unit; it provides methods for any object that you can route to another Agile PLM user;
IChange, IPackage, and ITransferOrder all extend IRoutable.
à Metadata interfaces – This group of classes defines the metadata (and meta-metadata) for the
Agile Application Server. Metadata is simply data that describes other data. The metadata
interfaces include classes such as IAgileClass, INode, IRoutableDesc,
ITableDesc, and IWorkflow.
SDK Developer Guide - Using Agile APIs
8 Agile Product Lifecycle Management
à Factory classesAgileSessionFactory is a factory class that is used to create a session
(IAgileSession) and access transaction management. IAgileSession is also a factory
object allowing you to instantiate other objects. Many Agile API objects, in turn, are factory
objects for tables or other referenced objects. Tables, in turn, are factories for rows.
à Exception classes – There’s only one Exception class, APIException.
à Constants – These classes contain IDs for attributes, tables, classes, and so on. All classes
containing only constants have class names that end with “Constants,” for example,
ChangeConstants, ItemConstants, UserConstants, and so on.
Network Class Loading
The Agile API has two main software components:
à Client-side library, AgileAPI.jar
à Server-side implementation classes
The server-side implementation classes are installed automatically with every instance of the Agile
Application Server.
The Agile API Client-side library is composed almost entirely of interfaces; it’s essentially a class
loader. When you run an Agile API program, it connects to the Agile Application Server and
automatically downloads whatever implementation classes it needs. For example, if your program
uses methods of IItem, it downloads an implementation of IItem at run time.
Figure 2: Agile API architecture
Network class loading provides many benefits, including the ability to update client implementation
classes by automatically downloading them from a server. Any Agile API classes that are
downloaded from the server are automatically cached to a local disk. When an Agile API program
needs to load a particular class, it retrieves it from the cache rather than downloading it again from
the network. The cache results in faster loading of classes and reduced network load.
Chapter 2: Getting Started with Agile API
v9.3.1.2 9
If the network class loader detects that its cache is stale, that is, its classes are older than the
classes on the server, it invalidates the cache and reloads the necessary classes from the server.
This allows you to update Agile SDK Clients to use the latest implementation classes without
redeploying applications throughout the enterprise.
Single-Threaded versus Multi-Threaded Applications
The Agile API has been certified thread-compatible. It can be used for both Single-Threaded and
Multi-Threaded application development. You can safely use Agile API calls concurrently, by
surrounding each method invocation (or sequence of method invocations) with external
synchronization.
Packaging an Agile API Program
After you develop a program that makes calls to the Agile API, you’ll need to package its files so
that you or other users can install it. Many development environments include tools for packaging
and deploying applications.
You can also choose to package your program manually. If you choose to do this, you’ll need to
know the dependencies your project has. Again, many development environments include tools for
generating dependency files. A dependency file lists the runtime components that must be
distributed with your program’s project files.
Distributing Agile API Files
You can freely distribute any Java applications or applets that you create that make calls to the
Agile API. You can include the Agile API library, AgileAPI.jar, when you package your
application’s files.
Your development environment may require you to distribute other class files or libraries with your
program. Check the documentation for your development environment to see which runtime files
you must distribute with your program. Consult the applicable license agreement of the
manufacturer for each of the files you plan to distribute to determine whether you are authorized to
distribute the files with your application.
Sample Programs
The Agile SDK provides several sample programs that demonstrate how to use its APIs. These
sample programs are in the api, dx, px, and wsx folders. You can find them in the SDK_samples
(ZIP file). To access this file, see the Note in
Client-Side Components on page 2.
Each sample program has its own Readme.txt file. Be sure to review the Readme.txt document
before trying to run a sample program.
SDK Developer Guide - Using Agile APIs
10 Agile Product Lifecycle Management
Starting an Agile API Program
When you create a program using the Agile API, follow this general approach for structuring your
program:
1. At the top of each class file, add an import statement to import Agile API classes:
import com.agile.api.*;
2. Get an instance of the Agile Application Server.
3. Create an Agile session.
4. Complete one or more business processes. This is where most of your program code goes.
5. Close the Agile session.
Setting the Class Path for the Agile API Library
When Java looks for a class referenced in your source, it checks the directories specified in the
CLASSPATH variable. To create Agile API programs, you must include AgileAPI.jar in the
class path.
If you are using a Java development environment, you usually can modify the class path for each
project. If you don’t let your development environment know where the Agile API library is located, it
is not able to build the application.
Importing Agile API Classes
The only Java package your program has access to automatically is java.lang. To refer to Agile
API classes, you should import the com.agile.api package at the beginning of each class file:
import com.agile.api.*;
Rather than importing the com.agile.api package, you can also refer to Agile API classes by
their full package name, for example:
com.agile.api.IItem source =
(com.agile.api.IItem)m_session.getObject(com.agile.api.IItem.OBJECT_TYP
E, "1000-02");
As you can see, if you don’t import the com.agile.api package, it’s cumbersome to type the full
package name whenever you refer to one of its classes. Also, when you don’t import the
com.agile.api package, or reference the Agile API classes by full package name, the Java
compiler will return an error when you try to build your program.
Chapter 2: Getting Started with Agile API
v9.3.1.2 11
Creating a Session and Logging In
Note Use the JVM parameter called disable.agile.sessionID.generation=true to
create a session when the login user is a LDAP user. This is applicable only when Agile
runs on Weblogic server. If the Client is a standalone SDK Client, add the JVM option
java -Ddisable.agile.sessionID.generation=true pk.sample.
Alternatively you can set the parameter in the code as follows:
System.setProperty("disable.agile.sessionID.generation", "true");
HashMap params = new HashMap();
params.put(AgileSessionFactory.USERNAME, USERNAME);
params.put(AgileSessionFactory.PASSWORD, PASSWORD);
AgileSessionFactory factory =
AgileSessionFactory.getInstance(URL);
IagileSession session = factory.createSession(params);
To start an Agile API program, you must complete the following two tasks:
1. Get an instance of the Agile Application Server.
Use the AgileSessionFactory.getInstance() method to get an instance of the Agile
server. You must specify a connection URL for the server. The URL you specify depends on
whether you connect directly to the Agile server or through a proxy Web server.
y To connect directly to the Agile server, type this URL: http://appserver:port/virtualPath
y To connect to the Agile server through a proxy Web server, type this URL:
protocol://webserver:port/virtualPath
where
y appserver is the name of the Agile server computer.
y webserver is the name of the Web server computer.
y virtualPath is the virtual path for your Agile PLM server. The default value is Agile. The
virtual path is specified when the Agile PLM system is installed. For more information, refer
to the Agile PLM Installation Guide.
y protocol is either HTTP or HTTPS.
y port is the port number used for the specified protocol. The port is needed only if a
nonstandard port number is being used. Otherwise, you can omit it.
2. Create a session for the Agile PLM server instance.
Use the AgileSessionFactory.createSession() method to create a session. For the
params parameter of createSession(), specify a Map object containing the login
parameters (username and password).
The following example shows how an Agile API program creates a session and logs into the Agile
PLM server.
Example: Creating a session and logging in
private IAgileSession login(String username, String password) throws
APIException {
//Create the params variable to hold login parameters
HashMap params = new HashMap();
//Put username and password values into params
SDK Developer Guide - Using Agile APIs
12 Agile Product Lifecycle Management
params.put(AgileSessionFactory.USERNAME, username);
params.put(AgileSessionFactory.PASSWORD, password);
//Get an Agile server instance. ("agileserver" is the name of the Agile
proxy server,
and "virtualPath" is the name of the virtual path used for the Agile
system.)
AgileSessionFactory instance =
AgileSessionFactory.getInstance
("http://<agileserver>/<virtualPath
>");
//Create the Agile PLM session and log in
return instance.createSession(params);
}
Your Oracle Agile PLM agreement determines the maximum number of concurrent open sessions
to the Agile Application Server per user account. If you exceed this maximum number, the server
prevents you from logging in. Therefore, it is important to use the IAgileSession.close()
method to properly log out and close a session when your program is finished running. If the Agile
PLM system is hosted on Oracle Application Servers, you are limited to only one session per
thread.
Creating a Session by Accessing a Password Protected URL
To provide additional security for users accessing Agile PLM across a firewall, the proxy server may
have a password-protected URL. If so, the normal method of obtaining a server instance and then
creating a session will not work. Instead, you must use the
AgileSessionFactory.createSessionEx() method to specify the username, password, and
URL parameters needed to log in. The login code is simpler if you use createSessionEx()
because you don’t need to call the method AgileSessionFactory.getInstance() first to
obtain a server instance. The createSessionEx() method obtains the server instance and
creates the session in one call as shown in the following example.
Example: Creating a session by accessing a password-controlled URL
private IAgileSession securelogin(String username, String password)
throws APIException {
//Create the params variable to hold login parameters
HashMap params = new HashMap();
//Put username, password, and URL values into params
params.put(AgileSessionFactory.USERNAME, username);
params.put(AgileSessionFactory.PASSWORD, password);
params.put(AgileSessionFactory.URL,
"
http://agileserver.agilesoft.com/Agile");
//Create the Agile PLM session and log in
return AgileSessionFactory.createSessionEx(params);
}
The createSessionEx()method also works for URLs that are not password-protected, so you
can use it instead of createSession() if you prefer.
Chapter 2: Getting Started with Agile API
v9.3.1.2 13
Creating a Session from an Agile Web Service
If you developed a web service using web service extensions and deployed it in the same container
as Agile PLM, you can take advantage of the Agile API to access Agile PLM server functionality
from within the web service. To get an Agile PLM server instance for your web service, use the
AgileSessionFactory.getInstance() method, but pass a null value for the url
parameter.
Once you have retrieved an AgileSessionFactory object, you can also create a session. The
web service request provides user authentication, so you don’t need to specify a username or
password when you create an Agile API session. Therefore, make sure you specify a null value
for the params parameter of AgileSessionFactory.createSession().
AgileSessionFactory factory = AgileSessionFactory.getInstance(null);
IAgileSession session = factory.createSession(null);
If you pass a null value for the params parameter of createSession(), the user authentication
that took place when the Agile PLM server intercepted the web service request is reused for the
Agile API session. You don’t need to log in again. Do not attempt to close the session using
IAgileSession.close(); the authorization handler will automatically close the session.
Specifying a null parameter for the createSession() method creates an IAgileSession
corresponding to the session created by the authorization handler. If your web service doesn’t use
the authorization handler, or if you want to create a session for a different user than the one used
for the authorization handler, you can still use createSession(params) to create a session. For
the params parameter, specify a Map object containing the login parameters (username and
password). If you don’t use the authorization handler to create a session, you are responsible for
closing it. Call the IAgileSession.close() method to close the session. For more information
about web service extensions, see Developing Web Service Extensions.
Creating a Session in a Cluster Environment
The AgileSessionFactory.getInstance() and
AgileSessionFactory.createSession()that you use to create an instance of the
AgileSessionFactory, cache the Agile server properties to get the instance. Because of this
caching, the getInstance() method retrieves the same instance of AgileSessionFactory
anytime it is invoked.
While retrieving the same instance of AgileSessionFactory is not an issue in single server
environments, it can be problematic in Agile cluster environments when the cached server is down.
This is due to the following facts:
1. When AgileSessionFactory is initiated with a proxy URL, a specific server in the cluster is
cached and is used to create the session.
2. When the cached server is down, AgileSessionFactory.createSession() will try to
establish a connection with the server, but will fail because the server is down.
SDK Developer Guide - Using Agile APIs
14 Agile Product Lifecycle Management
To overcome this issue, the Agile SDK exposes the following APIs to refresh the
AgileSessionFactory instance for Agile cluster environments. These new APIs clear the
cached server details and create a new instance of the AgileSessionFactory.
à AgileSessionFactory.refreshInstance(String url)
à AgileSessionFactory.refreshInstanceEx(Map params)
à AgileSessionFactory.refreshSessionEx(Map params)
The following examples use these APIs to create Agile sessions in cluster environments
Example: Creating a session with public static AgileSessionFactory refreshInstance(String
url)
AgileSessionFactory factory =
AgileSessionFactory.refreshInstance(URL);
HashMap params = new HashMap();
params.put(AgileSessionFactory.USERNAME, USERNAME);
params.put(AgileSessionFactory.PASSWORD, PASSWORD);
IAgileSession lsession = factory.createSession(params);
Example: Creating a session with public static AgileSessionFactory refreshInstanceEx (Map
map)
HashMap params = new HashMap();
params.put(AgileSessionFactory.URL, URL);
params.put(AgileSessionFactory.USERNAME, USERNAME);
params.put(AgileSessionFactory.PASSWORD, PASSWORD);
AgileSessionFactory factory =
AgileSessionFactory.refreshInstanceEx(params);
IAgileSession lsession = factory.createSession(params);
Example: Creating a session with public static IAgileSession refreshSessionEx(Map
params)
HashMap params = new HashMap();
params.put(AgileSessionFactory.URL, URL);
params.put(AgileSessionFactory.USERNAME, USERNAME);
params.put(AgileSessionFactory.PASSWORD, PASSWORD);
IAgileSession lsession =
AgileSessionFactory.refreshSessionEx(params);
Loading and Creating Agile PLM Objects
With every Agile API program, a basic requirement is the ability to get and create objects. The
following interfaces map to objects that you can work with in the Agile API:
à IChange à IManufacturer à IRequestForQuote
à ICommodity à IManufacturerPart à IServiceRequest
à ICustomer à IManufacturingSite à ISpecification
à IDeclaration à IPackage à ISubstance
à IDesign à IPrice à ISupplier
à IDiscussion à IProgram à ISupplierResponse
à IFileFolder à IProject à ITransferOrder
à IFolder à IQualityChangeRequest à IUser
à IItem à IQuery à IUserGroup
Chapter 2: Getting Started with Agile API
v9.3.1.2 15
To load and create these Agile PLM objects, you must first get an instance of the
AgileSessionFactory object and then create an Agile PLM session. Then use
IAgileSession.getObject() to load Agile PLM objects and
IAgileSession.createObject() to create objects.
For more information about creating queries and folders, see
Creating and Loading Queries on
page
35 and Working with Folders on page 101.
Loading Objects
To load an Agile PLM object, use one of the IAgileSession.getObject()methods.
à IAgileObject getObject(Object objectType, Object params)
à IAgileObject getObject(int objectType, Object params)
Note If not specified by the user, objects will always load according to their base class which
are derived from the subclass or class. Objects will also load correctly when the object's
derived base class is correct. However, the SDK will load an object even if an invalid
subclass is passed for that object when the derived base class of the invalid class and
that of the object are both the same.
Specifying Object Types
The two getObject() methods let you specify the objectType parameter using these values:
à An IAgileClass instance that represents one of the Agile PLM classes.
à A class ID (for example, ItemConstants.CLASS_PART corresponds to the Part class).
Predefined class IDs are available in the various *Constants files provided with the Agile API.
à An OBJECT_TYPE constant, such as IItem.OBJECT_TYPE or IChange.OBJECT_TYPE
à A class name (for example, “Part”). However, Oracle does not recommend using class names
to instantiate objects because the class names can be modified and are not guaranteed to be
unique.
Note When you use the getObject() method to load an object, you can specify abstract or
concrete Agile PLM classes. For more information, see Concrete and Abstract Classes
on page
338.
Specifying Object Parameters
The params parameter for the getObject() method can be a Map or String. If you specify a Map
object for the params parameter, it must contain attributes (either attribute IDs or IAttribute objects)
and their corresponding values. The Map must contain all identification related information. For
example, when you load an IManufacturerPart, both the Manufacturer Name and Manufacturer Part
Number must be specified.
If the Map object you specify for the params parameter contains additional attributes other than the
identifying information, those attributes are ignored. The server uses only identifying information to
retrieve an object. For a complete list of attributes used to uniquely identify Agile PLM objects, see
SDK Developer Guide - Using Agile APIs
16 Agile Product Lifecycle Management
"Identifying Attributes for Agile PLM Classes" in SDK Developer Guide - Developing PLM
Extensions.
This example shows how to load part 1000-02 using a Map parameter that specifies the attribute
(ItemConstants.ATT_TITLE_BLOCK_NUMBER) and a value.
Example: Loading a part using a Map
try {
Map params = new HashMap();
params.put(ItemConstants.ATT_TITLE_BLOCK_NUMBER,
"1000-02");
IItem item = (IItem)m_session.getObject(ItemConstants.CLASS_PART,
params);
} catch (APIException ex) {
System.out.println(ex);
}
If the object you’re loading has a single attribute that serves as a unique identifier, you can enter the
String value for that attribute as the params parameter. For example, the unique identifier for a
part is a part number. Therefore, you can enter the part number as the parameter to load the object.
Note Not all objects have one attribute that serves as a unique identifier. For example, a
manufacturer part is identified by both its manufacturer name and manufacturer part
number. Therefore, to load a manufacturer part you must specify values for at least
those two attributes.
This example shows how to load part 1000-02 by specifying a unique String identifier.
Example: Loading a part using a String
try {
IItem item = (IItem)m_session.getObject(ItemConstants.CLASS_PART,
"1000-02");
} catch (APIException ex) {
System.out.println(ex);
}
Loading Different Types of Objects
The following example shows how to load different types of Agile PLM objects.
try {
//Load a change
IChange change = (IChange)m_session.getObject(IChange.OBJECT_TYPE,
"C00002");
System.out.println("Change : " + change.getName());
//Load a commodity
ICommodity comm =
(ICommodity)m_session.getObject(ICommodity.OBJECT_TYPE, "Res");
System.out.println("Commodity : " + comm.getName());
//Load a customer
ICustomer cust =
(ICustomer)m_session.getObject(ICustomer.OBJECT_TYPE,
"CUST00006");
Chapter 2: Getting Started with Agile API
v9.3.1.2 17
System.out.println("Customer : " + cust.getName());
//Load a declaration
IDeclaration dec =
(IDeclaration)m_session.getObject(IDeclaration.OBJECT_TYPE,
"MD00001");
System.out.println("Declaration : " + dec.getName());
//Load a discussion
IDiscussion discussion =
(IDiscussion)m_session.getObject(IDiscussion.OBJECT_TYPE,
"D00002");
System.out.println("Discussion : " + discussion.getName());
//Load a file folder
IFileFolder ff =
(IFileFolder)m_session.getObject(IFileFolder.OBJECT_TYPE,
"FOLDER00133");
System.out.println("File Folder : " + ff.getName());
//Load a folder
IFolder folder =
(IFolder)m_session.getObject(IFolder.OBJECT_TYPE, "/Personal
Searches/MyTemporaryQueries");
System.out.println("Folder : " + folder.getName());
//Load an item
IItem item = (IItem)m_session.getObject(IItem.OBJECT_TYPE, "1000-
02");
System.out.println("Item : " + item.getName());
//Load a manufacturer
Map params = new HashMap();
params.put(ManufacturerConstants.ATT_GENERAL_INFO_NAME, "World
Enterprises");
IManufacturer mfr =
(IManufacturer)m_session.getObject(IManufacturer.OBJECT_TYPE,
params);
System.out.println("Manufacturer : " + mfr.getName());
//Load a manufacturer part
params.clear();
params.put(ManufacturerPartConstants.ATT_GENERAL_INFO_MANUFACTURE
R_NAME, "World Enterprises");
params.put(ManufacturerPartConstants.ATT_GENERAL_INFO_MANUFACTURE
R_PART_NUMBER, "WE10023-45");
IManufacturerPart mfrPart =
(IManufacturerPart)m_session.getObject(IManufacturerPart.OBJECT_T
YPE, params); System.out.println("ManufacturerPart : " +
mfrPart.getName());
//Load a manufacturing site
IManufacturingSite siteHK =
(IManufacturingSite)m_session.getObject(ManufacturingSiteConstant
s.CLASS_SITE, "Hong Kong");
System.out.println("ManufacturingSite : " + siteHK.getName());
//Load a package
IPackage pkg =
(IPackage)m_session.getObject(PackageConstants.CLASS_PACKAGE,
"PKG00010");
System.out.println("Package : " + pkg.getName());
SDK Developer Guide - Using Agile APIs
18 Agile Product Lifecycle Management
//Load a price
IPrice price =
(IPrice)m_session.getObject(IPrice.OBJECT_TYPE, "PRICE10008");
System.out.println("Price : " + price.getName());
//Load a program
IProgram program =
(IProgram)m_session.getObject(IProgram.OBJECT_TYPE, "PGM10008");
System.out.println("Program : " + program.getName());
//Load a PSR
IServiceRequest psr =
(IServiceRequest)m_session.getObject(IServiceRequest.OBJECT_TYPE,
"NCR01562");
System.out.println("PSR : " + psr.getName());
//Load a QCR
IQualityChangeRequest qcr =
(IQualityChangeRequest)m_session.getObject(IQualityChangeRequest.
OBJECT_TYPE, "CAPA02021");
System.out.println("QCR : " + qcr.getName());
//Load a query
IQuery query =
(IQuery)m_session.getObject(IQuery.OBJECT_TYPE,
"/Personal Searches/Part Numbers Starting with P");
System.out.println("Query : " + query.getName());
//Load an RFQ
IRequestForQuote rfq =
(IRequestForQuote)m_session.getObject(IRequestForQuote.OBJECT_TYPE,
"RFQ01048");
System.out.println("RFQ : " + rfq.getName());
//Load an RFQ response
params.clear();
params.put(SupplierResponseConstants.ATT_COVERPAGE_RFQ_NUMBER,
"RFQ01048");
params.put(SupplierResponseConstants.ATT_COVERPAGE_SUPPLIER,
"SUP20013");
ISupplierResponse rfqResp =
(ISupplierResponse)m_session.getObject(ISupplierResponse.OBJECT_TYPE
, params);
System.out.println("RFQ Response : " + rfqResp.getName());
//Load Sourcing Projects
IProject prj =
(IProject)m_session.getObject(IProject.OBJECT_TYPE, "PRJACME_110");
System.out.println("Project : " + prj.getName());
//Load a specification
ISpecification spec =
(ISpecification)m_session.getObject(ISpecification.OBJECT_TYPE,
"WEEE");
System.out.println("Specification : " + spec.getName());
Chapter 2: Getting Started with Agile API
v9.3.1.2 19
//Load a substance
ISubstance sub =
(ISubstance)m_session.getObject(ISubstance.OBJECT_TYPE, "Cadmium");
System.out.println("Substance : " + sub.getName());
//Load a supplier
ISupplier supplier =
(ISupplier)m_session.getObject(ISupplier.OBJECT_TYPE, "SUP20013");
System.out.println("Supplier : " + supplier.getName());
//Load a transfer order
ITransferOrder to =
(ITransferOrder)m_session.getObject(TransferOrderConstants.CLASS_CTO
, "456602");
System.out.println("TransferOrder : " + to.getName());
//Load a user
params.clear();
params.put(UserConstants.ATT_GENERAL_INFO_USER_ID, "OWELLES");
IUser user =
(IUser)m_session.getObject(IUser.OBJECT_TYPE, params);
System.out.println("User : " + user.getName());
//Load a user group
params.clear();
params.put(UserGroupConstants.ATT_GENERAL_INFO_NAME, "Designers");
IUserGroup group =
(IUserGroup)m_session.getObject(IUserGroup.OBJECT_TYPE, params);
System.out.println("UserGroup : " + group.getName());
} catch (APIException ex) {
System.out.println(ex);
}
Creating Objects
To create an Agile PLM object, use one of the IAgileSession.createObject() methods:
à IAgileObject createObject(Object objectType, Object params)
à IAgileObject createObject(int objectType, Object params)
Note The SDK does not support setting the Lifecycle Phase (LCP)/Workflow status attribute of
an object while you are creating that object. The reason is that the necessary settings for
LCP are not available until after the object is created. The same is also applicable in the
UI. For example, IChange will not get Workflow status values until a Workflow is
selected. However, you can use the SDK to create objects, and then set and modify the
LCP/Workflow status attribute. Also, you cannot get a list of values for this field, until the
object is created, and the relevant actions are performed on the object.
The objectType and params parameters are identical to those used in the
IAgileSession.getObject() methods; for more information, see
Loading Objects on page 15.
Except for IFolder and IQuery objects, you must specify a concrete class for the objectType
parameter. For example, if you are creating a part, you can’t specify
SDK Developer Guide - Using Agile APIs
20 Agile Product Lifecycle Management
ItemConstants.CLASS_PARTS_CLASS because that class is an abstract class that can’t be
instantiated. However, you can specify the class ID of any predefined or user-defined concrete
class, such as ItemConstants.CLASS_PART.
If you are creating an object of a user-defined subclass, the objectType parameter of
createObject()should be an Integer object corresponding to the subclass ID.
In addition to a Map or String type, the params parameter for
IAgileSession.createObject() can also be an INode object representing an autonumber
source for the particular object class. The Agile Application Server queries the autonumber source
for the next number in its sequence, and that number is used as the unique identifier.
Note You cannot specify an INode object for the params parameter for objects that don’t
have their autonumber sources available.
The following example shows how to create part 1000-02 using a Map parameter that specifies an
attribute (ItemConstants.ATT_TITLE_BLOCK_NUMBER) and a value.
Example: Creating a part using a Map
try {
Map params = new HashMap();
params.put(ItemConstants.ATT_TITLE_BLOCK_NUMBER, "1000-02");
IItem item = (IItem)m_session.createObject(ItemConstants.CLASS_PART,
params);
} catch (APIException ex) {
System.out.println(ex);
}
The following example shows how to create part 1000-02 by specifying a unique String identifier.
Example: Creating a part using a String
try {
IItem item = (IItem)m_session.createObject(ItemConstants.CLASS_PART,
"1000-02");
} catch (APIException ex) {
System.out.println(ex);
}
Working with Agile PLM Classes
Because classes are customized for each Agile Application Server, you should avoid hard-coding
references to class names, particularly if your program is going to be used on multiple Agile
Application Servers or in different locales. Instead, you can retrieve the classes for each object type
at run time. Your program can then provide a user interface to allow the user to select a class from
the list.
The following example shows how to retrieve the list of classes for a particular object type at run
time.
Example: Getting classes
try {
// Get the IAdmin interface for this session
IAdmin m_admin = session.getAdminInstance();
Chapter 2: Getting Started with Agile API
v9.3.1.2 21
// Get the Item base class
IAgileClass itemClass =
m_admin.getAgileClass(ItemConstants.CLASS_ITEM_BASE_CLASS);
// Get the Item subclass names
IAgileClass[] subclasses = itemClass.getSubclasses();
for (int i = 0; i < subclasses.length; ++i) {
String listSubclasses = subclasses[i].getName();
System.out.println(listSubclasses);
}
} catch (APIException ex) {
System.out.println(ex);
}
Creating Objects of User-Defined Subclasses
User-defined subclasses are classes created specifically for your Agile PLM system. Consequently,
the Agile API doesn’t provide predefined class ID constants for them. To specify a user-defined
subclass for the objectType parameter of createObject(), pass an Integer corresponding to
the class ID. To get the class ID for a user-defined class, use the IAgileClass.getId() method.
The following example shows how to create a Resistor object. In this example, Resistor is a user-
defined subclass of the Parts class.
Example: Creating an object of a user-defined subclass
try {
//Define a variable for the Resistor subclass
Integer classResistor = null;
//Get the Resistor subclass ID
IAgileClass[] classes =
m_admin.getAgileClasses(IAdmin.CONCRETE);
for (int i = 0; i < classes.length; i++) {
if (classes[i].getName().equals("Resistor")) {
classResistor = (Integer)classes[i].getId();
break;
}
}
//Create a Resistor object
if (classResistor != null) {
IItem resistor =
(IItem)m_session.createObject(classResistor, "R10245");
}
} catch (APIException ex) {
System.out.println(ex);
}
Of course, you can also reference a user-defined subclass by name, as in the following example.
However, class names are not necessarily unique. If there are two subclasses with the same name,
the Agile API matches the first one found, which may not be the one you intended.
SDK Developer Guide - Using Agile APIs
22 Agile Product Lifecycle Management
Creating an object by referencing the subclass name //Creating an
object by referencing the subclass name try { IItem resistor =
(IItem)m_session.createObject("Resistor", "R10245");
} catch (APIException ex) {
System.out.println(ex);
}
Using AutoNumbers
An Agile PLM class can have one or more AutoNumber sources. An AutoNumber source is a
predefined sequence of numbers that automatically number an object. AutoNumber sources are
defined in the administrative functionality of Agile Java Client.
Note The Manufacturers and Manufacturer Parts classes, and their user-defined subclasses,
do not support automatic numbering.
You must configure your Agile Application to use AutoNumber when you create an object of a
particular class. However, the Agile API does not enforce automatic numbering of objects, even
when it is required for a particular class. If your environment requires this capability, you must
develop the necessary routine. Thus, if you develop a GUI program that allows users to create Agile
PLM objects, make sure the user interface enforces automatic numbering when it is required. For
an example of how a client program enforces automatic numbering, create a few objects using Agile
Web Client and note how the user interface works.
To get the next available AutoNumber in the sequence:
Use the IAutoNumber.getNextNumber(IAgileClass) method to assign the next available
AutoNumber in the sequence. This method will check to ensure the number is not used by another
object. It will continue this process until it finds and returns the first available AutoNumber for the
specified Agile subclass. This method will throw an exception if it fails to get the next available
AutoNumber. The IAutoNumber.getNextNumber() method will not check and skip if the
number is already used by another object.
The following example shows how to create a part using the next AutoNumber.
Example: Getting the next available AutoNumber
private void createPart(String partNumber) throw APIException {
IAdmin admin;
IAgileClass cls;
IItem part;
IAutoNumber[] numSources;
String nextAvailableAutoNumber;
//Get the Admin instance
admin = session.getAdminInstance();
//Get the Part class
cls = admin.getAgileClass(ItemConstants.CLASS_PART);
//Check if AutoNumber is required
if (isAutoNumberRequired(cls)) {
// Get AutoNumber sources for the Part class
numSources = cls.getAutoNumberSources();
Chapter 2: Getting Started with Agile API
v9.3.1.2 23
// Get the next available AutoNumber using the first autonumber source
nextAvailableAutoNumber = numSources[0].getNextNumber(cls);
// Create the part using the available AutoNumber
part =
(IItem)session.createObject(ItemConstants.CLASS_PART,
nextAvailableAutoNumber);
} else {
// Create the part using the specified number
// (if AutoNumber is not required)
part = (IItem)session.createObject(ItemConstants.CLASS_PART,
partNumber);
}
public boolean isAutoNumberRequired(IAgileClass cls) throws
APIException {
if (cls.isAbstract()) {
return false;
}
IProperty p =
((INode)cls).getProperty(PropertyConstants.PROP_AUTONUMBER_REQUIRED);
if (p != null) {
IAgileList value = (IAgileList)p.getValue();
return ((Integer)(value.getSelection()[0]).getId()).intValue() ==
1;
}
return false;
}
Setting the Required Fields
A class can be defined with several required attributes. To make a particular attribute mandatory,
the Agile PLM administrator sets the Visible and Required properties for the attribute to Yes. If you
try to create an object in Agile Java Client or Agile Web Client without completing the required
fields, the Client does not allow you to save the object until you set the values for all required fields.
Although the Agile PLM administrator can define whether an attribute is required for a class, the
Agile API doesn’t automatically enforce required fields when you set values. Consequently, you can
use the API to create and save an object even if values aren’t set for all required fields. If you want
to enforce required fields in your Client program and make them behave the way they do in Agile
Web and Java Clients, you have to write that code.
To check for required fields:
1. Call ITable.getAttributes() or ITableDesc.getAttributes() to get the list of
attributes for a table.
2. For each attribute, call
IAttribute.getProperty(PropertyConstants.PROP_REQUIRED).getValue() to
get the value for the Required property.
The following example shows how to get the array of required attributes for Page One, Page Two,
and Page Three for a class.
Example: Getting required attributes for a class
SDK Developer Guide - Using Agile APIs
24 Agile Product Lifecycle Management
/**
* Returns true if the specified attribute is required and visible.
*/
public boolean isRequired(IAttribute attr) throws APIException {
boolean result = false;
IProperty required =
attr.getProperty(PropertyConstants.PROP_REQUIRED);
if (required != null) {
Object value = required.getValue();
if (value != null) {
result = value.toString().equals("Yes");
}
}
IProperty visible = attr.getProperty(PropertyConstants.PROP_VISIBLE);
if (visible != null) {
Object value = visible.getValue();
if (value != null) {
result &= value.toString().equals("Yes");
}
}
return result;
}
/**
* Returns an array containing the required attributes for the
specified class.
*/
public IAttribute[] getRequiredAttributes(IAgileClass cls) throws
APIException {
//Create an array list for the results
ArrayList result = new ArrayList();
//Check if the class is abstract or concrete
if (!cls.isAbstract()) {
IAttribute[] attrs = null;
//Get required attributes for Page One
ITableDesc page1 =
cls.getTableDescriptor(TableTypeConstants.TYPE_PAGE_ONE);
if (page1 != null) {
attrs = page1.getAttributes();
for (int i = 0; i < attrs.length; i++) {
IAttribute attr = attrs[i];
if (isRequired(attr)) {
result.add(attr);
}
}
}
//Get required attributes for Page Two
Chapter 2: Getting Started with Agile API
v9.3.1.2 25
ITableDesc page2 =
cls.getTableDescriptor(TableTypeConstants.TYPE_PAGE_TWO);
if (page2 != null) {
attrs = page1.getAttributes();
for (int i = 0; i < attrs.length; i++) {
IAttribute attr = attrs[i];
if (isRequired(attr)) {
result.add(attr);
}
}
}
//Get required attributes for Page Three
ITableDesc page3 =
cls.getTableDescriptor(TableTypeConstants.TYPE_PAGE_THREE);
if (page3 != null) {
attrs = page3.getAttributes();
for (int i = 0; i < attrs.length; i++) {
IAttribute attr = attrs[i];
if (isRequired(attr)) {
result.add(attr);
}
}
}
}
return (IAttribute[])result.toArray(new IAttribute[0]);
}
Note Primary key fields that are used to create an object are required regardless of the setting
for the Required property. For example, for items the [Title Block.Number] field
must be specified to create a new item regardless whether the field is required.
Creating Different Types of Objects
The following example shows several different ways to create various types of Agile PLM objects.
To simplify the code, AutoNumbers are not used.
Example: Creating different types of objects
try {
//Create a Map object to store parameters
Map params = new HashMap();
//Create a change
IChange eco =
(IChange)m_session.createObject(ChangeConstants.CLASS_ECO,
"C00002");
System.out.println("Change : " + eco.getName());
//Create a commodity
ICommodity comm =
(ICommodity)m_session.createObject(CommodityConstants.CLASS_COMMODIT
Y,"RES");
SDK Developer Guide - Using Agile APIs
26 Agile Product Lifecycle Management
System.out.println("Commodity : " + comm.getName());
//Create a customer
params.clear();
params.put(CustomerConstants.ATT_GENERAL_INFO_CUSTOMER_NUMBER,
"CUST00006");
params.put(CustomerConstants.ATT_GENERAL_INFO_CUSTOMER_NAME, "Western
Widgets");
ICustomer customer =
(ICustomer)m_session.createObject(CustomerConstants.CLASS_CUSTOMER,
params);
System.out.println("Customer : " + customer.getName());
//Create a declaration
params.clear();
ISupplier supplier =
(ISupplier)m_session.getObject(ISupplier.OBJECT_TYPE, "SUP20013");
params.put(DeclarationConstants.ATT_COVER_PAGE_NAME, "MD00001");
params.put(DeclarationConstants.ATT_COVER_PAGE_SUPPLIER, supplier);
IDeclaration dec = (IDeclaration)
m_session.createObject(DeclarationConstants.CLASS_SUBSTANCE_DECLARAT
ION, params);
System.out.println("Declaration : " + dec.getName());
//Create a discussion
params.clear();
params.put(DiscussionConstants.ATT_COVER_PAGE_NUMBER, "D000201");
params.put(DiscussionConstants.ATT_COVER_PAGE_SUBJECT, "Packaging
issues");
IDiscussion discussion =
(IDiscussion)m_session.createObject(DiscussionConstants.CLASS_DISCUS
SION, params);
System.out.println("Discussion : " + discussion.getName());
//Create a file folder
IFileFolder ff =
(IFileFolder)m_session.createObject(FileFolderConstants.CLASS_FILE_F
OLDER, "FOLDER00133");
System.out.println("File Folder : " + ff.getName());
//Create a folder
params.clear();
IFolder parentFolder =
(IFolder)m_session.getObject(IFolder.OBJECT_TYPE, "/Personal
Searches");
params.put(FolderConstants.ATT_FOLDER_NAME, "MyTemporaryQueries");
params.put(FolderConstants.ATT_PARENT_FOLDER, parentFolder);
IFolder folder = (IFolder)m_session.createObject(IFolder.OBJECT_TYPE,
params);
System.out.println("Folder : " + folder.getName());
//Create an item
IItem part =
(IItem)m_session.createObject(ItemConstants.CLASS_PART, "1000-02");
System.out.println("Item : " + part.getName());
Chapter 2: Getting Started with Agile API
v9.3.1.2 27
//Create a manufacturer
params.put(ManufacturerConstants.ATT_GENERAL_INFO_NAME, "World
Enterprises");
IManufacturer mfr =
(IManufacturer)m_session.createObject(ManufacturerConstants.CLASS_MA
NUFACTURER, params);
System.out.println("Manufacturer : " + mfr.getName());
//Create a manufacturer part
params.clear();
params.put(ManufacturerPartConstants.ATT_GENERAL_INFO_MANUFACTURER_NAME
, "World Enterprises");
params.put(ManufacturerPartConstants.ATT_GENERAL_INFO_MANUFACTURER_PART
_NUMBER, "WE10023-45");
IManufacturerPart mfrPart =
(IManufacturerPart)m_session.createObject
(ManufacturerPartConstants.CLASS_MANUFACTURER_PART, params);
System.out.println("ManufacturerPart : " + mfrPart.getName());
//Create a manufacturing site
IManufacturingSite siteHK =
(IManufacturingSite)m_session.createObject(ManufacturingSiteConstant
s.CLASS_SITE, "Hong Kong");
System.out.println("ManufacturingSite : " + siteHK.getName());
//Create a package
IPackage pkg =
(IPackage)m_session.createObject(PackageConstants.CLASS_PACKAGE,
"PKG00010");
System.out.println("Package : " + pkg.getName());
//Create a price
params.clear();
params.put(PriceConstants.ATT_GENERAL_INFORMATION_NUMBER,
"PRICE10008");
params.put(PriceConstants.ATT_GENERAL_INFORMATION_CUSTOMER,
"CUST00006");
params.put(PriceConstants.ATT_GENERAL_INFORMATION_ITEM_NUMBER, "1000-
02");
params.put(PriceConstants.ATT_GENERAL_INFORMATION_ITEM_REV, "B");
params.put(PriceConstants.ATT_GENERAL_INFORMATION_PROGRAM,
"PROGRAM0023");
params.put(PriceConstants.ATT_GENERAL_INFORMATION_MANUFACTURING_SITE,
"San Jose");
params.put(PriceConstants.ATT_GENERAL_INFORMATION_SUPPLIER,
"SUP20013");
IPrice price =
(IPrice)m_session.createObject(PriceConstants.CLASS_PUBLISHED_PRICE,
params);
System.out.println("Price : " + price.getName());
//Create a program
DateFormat df =
new SimpleDateFormat("MM/dd/yy");
IAttribute attr =
SDK Developer Guide - Using Agile APIs
28 Agile Product Lifecycle Management
m_admin.getAgileClass(ProgramConstants.CLASS_PROGRAM).getAttribute(P
rogramConstants.ATT_GENERAL_INFO_DURATION_TYPE);
IAgileList list = attr.getAvailableValues();
list.setSelection(new Object[] {"Fixed"});
params.clear();
params.put(ProgramConstants.ATT_GENERAL_INFO_NAME, "Wingspan Program");
params.put(ProgramConstants.ATT_GENERAL_INFO_SCHEDULE_START_DATE,
df.parse("06/01/05"));
params.put(ProgramConstants.ATT_GENERAL_INFO_SCHEDULE_END_DATE,
df.parse("06/30/05"));
params.put(ProgramConstants.ATT_GENERAL_INFO_DURATION_TYPE, list);
IProgram program =
(IProgram)m_session.createObject(ProgramConstants.CLASS_PROGRAM,
params);
System.out.println("Program : " + program.getName());
//Create a PSR
IServiceRequest psr =
(IServiceRequest)m_session.createObject(ServiceRequestConstants.CLAS
S_NCR, "NCR01562");
System.out.println("PSR : " + psr.getName());
//Create a QCR
IQualityChangeRequest qcr =
(IQualityChangeRequest)m_session.createObject(
QualityChangeRequestConstants.CLASS_CAPA, "CAPA02021");
System.out.println("QCR : " + qcr.getName());
//Create a query
params.clear();
IFolder parent =
(IFolder)m_session.getObject(IFolder.OBJECT_TYPE, "/Personal
Searches");
String condition =
"[Title Block.Number] starts with 'P'";
params.put(QueryConstants.ATT_CRITERIA_CLASS,
ItemConstants.CLASS_ITEM_BASE_CLASS);
params.put(QueryConstants.ATT_CRITERIA_STRING, condition);
params.put(QueryConstants.ATT_PARENT_FOLDER, parent);
params.put(QueryConstants.ATT_QUERY_NAME, "Part Numbers Starting with
P");
IQuery query =
(IQuery)m_session.createObject(IQuery.OBJECT_TYPE, params);
System.out.println("Query : " + query.getName());
//Create a specification
ISpecification spec = (ISpecification)
m_session.createObject(SpecificationConstants.CLASS_SPECIFICATION,
"WEEE");
System.out.println("Specification : " + spec.getName());
//Create a substance
ISubstance sub =
(ISubstance)m_session.createObject(SubstanceConstants.CLASS_SUBSTANC
E, "Cadmium");
Chapter 2: Getting Started with Agile API
v9.3.1.2 29
System.out.println("Substance : " + spec.getName());
//Create a transfer order
ITransferOrder to =
(ITransferOrder)m_session.createObject(TransferOrderConstants.CLASS_
CTO, "456602");
System.out.println("TransferOrder : " + to.getName());
//Create a user
params.clear();
params.put(UserConstants.ATT_GENERAL_INFO_USER_ID, "OWELLES");
params.put(UserConstants.ATT_LOGIN_PASSWORD, “agile”);
IUser user =
(IUser)m_session.createObject(UserConstants.CLASS_USER, params);
System.out.println(“User : “ + user.getName());
//Create a user group
params.clear();
params.put(UserGroupConstants.ATT_GENERAL_INFO_NAME, “Designers”);
IUserGroup group =
(IUserGroup)m_session.createObject(UserGroupConstants.CLASS_USER_GRO
UP, params);
System.out.println(“UserGroup : “ + group.getName());
} catch (APIException ex) {
System.out.println(ex);
}
Note You cannot use the Agile API to create a SupplierResponse.
Checking the State of Agile PLM Objects
The IStateful interface supports Agile objects that have either Agile Workflow status or Agile
lifecycle phases. Objects that support this interface are Item and routable objects.
Routable objects are:
à IChange
à IDeclaration
à IFileFolder
à IPackage
à IProgram
à IQualityChangeRequest
à IServiceRequest
à ITransferOrder
The following example returns an array that shows all states of the object, or null when they are not
defined.
SDK Developer Guide - Using Agile APIs
30 Agile Product Lifecycle Management
Example: Getting the array that defines the different states of an object
public interface IStateful {
public IStatus[] getStates()
throws APIException;
}
The following example returns the current state of the object, or null if it is not defined.
Example: Getting the current state of the object
public interface IStateful {
public IStatus getStatus()
throws APIException;
}
Propagating Values to Related Objects
Several objects in Agile PLM have related objects. For example, problem reports and
nonconformance reports have a Related PSR table. On the Related PSR table, you can specify that
a Workflow event should trigger a particular result in a related object, such as another problem
report or noncomformance report. The triggered result does not occur instantaneously. In fact, there
may be a noticeable delay—perhaps several seconds—in the time it takes Agile PLM to propagate
values to related objects.
Saving an Object to a New Object
The Agile API lets you save an existing object as a new object. For example, in addition to a Save
button, a dialog box in your program may have a Save As button, which saves the data to a new
object. When you use the IDataObject.saveAs() method, you must specify the subclass that
you are using to save the object and the object number. If the subclass supports it, you can use an
AutoNumber.
This example shows how to save the current object to a new object using the next AutoNumber for
the specified subclass.
Example: Saving an object as a new object
private void saveAsObject(IDataObject obj, IAgileClass sub) {
String nextNum;
try {
// Get the next autonumber for the sublass
IAutoNumber[] numSources = sub.getAutoNumberSources();
nextNum = numSources[0].getNextNumber();
// Save the object
obj.saveAs(sub, nextNum);
} catch (APIException ex) {
System.out.println(ex);
}
}
Chapter 2: Getting Started with Agile API
v9.3.1.2 31
Sharing an Object
The IShareable interface is implemented by every Agile PLM business object that the Agile API
exposes. Therefore, every business object can be shared. Sharing lets you grant one or more of
your roles to another Agile PLM user or user group for a specific object. The roles you can assign
when you share an object include your assigned or permanent roles and any roles assigned to you
from membership in a user group.
Users that have been shared an object can perform actions permitted by the roles for that object
only. They don’t acquire the roles in a global fashion.
The IShareable interface has only two methods, getUsersAndRoles() and
setUsersAndRoles(). The getUsersAndRoles() method returns a Map object. Each user in
the Map has an associated array of roles. The setUsersAndRoles() method has one parameter,
a Map object, which, like the Map returned by getUsersAndRoles(), maps each user to an array
of roles. Each user can be assigned a different selection of roles.
Example: Sharing an object
private void getDataForSharing() throws Exception {
//Get item
IItem item =
(IItem)m_session.getObject(ItemConstants.CLASS_ITEM_BASE_CLASS,
"P10011");
//Get users
IUser user1 = (IUser)m_session.getObject(UserConstants.CLASS_USER,
"albertl");
IUser user2 = (IUser)m_session.getObject(UserConstants.CLASS_USER,
"peterl");
IUser[] users = new IUser[]{user1, user2};
//Get roles
INode nodeRoles =
(INode)m_session.getAdminInstance().getNode(NodeConstants.NODE_ROLES);
IRole role1 = (IRole)nodeRoles.getChildNode("Component Engineer");
IRole role2 = (IRole)nodeRoles.getChildNode("Incorporator");
IRole[] roles = new IRole[]{role1, role2};
//Share the item
shareItem(item, users, roles);
}
private void shareItem(IItem item, IUser[] users, IRole[] roles) throws
Exception {
Map map = new HashMap();
for (int i = 0; i < users.length; i++) {
map.put(users[i], roles);
}
IShareable shareObj = (IShareable)item;
shareObj.setUsersAndRoles(map);
}
Note Each user and user group has a Share table that lists objects that have been shared and
which roles have been granted for those objects.
SDK Developer Guide - Using Agile APIs
32 Agile Product Lifecycle Management
Deleting and Undeleting Objects
The Agile API, like Agile Web Client, lets you delete and undelete objects. To delete and undelete
an object, you must have Delete and Undelete privileges, respectively, for the particular object type.
The Agile API supports “soft” and “hard” deletes. The first time you delete an object, it is “soft-
deleted.” Though it is marked “Deleted” in the database, it is not permanently removed. You can still
retrieve a soft-deleted object; for example, you could use the IAgileSession.getObject()
method to get a deleted object. When you run a query, soft-deleted objects are not included in the
query results. However, Agile provides predefined queries (such as the Deleted Items query in the
Change Analyst Searches folder) that let you find deleted objects.
To remove an object permanently, you delete it a second time, which is a “hard” delete. Once you
hard-delete an object, you cannot restore it using the IDataObject.undelete() method.
Not all Agile PLM objects can be deleted. For example, the following objects cannot be deleted. If
you attempt to delete one of these objects, the delete() method throws an exception.
à An item with a pending change
à An item with a revision history
à An item with a canceled change
à An item with an AML
à A released change
à A manufacturer part currently used on the Manufacturers tab of another object
à A manufacturer with one or more manufacturer parts
If you try to delete an Item that is used on the BOM tab of another item, the Agile PLM server
throws an exception whose ID is ExceptionConstants.APDM_DELETECOMPINUSE_WARNING.
The following example shows how to disable this warning and delete the item.
Example: Deleting an Item
private void deleteItem(IDataObject obj) {
try {
// Delete the Item
obj.delete();
} catch (APIException ex) {
// Check for "Item is Used" warning
if (ex.getErrorCode() ==
ExceptionConstants.APDM_DELETECOMPINUSE_WARNING) {
int i = JOptionPane.showConfirmDialog(null, "This Item is used by
another Item. " +
"Would you still like to delete it?", "Item is Used Warning",
JOptionPane.YES_NO_OPTION);
}
if (i == 0) {
try {
// Disable "Item is Used" warning
Chapter 2: Getting Started with Agile API
v9.3.1.2 33
m_session.disableWarning(ExceptionConstants.APDM_DELETECOMPINUSE_WARNIN
G);
// Delete the object
obj.delete();
// Enable "Item is Used" warning
m_session.enableWarning(ExceptionConstants.APDM_DELETECOMPINUSE_WARNING
);
} catch (APIException exc) {
System.out.println(exc);
}
} else {
System.out.println(ex);
}
}
}
To restore an object that has been soft-deleted, use the IDataObject.undelete() method.
Once again, to undelete an object, the user must have Undelete privileges for that object type.
However, soft-deleted changes that have items on the Affected Items tab cannot be restored,
regardless of the user’s privileges. The following example shows how to undelete an object that has
been deleted.
Example: Undeleting an object
private void undeleteObject(Object obj) throws APIException {
// Make sure the object is deleted before undeleting it
if (obj.isDeleted()) {
// Restore the object
obj.undelete();
}
}
Closing a Session
Each Agile PLM user can open up to three concurrent sessions. Therefore, each session that you
open using the Agile API should be closed properly. If you fail to close a session properly, you may
not be able to log in with a new session until one of the concurrent sessions time out.
Example: Closing a session
public void disconnect(IAgileSession m_session) {
m_session.close();
}
v9.3.1.2 35
Chapter 3
Creating and Loading Queries
This chapter includes the following:
About Queries...................................................................................................................................................... 35
Creating a Query ................................................................................................................................................. 35
Saving a Query to a Folder.................................................................................................................................. 36
Generating Ordered (sorted) or Unordered Query Results ................................................................................. 37
Specifying Query Attributes when Creating a Query........................................................................................... 37
Specifying Search Criteria................................................................................................................................... 38
Using SQL Syntax for Search Criteria................................................................................................................. 50
Setting Result Attributes for a Query................................................................................................................... 53
Working with Query Results ................................................................................................................................ 60
Creating a Where-Used Query............................................................................................................................ 61
Loading a Query.................................................................................................................................................. 62
Deleting a Query..................................................................................................................................................63
Simple Query Examples...................................................................................................................................... 63
About Queries
An IQuery is an object that defines how to search for Agile PLM data. It defines a search similar
to the searches that you can use in Agile Web Client. The search can have multiple search criteria
(like an Advanced Search in Agile Web Client), or it can be a simple search that specifies only one
criterion.
Creating a Query
To create and execute a query, you must first create an IQuery object. As with other Agile API
objects, you create the object using the IAgileSession.createObject() method.
In its simplest form, the parameters that you pass with the createObject() method to create a
query are the IQuery object type and the query class used in the search. In the following example,
the query class is the Item class.
Example: Creating a query
try {
IQuery query =
(IQuery)session.createObject(IQuery.OBJECT_TYPE,
ItemConstants.CLASS_ITEM_BASE_CLASS);
query.setCaseSensitive(false);
query.setCriteria("[Title Block.Number] starts with 'P'");
ITable results = query.execute();
} catch (APIException ex) {
System.out.println(ex);
}
SDK Developer Guide - Using Agile APIs
36 Agile Product Lifecycle Management
The query class you specify with the createObject() method also includes objects from all of its
subclasses. For example, if you search for objects in the Item class, the results include parts and
documents. If you search for objects in the Change class, the results include objects from all
Change subclasses (Deviation, ECO, ECR, MCO, PCO, SCO, and Stop Ship). If you want to search
only a specific subclass, you should explicitly specify that class.
The following example shows how to create a query that searches for objects in a subclass named
Foobar:
Example: Specifying the query class
IAdmin admin = m_session.getAdminInstance();
IAgileClass cls = admin.getAgileClass("Foobar");
IQuery query = (IQuery)m_session.createObject(IQuery.OBJECT_TYPE, cls);
Saving a Query to a Folder
After you name a query using the IQuery.setName() method, you can add it to a folder. The
following example shows how to name a query and add it to the Personal Searches folder. You can
retrieve the query from the folder later to reuse it.
Example: Naming a query and adding it to a folder
try {
IQuery query =
(IQuery)session.createObject(IQuery.OBJECT_TYPE,
ItemConstants.CLASS_ITEM_BASE_CLASS);
query.setCaseSensitive(false);
query.setCriteria("[Title Block.Number] starts with 'P'");
query.setName("Items Whose Number Starts with P");
IFolder folder =
(IFolder)m_session.getObject(IFolder.OBJECT_TYPE,
"/Personal Searches");
folder.addChild(query);
} catch (APIException ex) {
System.out.println(ex);
}
You can also use the IQuery.saveAs() method to name a query and save it to a folder.
Example: Using IQuery.saveAs() to save a query to a folder
try {
IQuery query = (IQuery)session.createObject(IQuery.OBJECT_TYPE,
ItemConstants.CLASS_ITEM_BASE_CLASS);
query.setCaseSensitive(false);
query.setCriteria("[Title Block.Number] starts with 'P'");
IFolder folder = (IFolder)m_session.getObject(IFolder.OBJECT_TYPE,
"/Personal Searches");
query.saveAs("Items Whose Number Starts with P", folder);
} catch (APIException ex) {
System.out.println(ex);
}
Chapter 3: Creating and Loading Queries
v9.3.1.2 37
Note Any query that you create without explicitly saving it to a folder is considered a temporary
query. The Agile Application will automatically delete all temporary queries when the
user session is closed.
Generating Ordered (sorted) or Unordered Query
Results
As shown in examples for Creating a Query on page 35, executing IQuery.execute() and
IQuery.execute(Object[] params) methods returns an ordered query result in ITable.
To improve query performance, the SDK provides the following methods to return results that are
not sorted in the default order. However, if the query criteria has the starts with condition, then
results are always sorted on that attribute and passing skipOrdering as true in
execute(boolean) will not skip ordering.
Note To sort query results by other than the default order, see
Sorting Query Results on page
60.
à IQuery.execute(boolean skipOrdering)
à IQuery.execute(Object[] params, boolean skipOrdering)
To skip or perform ordering, set the boolean skipOrdering to true or false as shown in the
following example.
Example: Skip ordering in query results
try {
IQuery query =
(IQuery)session.createObject(IQuery.OBJECT_TYPE,
ItemConstants.CLASS_ITEM_BASE_CLASS);
query.setCaseSensitive(false);
query.setCriteria("[Title Block.Number] starts with 'P'");
// The boolean is set to true to skip ordering
ITable results = query.execute(true);
} catch (APIException ex) {
System.out.println(ex);
}
Specifying Query Attributes when Creating a Query
Instead of passing only the query class when you create a query, you can use a more advanced
form of the createObject() method and pass a Map object containing one or more attribute
values. The QueryConstants class contains several constants for query attributes that you can
set when you create a query. These are virtual attributes that do not exist in the Agile PLM
database, but that can be used to define the query at run time.
SDK Developer Guide - Using Agile APIs
38 Agile Product Lifecycle Management
Attribute Constant Description
ATT_CRITERIA_CLASS
Query class.
ATT_CRITERIA_PARAM
Search condition parameter value (for a parameterized search condition).
ATT_CRITERIA_STRIN
G
Search condition string.
ATT_PARENT_FOLDER
Parent folder where the query resides.
ATT_QUERY_NAME
Query name.
The following example shows how to set the query class, search condition, parent folder, and query
name when you create the query.
Example: Specifying query attributes when you create a query
try {
String condition = "[Title Block.Number] starts with 'P'";
IFolder parent = (IFolder)m_session.getObject(IFolder.OBJECT_TYPE,
"/Personal Searches");
HashMap map = new HashMap();
map.put(QueryConstants.ATT_CRITERIA_CLASS,
ItemConstants.CLASS_ITEM_BASE_CLASS);
map.put(QueryConstants.ATT_CRITERIA_STRING, condition);
map.put(QueryConstants.ATT_PARENT_FOLDER, parent);
map.put(QueryConstants.ATT_QUERY_NAME, "Part Numbers Starting with
P");
IQuery query = (IQuery)m_session.createObject(IQuery.OBJECT_TYPE,
map);
ITable results = query.execute();
} catch (APIException ex) {
System.out.println(ex);
}
Specifying Search Criteria
You can narrow the number of objects returned from a search by specifying search criteria. If you
don’t specify search criteria, the query returns references to all objects in the specified query class.
It’s a good idea to limit the search criteria as much as possible, as the amount of data returned may
be excessively large, resulting in decreased performance.
There are three different setCriteria() methods you can use to specify query criteria:
à setCriteria(ICriteria criteria) – Sets the query criteria from data stored in the
Criteria administrative node. The Criteria administrative node defines reusable criteria for the
Workflow, but the nodes can also be used as ordinary search criteria.
Note Workflow query is not supported in the current Release of the SDK.
à setCriteria(java.lang.String criteria) – Sets the search criteria from a specified
String.
Chapter 3: Creating and Loading Queries
v9.3.1.2 39
à setCriteria(java.lang.String criteria, java.lang.Object[] params)
Sets the search criteria from a specified String that references one or more parameters.
Unless you use the first setCriteria() method, which takes an ICriteria object for its
parameter, the Agile API parses the search criteria as a String.
Search Conditions
The Agile API provides a simple yet powerful query language for specifying search criteria. The
query language defines the proper syntax for filters, conditions, attribute references, relational
operators, logical operators, and other elements.
Search criteria consist of one or more search conditions. Each search condition contains the
following elements:
1. Left operand – The left operand is always an attribute enclosed in brackets, such as [Title
Block.Number]. You can specify the attribute as an attribute name (fully qualified name or
short name) or attribute ID number. The attribute specifies which characteristic of the object to
use in the search.
2. Relational operator – The relational operator defines the relationship that the attribute has to the
specified value, for example, “equal to” or “not equal to.”
3. Right operand – The matching value for the specified attribute in the left operand. The right
operand can be a constant expression or a set of constant expressions. A set of constant
expressions is needed if the relational operator is “between,” “not between,” “in,” or “not in.”
Following is an example of a search condition:
[Title Block.Description] == 'Computer'
This is another example where the right operand is a set of constant expressions:
[Page Two.Numeric01] between ('1000', '2000')
Query Language Keywords
When you specify a search condition, you must use proper keywords to construct the statement.
The following keywords are available:
and does less or to
asc equal like order union
between from minus phrase where
by greater none select with
contain in not start word
contains intersect null starts words
desc is of than
Query language keywords are not localized. You must use English keywords, regardless of locale.
You can use the keywords in lower case or upper case. In addition to keywords, you can use Agile
PLM variables such as $USER (for current user) and $TODAY (for today’s date) in Agile API queries.
SDK Developer Guide - Using Agile APIs
40 Agile Product Lifecycle Management
Note The "in" operator does not support MultiList in (set) query criteria.
Specifying Search Attributes
Every Agile PLM object that you can search for also has an associated set of attributes, which are
inherent characteristics of the object. You can use these attributes as the left operand of a search
condition. The right operand of the search condition specifies the attribute’s value(s).
A search attribute must be enclosed within brackets, for example, [Title Block.Number]. The
brackets are needed because many attribute names have spaces. If a search attribute is not
enclosed within brackets, your query will fail.
You can specify a search attribute in the following ways:
Attribute reference Example
attribute ID number
[1001]
fully-qualified attribute name
[Title Block.Number]
short attribute name
[Number]
Note Because attribute names can be modified, Agile recommends referencing attributes by
ID number or constant. However, many of the examples in this chapter reference
attributes by name simply to make them more readable. If you choose to reference
attributes by name, use the fully-qualified attribute name instead of the short name. Short
attribute names are not guaranteed to be unique and could therefore cause your query to
fail or produce unexpected results.
Attribute names, whether you use the long or short form, are case-insensitive. For example,
[Title Block.Number] and [TITLE BLOCK.NUMBER] are both allowed. Attribute names are
also localized. The names of Agile PLM attributes vary based on the locale of your Agile Application
Server. If you are creating a query that is going to be used on servers in different locales, you
should reference attributes by ID number (or the equivalent constant) instead of by name.
Note The APIName field, described in
Accessing PLM Metadata with APIName Field on page
123, does not support specifying search attributes.
If the attribute name contains special characters, such as quotes or backslashes, you can type
these characters using the backslash (\) as an escape character. For example, to include a quote
character in your string, type \'. If you want to write a backslash, type two of them together (\\). If the
attribute name contains square brackets, enclose the entire name in quotes:
['Page Two.Unit of Measure [g or oz]']
There are other less intuitive ways to specify attributes. For example, you can pass in an
IAttribute reference using a parameter of the setCriteria() method. In the following
example, ‘%0’ references the attribute in the Object array parameter.
query.setCriteria("[%0] == 'Computer'", new Object[] { attr });
You can also use String concatenation to reference an attribute constant:
query.setCriteria("[“ + ItemConstants.ATT_TITLE_BLOCK_DESCRIPTION + “]
== 'Computer'”);
Chapter 3: Creating and Loading Queries
v9.3.1.2 41
Retrieving Searchable Attributes
The searchable attributes for a query depend on the specified query class or subclass. However,
the searchable attributes for a subclass can differ greatly from searchable attributes for its parent
class.
Due to database considerations, not all attributes are searchable. Generally, a few select Page One
attribute (namely: Title Page, Cover Page, and General Info attributes) are searchable for each
class.
If a tab is not configured in Java Client to be visible, you can still search for an attribute on that tab
in the Agile SDK. However, you must search for the Table name that corresponds to the Tab name.
Note Because you use the table name to setup IQuery, it does not matter if an Agile
administrator changes a Tab name from the name specified in Agile Java Client. Tab
name changes do not affect SDK table names.
To find the searchable attributes for a query, use the IQuery.getSearchableAttributes()
method.
Note Even though an attribute may not be searchable, it can still be included as a column in
the query results. For more information, see Setting Result Attributes for a Query on
page
53.
Using Relational Operators
Table below lists relational operators that are supported by the Agile API query language.
English operator Notation Description
equal to ==
Finds only an exact match with the specified value.
not equal to !=
Finds any value other than an exact match with the specified
value.
greater than >
Finds any value greater than the specified value.
greater than or equal
to
>=
Finds any value greater than or equal to the specified value.
less than <
Finds any value less than the specified value.
less than or equal to <=
Finds any value less than or equal to the specified value.
contains, contains
all
Finds any value that includes the specified value.
does not contain,
does not contain all
Finds any value that does not include the specified value.
contains any
Finds any value that includes the specified value.
does not contain any
Finds any value that does not include the specified value.
SDK Developer Guide - Using Agile APIs
42 Agile Product Lifecycle Management
English operator Notation Description
contains none of
Finds any value that includes none of the specified values.
does not contain none
of
Behaves the same as does not contain any.
starts with
Finds values that begin with characters in the specified value.
does not start with
Finds values that do not begin with characters in the specified
value.
is null
Finds objects where the selected attribute contains no value.
is not null
Finds objects where the selected attribute contains a value.
like
Performs a wildcard search, finding objects that match a single
character or any string.
not like
Performs a wildcard search, finding objects that do not match a
single character or any string.
between
Finds objects that fall between the specified values.
not between
Finds objects that do not fall between the specified values.
in
Finds objects that match any of the specified values.
not in
Finds objects that do not match any of the specified values.
contains phrase
Finds objects with files that contain the specified phrase.
contains all words
Finds objects with files that contain all of the specified words.
contains any word
Finds objects with files that contain any of the specified words.
contains none of
Finds objects with files that contain none of the specified words.
Relational operators are not localized. You must use English keywords, regardless of locale. As
with other query language keywords, you can use them in lower case or upper case.
Using Unicode Escape Sequences
Agile SDK Query language supports Unicode escape sequences. The primary usage of Unicode
escape sequences in a query string is to search for nonburnable or foreign local character sets. A
Unicode character is represented with the Unicode escape sequence \uxxxx, where xxxx is a
sequence of four hexadecimal digits.
For example, to search for an item with Unicode 3458, use the following query:
Select * from [Items] where [Description] contains '\u3458'
There is another query operation for contains’ usage in the case of MultiList.
Chapter 3: Creating and Loading Queries
v9.3.1.2 43
Using Between, Not Between, In, and Not In Operators
The ‘between’, ‘not between’, ‘in’, and ‘not in’ relational operators are not supported directly by Agile
PLM Java and Web Clients. These relational operators provide a convenient shorthand method for
specifying ‘equal to’, ‘not equal to’, ‘greater than or equal to’, or ‘less than or equal to’ operations
with a set of values.
Short form Equivalent long form
[Number] between ('1','6') [Number] >= '1' and [Number] <= '6'
[Number] not between
('1','6')
[Number] < '1' and [Number] > '6'
[Number] in
('1','2','3','4',5','6')
[Number] == '1' or [Number] == '2' or [Number] ==
'3' or [Number] == '4' or [Number] == '5' or
[Number] == '6'
[Number] not in
('1','2','3','4','5','6')
[Number]!= '1' and [Number] != '2' and [Number] !=
'3' and [Number] != '4' and [Number] != '5' and
[Number] != '6'
As shown in the preceding table, when you use the ‘between’, ‘not between’, ‘in’, and ‘not in’
relational operators, each value in the set of values must be enclosed in quotes and delimited by
commas. Here are more criteria examples that use ‘between’ and ‘in’ relational operators:
[Title Block.Number] in ('1000-02', '1234-01', '4567-89')
[Title Block.Effectivity Date] between ('01/01/2001', '01/01/2002')
[Page Two.Numeric01] between ('1000', '2000')
Note The relational operators any , all, none of, and not all are not supported in the
SDK.
Using the Nested Criteria to Search for Values in Object Lists
Several lists in Agile PLM contain business objects, such as Agile PLM users. To search for an
object in such a dynamic list, you can specify nested query criteria. Nested criteria are enclosed in
parentheses and separated from each other by a logical AND (&&) or OR (||) operator. A comma
can also be used to separate nested criteria; it’s equivalent to a logical OR.
The following criteria find a user with the first name Christopher OR the last name Nolan.
[Page Two.Create User] in ([General Info.First Name] == 'Christopher',
[General Info.Last Name] == 'Nolan')
The following criteria find a user with the first name Christopher AND the last name Nolan.
[Page Two.Create User] in ([General Info.First Name] == 'Christopher'
&&
[General Info.Last Name] == 'Nolan')
If Part.Page Three.List01 is enabled and set to Part Families list, the following criteria
finds a Part Family with the name PartFamily_01
[Page Three.List01] in ([General Info.Name] == ‘PartFamily_01’)
SDK Developer Guide - Using Agile APIs
44 Agile Product Lifecycle Management
The parameter query is not supported in nested queries and multiple values for one placeholder in
query parameters must be specified in two dimensional arrays as shown in the example below.
Example: Correct and incorrect parameter query in nested query criteria
à The parameter query specified in the following nested query criteria will fail to execute:
[Page Two.User1] in ([General Info.First Name] == %0)
à However, when it is explicitly specified as a string value, instead of the placeholder, it will
succeed:
[Page Two.User1] in ([General Info.First Name] == ‘Christopher’)
Using Criteria Selected from Criteria Library in SDK Queries
Criteria nodes in Java or Web Client's Criteria library are ICriteria objects that you can use in
SDK queries. To view a listing in Java Client as shown below, select Admin > Settings > Data Settings >
Criteria.
Figure 3: Criteria nodes in Java Client's Criteria library
The following example gets a Criteria node from the Criteria library and loads and sets it as the SDK
query criteria.
Example: Using criteria from the Criteria Library in SDK queries
IQuery query = (IQuery) session.createObject(IQuery.OBJECT_TYPE,
ItemConstants.CLASS_ITEM_BASE_CLASS);
IAdmin admin = session.getAdminInstance();
// Get the Criteria Library node
INode criteriaLibrary =
admin.getNode(NodeConstants.NODE_CRITERIA_LIBRARY);
// Load the Criteria relevant to the query class (For example it is
Items base class)
ICriteria criteria = (ICriteria) criteriaLibrary.getChild("All
Released Items");
// Set the ICriteria in SDK Query Criteria
query.setCriteria(criteria);
Chapter 3: Creating and Loading Queries
v9.3.1.2 45
Using Relationships and Content in SDK Queries
Agile SDK provides APIs to perform the Relationships and Content Search using the IQuery
interface. The query criteria can contain the attributes of both the base search class and the related
class.
To search using an object's Relationships:
1. Set searchType to QueryConstants.RELATIONSHIPS using
IQuery.setSearchType(int searchType).
2. Set the related class using IQuery.setRelatedContentClass(Object
relatedClass).
Example: Using an object's Relationships as the query criteria
IQuery query1 = (IQuery) session.createObject(IQuery.OBJECT_TYPE,
ItemConstants.CLASS_PART);
query1.setSearchType(QueryConstants.RELATIONSHIPS);
query1.setRelatedContentClass("Substance"); // ID or API Name
query1.setCriteria("[Relationships.Name] Is Not Null and [Title
Block.Number] equals ‘P00001’ and [Relationships.Substance.General
Info.Name] Is Not Null");
To search using a Project object's Content:
1. Set searchType to QueryConstants.RELATIONSHIPS using
IQuery.setSearchType(int searchType).
2. Set the related class using IQuery.setRelatedContentClass(Object
relatedClass).
Example: Using a Project object's Content as the query criteria
IQuery query1 = (IQuery) session.createObject(IQuery.OBJECT_TYPE,
ProgramConstants.CLASS_ACTIVITIES_CLASS);
query1.setSearchType(QueryConstants.RELATIONSHIPS);
query1.setRelatedContentClass("ECO"); // ID or API Name
query1.setCriteria("[Content.Criteria Met] Is Not Null and
[Content.ECO.Cover Page.Originator] in ([General Info.First Name] ==
‘admin’)
To search using a Transfer Orders object's Selected Content:
1. Set searchType to QueryConstants.TRANSFER_ORDER_SELECTED_CONTENT using
IQuery.setSearchType(int searchType).
2. Set the related class using IQuery.setRelatedContentClass(Object
relatedClass).
Example: Using a Transfer Orders object's Selected Content as the query criteria
IQuery query1 = (IQuery) session.createObject(IQuery.OBJECT_TYPE,
TransferOrderConstants.CLASS_CTO);
query1.setSearchType(QueryConstants.TRANSFER_ORDER_SELECTED_CONTENT)
;
query1.setRelatedContentClass("ECR"); // ID or API Name
query1.setCriteria("[Selected Content.ECR.Cover Page.Number] equal
to 'C0001'");
SDK Developer Guide - Using Agile APIs
46 Agile Product Lifecycle Management
Searching for Words or Phrases Contained in Attachments
Two special attributes, [Attachments.File Document Text] and [Files.Document
Text] are used to index files and search for files indexed by File Manager that reside on the Agile
file management server. If you are hosting your database on Oracle, you can take advantage of a
feature that lets you search for words or phrases contained in attachments, when you create search
criteria that use either of these attributes.
There are four additional relational operators that you can use:
à contains phrase
à contains all words
à contains any word
à contains none of
The following table shows several search conditions that search for words or phrases in
attachments.
Search Condition Finds
[Attachments.File Document Text] contains
phrase 'adding new materials'
Objects in which any of their attachments contain the
phrase “adding new materials.
all [Attachments.File Document Text]
contains all words 'adding new materials'
Objects in which all their attachments contain the words
“adding,” “new,” and “materials.”
none of [Attachments.File Document Text]
contains any word 'containers BOM return
output'
Objects in which none of their attachments contain any
of the words “containers,” “BOM,” “return,” or “output.”
[Attachments.File Document Text] contains
none of 'containers BOM output'
Objects in which any of their attachments do not contain
the words “containers,” “BOM,” or “output.”
Creating a Parameterized Query
When you specify criteria for a query, you can use a number preceded by a percent sign (%) to
indicate a parameter placeholder. The parameter value is specified later, for example at runtime.
Parameters provide a convenient way to pass values to a query, and they can save time and
reduce extra coding. Parameterized queries can be saved and reused later.
Note The right hand operand query parameter supports one placeholder per each query
operator, so if the query criteria have three query operators, then the query can have a
total of three placeholders corresponding to the three operators. The between and not
between query operations are different. For example, [2091] contains none of
(%0,%1);is not allowed, but [2091] contains none of (%0); is allowed, and
query.execute(new Object[]{new Object[]{"B", "C"}}); is not allowed.
Indexes for query parameters are 0-based. Parameters are numbered 0, 1, 2, and so on. Always
enumerate the parameters in ascending order. The following example shows a query with three
parameters whose values are specified using the IQuery.execute(Object[]) method.
Example: Parameterized query using IQuery.execute(Object[])
Chapter 3: Creating and Loading Queries
v9.3.1.2 47
public ITable runParameterizedQuery() throws Exception {
String condition = "[Title Block.Number] starts with %0 and" +
"[Title Block.Part Category] == %1 and" +
"[Title Block.Description] contains %2";
IQuery query = (IQuery)m_session.createObject(IQuery.OBJECT_TYPE,
ItemConstants.CLASS_PART);
query.setCriteria(condition);
ITable table = query.execute(new Object[] {"1", "Electrical",
"Resistor"});
return table;
}
You can also specify query parameters using IQuery.setParams() method, as shown in the
following example. Make sure you set the query parameter values before calling
IQuery.execute(). Otherwise, when you run the query it will use previous parameter values. If
parameters have not been set, the query uses null values. Similarly, if you do not pass any
parameters to a query, then the IQuery.getParams() method returns null.
Example: Parameterized query using IQuery.setParams()
public ITable runParameterizedQuery() throws Exception {
String condition = "[Title Block.Number] starts with %0 and" +
"[Title Block.Part Category] == %1 and" +
"[Title Block.Description] contains %2";
IQuery query = (IQuery) m_session.createObject(IQuery.OBJECT_TYPE,
ItemConstants.CLASS_PART);
query.setCriteria(condition);
query.setParams(new Object[] {"1", "Electrical", "Resistor"});
ITable table = query.execute();
return table;
}
Do not use quote characters around parameterized queries because they will create a set of values
(more than one element) for the query when parameters can only refer to a given value. The
following examples show the proper use of quote characters when creating parameterized queries:
Example: Correct use of quote characters in a parameterized search query
String criteria = "[NUMBER] == %0";
query.execute(new Object[]{"P1000-02"});
String criteria = "[P2.LIST01] in %0";
query.execute(new Object[]{new Object[]{"A1", "B2"}});
Formatting Dates in Query Criteria
Several types of queries require date values. To pass a date as a String, use the
IAgileSession.setDateFormats() method to specify a date format. The
setDateFormats() method also applies to all Agile API values that you specify with
setValue() methods.
SDK Developer Guide - Using Agile APIs
48 Agile Product Lifecycle Management
Note If you don’t set date formats explicitly using the setDateFormats() method, the Agile
API uses the user’s date format for the Agile PLM system. To see your date format in
Agile Web Client, choose Settings > User Profile and then click the Preferences tab.
Example: Setting the date format for a query
m_session.setDateFormats(new DateFormat[] {new
SimpleDateFormat("MM/dd/yyyy")});
query.setCriteria("[Title Block.Rev Release Date] between” +
“('9/2/2001', '9/2/2003')");
query.setCriteria("[Title Block.Rev Release Date]
between (%0,%1)", new String[] {"9/2/2001", "9/2/2003"} );
Alternatively, if you use the setCriteria(String criteria, Object[] params) method,
you can pass Date objects as parameters to the method.
Example: Passing Date objects as parameters of setCriteria()
DateFormat df = new SimpleDateFormat("MM/dd/yyyy");
query.setCriteria("[Title Block.Rev Release Date] between (%0,%1)",
new Object[] { df.parse("9/2/2001"), df.parse("9/2/2003") });
Using Logical Operators
You can use logical operators to combine multiple search conditions into a complex filter. When you
have two or more conditions defined in a set of query criteria, the relationship between them is
defined as either ‘and’ or ‘or’.
à and narrows the search by requiring that both conditions are met. Each item in the results must
match both conditions. The ‘and’ logical operator can also be specified using two ampersands,
‘&&’.
à or broadens the search by including any object that meets either condition. Each item in the
results table needs to match only one of the conditions, but may match both. The ‘or’ logical
operator can also be specified using two vertical bars, ‘||’.
Logical operators are case-insensitive. For example, ‘and’ or ‘AND’ are both allowed.
The following query criteria finds parts that have both a part category equal to Electrical and a
lifecycle phase equal to Inactive.
[Title Block.Part Category] == 'Electrical' and
[Title Block.Lifecycle Phase] == 'Inactive'
If you replace the ‘and’ operator with ‘or’, the query locates all parts with either a part category of
Electrical or a lifecycle phase of Inactive, which could be a large number of parts.
[Title Block.Part Category] == 'Electrical' or
[Title Block.Lifecycle Phase] == 'Inactive'
Note The Agile API provides three where-used set operators. For more information, see
Creating a Where-Used Query on page 61.
Logical operators, including the where-used set operators, are not localized. You must
use English keywords, regardless of locale.
Chapter 3: Creating and Loading Queries
v9.3.1.2 49
Using Wildcard Characters with the Like Operator
If you define a search condition using the ‘like’ operator, you can use two wildcard characters: the
asterisk (*) and question mark (?). The asterisk matches any string of any length, so *at finds cat,
splat, and big hat. For example, [Title Block.Description] like '*book*' returns all
objects that contain the word “book,” such as textbook, bookstore, books, and so on.
The question mark matches any single character, so ?at finds hat, cat, and fat, but not splat. For
example, [Title Block.Description] like '?al*' matches any word containing “al” that
is preceded by a single letter, such as tall, wall, mall, calendar, and so on.
Using Parentheses in Search Criteria
Where-used, set operators have higher priority than and and or logical operators, as shown by the
following table.
Priority Operator(s)
1
à union
à intersection
à minus
2
à and
à or
Therefore, search conditions joined by union, intersection, and minus operators are evaluated before
conditions joined by and or or.
If you use where-used set operators (‘union’, ‘intersect’, or ‘minus’) in search criteria, you can use
parentheses to change the order that criteria are evaluated. If only ‘and’ or ‘or’ logical operators are
used in a search criteria, additional parentheses aren’t needed because they don't change the
result of criteria evaluation.
The following two criteria, although they contain the same search conditions, provide different
results because parentheses are placed differently:
([Title Block.Part Category] == 'Electrical' and
[Title Block.Description] contains 'Resistor') union
([Title Block.Description] contains '400' and
[Title Block.Product Line(s)] contains 'Taurus')
[Title Block.Part Category] == 'Electrical' and
([Title Block.Description] contains 'Resistor' union
[Title Block.Description] contains '400') and
[Title Block.Product Line(s)] contains 'Taurus'
SDK Developer Guide - Using Agile APIs
50 Agile Product Lifecycle Management
Setting Search Criteria for Lists Containing Large Number of
Objects
When using the SDK to query lists that contain a large number of objects, you can improve
performance if you use the object ID in the query criteria to set the value for the list
For example, you can replace this routine:
query.setCriteria("[Page Three.List25] equal to 'Administrator
(admin)'");
with the following for better performance:
IUser user = (IUser)session.getObject(IUser.OBJECT_TYPE, "admin");
query.setCriteria("[Page Three.List25] equal to
"+user.getObjectId());
Using SQL Syntax for Search Criteria
In addition to its standard query language, the Agile API also supports SQL-like syntax for search
criteria. If you’re familiar with how to write SQL statements, you may find this extended query
language easier to work with, more flexible, and more powerful. It combines in one operation the
specification of the query result attributes, the query class, the search condition, and the sort
column(s).
This is a simple example that demonstrates the syntax:
à Query result attributes: SELECT [Title Block.Number], [Title
Block.Description]
à Query class: FROM [Items]
à Search condition: WHERE [Title Block.Number] starts with 'P'
à Sort column(s): ORDER BY 1 asc
To improve readability, it’s recommended that SQL key words such as SELECT and FROM are all
typed using capital letters and each part of the statement appears on a separate line. This is merely
a convention, not a requirement. SQL key words are not case-sensitive, and you can write the
entire query string on one line if you prefer.
The best way to demonstrate the advantages of SQL syntax is to compare the code for a query that
uses standard Agile API query syntax for search criteria with one that uses SQL syntax. The
following example shows a query created using the standard Agile API query syntax:
Example: Query using standard Agile API query syntax
try {
IQuery query = (IQuery)m_session.createObject(IQuery.OBJECT_TYPE,
"Items");
query.setCriteria("[Page Two.Nummeric01] between (1000, 2000)");
//Set result attributes
String[] attrs = { "Title Block.Number", "Title Block.Description",
"Title Block.Lifecycle Phase" };
query.setResultAttributes(attrs);
Chapter 3: Creating and Loading Queries
v9.3.1.2 51
//Run the query
ITable results = query.execute();
} catch (APIException ex) {
System.out.println(ex);
}
This example shows the same query rewritten in SQL syntax. Although the example doesn’t have
fewer lines of code, you may find that it’s more readable than Agile API query syntax, particularly if
you’re familiar with SQL.
Example: Query using SQL syntax
try {
IQuery query = (IQuery)m_session.createObject(IQuery.OBJECT_TYPE,
"SELECT " +
"[Title Block.Number],[Title Block.Description], " +
"[Title Block.Lifecycle Phase] " +
"FROM " +
"[Items] " +
"WHERE " +
"[Title Block.Number] between (1000, 2000)"
);
//Run the query
ITable results = query.execute();
} catch (APIException ex) {
System.out.println(ex);
}
The following example shows a query written with SQL syntax that specifies the search criteria
using the ATT_CRITERIA_STRING query attribute. For more information about how to use query
attributes, see
Specifying Query Attributes when Creating a Query on page 37.
Example: Using SQL syntax to specify query attributes
try {
String statement =
"SELECT " +
"[Title Block.Number], [Title Block.Description] " +
"FROM " +
"[Items] " +
"WHERE " +
"[Title Block.Description] like %0";
HashMap map = new HashMap();
map.put(QueryConstants.ATT_CRITERIA_STRING, statement);
map.put(QueryConstants.ATT_CRITERIA_PARAM, new Object[] { "Comp*" }
);
IQuery query = (IQuery)m_session.createObject(IQuery.OBJECT_TYPE,
map);
ITable results = query.execute();
} catch (APIException ex) {
System.out.println(ex);
}
SDK Developer Guide - Using Agile APIs
52 Agile Product Lifecycle Management
Note Remember, the FROM part of the search condition specifies the query class. If you use
the ATT_CRITERIA_CLASS attribute to also specify a query class, the query class
specified in the SQL search condition takes precedence.
Although you can use the IQuery.setCriteria() method to specify a search condition in SQL
syntax, the IQuery.getCriteria() method always returns the search condition in the standard
Agile API query syntax.
Using SQL Wildcards
You can use both the asterisk (*) and question mark (?) wildcards in a query that uses SQL syntax.
As in standard Agile API query language, the asterisk matches any string and the question mark
matches any single character. You can use wildcards in the SELECT statement (the specified query
result attributes) and the WHERE statement (the search condition). For example, "SELECT *"
specifies all available query result attributes.
Sorting Query Results Using SQL Syntax
If you specify search criteria using SQL syntax instead of the standard Agile API query language,
you can use the ORDER BY keyword to sort the query results. You can sort the results in
ascending or descending order by any attributes specified in the SELECT statement.
In the ORDER BY statement, refer to attributes by the one-based numerical order in which they
appear in the SELECT statement. To specify whether to sort in ascending or descending order, type
“asc” or “desc” after the attribute number. If “asc” or “desc” is omitted, ascending order is used by
default.
Example Description
ORDER BY 1 Sort by the first SELECT attribute in ascending order (the default)
ORDER BY 2 desc Sort by the second SELECT attribute in descending order
ORDER BY 1 asc, 3 desc Sort by the first SELECT attribute in ascending order and the third SELECT attribute in
descending order
Attributes not specified in the SELECT statement cannot be used to sort query results. Also, if you
use "SELECT *" to select all available result attributes, the results cannot be sorted because the
attribute order is undefined.
The following example sorts results in ascending order by [Title Block.Number] and [Title
Block.Sites], the first and third attributes in the SELECT statement.
Example: Using SQL syntax to sort query results
IQuery query = (IQuery)m_session.createObject(IQuery.OBJECT_TYPE,
"SELECT " +
"[Title Block.Number],[Title Block.Description], " +
"[Title Block.Sites],[Title Block.Lifecycle Phase] " +
"FROM " +
"[Items] " +
"WHERE " +
"[Title Block.Number] between (1000, 2000)" +
Chapter 3: Creating and Loading Queries
v9.3.1.2 53
"ORDER BY " +
"1, 3"
);
Setting Result Attributes for a Query
When you run a query, it returns several output fields, which are also called result attributes. By
default, there are only a few result attributes for each query class. You can add or remove result
attributes using the IQuery.setResultAttributes() method.
The following table shows the default query result attributes for each predefined Agile PLM class.
Query class Default result attributes
Changes
Change Orders
ECO
Change Requests
ECR
Deviations
Deviation
Manufacturer Orders
MCO
Price Change Orders
PCO
Sites Change Orders
SCO
Stop Ships
Stop Ship
Cover Page.Change Type
Cover Page.Number
Cover Page.Description
Cover Page.Status
Cover Page.Workflow
Customers
Customers
Customer
General Info.Customer Type
General Info.Customer Number
General Info.Customer Name
General Info.Description
General Info.Lifecycle Phase
SDK Developer Guide - Using Agile APIs
54 Agile Product Lifecycle Management
Query class Default result attributes
Declarations
Homogeneous Material
Declarations
Homogeneous Material
Declaration
IPC 1752-1 Declarations
IPC 1752-1 Declaration
IPC 1752-2 Declarations
IPC 1752-2 Declaration
JGPSSI Declarations
JGPSSI Declaration
Part Declarations
Part Declaration
Substance Declarations
Substance Declaration
Supplier Declarations of
Conformance
Supplier Declaration of
Conformance
Cover Page.Name
Cover Page.Description
Cover Page.Supplier
Cover Page.Status
Cover Page.Workflow
Cover Page.Compliance Manager
Cover Page.Due Date
Cover Page.Declaration Type
Discussions
Discussions
Discussion
Cover Page.Subject
Cover Page.Status
Cover Page.Priority
Cover Page.Type
File Folders
File Folders
File Folder
Title Block.Type
Title Block.Number
Title Block.Description
Title Block.Lifecycle Phase
Items
Parts
Part
Documentation
Document
Title Block.Item Type
Title Block.Number
Title Block.Description
Title Block.Lifecycle Phase
Title Block.Rev
Chapter 3: Creating and Loading Queries
v9.3.1.2 55
Query class Default result attributes
Manufacturers
Manufacturers
Manufacturer
General Info.Name
General Info.City
General Info.State
General Info.Lifecycle Phase
General Info.URL
Manufacturer Parts
Manufacturer Parts
Manufacturer Part
General Info.Manufacturer Part Number
General Info.Manufacturer Name
General Info.Description
General Info.Lifecycle Phase
Packages
Packages
Package
Cover Page.Package Number
Cover Page.Description
Cover Page.Assembly Number
Cover Page.Status
Cover Page.Workflow
Part Groups
Part Groups
Commodity
Part Family
General Info.Name
General Info.Description
General Info.Lifecycle Phase
General Info.Commodity Type
General Info.Overall Compliance
Prices
Published Prices
Contracts
Published Price
Quote History
Quote History
General Info.Price Number
General Info.Description
General Info.Rev
General Info.Price Type
General Info.Lifecycle Phase
General Info.Projects
General Info.Customer
General Info.Supplier
Product Service Requests
Non-Conformance Reports
NCR
Problem Reports
Problem Report
Cover Page.PSR Type
Cover Page.Number
Cover Page.Description
Cover Page.Status
Cover Page.Workflow
SDK Developer Guide - Using Agile APIs
56 Agile Product Lifecycle Management
Query class Default result attributes
Projects
Activities
Phase
Program
Project
Task
Gates
Gate
General Info.Name
General Info.Description
General Info.Status
General Info.Health
General Info.Owner
General Info.Root Parent
General Info.Workflow
General Info.Type
Sourcing Projects
Sourcing projects
Sourcing Projects
General Info.Project Type
General Info.Number
General Info.Description
General Info.Manufacturing Site
General Info.Ship To Location
General Info.Projects
General Info.Customer
General Info.Lifecycle Phase
Quality Change Requests
Corrective Action/Preventive
Action
CAPA
Audits
Audit
Cover Page.QCR Type
Cover Page.QCR Number
Cover Page.Description
Cover Page.Status
Cover Page.Workflow
RFQ Responses
RFQ Responses
RFQ Response
Cover Page.RFQ Number
Cover Page.RFQ Description
Cover Page.Lifecycle Phase
Cover Page.Requested
Cover Page.Completed
Cover Page.Due Date
Chapter 3: Creating and Loading Queries
v9.3.1.2 57
Query class Default result attributes
RFQs
RFQs
RFQ
Cover Page.RFQ Number
Cover Page.RFQ Description
Cover Page.MFG Site
Cover Page.Ship-To Location
Cover Page.Projects
Cover Page.Customer
Cover Page.Lifecycle Phase
Cover Page.RFQ Type
Sites
Sites
Site
General Info.Name
General Info.Contact
General Info.Phone
Specifications
Specifications
Specification
General Info.Name
General Info.Description
General Info.Lifecycle Phase
General Info.Jurisdictions
General Info.Validation Type
General Info.Specification Type
Substances
Materials
Material
Subparts
Subpart
Substance Groups
Substance Group
Substances
Substance
General Info.Name
General Info.Description
General Info.CAS Number
General Info.Lifecycle Phase
General Info.Substance Type
Suppliers
Suppliers
Component
Manufacturer
Contract Manufacturer
Distributor
Manufacturer Rep
General Info.Supplier Type
General Info.Number
General Info.Name
General Info.Description
General Info.Status
SDK Developer Guide - Using Agile APIs
58 Agile Product Lifecycle Management
Query class Default result attributes
Transfer Orders
Content Transfer Orders
CTO
Automated Transfer Orders
ATO
Cover Page.Transfer Order Type (See Retrieving CTO
Originator Name on page 59)
Cover Page.Transfer Order Number
Cover Page.Description
Cover Page.Status
Cover Page.Workflow
Specifying Result Attributes
If you run a query and find that the resulting ITable object does not contain the attributes you
expected, it’s because you didn’t specify result attributes. The following example shows how to
specify the result attributes for a query.
Example: Setting query result attributes
private void setQueryResultColumns(IQuery query) throws APIException {
// Get Admin instance
IAdmin admin = m_session.getAdminInstance();
// Get the Part class
IAgileClass cls = admin.getAgileClass("Part");
// Get some Part attributes, including Page Two and Page Three
attributes
IAttribute attr1 =
cls.getAttribute(ItemConstants.ATT_TITLE_BLOCK_NUMBER);
IAttribute attr2 =
cls.getAttribute(ItemConstants.ATT_TITLE_BLOCK_DESCRIPTION);
IAttribute attr3 =
cls.getAttribute(ItemConstants.ATT_TITLE_BLOCK_LIFECYCLE_PHASE);
IAttribute attr4 =
cls.getAttribute(ItemConstants.ATT_PAGE_TWO_TEXT01);
IAttribute attr5 =
cls.getAttribute(ItemConstants.ATT_PAGE_TWO_NUMERIC01);
IAttribute attr6 =
cls.getAttribute(ItemConstants.ATT_PAGE_THREE_TEXT01);
// Put the attributes into an array
IAttribute[] attrs = {attr1, attr2, attr3, attr4, attr5, attr6};
// Set the result attributes for the query
query.setResultAttributes(attrs);
}
The IQuery.setResultAttributes() method takes an Object[] value for the attrs
parameter, supporting String, Integer,, or IAttribute arrays. Therefore, instead of
specifying an array of IAttribute objects, you can also specify an array of attribute names (such
as {"Title Block.Description", "Title Block.Number"} ) or attribute ID constants.
Chapter 3: Creating and Loading Queries
v9.3.1.2 59
The following example shows how to specify result attributes using ID constants.
Example: Setting query result attributes by specifying ID constants
private void setQueryResultColumns(IQuery query) throws APIException {
// Put the attribute IDs into an array
Integer[] attrs = { ItemConstants.ATT_TITLE_BLOCK_NUMBER,
ItemConstants.ATT_TITLE_BLOCK_DESCRIPTION,
ItemConstants.ATT_TITLE_BLOCK_LIFECYCLE_PHASE,
ItemConstants.ATT_PAGE_TWO_TEXT01,
ItemConstants.ATT_PAGE_TWO_NUMERIC01,
ItemConstants.ATT_PAGE_THREE_TEXT01 };
// Set the result attributes for the query
query.setResultAttributes(attrs);
}
When you use the setResultAttributes() method, make sure you specify valid result
attributes. Otherwise, the setResultAttributes() method will fail. To get an array of available
result attributes that can be used for a query, use getResultAttributes(), as shown in the
following example.
Example: Getting the array of available result attributes
private IAttribute[] getAllResultAttributes(IQuery query) throws
APIException {
IAttribute[] attrs = query.getResultAttributes(true);
return attrs;
}
Retrieving CTO Originator Name
The Cover Page of the Content Transfer Order (CTO) includes the Originator field which specifies
roles and site assignments of users who originate CTOs. To retrieve the user name, you can not
query this field directly and need to retrieve data in UserConstants. For example, the following
statement which attempts to retrieve the user name directly, will not work:
QueryString = ("[Cover Page.Originator] equal to '<Last_name>,
<First_name>'");
But the following statements which also specify the data in UserConstants will work:
QueryString = "[Cover Page.Originator] in
(["+UserConstants.ATT_GENERAL_INFO_USER_ID+"]=='<UserID>')";
Or,
QueryString = "[Cover Page.Originator] in
(["+UserConstants.ATT_GENERAL_INFO_LAST_NAME+"]=='<Last_name>'"+
"&&
["+UserConstants.ATT_GENERAL_INFO_FIRST_NAME+"]=='<First_name>');
The query criteria for any innumerable attribute type such as IItem, IChange, and so on, must be
in a nested form. This applies to the Originator attribute which points to Agile All users.
SDK Developer Guide - Using Agile APIs
60 Agile Product Lifecycle Management
Duplicate Results for Site-Related Objects and AMLs
The manufacturing sites functionality of the Agile Application Server can have unintended results
when you search for items or changes. If you search for items or changes and include a sites
attribute—[Title Block.Site] for items and [Cover Page.Site(s)] for changes—in the
result attributes, the query results include duplicate objects for each site associated with the object.
Similarly, if you search for items and include an AML attribute—such as [Manufacturers.Mfr.
Part Number]—in the result attributes, the query results include duplicate items for each
manufacturer part listed on an item’s Manufacturers table.
For example, a part with the number 1000-02 has five sites associated with it. If you search for that
part and include Title Block.Site in the result attributes, the resulting ITable object returned
by the IQuery.execute method contains five rows, not one. Each row references the same
object, part number 1000-02, but the Site cell has a different value. If you use
ITable.getReferentIterator to iterate through referenced objects in the search results, the
duplicate objects would be more apparent; in this example, you would iterate over the same item
five times.
Working with Query Results
When you run a query, the Agile API returns an ITable object, which extends
java.Util.Collection. You can use the methods of ITable and of
java.Util.Collection to work with the results. For example, the following code shows how to
use the Collection.iterator() method.
Iterator it = query.execute().iterator();
The ITwoWayIterator interface lets you traverse the list of rows in
either direction using the next() and previous() methods.
ITwoWayIterator it = query.execute().getTableIterator();
ITwoWayIterator it = query.execute().getReferentIterator();
For more information about using ITwoWayIterator, see
Iterating Over Table Rows on page 75.
Sorting Query Results
Unlike other Agile API tables, you cannot create a sorted iterator for query results using the
ITable.ISortBy interface. To sort query results, use SQL syntax and specify an ORDER BY
statement with the search criteria. For more information, see
Using SQL Syntax for Search Criteria
on page
50.
Query Result Datatypes
Values in a query results table have the same datatype as their attributes. That is, if an attribute’s
datatype is an Integer, its value in a query results table is also an Integer.
Important Remember that in Agile 9.0 SDK, all values in a query results table are strings. In post
Agile 9.2, these values are integers.
Chapter 3: Creating and Loading Queries
v9.3.1.2 61
Managing Large Query Results
Agile PLM has a system preference named Maximum Query Results Displayed that sets a limit on
the maximum number of rows that can be returned from any query. However, that preference
doesn’t affect Agile SDK Clients. Queries that you run from an Agile SDK Client always return all
results.
Although you can access the entire query result set with the returned ITable object, the Agile API
internally manages retrieving partial results as necessary. For example, let’s say a particular query
returns 5000 records. You can use the ITable interface to access any of those 5000 rows. You
don’t need to worry about how many of the 5000 rows the Agile API actually loaded into memory.
Note Searches that you run from other Agile PLM Clients, such as Agile Web Client, adhere to
the limit imposed by the Maximum Query Results Displayed preference.
Query Performance
The response time for running queries can be the biggest bottleneck in your Agile API program. To
improve performance, you should try to construct queries that return no more than a few hundred
results. A query that returns more than a 1000 results can take several minutes to finish processing.
Such queries also eat up valuable processing on the Agile Application Server, potentially slowing
down your server for all users.
Creating a Where-Used Query
Previous sections of this chapter described how to create queries that search for Agile PLM objects,
for example, items or changes. You can also create where-used queries. In a where-used query,
the search conditions define the items that appear on the BOMs of objects. You can use a where-
used query to find the assemblies on which a particular part is used.
The interface for a where-used query is similar to a standard object query. With minor changes, you
can turn an object query into a where-used query as long as the query class is an Item class.
Note Where-used queries are only defined for Item classes.
To define a where-used query, use the IQuery.setSearchType() method. You can also use
the following logical operators, also called where-used set operators, to further define the
relationships between grouped sets of search conditions. Only one logical operator can be used for
each search condition.
Where Used set
operator
Description
intersect
Produces records that appear in both result sets from two different groups of search conditions.
minus
Produces records that result from the first group of search conditions but not the second.
union
Produces records that are the combination of results from two groups of search conditions.
SDK Developer Guide - Using Agile APIs
62 Agile Product Lifecycle Management
Note Where-used set operators have higher priority than other logical operators. Therefore,
search conditions joined by where-used set operations are evaluated before those joined
by ‘and’ or ‘or’ operators.
Example: Where-used query
void btnFind_actionPerformed(ActionEvent e) {
try {
// Create the query
IQuery wuquery =
(IQuery)m_session.createObject(IQuery.OBJECT_TYPE,
ItemConstants.CLASS_ITEM_BASE_CLASS);
// Set the where-used type
wuquery.setSearchType(QueryConstants.WHERE_USED_ONE_LEVEL_LATEST_RELEAS
ED);
// Add query criteria
wuquery.setCriteria(
"[Title Block.Part Category] == 'Electrical'" +
"and [Title Block.Description] contains 'Resistor'" +
"union [Title Block.Description] contains '400'" +
"and [Title Block.Product Line(s)] contains 'Taurus'");
// Run the query
ITable results = wuquery.execute();
// Add code here to display the results
}
catch (APIException ex) {System.out.println(ex);}
}
Loading a Query
There are two ways to load a query:
à Use the IAgileSession.getObject() method to specify the full path of a query.
à Use the IFolder.getChild() method to specify the location of a query relative to a folder.
The following example shows how to load a query by specifying its full path.
Example: Loading a query using IAgileSession.getObject()
try {
//Load the "Changes Submitted to Me" query
IQuery query =
(IQuery)m_session.getObject(IQuery.OBJECT_TYPE,
"/Workflow Routings/Changes Submitted To Me");
} catch (APIException ex) {
System.out.println(ex);
}
Chapter 3: Creating and Loading Queries
v9.3.1.2 63
The following example shows how to load a query by specifying its path relative to a folder, in this
case the user’s Public In-box folder.
Example: Loading a query using IFolder.getChild()
try {
//Get the Workflow Routings folder
IFolder folder =
(IFolder)m_session.getObject(IFolder.OBJECT_TYPE, "/Workflow
Routings");
//Load the "Changes Submitted to Me" query
IQuery query =
(IQuery)folder.getChild("Changes Submitted To Me");
} catch (APIException ex) {
System.out.println(ex);
}
Deleting a Query
To delete a saved query, use the IQuery.delete() method. Temporary queries, that is, queries
that are created but not saved to a folder are automatically deleted after the user session is closed.
For lengthy sessions, you can use the delete()method to explicitly delete a temporary query after
you’re finished running it.
Example: Deleting a query
void deleteQuery(IQuery query) throws APIException {
query.delete();
}
Simple Query Examples
Figure below depicts an example of dialog box that performs a simple query.
Figure 4: Simple Query dialog box
The Simple Query dialog box lets the user specify an item number to search for. When the user
clicks the Find button, the program constructs a query to find all items that contain the specified text
in the Item Number field. This example shows the code that runs the query when the user clicks
the Find button.
SDK Developer Guide - Using Agile APIs
64 Agile Product Lifecycle Management
Example: Simple Query code
void btnFind_actionPerformed(ActionEvent e) {
try {
// Create the query
IQuery query = (IQuery)m_session.createObject(IQuery.OBJECT_TYPE,
ItemConstants.CLASS_ITEM_BASE_CLASS);
// Turn off case-sensitivity
query.setCaseSensitive(false);
// Specify the criteria data
query.setCriteria("[Title Block.Number] contains (%0)",
new String[] { this.txtItemNum.getText().toString() });
// Run the query
ITable queryResults = query.execute();
Iterator i = queryResults.iterator();
// If there are no matching items, display an error message.
if (!i.hasNext()) {
JOptionPane.showMessageDialog(null, "No matching items.", "Error",
JOptionPane.ERROR_MESSAGE);
return;
}
// Define arrays for the table data
final String[] names = {"Item Number", "Item Description"};
final Object[][] data = new Object[resultCount][names.length];
int j = 0;
while (i.hasNext()) {
IRow row = (IRow)i.next();
data[j][0] =
row.getValue(ItemConstants.ATT_TITLE_BLOCK_NUMBER).toString();
data[j][1] =
row.getValue(ItemConstants.ATT_TITLE_BLOCK_DESCRITPION).toString();
j++;
}
catch (APIException ex) {
System.out.println(ex);
}
// Create a table model
TableModel newDataModel = new AbstractTableModel() {
// Add code here to implement the table model
};
// Populate the table with data from the table model
myTable.setModel(newDataModel);
}
v9.3.1.2 65
Chapter 4
Working with Tables
This chapter includes the following:
About Tables........................................................................................................................................................ 65
Retrieving a Table................................................................................................................................................ 66
Accessing the New and Merged Relationships Tables........................................................................................ 67
Retrieving the Metadata of a Table......................................................................................................................69
Adding Table Rows.............................................................................................................................................. 69
Adding and Updating Multiple Table Rows.......................................................................................................... 72
Iterating Over Table Rows................................................................................................................................... 75
Sorting Table Rows ............................................................................................................................................. 76
Removing Table Rows......................................................................................................................................... 78
Retrieving the Referenced Object for a Row....................................................................................................... 78
Checking Status Flags of a Row..........................................................................................................................83
Working with Page 1, Page 2, and Page 3.......................................................................................................... 83
Redlining..............................................................................................................................................................84
Removing Redline Changes................................................................................................................................ 86
Identifying Redlined Rows and Redlined Cells.................................................................................................... 87
About Tables
Whenever you work with an Agile PLM object in your program, you inevitably need to get and
display the object’s data. The data is contained in one or more tables. In Agile Web Client, these
tables are equivalent to the separate tabs in a window, such as the Manufacturers and BOM tabs.
The following figure shows the BOM tab for an item in Agile Web Client.
Figure 5: BOM tab for Item
In some cases, a tab in Agile Web Client contains multiple tables. For example, the Changes tab for
an item contains the Pending Changes table and the Change History table. The tabs and the tables
SDK Developer Guide - Using Agile APIs
66 Agile Product Lifecycle Management
that they contain is not always the same for different Agile products. Also, they are not the same for
each Agile PLM Dataobject. For example, tables for Parts objects are different from tables for
Manufacturers objects. See
Retrieving a Table on page 66.
To work with data in an Agile PLM table, follow these basic steps:
1. Create or get an object (for example, an item or a change order).
2. Retrieve a table (for example, the BOM table).
3. Iterate through the table rows to retrieve a row.
4. Get or set one or more attribute values for the selected row.
ITable, like IFolder, extends java.util.Collection and supports all the methods provided
by that superinterface. This means that you can work with an ITable object as you would any Java
Collection.
Interface Inherited methods
java.util.Collecti
on
add(), addAll(), clear(), contains(), containsAll(),
equals(), hashCode(), isEmpty(), iterator(), remove(),
removeAll(), retainAll(), size(), toArray(), toArray()
Retrieving a Table
After you create or get an object, you can use the IDataObject.getTable() method to retrieve
a particular Agile PLM table. IDataObject is a general-purpose object that represents any Agile
PLM object that contains tables of data. It is a superinterface of several other objects, including
IItem, IChange, and IUser.
Note When retrieving PG&C’s Supplier Declaration of Conformance (SDOC) tables,
IDataObject.getTable() retrieves all 14 SDOC tables belonging to this base class.
However, six of these tables (Items, Manufacturer Parts, Part Groups, Item Composition,
Manufacturer Part Composition, Part Group Composition) are not enabled.
Tables vary for each Agile PLM dataobject. Tables for change objects are different from tables for
items. Each table for a particular dataobject is identified by a constant in the constants class for that
dataobject. Item constants are contained in the ItemConstants class, change constants are
contained in the ChangeConstants class, and so on.
For information to use these tables, refer to the following Agile product administration documents:
à Getting Started with Agile PLM
à Agile PLM Administrator Guide
à Agile PLM Product Governance & Compliance User Guide
à Agile PLM Product Portfolio Management User Guide
Chapter 4: Working with Tables
v9.3.1.2 67
Accessing the New and Merged Relationships Tables
In Release 9.2.2, the following tables were merged into a single table called the Relationships
table.
à Relationships.AffectedBy
à Relationships.Affects
à Relationships.Reference
In addition, the constants that are used by these tables (TABLE_REFERENCES,
TABLE_RELATIONSHIPSAFFECTS, and TABLE_RELATIONSHIPSAFFECTEDBY) were also
removed. If you need these constants, you must rewrite them in your routines.
Note For a complete list of table constants that are merged and mapped into a single
constants, or mapped into a new constant, see Migrating Release 9.2.1 and Older
Table Constants to Release 9.2.2 on page 361.
For information to use these tables, refer to the following Agile documents:
à To use these tables in Agile PLM products, refer to Getting Started with Agile PLM and Agile
PLM Administrator Guide
à To use these tables in Agile PPM products, refer to Agile PLM Product Portfolio Management
User Guide
Accessing the Relationships Table
The IRelationshipContainer interface was implemented to access this table. Any Agile
business object that contains the Relationships table implements this interface. You can access this
table using IRelationshipContainer, or IDataObject.getTable() with
CommonConstants.TABLE_RELATIONSHIPS constant.
IRelationshipContainer container = (IRelationshipContainer) object;
ITable relationship = container.getRelationship();
Accessing the Merged Tables
If you used these tables in previous releases of Agile PLM, and require the functionalities that they
provided, modify your code as shown below.
Accessing the Merged Relationships.AffectedBy Table
à Code used in Release 9.2.1.x and earlier releases:
ITable affectedBy =
object.getTable(ChangeConstants.TABLE_RELATIONSHIPSAFFECTEDBY);
à Code recommended for this release:
ITable affectedBy =
object.getTable(CommonConstants.TABLE_RELATIONSHIPS)
.where("[2000007912] == 1", null);
SDK Developer Guide - Using Agile APIs
68 Agile Product Lifecycle Management
Accessing the Merged Relationships.Affects table
à Code used in Release 9.2.1.x and earlier releases:
ITable affects =
object.getTable(ChangeConstants.TABLE_RELATIONSHIPSAFFECTS);
à Code recommended for this release:
ITable affects =
object.getTable(CommonConstants.TABLE_RELATIONSHIPS)
.where("[2000007912] == 2", null);
Accessing the Merged Relationships.References Table
à Code used in Release 9.2.1.x and earlier releases:
ITable references =
object.getTable(ChangeConstants.TABLE_RELATIONSHIPS_REFERENCES);
à Code recommended for this release:
ITable references =
object.getTable(CommonConstants.TABLE_RELATIONSHIPS)
.where("[2000007912] == 3", null);
Important The ITable.where() method is certified for deployment with these three tables
only, and it may fail if it is used to access other tables from the SDK.
The following example shows how to retrieve and print the BOM table for an item.
Example: Retrieving the BOM table
//Load an item
private static IItem loadPart(String number) throws APIException {
IItem item = (IItem)m_session.getObject(ItemConstants.CLASS_PART,
number);
return item;
}
//Get the BOM table
private static void getBOM(IItem item) throws APIException {
IRow row;
ITable table = item.getTable(ItemConstants.TABLE_BOM);
Iterator it = table.iterator();
while (it.hasNext()) {
row = (IRow)it.next();
//Add code here to do something with the BOM table
}
}
Chapter 4: Working with Tables
v9.3.1.2 69
Working with Read-only Tables
Several Agile PLM tables store history information or data about related objects. These tables are
read-only and as such, you cannot modify these tables. When you write code to access a table, use
the ITable.isReadOnly() method to check if the table is read-only.
Retrieving the Metadata of a Table
The ITableDesc is an interface that represents the metadata of a table which is the underlying
data that describes a table’s properties. ITableDesc is related to ITable in the same way that
IAgileClass is related to IDataObject. At times you may need to identify the attributes for a
particular table, its ID, or its table name without loading a dataobject. The following example shows
how to use the ITableDesc interface to retrieve the collection of all attributes (including ones that
aren’t visible) for a table.
Example: Retrieving the metadata of a table
private IAttribute[] getBOMAttributes() throws APIException {
IAgileClass cls = admin.getAgileClass(ItemConstants.CLASS_PART);
ITableDesc td = cls.getTableDescriptor(ItemConstants.TABLE_BOM);
IAttribute[] attrs = td.getAttributes();
return attrs;
}
You can also use the API Name field to identify a table's name or ID. For information to use this
field, see
Accessing PLM Metadata with APIName Field on page 123. For information to use the
Agile API to work with metadata, see
Performing Administrative Tasks on page 329.
Adding Table Rows
To create a table row, use the ITable.createRow(java.lang.Object) method, which creates
a new row and initializes it with the data specified in the param parameter. The param parameter
of createRow is available to pass the following data:
à a set of attributes and values for the row’s cells
à files or URLs to add to the Attachments table
à an Agile PLM object (such as an IItem) to add to the table
When you add a row to a table, it’s not necessarily added at the end of the table.
Note There is also a deprecated, parameter-less version of the createRow() method, which
creates an empty row. Avoid using that method because it may not be supported in
future Agile PLM releases. You must initialize a row with data when you create it.
You can also add table rows in batch format with ITable.createRow(). See Adding and
Updating Multiple Table Rows on page 72.
SDK Developer Guide - Using Agile APIs
70 Agile Product Lifecycle Management
Adding an Item to the BOM Table
The following example shows how to use the ITable.createRow() method to add an item to a
BOM table.
Example: Adding a row and setting values
private static void addToBOM(String number) throws APIException {
IItem item = (IItem)m_session.getObject(ItemConstants.CLASS_PART,
number);
ITable table = item.getTable(ItemConstants.TABLE_BOM);
Map params = new HashMap();
params.put(ItemConstants.ATT_BOM_ITEM_NUMBER, "1543-01");
params.put(ItemConstants.ATT_BOM_QTY, "1");
item.setManufacturingSite(ManufacturingSiteConstants.COMMON_SITE);
IRow row = table.createRow(params);
}
Note To add a site-specific row to the BOM table, use
IManufacturerSiteSelectable.setManufacturingSite() to select a specific
site before calling ITable.createRow().
Adding an Attachment to the Attachments Table
The following example shows how to use the ITable.createRow(java.lang.Object)
method to add a row to the Attachments table. The code adds a row to the table and initializes it
with the specified file. After adding the row, the code also sets the value of the File Description field.
Example: Adding a row to the Attachments table
private static void addAttachmentRow(String number) throws APIException
{
File file = new File("d:/MyDocuments/1543-01.dwg");
IItem item = (IItem)m_session.getObject(ItemConstants.CLASS_PART,
number);
ITable table = item.getTable(ItemConstants.TABLE_ATTACHMENTS);
IRow row = table.createRow(file);
}
Adding a Manufacturer Part to the Manufacturers Table
The following example shows how to use the ITable.createRow(java.lang.Object) method
to add a row to the Manufacturers table of an item. The code adds a row to the table and initializes
it with the specified IManufacturerPart object.
Example: Adding a row to the Manufacturers table
private static void addMfrPartRow(String number) throws APIException {
HashMap info = new HashMap();
info.put(ManufacturerPartConstants.ATT_GENERAL_INFO_MANUFACTURER_PART_N
UMBER, "TPS100-256");
Chapter 4: Working with Tables
v9.3.1.2 71
info.put(ManufacturerPartConstants.ATT_GENERAL_INFO_MANUFACTURER_NAME,
"TPS_POWER");
IManufacturerPart mfrPart = (IManufacturerPart)m_session.getObject(
ManufacturerPartConstants.CLASS_MANUFACTURER_PART, info
);
IItem item = (IItem)m_session.getObject(ItemConstants.CLASS_PART,
number);
item.setManufacturingSite(ManufacturingSiteConstants.COMMON_SITE);
ITable table = item.getTable(ItemConstants.TABLE_MANUFACTURERS);
IRow row = table.createRow(mfrPart);
}
Note To add a site-specific row to the Manufacturers table, use
IManufacturerSiteSelectable.setManufacturingSite() to select a specific
site before calling ITable.createRow().
Adding an Item to the Affected Items Table
The following example shows how to use the ITable.createRow(java.lang.Object) method
to add a row to the Affected Items table of a change order. The code adds a row to the table and
initializes it with the specified IItem object.
Example: Adding a row to the Affected Items table
private static void addItemRow(String number) throws APIException {
IItem item = (IItem)m_session.getObject(ItemConstants.CLASS_PART,
"P522-103");
IChange change =
(IChange)m_session.getObject(ChangeConstants.CLASS_ECO, number);
ITable table = change.getTable(ChangeConstants.TABLE_AFFECTEDITEMS);
IRow row = table.createRow(item);
}
Because the BOM table also references IItem objects, you can use code similar to those in
Example 49 to add a row to a BOM table.
Adding a Task to the Schedule Table
The following example shows how to use the ITable.createRow(java.lang.Object) method to add a
row to the Schedule table of a Project. The code adds a row to the table and initializes it with the
specified IProgram object.
Example: Adding a row to the Schedule table
private static void addTaskRow(IProgram program, IProgram task) throws
APIException {
// Get the Schedule table of the program
ITable table = program.getTable(ProgramConstants.TABLE_SCHEDULE);
// Add the task to the schedule
IRow row = table.createRow(task);
}
SDK Developer Guide - Using Agile APIs
72 Agile Product Lifecycle Management
Adding and Updating Multiple Table Rows
The ITable interface provides two convenient methods for adding and updating multiple table rows
with one API call:
à ITable.createRows()
à ITable.updateRows()
Because these methods group multiple table rows in one API call, they can improve performance by
reducing the number of Remote Procedure Calls (RPCs), particularly if you are connecting to the
server across a Wide Area Network (WAN). However, these methods do not result in efficient batch
operations on the Agile Application Server, which simply iterates through each row being added or
updated.
Important The ITable.createRows() and ITable.updateRows() methods are supported
only when you are adding or updating multiple rows on the BOM table of items, or the
Affected Items table of Changes.
Adding Multiple Team Members to the Team Table of a Project
The following example shows how the ITable.createRows() method supports the Team Table
of a Project.
Example: Adding Multiple Team members to a Program using the Bulk API
private static void createTeamRows(String[] addTeamMembers) throws
APIException {
//Get the Project
IProgram program = (IProgram)session.getObject(IProgram.OBJECT_TYPE,
programNumber);
//Get the Team Table
ITable teamTable = program.getTable(ProgramConstants.TABLE_TEAM);
IAgileList attrRolesValues =
teamTable.getAvailableValues(ProgramConstants.ATT_TEAM_ROLES);
attrRolesValues.setSelection(new Object[]{"Change
Analyst","Program Team Member"});
//Collect team members already on Team Table
Set presentMembers = new HashSet();
Iterator it = teamTable.iterator();
while(it.hasNext()) {
IRow row = (IRow)it.next();
IUser user = (IUser)row.getReferent();
presentMembers.add(user);
}
//Validate new team members and filter out existing members to
and to Team Table
IUser user = null;
IUser[] newUsers= new IUser[addTeamMembers.length];
int usrCount = 0;
for(int i =0; i<addTeamMembers.length; i++ ) {
Chapter 4: Working with Tables
v9.3.1.2 73
user = (IUser)session.getObject(IUser.OBJECT_TYPE,
addTeamMembers[i]);
if(!presentMembers.contains(user) || user==null) {
newUsers[usrCount++]=user;
}
}
//Using createRows() API to add all Team members at onece
//In this bulk approach, make sure each map in array is complete
by it self to create a new row in Team Table.
List<Map> newTeam=new ArrayList<Map>();
for (int i=0; i<usrCount; i++) {
Map teamMap = new HashMap();
teamMap.put(ProgramConstants.ATT_TEAM_NAME, newUsers[i]);
teamMap.put(ProgramConstants.ATT_TEAM_ROLES,
attrRolesValues);
teamMap.put(ProgramConstants.ATT_TEAM_ALLOCATION, 0);
newTeam.add(teamMap);
}
teamTable.createRows(newTeam.toArray(new Object[0]));
}
Adding Multiple Items to the BOM Table
The following example shows how to use the ITable.createRows() method to add multiple
items to a BOM table.
Example: Adding multiple rows and setting values
private static void createBOMRows(String partNumber) throws
APIException {
IItem[] child = new IItem [3];
IItem parent = null;
ITable tab = null;
// Get the parent item
parent = (IItem) m_session.getObject(IItem.OBJECT_TYPE, partNumber);
// Get the BOM table
tab = parent.getTable(ItemConstants.TABLE_BOM);
// Create child items
child[0] = (IItem) m_session.createObject(ItemConstants.CLASS_PART,
partNumber + "-1");
child[1] = (IItem) m_session.createObject(ItemConstants.CLASS_PART,
partNumber + "-2");
child[2] = (IItem) m_session.createObject(ItemConstants.CLASS_PART,
partNumber + "-3");
// Create a row array
IRow[] rowArray = new IRow[3];
// Add the items to the BOM
SDK Developer Guide - Using Agile APIs
74 Agile Product Lifecycle Management
rowArray = tab.createRows(new Object[]{child[0], child[1],
child[2]});
}
Note To add a site-specific row to the BOM table, use
IManufacturerSiteSelectable.setManufacturingSite() to select a specific
site before calling ITable.createRow().
Updating Multiple BOM Rows
To update multiple rows, use the ITable.updateRows() method. This method batches together
multiple update operations into a single call. Instead of calling IRow.setValues() for multiple
rows in a table, this API updates an entire table in one method call.
The rows parameter of updateRow() can be used to pass a Map containing IRow instances as
keys with instances for values. The value Map objects should have attribute IDs as keys and
replacement data for values.
Example: Updating multiple BOM rows
private static void updateBOMRows(String partNumber) throws
APIException {
IItem parent = null;
ITable tab = null;
HashMap[] mapx = new HashMap[3];
Map rows = new HashMap();
IRow[] rowArray = new IRow[3];
// Get the parent item
parent = (IItem) m_session.getObject(IItem.OBJECT_TYPE, partNumber);
// Get the BOM table
tab = parent.getTable(ItemConstants.TABLE_BOM);
// Create three items
IItem child1 = (IItem)
m_session.createObject(ItemConstants.CLASS_PART, partNumber + "-1");
IItem child2 = (IItem)
m_session.createObject(ItemConstants.CLASS_PART, partNumber + "-2");
IItem child2 = (IItem)
m_session.createObject(ItemConstants.CLASS_PART, partNumber + "-3");
// Add these items to BOM table
rowArray = tab.createRows(new Object[]{child1, child2, child3});
// New values for child[0]
mapx[0] = new HashMap();
mapx[0].put(ItemConstants.ATT_BOM_FIND_NUM, new Integer(1));
mapx[0].put(ItemConstants.ATT_BOM_QTY, new Integer(3));
mapx[0].put(ItemConstants.ATT_BOM_REF_DES, "A1-A3");
rows.put(rowArray[0], mapx[0]);
// New values for child[1]
mapx[1] = new HashMap();
mapx[1].put(ItemConstants.ATT_BOM_FIND_NUM, new Integer(2));
mapx[1].put(ItemConstants.ATT_BOM_QTY, new Integer(3));
mapx[1].put(ItemConstants.ATT_BOM_REF_DES, "B1-B3");
rows.put(rowArray[1], mapx[1]);
// new values for child[2]
Chapter 4: Working with Tables
v9.3.1.2 75
mapx[2] = new HashMap();
String strA = "BOM-Notes" + System.currentTimeMillis();
mapx[2].put(ItemConstants.ATT_BOM_BOM_NOTES, strA);
mapx[2].put(ItemConstants.ATT_BOM_FIND_NUM, new Integer(3));
rows.put(rowArray[2], mapx[2]);
// Update the BOM table rows
tab.updateRows(rows);
}
Iterating Over Table Rows
When you use the Agile API to get a table, such as a BOM table, your program often needs to
browse the rows contained in the table. To access an individual row, you first have to get an iterator
for the table. You can then iterate over each row to set cell values.
The Agile API does not support random access of rows in a table. This means that you can’t
retrieve a specific row by index number and then update it. When you add or remove a row, the
entire table is resorted and the existing table iterator is no longer valid.
To browse the data in table, create an iterator for the table using one of these methods:
à ITable.iterator() – returns an Iterator object, allowing you to traverse the table from
the first row to the last.
à ITable.getTableIterator() – returns an ITwoWayIterator object, allowing you to
traverse the table rows forwards or backwards. You can also use ITwoWayIterator to skip a
number of rows. ITwoWayIterator is preferred over Iterator if your program displays table rows
in a user interface.
à ITable.getTableIterator(ITable.ISortBy[]) – returns a sorted ITwoWayIterator
object.
à ITable.getReferentIterator() – returns an ITwoWayIterator object for the objects
referenced in the table.
When you work with an iterator for a table, you don’t need to know the total number of rows in the
table. Instead, you work with one row at a time. Although the ITable interface provides a size()
method, which calculates the total number of rows in the table, it’s considered a resource extensive
operation performance-wise and as such, is not recommended for large tables, particularly if your
code already uses an iterator to browse the table.
The following example demonstrates how to get an iterator for a table and use ITwoWayIterator
to traverse forwards and backwards over the table rows.
Example: Iterating over table rows
try {
// Get an item
IItem item = (IItem)m_session.getObject(ItemConstants.CLASS_PART,
"1000-02");
// Get the BOM table
ITable bom = item.getTable(ItemConstants.TABLE_BOM);
ITwoWayIterator i = bom.getTableIterator();
// Traverse forwards through the table
while (i.hasNext()) {
SDK Developer Guide - Using Agile APIs
76 Agile Product Lifecycle Management
IRow row = (IRow)i.next();
// Add code here to do something with the row
}
// Traverse backwards through the table
while (i.hasPrevious()) {
IRow row = (IRow)i.previous();
// Add code here to do something with the row
}
} catch (APIException ex) {
System.out.println(ex);
}
The ITwoWayIterator object allows a user interface to display table rows on multiple pages,
which is perhaps more practical than the use of ITwoWayIterator shown in the preceding
example. For example, instead of displaying a single scrolling page of several hundred BOM items,
you can break the table into pages displaying 20 BOM items per page. To navigate from page to
page, your program should provide navigation controls such as those shown in the figure below.
Figure 6: Navigation controls in the Agile Web Client
Updating Objects in Query Results with Multiple Page Tables
When you invoke getReferentIterator to update objects in search results tables that contain
more than 200 results, getReferentIterator will not update all the objects that are returned by
the query. For example, when you run a query to match a value in a field, and then edit the same
value while iterating through the results with getReferentIterator, the query completes the first
page with no problem. However, when it queries the remaining pages, some table rows are not
updated. There are several ways to overcome this limitation. The following is one such example.
Example: Updating all table rows when iterating large query results
1. Increase the table page size for this query so that it can contain the results in a single page.
2. Run the query several times and keep updating the results until query results are empty.
3. Do not query on the same field that you are updating.
Sorting Table Rows
To sort the rows in a table by a particular attribute, use
getTableIterator(ITable.ISortBy[]) to return a sorted iterator. The ISortBy parameter
of getTableIterator() is an array of ITable.ISortBy objects. To create an ISortBy object,
use createSortBy(IAttribute, ITable.ISortBy.Order). The order parameter of
createSortBy() is one of the ITable.ISortBy.Order constants either ASCENDING or
DESCENDING.
Note The Agile API allows you to sort a table by only one attribute. Therefore, the ISortBy
array that you specify for the ISortBy parameter of getTableIterator() must
contain only one ISortBy object.
Chapter 4: Working with Tables
v9.3.1.2 77
The following example sorts the BOM table by the BOM | Item Number attribute.
Example: Sorting a table iterator
try {
// Get an item
IItem item = (IItem)m_session.getObject(ItemConstants.CLASS_PART,
"1000-02");
// Get the BOM table
ITable bom = item.getTable(ItemConstants.TABLE_BOM);
// Get the BOM | Item Number attribute
IAgileClass cls = item.getAgileClass();
IAttribute attr =
cls.getAttribute(ItemConstants.ATT_BOM_ITEM_NUMBER);
// Specify the sort attribute for the table iterator
ITable.ISortBy sortByNumber = bom.createSortBy(attr,
ITable.ISortBy.Order.ASCENDING);
// Create a sorted table iterator
ITwoWayIterator i = bom.getTableIterator(new ITable.ISortBy[]
{sortByNumber});
// Traverse forwards through the table
while (i.hasNext()) {
IRow row = (IRow)i.next();
// Add code here to do something with the row
}
} catch (APIException ex) {
System.out.println(ex);
}
The following Product Sourcing and Projects Execution objects load tables a bit differently and
therefore cannot be sorted using the getTableIterator(ITable.ISortBy[]) method. For
any tables of these objects, create an unsorted iterator using the iterator() or
getTableIterator() methods.
à IDiscussion
à IPrice
à IProgram
à IProject
à IRequestForQuote
à ISupplier
à ISupplierResponse
The ITable.ISortBy interface is not supported for query result tables. To sort query results, use
SQL syntax and specify an ORDER BY statement with the search criteria. For more information, see
Using SQL Syntax for Search Criteria on page 50.
SDK Developer Guide - Using Agile APIs
78 Agile Product Lifecycle Management
Removing Table Rows
To remove a row from a table, use the ITable.removeRow() method, which takes one
parameter, an IRow object. You can retrieve a row by iterating over the table rows.
If a table is read-only, you can’t remove rows from it. For more information, see
Working with Read-
only Tables on page 68. If you are working with a released revision of an item, you can’t remove a
row from the item’s tables until you create a change order for a new revision.
Example: Removing a table row
try {
// get an item
IItem item = (IItem)m_session.getObject(ItemConstants.CLASS_PART,
"1000-02");
// get the BOM table
ITable bom = item.getTable(ItemConstants.TABLE_BOM);
ITwoWayIterator i = bom.getTableIterator();
// find the bom component 6642-01 and remove it
while (i.hasNext()) {
IRow row = (IRow)i.next();
String bomitem =
(String)row.getValue(ItemConstants.ATT_BOM_ITEM_NUMBER);
if (bomitem.equals("6642-01")) {
bom.removeRow(row);
break;
}
}
} catch (APIException ex) {
System.out.println(ex);
}
Because ITable implements the Collection interface, you can use Collection methods to
remove table rows. To remove all rows in a table, use Collection.clear().
Example: Clearing a table
public void clearAML(IItem item) throws APIException {
// Get the Manufacturers table
ITable aml = item.getTable(ItemConstants.TABLE_MANUFACTURERS);
// Clear the table
aml.clear();
}
Chapter 4: Working with Tables
v9.3.1.2 79
Retrieving the Referenced Object for a Row
Several Agile PLM tables contain rows of information that reference other Agile PLM objects. For
example, the BOM table lists all items that are included in a Bill of Material. Each row of the BOM
table represents an item. While working with a row on a BOM table, your program can allow the
user to open the referenced item to view or modify its data.
The table below lists Agile PLM tables that reference other Agile PLM objects. All Agile PLM objects
are referenced by number (for example, Item Number, Change Number, or Manufacturer Part
Number).
Object Table Referenced Object(s)
IChange
Affected Items
Affected Prices
Attachments
Relationships
IItem
IPrice
IAttachmentFile
Multiple object types
ICommodity
Attachments
Compositions
Parts
Specifications
Substances
Suppliers
IAttachmentFile
IDeclaration
IItem
ISpecification
ISubstance
ISupplier
ICustomer
Attachments
Related PSR
IAttachmentFile
IServiceRequest
IDeclaration
Attachments
Item Composition
Items
Manufacturer Part Composition
Manufacturer Parts
Part Group Composition
Part Groups
Relationships
Specifications
IAttachmentFile
ISubstance
IItem
ISubstance
IManufacturerPart
ISubstance
ICommodity
Multiple object types
ISpecification
IDiscussion
Attachments
Where Used
IAttachmentFile
Not supported
IFileFolder
Files
Relationships
IAttachmentFile
Multiple object types
SDK Developer Guide - Using Agile APIs
80 Agile Product Lifecycle Management
Object Table Referenced Object(s)
Where Used Multiple object types
IItem
Attachments
BOM
Change History
Compositions
Manufacturers
Pending Change Where Used
Pending Changes
Prices
Quality
Redline BOM
Redline Manufacturers
Sites
Specifications
Substances
Where Used
IAttachmentFile
IItem
IChange
IDeclaration
IManufacturerPart
IItem
IChange
IPrice
IServiceRequest or
IQualityChangeRequest
IItem
IManufacturerPart
IManufacturingSite
ISpecification
ISubstance
IItem
IManufacturerPart
Attachments
Compositions
Prices
Specifications
Substances
Suppliers
Where Used
IAttachmentFile
IDeclaration
IPrice
ISpecification
ISubstance
ISupplier
IItem
IManufacturer
Attachments
Where Used
IAttachmentFile
IManufacturerPart
IManufacturingSite
Attachments
IAttachmentFile
IPackage
Attachments
IAttachmentFile
IPrice
Attachments
Change History
Pending Changes
IAttachmentFile
IChange
IChange
Chapter 4: Working with Tables
v9.3.1.2 81
Object Table Referenced Object(s)
IProgram
Attachments
Deliverables - Affected By
Deliverables - Affects
Dependencies - Dependent
Upon
Dependencies - Required For
Discussion
Links
Schedule
Team
IAttachmentFile
Multiple object types
Multiple object types
IProgram
IProgram
IDiscussion
Multiple object types
IProgram
IUser and IUserGroup
IProject
Attachments
BOM
Item Changes
Items
Manufacturer Items
Pending Change
Responses
RFQs
IAttachmentFile
IItem
IChange
IItem
IManufacturerPart
IChange
ISupplierResponse
IRequestForQuote
IQualityChangeRequ
est
Affected Items
Attachments
PSR Items
Relationships
IItem
IAttachmentFile
IItem
Multiple object types
IRequestForQuote
Attachments
IAttachmentFile
IServiceRequest
Affected Items
Attachments
Related PSR
Relationships
IItem
IAttachmentFile
IServiceRequest
Multiple object types
ISpecification
Attachments
Substances
IAttachmentFile
ISubstance
ISubstance
Attachments
Composition
Where Used
IAttachmentFile
ISubstance
Multiple object types
ISupplierResponse
Attachments
IAttachmentFile
SDK Developer Guide - Using Agile APIs
82 Agile Product Lifecycle Management
Object Table Referenced Object(s)
ISupplier
Attachments
Manufacturers
PSRs
IAttachmentFile
IManufacturer
IServiceRequest
ITransferOrder
Attachments
Selected Objects
IAttachmentFile
Multiple object types
IUser
Attachments
Subscription
User Group
IAttachmentFile
Multiple object types
IUserGroup
IUserGroup
Attachments
Users
IAttachmentFile
IUser
The following example shows how to retrieve the referenced IChange object from the Pending
Changes table for an item.
Example: Retrieving a referenced Change object
void getReferencedChangeObject(ITable changesTable) throws APIException
{
Iterator i = changesTable.iterator();
while (i.hasNext()) {
IRow row = (IRow)i.next();
IChange changeObj = (IChange)row.getReferent();
if (changeObj != null) {
//Add code here to do something with the IChange object
}
}
}
The following example shows how to simplify the code in the previous example by using the
ITable.getReferentIterator() method to iterate through the table’s referenced objects.
Example: Iterating through referenced objects
void iterateReferencedChangeObjects(ITable changesTable) throws
APIException {
Iterator i = changesTable.getReferentIterator();
while (i.hasNext()) {
IChange changeObj = (IChange)i.next();
if (changeObj != null) {
//Add code here to do something with the IChange object
}
}
}
Chapter 4: Working with Tables
v9.3.1.2 83
Checking Status Flags of a Row
Sometimes you may want to perform an action on an object only if it meets certain status criteria.
For example, if the selected object is a released change order, your program may not allow the user
to modify it. To check the status of an object, use the IRow.isFlagSet() method. The
isFlagSet() method returns a boolean value true or false.
Status flag constants are defined in the following classes:
à CommonConstants – Contains status flag constants common to Agile PLM objects.
à ChangeConstants – Contains status flag constants for IChange objects.
à ItemConstants – Contains status flag constants for IItem objects.
The following example shows how to use the isFlagSet() method to determine whether an item
has attachments.
Example: Checking the status flag of an object
private static void checkAttachments(IRow row) throws APIException {
try {
boolean b;
b = row.isFlagSet(CommonConstants.FLAG_HAS_ATTACHMENTS);
if (!b) {
JOptionPane.showMessageDialog(null, "The specified row does not
have attached files.", "Error", JOptionPane.ERROR_MESSAGE);
}
} catch (Exception ex) {}
}
Working with Page 1, Page 2, and Page 3
Page One (that is, Title Block, Cover Page, and General Info pages), Page Two, and Page Three
contain a single row of data and are therefore not tabular in format. All other tables contain multiple
rows. Consequently, the data on Page One, Page Two, and Page Three is directly accessible. To
get and set values for these pages, you don’t need to get a table and then select a row. Instead, get
a specified cell, and then use the getValue() and setValue() methods to display or modify the
data.
If you prefer accessing data cells in a consistent way throughout your program, you can still use the
Page One, Page Two, and Page Three tables to get and set values. The following example shows
two methods that edit the values for several Page Two fields for an item. The first method retrieves
the Page Two table and then sets the values for several cells. The second method accesses the
Page Two cells directly by calling the IDataObject.getCell() method. Either approach is valid,
but you can see that the second approach results in fewer lines of code.
Example: Editing Page Two cells
// Edit Page Two cells by first getting the Page Two table
private static void editPageTwoCells(IItem item) throws Exception {
ICell cell = null;
DateFormat df = new SimpleDateFormat("MM/dd/yy");
SDK Developer Guide - Using Agile APIs
84 Agile Product Lifecycle Management
ITable table = item.getTable(ItemConstants.TABLE_PAGETWO);
Iterator it = table.iterator();
IRow row = (IRow)it.next();
cell = row.getCell(ItemConstants.ATT_PAGE_TWO_TEXT01);
cell.setValue("Aluminum clips");
cell = row.getCell(ItemConstants.ATT_PAGE_TWO_MONEY01);
cell.setValue(new Money(new Double(9.95), "USD"));
cell = row.getCell(ItemConstants.ATT_PAGE_TWO_DATE01);
cell.setValue(df.parse("12/01/03"));
}
// Edit Page Two cells by calling IDataObject.getCell()
private static void editPageTwoCells2(IItem item) throws Exception {
ICell cell = null;
DateFormat df = new SimpleDateFormat("MM/dd/yy");
cell = item.getCell(ItemConstants.ATT_PAGE_TWO_TEXT01);
cell.setValue("Aluminum clips");
cell = item.getCell(ItemConstants.ATT_PAGE_TWO_MONEY01);
cell.setValue(new Money(new Double(9.95), "USD"));
cell = item.getCell(ItemConstants.ATT_PAGE_TWO_DATE01);
cell.setValue(df.parse("12/01/03"));
}
Redlining
When you issue a change for a released item or a price agreement, the Agile API lets you redline
certain tables affected by the change. In the Agile PLM Clients, redline tables visually identify
values that have been modified from the previous revision. Red underlined text—thus the term
“redline”—indicates values that have been added, and red strikeout text indicates values that have
been deleted. People responsible for approving the change can review the redline data.
The Agile PLM system provides the following redline tables:
à Redline BOM
à Redline Manufacturers (AML)
à Redline Price Lines
à Redline Title Block
Note The Web Client supports redlining the Item's Cover Page, Page Two, and Page Three
tables together. However, in the SDK, these operations are performed separately, using
different tables for each page.
To redline BOM, Manufacturers, or Price Lines tables:
1. Get a released revision of an item or price object.
2. Create a new change, such as an ECO, MCO, SCO, or PCO
y ECOs let you modify an item’s BOM or Manufacturers tables
Chapter 4: Working with Tables
v9.3.1.2 85
y MCOs let you modify an item’s Manufacturers table
y SCOs let you modify an item’s site-specific BOM, Manufacturers
y PCOs let you modify a price’s Price Lines table
3. Add the item or price to the Affected Items or Affected Prices table of the change.
4. For ECOs and PCOs, specify the new revision for the change.
5. SCOs and MCOs do not affect an item’s revision.
6. Modify a redline table, such as the Redline BOM, Redline Manufacturers (AML), Redline Price
Lines.
To redline the Manufacturers table of an item:
This example shows how to redline the Manufacturers table (AML) of an item.
Example: Redlining the Manufacturers table of an item
private void redlineAML() throws APIException {
IAttribute attrPrefStat = null;
IAgileList listvalues = null;
Map params = new HashMap();
// Get a released item
IItem item = (IItem)m_session.getObject("Part", "1000-02");
// Get the Preferrred status value
IAgileClass cls = item.getAgileClass();
attrPrefStat =
cls.getAttribute(ItemConstants.ATT_MANUFACTURERS_PREFERRED_STATUS);
listvalues = attrPrefStat.getAvailableValues();
listvalues.setSelection(new Object[] { "Preferred" });
// Create an MCO
IChange change =
(IChange)m_session.createObject(ChangeConstants.CLASS_MCO,
"M000024");
// Set the Workflow ID of the MCO
change.setWorkflow(change.getWorkflows()[0]);
// Get the Affected Items table
ITable affectedItems =
change.getTable(ChangeConstants.TABLE_AFFECTEDITEMS);
// Add a new row to the Affected Items table
IRow affectedItemRow = affectedItems.createRow(item);
// Get the Redline Manufacturers table
ITable redlineAML =
item.getTable(ItemConstants.TABLE_REDLINEMANUFACTURERS);
// Add a manufacturer part to the table
params.put(ItemConstants.ATT_MANUFACTURERS_MFR_NAME, "AMD");
params.put(ItemConstants.ATT_MANUFACTURERS_MFR_PART_NUMBER, "1234-
009");
params.put(ItemConstants.ATT_MANUFACTURERS_PREFERRED_STATUS,
listvalues);
redlineAML.createRow(params);
// Add another manufacturer part to the table
params.clear();
params.put(ItemConstants.ATT_MANUFACTURERS_MFR_NAME, "DIGITAL
POWER");
SDK Developer Guide - Using Agile APIs
86 Agile Product Lifecycle Management
params.put(ItemConstants.ATT_MANUFACTURERS_MFR_PART_NUMBER,
"355355");
params.put(ItemConstants.ATT_MANUFACTURERS_PREFERRED_STATUS,
listvalues);
redlineAML.createRow(params);
}
To redline the Title Block table of an item:
The following is an example of redlining the Title Block table of the item. It assumes
Item.Page_Two and the attribute Text01 are visible and Text01 is change controlled.
Example: Redlining the Title Block table of an item
ITable page2Tab = item.getTable(ItemConstants.TABLE_REDLINEPAGETWO);
Iterator it = page2Tab.getTableIterator();
IRow redPage2Row = (IRow)it.next();
ICell cell =
redPage2Row.getCell(CommonConstants.ATT_PAGE_TWO_TEXT01);
System.out.println("old value, before update: " +
cell.getOldValue());
redPage2Row.getCell(CommonConstants.ATT_PAGE_TWO_TEXT01).setValue("u
pdated Text01")
Removing Redline Changes
When you make redline changes to a table such as a BOM table, you may want to undo the
changes for a row and restore it to its original state. You can use the
IRedlinedRow.undoRedline() method to undo any redline changes to a row.
If you undo the redlines for a row, any cells that are modified are restored to their original values. A
redlined row can also be one that was added or deleted. If you undo the redlines for a row that was
added, the entire row is removed from that revision. If you undo the redlines for a row that was
deleted, the entire row is restored.
Example: Removing redline changes from the BOM table
private static undoBOMRedlines(IItem item, String rev) throws
APIException {
item.setRevision(rev);
ITable redlineBOM = item.getTable(ItemConstants.TABLE_REDLINEBOM);
Iterator it = redlineBOM.iterator();
while (it.hasNext()) {
IRedlinedRow row = (IRedlinedRow)it.next();
row.undoRedline();
}
}
Chapter 4: Working with Tables
v9.3.1.2 87
Removing Redline Changes in Bulk Mode
Removing Redline Changes in Bulk Mode
Agile SDK enables removing (undoing) redlines with the aid of IRedlinedTable. This interface
provides the API to perform bulk redline undos as shown below.
IRedlinedTable.undoRedline(Collection rows);
IRedlinedTable.undoAllRedline();
Note See
Redlining on page 84.
Example: Typecasting Redline tables to IRedlinedTable interface
IItem item = (IItem) session.getObject(ItemConstants.CLASS_PART,
"PART_001");
item.setRevision("B"); // Unreleased change
ITable bomTable = item.getTable(ItemConstants.TABLE_REDLINEBOM);
Iterator it = bomTable.iterator();
List rows = new ArrayList();
while(it.hasNext()) {
IRow row = (IRow) it.next();
if(((IRedlined)row).isRedlineModified())
rows.add(row);
}
// Only Redline tables can be typecasted to IRedlinedTable interface
// Case 1:
((IRedlinedTable)bomTable).undoRedline(rows);
// Case 2:
((IRedlinedTable)bomTable).undoAllRedline();
Identifying Redlined Rows and Redlined Cells
The IRedlined interface is designed to identify redlined rows and redlined cells. It is only
supported on redlined tables. The interface works in conjunction with the isRedlineModified()
method to show if objects are redlined. The interface typecasts IRow and ICell objects as
follows:
à IRow indicates if the row is redline modified
à ICell indicates if the cell is redline modified.
Example: Identifying redlined rows and cells
public interface IRedlined {
public boolean isRedlineModified()
throws APIException;
}
The IRedlined.isRedlineModified() method returns a boolean value. This value is TRUE
when cells or rows are redlined.
Note IRedlined.isRedlineModified() returns a FALSE value for all cells on redline
added or redline removed rows.
SDK Developer Guide - Using Agile APIs
88 Agile Product Lifecycle Management
Using ICell.getOldValue
With the introduction of the IRedlined interface, the ICell.getOldValue() method is no
longer defined for redline added and redline removed rows. The ICell.getOldValue() method
has a meaningful result only when FLAG_IS_REDLINE_MODIFIED is true for the row.
Note Do not call this method for redline added or redlined removed rows.
v9.3.1.2 89
Chapter 5
Working with Data Cells
This chapter includes the following:
About Data Cells.................................................................................................................................................. 89
Data Types .......................................................................................................................................................... 89
Checking User's Discovery Privilege................................................................................................................... 90
Checking if the Cell is a Read-Only Cell.............................................................................................................. 91
Getting Values..................................................................................................................................................... 91
Getting Values..................................................................................................................................................... 93
Setting Values......................................................................................................................................................95
Getting and Setting List Values ...........................................................................................................................96
Using Reference Designator Cells.......................................................................................................................99
About Data Cells
An ICell object is a data field for an Agile PLM object that you have loaded or created in your
program. A cell can correspond to a field on a tab in Agile Web Client or a single cell on a table. The
ICell object consists of several properties that describe the current state of a cell. Most of the data
manipulation your Agile API programs perform will involve changes to the value or properties of
cells.
Data Types
The type of objects associated with the getValue() and setValue() methods depends on the
cell’s data type. The table below lists the object types of cell values for getValue() and
setValue() methods.
DataTypeConstants Object type associated with getValue and setValue
TYPE_DATE Date
TYPE_DOUBLE Double
TYPE_INTEGER Integer
TYPE_MONEY Money
TYPE_MULTILIST IAgileList
TYPE_OBJECT Object
TYPE_SINGLELIST IAgileList
TYPE_STRING String
TYPE_TABLE Table
SDK Developer Guide - Using Agile APIs
90 Agile Product Lifecycle Management
Note There are other Agile PLM datatypes, such as TYPE_WORKFLOW, but they are not used
for cell values.
Checking User's Discovery Privilege
The Discovery privilege is the most basic Agile PLM privilege. It allows users to find if an object
exists. If you do not have the Discovery privilege for an object, you won’t be able to view that object.
For example, if a user does not have the Discovery privilege for Manufacturer Parts, your program
will not allow the user to view several cells on the Manufacturers table of an item. You can use the
ICell.hasDiscoveryPrivilege() method to check if the user has the Discovery privilege for a
particular cell, as shown in the following example.
Note When you get the value for a cell for which you don’t have the Discovery privilege, the
Agile API returns a null string (""). This behavior is different with other Agile PLM Clients.
For example, Agile Web Client displays the value “No Privilege” when you try to view a
field for which you don’t have the necessary viewing privileges.
Example: Checking Discovery privilege
Object v;
Integer attrID = ItemConstants.ATT_MANUFACTURERS_MFR_NAME;
try {
// Get the Manufacturers table
ITable aml =
item.getTable(ItemConstants.TABLE_MANUFACTURERS);
// Get the first row of the Manufacturers table
IIterator iterator =
aml.getTableIterator();
if (iterator.hasNext()) {
IRow amlRow =
(IRow)iterator.next();
}
// Get the value for the Mfr. Name field.
// If the user does not have Discovery privilege, the value is a null
String.
v = amlRow.getValue(attrID);
txtMfrName.setText(v.toString());
// If the user does not have the Discovery privilege
// for the cell, make its text color red.
ICell cell =
amlRow.getCell(attrID);
if (cell.hasDiscoveryPrivilege()==false) {
txtMfrName.setForeground(Color.red);
}
} catch (APIException ex) {
System.out.println(ex);
}
Chapter 5: Working with Data Cells
v9.3.1.2 91
Checking if the Cell is a Read-Only Cell
Roles and privileges assigned to a user by Agile PLM administrators, determine the level of access
the user has to Agile PLM objects and their underlying data. For example, users with only ReadOnly
privileges can view Agile PLM objects but not modify them.
Whenever your program displays a value from a cell, you should check whether the cell is read-only
for the current user. If it is, your program must not allow the user to edit the value. If a user tries to
set a value for a read-only cell, the Agile API throws an exception.
Example: Checking whether a field is a read-only field
// ID for "Title Block.Description"
Integer attrID = ItemConstants.ATT_TITLE_BLOCK_DESCRIPTION;
// Set the value for the Description text field.
try {
txtDescription.setText(item.getValue(attrID).toString());
// Get the ICell object for "Title Block.Description"
ICell cell = item.getCell(attrID);
// If the cell is read-only, disable the cell
if (cell.isReadOnly()) {
txtDescription.setEnabled(false);
txtDescription.setBackground(Color.lightGray);
}
else {
txtDescription.setEnabled(true);
txtDescription.setBackground(Color.white);
}
} catch (APIException ex) {
System.out.println(ex);
}
Getting Values
The following table lists Agile API methods for getting values for cells.
Method Description
ICell.getValue()
Gets a cell value
IRow.getValue()
Gets a cell value contained within a row
IRow.getValues()
Gets all cell values contained within a row
IDataObject.getValue
()
Gets a cell value on Page One, Page Two, or Page Three
Before working with a cell’s value, you must select the cell. Agile PLM cells are instances of
attributes. To specify the attribute for a cell, specify either the attribute’s ID constant, it’s fully
qualified name (such as “Title Block.Description”), or an IAttribute object. For more information
about referencing attributes, see Referencing Attributes in SDK Developer Guide - Developing PLM
Extensions.
SDK Developer Guide - Using Agile APIs
92 Agile Product Lifecycle Management
Note You can use ICell getAPIName() to access Data Cell attribute values. For
information to use this field, see Accessing PLM Metadata with APIName Field on page
123.
The following example shows how to reference a cell by attribute ID constant.
Example: Specifying a cell by ID
Object v;
Integer attrID = ItemConstants.ATT_TITLE_BLOCK_NUMBER;
try {
v = item.getValue(attrID);
} catch (APIException ex) {
System.out.println(ex);
}
The following example shows how to reference a cell by the fully qualified attribute name.
Example: Specifying a field by fully qualified name
Object v;
String attrName = "Title Block.Number";
try {
v = item.getValue(attrName);
} catch (APIException ex) {
System.out.println(ex);
}
The method that you use to get a cell value depends on the current object in use by your program.
Use the ICell.getValue() method if you have already retrieved an ICell object and want to
retrieve a value.
Example: Getting a value using ICell.getValue()
private static Object getCellVal(ICell cell) throws APIException {
Object v;
v = cell.getValue();
return v;
}
Quite often, your program will first retrieve an object, such as an item, and then use the
IDataObject.getValue(java.lang.Object cellId) method to retrieve values for it.
Example: Getting a value using IDataObject.getValue(Object cellID)
private static Object getDescVal(IItem item) throws APIException {
Integer attrID = ItemConstants.ATT_TITLE_BLOCK_DESCRIPTION;
Object v;
v = item.getValue(attrID);
return v;
}
The object returned by the getValue() method is of the same data type as the Agile PLM
attribute. For more information about data types, see
Data Types on page 89.
Chapter 5: Working with Data Cells
v9.3.1.2 93
Note All cells in a table returned by a query contain String values regardless of the
datatypes associated with those cells. For more information about query result tables,
see
Working with Query Results on page 60.
If you are iterating over rows in an Agile PLM table, you can use the IRow.getValues() method
to retrieve a Map object containing all cell values for a particular row in the table. The returned Map
object maps attribute ID keys to cell values.
Understanding SDK Date Formats and User Preferences
In SDK, date is available as a Java Date object and does not format the date according to User
Preferences. However, end users can convert it to their preferred format in GUI’s User Preferences.
Important End users must use the GMT date format for PPM dates. For more information, refer
to the Agile PLM Product Portfolio Management User Guide.
Getting Values
The following table lists Agile API methods for getting values for cells.
Method Description
ICell.getValue()
Gets a cell value
IRow.getValue()
Gets a cell value contained within a row
IRow.getValues()
Gets all cell values contained within a row
IDataObject.getValue
()
Gets a cell value on Page One, Page Two, or Page Three
Before working with a cell’s value, you must select the cell. Agile PLM cells are instances of
attributes. To specify the attribute for a cell, specify either the attribute’s ID constant, it’s fully
qualified name (such as “Title Block.Description”), or an IAttribute object. For more information
about referencing attributes, see Referencing Attributes.
Note You can use ICell getAPIName() to access Data Cell attribute values. For
information to use this field, see Accessing PLM Metadata with APIName Field on page
123.
The following example shows how to reference a cell by attribute ID constant.
Example: Specifying a cell by ID
Object v;
Integer attrID = ItemConstants.ATT_TITLE_BLOCK_NUMBER;
try {
v = item.getValue(attrID);
} catch (APIException ex) {
System.out.println(ex);
}
SDK Developer Guide - Using Agile APIs
94 Agile Product Lifecycle Management
The following example shows how to reference a cell by fully a qualified attribute name.
Example: Specifying a field by fully qualified name
Object v;
String attrName = "Title Block.Number";
try {
v = item.getValue(attrName);
} catch (APIException ex) {
System.out.println(ex);
}
The method that you use to get a cell value depends on the current object in use by your program.
Use the ICell.getValue() method if you have already retrieved an ICell object and want to
retrieve a value.
Example: Getting a value using ICell.getValue()
private static Object getCellVal(ICell cell) throws APIException {
Object v;
v = cell.getValue();
return v;
}
Quite often, your program will first retrieve an object, such as an item, and then use the
IDataObject.getValue(java.lang.Object cellId) method to retrieve values for it.
Example: Getting a value using IDataObject.getValue(Object cellID)
private static Object getDescVal(IItem item) throws APIException {
Integer attrID = ItemConstants.ATT_TITLE_BLOCK_DESCRIPTION;
Object v;
v = item.getValue(attrID);
return v;
}
The object returned by the getValue() method is of the same data type as the Agile PLM
attribute. For more information about data types, see
Data Types on page 89.
Note All cells in a table returned by a query contain String values regardless of the
datatypes associated with those cells. For more information about query result tables,
see
Working with Query Results on page 60.
If you are iterating over rows in an Agile PLM table, you can use the IRow.getValues() method
to retrieve a Map object containing all cell values for a particular row in the table. The returned Map
object maps attribute ID keys to cell values.
Chapter 5: Working with Data Cells
v9.3.1.2 95
Setting Values
The following table lists Agile API methods for setting values for cells.
Method Description
ICell.setValue()
Sets a cell value
IRow.setValue()
Sets a cell value contained within a row
IRow.setValues()
Sets multiple cell values contained within a row
IDataObject.setValue(
)
Sets a cell value on Page One, Page Two, or Page Three
IDataObject.setValues
()
Sets multiple cell values on Page One, Page Two, or Page Three
The method you use to set a value depends on the current object in use by your program.
Use the ICell.setValue() method if you’ve already retrieved an ICell object and want to set
its value.
Example: Setting a value using ICell.setValue()
private static void setDesc(ICell cell, String text) throws
APIException {
cell.setValue(text);
}
If your program has already retrieved an object, such as a part, you can use the
IDataObject.setValue() method to set values for it.
Example: Setting a value using IDataObject.setValue()
private void setDesc(IItem item, String text) throws APIException {
Integer attrID = ItemConstants.ATT_TITLE_BLOCK_DESCRIPTION;
item.setValue(attrID, text);
}
If you are iterating over rows in an Agile PLM table, you can use the IRow.setValues() method
to set the cell values for an entire row. You can also use the IDataObject.setValues() method
to set multiple cell values on Page One, Page Two, or Page Three of an object. The Map parameter
you specify with setValues() maps attributes to cell values.
Example: Setting multiple values in a row using IRow.setValues()
private void setBOMRow(IRow row) throws APIException {
Map map = new HashMap();
map.put(ItemConstants.ATT_BOM_ITEM_NUMBER, "23-0753");
map.put(ItemConstants.ATT_BOM_QTY, "1");
map.put(ItemConstants.ATT_BOM_FIND_NUM, "0");
row.setValues(map);
}
When you set an Agile PLM value, you must know the cell’s data type. If you try to set a cell’s value
using an object of the wrong data type, the method fails. You may need to cast the object to another
class before using it to set a value.
SDK Developer Guide - Using Agile APIs
96 Agile Product Lifecycle Management
Note If you don't explicitly demarcate transactional boundaries in your code, every
setValue() operation your program performs is treated as a separate transaction.
Catching Exceptions for Locked Objects
If someone else is modifying an object, it is temporarily locked by that user. If you try to set the
value for a cell when another user has the object locked, your program will throw an exception.
Therefore, whenever your program sets values of cells, make sure you catch the following Agile
exceptions related to locked objects:
à ExceptionConstants.APDM_ACQUIRE_DBLOCK_FAILED
à ExceptionConstants.APDM_RELEASE_DBLOCK_FAILED
à ExceptionConstants.APDM_OBJVERSION_MISMATCH
You should also catch exception 813, which is related to locked objects.
The typical exception message that Agile PLM returns for a locked object is “Someone is working
on this object. Please try again later.
For more information about how to handle exceptions, see
Handling Exceptions on page 323.
Getting and Setting List Values
There are two different datatypes for list cells. One for SingleList and one for MultiList cells. When
you get the value for a SingleList or MultiList cell, the object returned is an IAgileList object. For
that reason, list cells are slightly more complicated to work with than other cells. The IAgileList
interface provides methods for getting and setting the current list selection. This section provides
examples showing how to get and set values for different types of Agile PLM lists, including
cascading lists.
When you use ICell.getAvailableValues() to get the available values for a list cell, the
returned IAgileList object may include obsolete list values. Your program should not permit
users to set the value for a list cell to an obsolete value. For information on how to check whether a
list value is obsolete, see
Making List Values Obsolete on page 170.
When a list contains String values, the values are case-sensitive. This means that whenever you
set the value for a list cell you must ensure that the value is the right case.
Getting and Setting Values for SingleList Cells
A SingleList cell allows you select one value from the list. When you get the value for a SingleList
cell, the object returned is an IAgileList. From that IAgileList object, you can determine
what the currently selected value is. The following example shows how to get and set values for the
“Title Block.Part Category” cell for an item.
Example: Getting and setting the value for a SingleList cell
private static String getPartCatValue(IItem item) throws APIException {
// Get the Part Category cell
Chapter 5: Working with Data Cells
v9.3.1.2 97
ICell cell =
item.getCell(ItemConstants.ATT_TITLE_BLOCK_PART_CATEGORY);
// Get the current IAgileList object for Part Category
IAgileList cl = (IAgileList)cell.getValue();
// Get the current value from the list
String value = null;
IAgileList[] selected = cl.getSelection();
if (selected != null && selected.length > 0) {
value = (selected[0].getValue()).toString();
}
return value;
}
private static void setPartCatValue(IItem item) throws APIException
{
// Get the Part Category cell
ICell cell =
item.getCell(ItemConstants.ATT_TITLE_BLOCK_PART_CATEGORY);
// Get available list values for Part Category
IAgileList values = cell.getAvailableValues();
// Set the value to Electrical
values.setSelection(new Object[] { "Electrical" });
cell.setValue(values);
}
Getting and Setting Values for MultiList Cells
A MultiList cell behaves very similar to a SingleList cell except that it allows you to select multiple
values. A MultiList cell cannot be a cascading list. The following example shows how to get and set
values for a MultiList cell, “Title Block.Product Line(s)” for an item.
Example: Getting and setting the value for a MultiList cell
private static String getProdLinesValue(IItem item) throws APIException
{
String prodLines;
// Get the Product Lines cell
ICell cell =
item.getCell(ItemConstants.ATT_TITLE_BLOCK_PRODUCT_LINES);
// Get the current IAgileList object for Product Lines
IAgileList list = (IAgileList)cell.getValue();
// Convert the current value from the list to a string
prodLines = list.toString();
return prodLines;
}
private static void setProdLinesValue(IItem item) throws APIException {
// Get the Product Lines cell
ICell cell =
item.getCell(ItemConstants.ATT_TITLE_BLOCK_PRODUCT_LINES);
// Get available list values for Product Lines
IAgileList values = cell.getAvailableValues();
// Set the Product Lines values
SDK Developer Guide - Using Agile APIs
98 Agile Product Lifecycle Management
values.setSelection(new Object[] {"Saturn","Titan","Neptune"});
cell.setValue(values);
}
Getting and Setting Values for Cascading Lists
A SingleList cell can be configured to be a cascading list. A cascading list presents a list in multiple
hierarchical levels, letting you drill down to a specific value in the list hierarchy. For more
information about working with cascading lists, see
Working with Lists on page 153.
When you get the value for a cascading list cell, a vertical bar (also called a piping character)
separates each level in the cascading list. To select the value for a cascading list, use the
IAgileList.setSelection() method. You can specify either an array of IAgileList leaf
nodes or a String array containing one string delimited by vertical bars. After you select the
value, save it using one of the setValue() methods.
The following example shows how to get and set the value for a cascading list.
Example: Getting and setting the value for a cascading list
private String getCascadeValue(IItem item) throws APIException {
String value = null;
// Get the Page Two.List01 value
IAgileList clist =
(IAgileList)item.getValue(ItemConstants.ATT_PAGE_TWO_LIST01);
// Convert the current value from the list to a string
value = clist.toString();
return value;
}
private void setCascadeValue(IItem item) throws APIException {
String value = null;
// Get the Page Two List01 cell
ICell cell = item.getCell(ItemConstants.ATT_PAGE_TWO_LIST01);
// Get available list values for Page Two List01
IAgileList values = cell.getAvailableValues();
// Set the value to "North America|United States|San Jose"
values.setSelection(new Object[] {"North America|United States|San
Jose"});
cell.setValue(values);
}
Although the previous example shows one way to set the value for a cascading list, there’s another
longer form you can use that illustrates the tree structure of the list. Instead of specifying a single
String to represent a cascading list value, you can set the selection for each level in the list. The
following example selects a value for a cascading list with three levels: continent, country, and city.
Example: Setting the value for a cascading list (long form)
private void setCascadeValue(IItem item) throws APIException{
// Get the Page Two List01 cell
ICell cell = item.getCell(CommonConstants.ATT_PAGE_TWO_LIST01);
// Get available list values for Page Two List01
IAgileList values = cell.getAvailableValues();
// Set the continent to "North America"
Chapter 5: Working with Data Cells
v9.3.1.2 99
IAgileList continent = (IAgileList)values.getChildNode("North
America");
// Set the country to "United States"
IAgileList country = (IAgileList)continent.getChildNode("United
States");
// Set the city to "San Jose"
IAgileList city = (IAgileList)country.getChildNode("San Jose");
values.setSelection(new Object[]{city});
// Set the cell value
cell.setValue(values);
}
Using Reference Designator Cells
You can control how to use reference designator cells with Agile 9 SDK. You can make reference
designator cells render collapsed or expanded depending on your system setting. The
IReferenceDesignatorCell interface contains three public APIs that allow the end user to
retrieve reference designator information in three formats:
à Collapsed–for example A1–A3; use getCollapsedValue()
à Expanded–A1, A2, A3; use getExpandedValue()
à Array of individual reference designators–[A1, A2, A3]; use getReferenceDesignators[]
The following table lists Agile API methods for retrieving reference designator values for cells.
Method Description
IReferenceDesignatorCel
l.getCollapsedValue()
Gets a collapsed representation of the reference designators. For
example, “A1,A2,A3” would be represented as “A1–A3”. Note that the
range separator, (“–”) is defined as part of the system preferences.
IReferenceDesignatorCel
l.getExpandedValue()
Gets an expanded value of a reference designator. For example, for “A1-
A3” the string, “A1, A2, A3” would be returned.
IReferenceDesignatorCel
l.getReferenceDesignato
rs()
Gets the individual reference designators as an array of strings. For
example, for “A1-A3” an array of these three strings, [“A1”, “A2”, “A3”]
would be returned.
Note In previous releases of Agile SDK, the value of a reference designator was a comma-
delimited list of reference designators. Because the functionality of cell.getValue()
for a reference designator will depend on the system setting controlling reference
designator presentation, the SDK user should not use cell.getValue() or
row.getValue(). We recommend that you get the cell and cast it into an
IReferenceDesignatorCell; then call the method that corresponds to your desired
data structure for processing or displaying reference designator information.
v9.3.1.2 101
Chapter 6
Working with Folders
This chapter includes the following:
About Folders ...................................................................................................................................................... 101
Loading a Folder..................................................................................................................................................103
Creating a Folder.................................................................................................................................................103
Setting the Folder Type ....................................................................................................................................... 104
Adding and Removing Folder Elements.............................................................................................................. 104
Getting Folder Elements......................................................................................................................................105
Deleting a Folder ................................................................................................................................................. 108
About Folders
An IFolder is a general purpose container used to hold IQuery and IFolder objects as well
as any of the main Agile PLM objects (IChange, IItem, IManufacturer,
IManufacturerPart, and IPackage). Folders are used to organize queries, or searches.
Note A file folder is different from a folder. It has its own interface called the IFileFolder.
Files in a file folder holds can be referenced from the Attachments table of other objects.
For more information about file folders, see
Working with Attachments and File Folders
on page
175.
There are several types of Agile PLM folders:
à Private – Folders that are accessible only to the user that created them. Users can create or
delete their own Private folders.
à Public – Folders that are accessible to all Agile PLM users. Only users with the GlobalSearches
privilege can create, delete, and modify Public folders.
à System – Predefined folders that ship with the Agile PLM system. Most users cannot modify or
delete System folders.
à My Bookmarks (or Favorites) – A predefined folder containing each user’s bookmarks to Agile PLM
objects. You cannot delete the My Bookmarks folder.
à Home – The predefined Agile PLM home folder. You cannot delete the Home folder.
à Personal Searches – The predefined parent folder for each user’s personal searches. You cannot
delete the Personal Searches folder.
à Recently Visited – A predefined folder containing links to recently visited objects. The SDK does
not populate this folder. It is only populated by Client applications. If required, you specify this
in your application.
SDK Developer Guide - Using Agile APIs
102 Agile Product Lifecycle Management
Note The recently visited folder is only flushed to the database periodically. Therefore,
secondary connections like process extensions with portals, or standalone SDK
applications will not see the same information that the user’s GUI displays.
à Report – A folder containing reports. Although you cannot use the Agile API to create, modify, or
delete report folders, you can create, modify, or delete them in Agile PLM Clients.
Note FolderConstants also includes a constant named
TYPE_MODIFIABLE_CONTENTS, but it is currently unused.
Each user’s selection of folders may vary. However, every user has a Home folder. From each
user’s Home folder, you can construct various subfolders and browse public and private queries. To
retrieve the Home folder for a user, use the
IUser.getFolder(FolderConstants.TYPE_HOME) method.
Folders are subject to the same transactional model as other Agile API objects. If you do not set a
transaction boundary for a folder, it is automatically updated as soon as you add anything to, or
remove anything from the folder.
IFolder extends java.util.Collection and ITreeNode support all the methods that are
provided by those Superinterfaces. That is, you can work with an IFolder object as you would
any Java Collection. Methods of ITreeNode allow you to deal with the hierarchical structure of
a folder by adding and removing children, getting children, and getting the parent folder.
Interface Inherited methods
java.util.Collection add(), addAll(), clear(), contains(),
containsAll(), equals(), hashCode(), isEmpty(),
iterator(), remove(), removeAll(), retainAll(),
size(), toArray()
ITreeNode addChild(), getChildNode(), getChildNodes(),
getParentNode(), removeChild()
Using Level Separation Characters in Folder and Object Names
The SDK supports level separation characters ‘|’ and ‘/’ when naming ITreeNode objects as
follows:
à ‘|’ in IAgileList object names
à ‘/’ in folder names
This feature primarily affects inherited ITreeNode methods shown in the table above. To use these
characters, it is necessary to explicitly prefix them with the backslash character (‘\’).
à \|
à \/
Note To use the backslash character in Java string constants defined in SDK applications, you
must specify it twice (“\\”).
Chapter 6: Working with Folders
v9.3.1.2 103
Loading a Folder
There are two ways to load a folder:
à Use the IAgileSession.getObject() method to specify the full path of a folder.
à Use the IFolder.getChild() method to specify the relative path of a subfolder.
Folder and query names are not case-sensitive. Therefore, you can specify a folder path using
upper or lower case. For example, to load the Personal Searches folder, you can specify
/Personal Searches or /PERSONAL SEARCHES.
The following example shows how to load a folder by specifying the full path to the folder.
Example: Loading a folder using IAgileSession.getObject()
try {
//Load the Personal Searches folder
IFolder folder = (IFolder)m_session.getObject(IFolder.OBJECT_TYPE,
"/Personal Searches");
} catch (APIException ex) {
System.out.println(ex);
}
The following example shows how to load a folder by specifying its path relative to another folder, in
this case the user’s Home Folder.
Example: Loading a folder using IFolder.getChild()
try {
//Get the Home Folder
IFolder homeFolder =
m_session.getCurrentUser().getFolder(FolderConstants.TYPE_HOME);
//Load the Personal Searches subfolder
IFolder folder = (IFolder)homeFolder.getChild("Personal Searches");
} catch (APIException ex) {
System.out.println(ex);
}
Creating a Folder
To create a folder, use the IAgileSession.createObject() method. When you create a
folder, you must specify the folder’s name and its parent folder. The following example shows how
to create a folder named “MyTemporaryQueries” in the Personal Searches folder.
Example: Creating a new folder
try {
//Get an Admin instance
IAdmin admin = m_session.getAdminInstance();
//Load the Personal Searches folder
SDK Developer Guide - Using Agile APIs
104 Agile Product Lifecycle Management
IFolder parentFolder =
(IFolder)m_session.getObject(IFolder.OBJECT_TYPE, "/Personal
Searches");
//Create parameters for a new folder
Map params = new HashMap();
params.put(FolderConstants.ATT_FOLDER_NAME, "MyTemporaryQueries");
params.put(FolderConstants.ATT_PARENT_FOLDER, parentFolder);
//Create a new folder
IFolder folder = (IFolder)session.createObject(IFolder.OBJECT_TYPE,
params);
} catch (APIException ex) {
System.out.println(ex);
Setting the Folder Type
By default, all new folders that you create are private folders unless otherwise specified. To change
a private folder to a public folder, use the IFolder.setType() method. You must have the
GlobalSearches privilege to be able to change a private folder to a public folder.
The two folder type constants you can use to set a folder’s type are
FolderConstants.TYPE_PRIVATE and FolderConstants.TYPE_PUBLIC. You cannot set a
folder to any other folder type.
Example: Setting the folder type
try {
//Get an Admin instance
IAdmin admin = m_session.getAdminInstance();
//Load the My Cool Searches folder
IFolder folder = (IFolder)m_session.getObject(IFolder.OBJECT_TYPE,
"/Personal Searches/My Cool Searches");
//Make the folder public
folder.setFolderType(FolderConstants.TYPE_PUBLIC);
} catch (APIException ex) {
System.out.println(ex);
}
Adding and Removing Folder Elements
An Agile PLM folder can contain IFolder objects (subfolders), IQuery objects, and any kind of
dataobject, such as IChange, IItem, IManufacturer, and IManufacturerPart objects. Use
the ITreeNode.addChild() method to add objects to a folder.
Chapter 6: Working with Folders
v9.3.1.2 105
Adding Folder Elements
The following example shows how to add objects to a table.
Example: Adding objects to a folder
public void addFolderItem(IFolder folder, Object obj) {
try {
folder.addChild(obj);
} catch (APIException ex) {
System.out.println(ex);
}
}
Removing Folder Elements
To remove a single folder element, use the ITreeNode.removeChild() method. To clear all
folder elements, use the java.util.Collection.clear() method.
Example: Removing objects from a Folder
void removeFolderElement(IFolder folder, Object obj) {
try {
folder.removeChild(obj);
} catch (APIException ex) {
System.out.println(ex);
}
}
void clearFolder(IFolder folder) {
try {
folder.clear();
} catch (APIException ex) {
System.out.println(ex);
}
}
Getting Folder Elements
All objects contained in a folder, including subfolders, can be loaded by name. To retrieve an object
from a folder, use the IFolder.getChild() method. Remember, the object type for folder
elements can vary. Depending on the object, you could be getting a subfolder, a query, or a
dataobject, such as an IItem.
Example: Getting a folder element
public void getFolderChild(IFolder folder, String name) {
try {
IAgileObject object = folder.getChild(name);
//If the object is a query, run it
if (object.getType()==IQuery.OBJECT_TYPE) {
IQuery query = (IQuery)object;
SDK Developer Guide - Using Agile APIs
106 Agile Product Lifecycle Management
ITable results = query.execute();
//Add code here to do something with the query results
}
} catch (APIException ex) {
System.out.println(ex);
}
}
The following example shows how to use the IFolder.getChildren() method to return an
IAgileObject array. In this case, the code checks the object type for each object in the array and
then prints the object’s name.
Example: Getting folder children
private void browseFolder(int level, IFolder folder) throws
APIException {
IAdmin admin = m_session.getAdminInstance();
Collection subObjects = folder.getChildNodes();
for (Iterator it = subObjects.iterator();it.hasNext();) {
IAgileObject obj = (IAgileObject)it.next();
System.out.println(indent(level * 4));
switch (obj.getType()) {
case IItem.OBJECT_TYPE:
System.out.println("ITEM: " + obj.getName());
break;
case IFolder.OBJECT_TYPE:
System.out.println("FOLDER: " + obj.getName());
browseFolder(level + 1, (IFolder)obj);
break;
case IQuery.OBJECT_TYPE:
System.out.println("QUERY: " + obj.getName());
break;
default:
System.out.println(
"UNKNOWN TYPE: " + obj.getType() + ":" + obj.getName());
}
}
}
private String indent(int level) {
if (level <= 0) {
return "";
}
char c[] = new char[level*2];
Arrays.fill(c, ' ');
return new String(c);
Chapter 6: Working with Folders
v9.3.1.2 107
}
private String indent(int level) {
if (level <= 0) {
return "";
}
char c[] = new char[level*2];
Arrays.fill(c, ' ');
return new String(c);
}
Another way to get a folder’s children is to iterate over the folder elements, moving from one end of
the folder to the other. To create an iterator for an IFolder object, use the
java.util.Collection.iterator() method.
Note If you need to traverse the folder contents both forward and backward, use the
IFolder.getFolderIterator() method to return an ITwoWayIterator object.
ITwoWayIterator provides previous(), next(), and skip() methods, among
others.
Example: Iterating over folder elements
try {
//Load the Project X folder
IFolder folder = (IFolder)m_session.getObject(IFolder.OBJECT_TYPE,
"/Personal Searches/Project X");
//Create a folder iterator
Iterator it = folder.iterator();
if (it.hasNext()) {
//Get the next folder element
Object obj = it.next();
//Write code here to display each folder
//element in your program’s UI
}
} catch (APIException ex) {
System.out.println(ex);
}
SDK Developer Guide - Using Agile APIs
108 Agile Product Lifecycle Management
Deleting a Folder
To delete a folder, use the IFolder.delete() method. You can delete folders that are empty
and that are not predefined Agile PLM system folders (such as the Global Searches and My Inbox
folders).
Unlike other dataobjects, folders are not “soft-deleted” the first time you delete them. When you
delete a folder, it is removed permanently from the system.
Example: Deleting a folder
void deleteFolder(IFolder folder) throws APIException {
folder.delete();
}
v9.3.1.2 109
Chapter 7
Working with Items, BOMs, and AMLs
This chapter includes the following:
Working with Items .............................................................................................................................................. 109
Working with BOMs............................................................................................................................................. 112
Working with AMLs.............................................................................................................................................. 119
Working with Items
An item is an object that helps define a product. Parts and documents are examples of types of
items. A part is shipped as part of a product and has costs associated with it. A part can also be an
assembly. A bill of material, or BOM, lists the separate components that make up the assembly. A
document generally is an internal document, drawing, or procedure that references a part.
Items are different from other Agile PLM objects because they:
à Have a revision history, with a set of data for each revision.
à Can be incorporated, or locked from future changes.
à Can have site-specific BOMs or approved manufacturers lists (AMLs).
Getting and Setting the Revision of an Item
The revision for an item is a special type of Agile PLM attribute. The revision is always paired with
another value, the number of its associated change object (such as an ECO). When you load an
item, it’s always loaded with the latest released revision.
Unlike other attributes, the “Title Block.Rev” field (whose ID constant is
ItemConstants.ATT_TITLE_BLOCK_REV) for an item is not directly accessible. This means that
you can’t retrieve or set a revision value using getValue() and setValue() methods. For
example, the revValue variable in the following code is always a null String.
Example: Failing to get a revision by accessing the Title Block.Rev field
IItem item = (IItem)m_session.getObject(IItem.OBJECT_TYPE, "1000-02");
IAgileList listRevValue =
(IAgileList)item.getValue(ItemConstants.ATT_TITLE_BLOCK_REV);
String revValue = listRevValue.toString();
if (revValue==null) {
System.out.println("Failed to get the revision.");
}
The correct way to get and set the revision for an item is to use methods of the IRevisioned
interface, as shown in the following example, which loads an item and then iterates through the
item’s revisions.
Example: Getting and setting the revision of an item
SDK Developer Guide - Using Agile APIs
110 Agile Product Lifecycle Management
try {
// Get an item
IItem item = (IItem)m_session.getObject(IItem.OBJECT_TYPE, "1000-
02");
// Print the item’s current revision
System.out.println("current rev : " + item.getRevision());
// Get all revisions for the item
Map revisions = item.getRevisions();
// Get the set view of the map
Set set = revisions.entrySet();
// Get an iterator for the set
Iterator it = set.iterator();
// Iterate through the revisions and set each revision value
while (it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String rev = (String)entry.getValue();
System.out.println("Setting rev : " + rev + "....");
item.setRevision(rev);
System.out.println("current rev : " + item.getRevision());
}
catch (APIException ex) {
System.out.println(ex);
}
}
The IRevisioned.setRevision() method accommodates several different ways to specify a
revision. The change parameter of the setRevision() method can be any of the following types
of objects:
à a null object to specify an Introductory revision:
item.setRevision(null);
à an IChange object associated with a particular revision:
item.setRevision(changeObject);
a change number (a String) associated with a particular revision:
item.setRevision("C00450");
revision identifier (a String such as “Introductory”, “A”, “B”, “C”,
and so on): item.setRevision("A");
à a String containing both a revision identifier and a change number separated by eight spaces
(“A 23450”):
item.setRevision("A C00450");
The last type of String object that you can specify for the change parameter allows you to pass
the same value used in other Rev cells in Agile PLM tables. For example, the “BOM.Item Rev” cell,
Chapter 7: Working with Items, BOMs, and AMLs
v9.3.1.2 111
unlike “Title Block.Rev,” is directly accessible. If you get the value for the cell, it returns a String
containing the revision identifier and a change number separated by eight spaces.
Example: Setting the revision using “BOM.Item Rev”
try {
// Get an item
IItem item = (IItem)m_session.getObject(IItem.OBJECT_TYPE, "1000-
02");
// Get the BOM table
ITable bomTable = item.getTable(ItemConstants.TABLE_BOM);
// Get part 1543-01 in the BOM
ITwoWayIterator it = bomTable.getTableIterator();
while (it.hasNext()) {
IRow row = (IRow)it.next();
String num =
(String)row.getValue(ItemConstants.ATT_BOM_ITEM_NUMBER);
if (num.equals("1543-01")) {
// Get the revision for this BOM item
// (bomRev = revID + 8 spaces + changeNumber)
String bomRev =
(String)row.getValue(ItemConstants.ATT_BOM_ITEM_REV);
// Load the referenced part
IItem bomItem = (IItem)row.getReferent();
// Set the revision
System.out.println("Setting rev : " + bomRev + "....");
bomItem.setRevision(bomRev);
System.out.println("current rev : " + bomItem.getRevision());
break;
}
}
} catch (APIException ex) {
System.out.println(ex);
}
Note If an item has no released revisions and no pending changes, the
IRevisioned.getRevision() method returns a null String and the
IRevisioned.getRevisions() method returns an empty Map object.
Changing the Incorporated Status of a Revision
Each revision of an item can be incorporated. When you incorporate the revision of an item, all
attachments for that revision are locked and cannot be checked out. After an item is incorporated,
you can still use Agile Web Client to view the item’s attachments, but you cannot modify them
unless you submit a new Change.
To incorporate or unincorporate an item, use the
IAttachmentContainer.setIncorporated() method. Special Agile PLM privileges are
required to incorporate and unincorporate Items. If a user does not have the appropriate privileges,
SDK Developer Guide - Using Agile APIs
112 Agile Product Lifecycle Management
the setIncorporated() method throws an exception.
Only items that have revision numbers can be incorporated. Therefore, a preliminary item that has
not been released cannot be incorporated. Once an ECO is submitted for that item and a pending
revision number is specified, the revision can then be incorporated. Example 7-4 shows how to
change the incorporated status of an item.
Example: Changing the incorporated status of an Item
try {
// Get an item
IItem item = (IItem)m_session.getObject(IItem.OBJECT_TYPE, "1000-
02");
// Incorporate the item, or unincorporate it,
// depending on its current state
item.setIncorporated(!item.isIncorporated());
} catch (APIException ex) {
System.out.println(ex);
}
Working with BOMs
A bill of material, or BOM, shows the components that make up a product. Each item that is listed
on a BOM can be a single item or an assembly of several items.
The BOM table, like other Agile PLM tables, consists of columns, or fields, of data. Each column
represents an Agile PLM attribute, such as “BOM.Item Number.” Each row of the BOM table
represents a separate item, either a part, a document, or a user-defined subclass.
In addition to the BOM table, there is also a redline BOM, which records redline changes to a BOM.
When you load a BOM table using the DataObject.getTable()method, make sure you specify
the correct table ID constant.
BOM Table ID Constant
Current BOM table
ItemConstants.TABLE_BOM
Redline BOM table
ItemConstants.TABLE_REDLINEBOM
For an example showing how to retrieve a BOM table, see Retrieving a Table on page 66.
Adding an Item to a BOM
Before adding an item to the BOM table, specify the manufacturing site. A BOM item is either site-
specific or common to all sites. Use the
IManufacturingSiteSelectable.setManufacturingSite() method to specify the site. To
add an item to the common BOM, use ManufacturingSiteConstants.COMMON_SITE.
Otherwise, specify a specific site, such as the user’s default site.
Note You can’t add rows to a BOM if the parent item is currently set to display all sites. Before
adding a row to a BOM, make sure the item’s site is not set to
ManufacturingSiteConstants.ALL_SITES. Otherwise, the API throws an
exception.
Chapter 7: Working with Items, BOMs, and AMLs
v9.3.1.2 113
Example: Adding items to a BOM
//Add an item to the common BOM
public void addCommonBOMItem(IItem item, String bomnumber) throws
APIException {
HashMap map = new HashMap();
map.put(ItemConstants.ATT_BOM_ITEM_NUMBER, bomnumber);
item.setManufacturingSite(ManufacturingSiteConstants.COMMON_SITE)
;
item.getTable(ItemConstants.TABLE_BOM).createRow(map);
}
//Add a site-specific item to the BOM using the user’s default site
public void addSiteBOMItem(IItem item, String bomnumber) throws
APIException {
HashMap map = new HashMap();
map.put(ItemConstants.ATT_BOM_ITEM_NUMBER, bomnumber);
item.setManufacturingSite(((IAgileList)m_session.getCurrentUser()
.getValue()
UserConstants.ATT_GENERAL_INFO_DEFAULT_SITE)).getSelection()[0].g
etValue());
item.getTable(ItemConstants.TABLE_BOM).createRow(map);
}
For more information about manufacturing sites, see
Managing Manufacturing Sites on page 147.
Expanding a BOM
The BOM table can be viewed as a table containing multiple levels even though the API doesn’t
present it that way. By default, the BOM table contains only top-level items. To expand a BOM to
show its hierarchy, you need to recursively load each BOM item and its subassemblies. The
following example shows how to print multiple levels of a BOM.
Example: Printing multiple levels of a BOM
private void printBOM(IItem item, int level) throws APIException {
ITable bom = item.getTable(ItemConstants.TABLE_BOM);
Iterator i = bom.getReferentIterator();
while (i.hasNext()) {
IItem bomItem = (IItem)i.next();
System.out.print(indent(level));
System.out.println(bomItem.getName());
printBOM(bomItem, level + 1);
}
}
private String indent(int level) {
if (level <= 0) {
return "";
}
char c[] = new char[level*2];
Arrays.fill(c, ' ');
return new String(c);
}
SDK Developer Guide - Using Agile APIs
114 Agile Product Lifecycle Management
Copying one BOM into another BOM
Quite often the BOMs of two items will be very similar. Instead of creating a BOM from scratch, it is
often easier to copy a BOM from one item to another and then make slight changes. The
Collection.addAll() method can be used to copy the contents of one table into a target table.
The addAll() method does not set a new revision for the item.
Note If you copy a BOM from one item to another, the target item must have the same
associated manufacturing sites as the source item.
Example: Copying a BOM using Collection.addAll()
private static void copyBOM(IItem source, IItem target) throws
APIException {
// Get the source BOM
ITable sourceBOM = source.getTable(ItemConstants.TABLE_BOM);
// Get the target BOM
ITable targetBOM = target.getTable(ItemConstants.TABLE_BOM);
// Add all rows from the source BOM to the target BOM
targetBOM.addAll(sourceBOM);
}
Another way to copy a BOM is to iterate through the rows of a source BOM and copy each row to a
target BOM.
Example: Copying a BOM by iteration
private static void copyBOM1(IItem source, IItem target) throws
APIException {
// Get the source BOM
ITable sourceBOM = source.getTable(ItemConstants.TABLE_BOM);
// Get an iterator for the source BOM
Iterator i = sourceBOM.iterator();
// Get the target BOM
ITable targetBOM = target.getTable(ItemConstants.TABLE_BOM);
// Copy each source BOM row to the target BOM
while (i.hasNext()) {
targetBOM.createRow(i.next());
}
}
Creating BOM-Related Product Reports
The SDK provides the IProductReport API with constants defined in
ProductReportConstants to prepare the following BOM-related product reports. These reports
are produced in the XML format.
à BOM Explosion reports – The BOM Explosion report displays the items that are in the bill of
Material(BOM) for the one or more specified assembly, up to the desired number of levels.
à BOM Comparison reports – The BOM Comparison XML reports is the result of comparing two
Chapter 7: Working with Items, BOMs, and AMLs
v9.3.1.2 115
different BOMs up to the specified number of levels.
For example, when a base BOM compared with the target BOM the comparison will show:
à d shown in BOM node – indicates only base assembly has the BOM
à a shown in BOM node – indicates only target assembly has the BOM
à u shown in BOM node – indicates both root assemblies have the same BOM
à m shown in BOM node – indicates both root assemblies have the BOM but with some
differences
All first level BOMs of both base and target assembly are categorized into another node BOMs. BOM
nodes under BOMs are first sorted by FindNum and then by ItemNumber.
There are several use cases for these reports. For example, archiving or comparative analysis with
outputs of ERP systems.
To create a product report, you must use the IAgileSession object. The following examples
show how to use IAgileSession and ProductReportConstants to prepare BOM Explosion
and BOM Comparison reports.
Example: Creating an Agile Session
AgileSessionFactory factory =
AgileSessionFactory.getInstance("
http://agileServer/virtualPath");
Map params = new HashMap();
params.put(AgileSessionFactory.USERNAME, "username");
params.put(AgileSessionFactory.PASSWORD, "pwd");
IAgileSession session = factory.createSession(params);
Example: Preparing a BOM Comparison report
Map param = new HashMap();
param.put(ProductReportConstants.REPORTPARAM_REPORT_TYPE,
ProductReportConstants.REPORT_BOM_COMPARISON);
param.put(ProductReportConstants.REPORTPARAM_ITEMREVSITE,
"item1;item2");
param.put(ProductReportConstants.BOMCOMP_BOM_ATTRS,
ProductReportConstants.BOM_ATT_ITEM_NUM +”;” +
ProductReportConstants.BOM_ATT_FIND_NUM);
param.put(ProductReportConstants.BOMCOMP_BOMLEVEL, "4");
IProductReport report = (IProductReport)
session.createObject(IProductReport.OBJECT_TYPE, "My BOM Comparison
Report");
String xmlReport = report.execute(param);
If the value for ProductReportConstants.BOMCOMP_BOM_ATTRS is not specified, then it is
assumed to be "Find Num;Item Number;Sites".
Example: Preparing a BOM Explosion report
Map param = new HashMap();
param.put(ProductReportConstants.REPORTPARAM_REPORT_TYPE,
ProductReportConstants.REPORT_BOM_EXPLOSION);
param.put(ProductReportConstants.BOMEXP_OBJTYPE, "Document;Part;");
param.put(ProductReportConstants.REPORTPARAM_ITEMREVSITE, "MM75-
01|23450|India;");
param.put(ProductReportConstants.BOMEXP_MAXLEVEL, "5");
IProductReport report = (IProductReport)
session.createObject(IProductReport.OBJECT_TYPE, "My BOM Explosion
Report");
SDK Developer Guide - Using Agile APIs
116 Agile Product Lifecycle Management
String xmlReport = report.execute(param);
In BOM Explosion reports, the value for
ProductReportConstants.REPORTPARAM_ITEMREVSITE can be as follows:
à <Item_number>|<Change_number>|<Site_number> where <Change_Number> and
<Site_number> are optional if:
y <Change_number> is not specified it is assumed to be the Latest revision
y <Site_number> is not specified it is assumed as Common Sites
à The value can have one or more Items delimited by semicolon
à Item1;Item2;Item3 are the Latest revision of Item1,Item2 and Item3 for Common Sites
à Item1|ECO1;Item2;Item3 (Item1 with ECO1 revision and latest revision of Item2,
Item3)
à Item1|ECO1|Site1;Item2|ECO2 (Item1 with ECO1 revision with Site1 Specific BOM and
Item2 with ECO2 revision)
à Item1|Site1;Item2 (Item1 with Site1 Specific BOM and Latest revision of Item2 with
Common Sites)
In BOM Comparison reports, the value for
ProductReportConstants.REPORTPARAM_ITEMREVSITE can be as follows:
à <Item_number>|<Change_number>|<Site_number> where <Change_Number> and
<Site_number> are optional when:
y <Change_number> is not specified, then it is assumed as Latest revision.
y <Site_number> is not specified, it is assumed as Common Sites.
à The value must have two Items delimited by a semicolon
à Item1;Item2 (Latest revision of Item1 and Item2 and all Sites)
à Item1|ECO1;Item2 (Item1 with ECO1 revision and Latest revision of Item2)
à Item1|ECO1|Site1;Item2|ECO2 (Item1 with ECO1 revision with Site1 Specific BOM and
Item2 with ECO2 revision)
à Item1|Site1;Item2 (Item1 with Site1 Specific BOM and Latest revision of Item2 with
Common Sites)
Redlining a BOM
To redline a BOM table, follow these steps:
1. Get a released assembly item.
2. Create a new Change Order, such as an ECO, for the item.
3. Add the item to the Affected Items table of the ECO. Also, specify the new revision in the
change and set the item’s revision to the associated change.
4. Modify the item’s Redline BOM table.
In the following sections, there are code examples for each of these steps.
Chapter 7: Working with Items, BOMs, and AMLs
v9.3.1.2 117
Note You can remove redlines from a row of the BOM table. See
Removing Redline Changes
on page 86.
Getting a Released Assembly Item
The following example shows how to load an assembly item from the Part subclass. Make sure the
Part you specify is released and has a BOM.
Example: Getting a released assembly
// Load a released assembly item
private static IItem loadItem(IAgileSession myServer, Integer
ITEM_NUMBER) throws APIException {
IItem item = (IItem)myServer.getObject("Part", ITEM_NUMBER);
if (item != null) {
//Check if the item is released and has a BOM
if (item.getRevision().equals("Introductory") ||
!item.isFlagSet(ItemConstants.FLAG_HAS_BOM)) {
System.out.println("Item must be released and have a BOM.");
item = null;
}
return item;
}
Creating a Change Order
To redline a BOM, you must create a Change Order, such as an ECO. Example below shows how
to create an ECO and select a Workflow for the selected ECO.
Example: Creating an ECO
private static IChange createChange(IAgileSession myServer, Integer
ECO_NUMBER)
throws APIException {
IChange change =
(IChange)myServer.createObject(ChangeConstants.CLASS_ECO, ECO_NUMBER);
// Set the Workflow ID
change.setWorkflow(change.getWorkflows()[0]);
return change;
}
Adding an Item to the Affected Items tab of a Change Order
After you create an ECO, you can add the Part you loaded to the Affected Items table of the ECO.
Every ECO is associated with a revision. The following example shows how to specify the new
revision in the ECO, and then set the revision for the Part to the one associated with the ECO.
Example: Adding an item to the Affected Items table of a change order
private static void addAffectedItems(IAgileSession myServer, IItem
item, IChange change)
throws APIException {
// Get the Affected Items table
SDK Developer Guide - Using Agile APIs
118 Agile Product Lifecycle Management
ITable affectedItems =
change.getTable(ChangeConstants.TABLE_AFFECTEDITEMS);
// Create a Map object to store parameters
Map params = new HashMap();
// Set the value of the item number by specifying the item object
params.put(ChangeConstants.ATT_AFFECTED_ITEMS_ITEM_NUMBER, item);
// Specify the revision for the change
params.put(ChangeConstants.ATT_AFFECTED_ITEMS_NEW_REV, "B");
// Add a new row to the Affected Items table
IRow affectedItemRow = affectedItems.createRow(params);
// Select the new revision for the part
item.setRevision(change);
}
Modifying the Redline BOM Table
After the Part has been added to the Affected Items table of an ECO and a revision has been
specified, you can begin to modify the Part’s Redline BOM table. The following example shows how
to get the Redline BOM table, add and remove rows, and set specific cell values.
Example: Modifying the Redline BOM table
private static void modifyRedlineBOM(IAgileSession myServer, IItem
item) throws APIException {
// Get the Redline BOM table
ITable redlineBOM = item.getTable(ItemConstants.TABLE_REDLINEBOM);
// Create two new items, 1000-002 and 1000-003
IItem item1 = (IItem) myServer.createObject(ItemConstants.CLASS_PART,
"1000-002");
IItem item2 = (IItem) myServer.createObject(ItemConstants.CLASS_PART,
"1000-003");
// Add item 1000-002 to the table
IRow redlineRow = redlineBOM.createRow(item1);
redlineRow.setValue(ItemConstants.ATT_BOM_QTY, new Integer(50));
redlineRow.setValue(ItemConstants.ATT_BOM_FIND_NUM, new
Integer(777));
// Add item 1000-003 to the table
redlineRow = redlineBOM.createRow(item2);
redlineRow.setValue(ItemConstants.ATT_BOM_QTY, new Integer(50));
redlineRow.setValue(ItemConstants.ATT_BOM_FIND_NUM, new
Integer(778));
// Remove item 1000-003 from the table
IRow delRow;
String itemNumber;
Iterator it = redlineBOM.iterator();
while (it.hasNext()) {
delRow = (IRow)it.next();
itemNumber =
(String)delRow.getValue(ItemConstants.ATT_BOM_ITEM_NUMBER);
if (itemNumber.equals("1000-003")) {
redlineBOM.removeRow(delRow);
break;
Chapter 7: Working with Items, BOMs, and AMLs
v9.3.1.2 119
}
}
// Change the Qty value for item 1000-002
IRow modRow;
it = redlineBOM.iterator();
while (it.hasNext()) {
modRow = (IRow)it.next();
itemNumber =
(String)modRow.getValue(ItemConstants.ATT_BOM_ITEM_NUMBER);
if (itemNumber.equals("1000-002")) {
modRow.setValue(ItemConstants.ATT_BOM_QTY, new Integer(123));
}
}
}
Working with AMLs
The Manufacturers table for an item is also called the approved manufacturers list, or AML. It lists
manufacturers that have been approved to supply a particular item. The list identifies the
manufacturer part for that item. The Manufacturers table consists of columns, or fields, of data.
Each column represents an Agile PLM attribute, such as “Manufacturers.MfrName.” Each row
of the Manufacturers table references a separate manufacturer part.
In addition to the Manufacturers table, there is also a redline Manufacturers table, which records
redline changes. When you load a Manufacturers table using the
DataObject.getTable()method, make sure you specify the correct table ID constant.
BOM Table ID Constant
Current Manufacturers table
ItemConstants.TABLE_MANUFACTURERS
Redline Manufacturers table
ItemConstants.TABLE_REDLINEMANUFACTURERS
Adding an Approved Manufacturer to the Manufacturers Table
Similar to the BOM Table, the Manufacturers Table requires that you specify the manufacturing site
before adding a new row to the table. An approved manufacturer is either site-specific or common
to all sites. Use the IManufacturingSiteSelectable.setManufacturingSite() method to
specify the site. To add an approved manufacturer to the common Manufacturers table, use
ManufacturingSiteConstants.COMMON_SITE. Otherwise, select a specific site, such as the
user’s default site.
Note You can’t add rows to an AML if the parent item is currently set to display all sites.
Before adding a row to an AML, make sure the item’s site is not set to
ManufacturingSiteConstants.ALL_SITES. Otherwise, the API throws an
exception.
SDK Developer Guide - Using Agile APIs
120 Agile Product Lifecycle Management
Example: Adding approved manufacturers to an AML
//Add a MfrPart to the common AML
public void addCommonApprMfr(IItem item, String mfrName, String
mfrPartNum) throws APIException {
HashMap map = new HashMap();
map.put(ManufacturerPartConstants.ATT_GENERAL_INFO_MANUFACTURER_PART_NU
MBER, mfrPartNum);
map.put(ManufacturerPartConstants.ATT_GENERAL_INFO_MANUFACTURER_NAME,
mfrName);
IManufacturerPart mfrPart = (IManufacturerPart)m_session.getObject(
ManufacturerPartConstants.CLASS_MANUFACTURER_PART, map
);
item.setManufacturingSite(ManufacturingSiteConstants.COMMON_SITE);
item.getTable(ItemConstants.TABLE_MANUFACTURERS).createRow(mfrPart);
}
//Add a site-specific MfrPart to the AML using the user’s default site
public void addSiteApprMfr(IItem item, String mfrName, String
mfrPartNum) throws APIException {
HashMap map = new HashMap();
map.put(ManufacturerPartConstants.ATT_GENERAL_INFO_MANUFACTURER_PART_NU
MBER, mfrPartNum);
map.put(ManufacturerPartConstants.ATT_GENERAL_INFO_MANUFACTURER_NAME,
mfrName);
IManufacturerPart mfrPart = (IManufacturerPart)m_session.getObject(
ManufacturerPartConstants.CLASS_MANUFACTURER_PART, map
);
item.setManufacturingSite(((IAgileList)m_session.getCurrentUser().getVa
lue(
UserConstants.ATT_GENERAL_INFO_DEFAULT_SITE)).getSelection()[0]
);
item.getTable(ItemConstants.TABLE_MANUFACTURERS).createRow(mfrPart);
}
For more information about manufacturing sites, see
Managing Manufacturing Sites on page 147.
Redlining an AML
Once an item is released, you can change the Manufacturers table only by issuing a new change
order. The change order allows you to redline the Manufacturers table.
Note You can remove redlines from a row of the Manufacturers table. See
Removing Redline
Changes on page 86.
To redline a Manufacturers table:
1. Get a released revision of an item.
2. Create a new ECO, MCO, or SCO.
Chapter 7: Working with Items, BOMs, and AMLs
v9.3.1.2 121
y ECOs lets you modify an item’s BOM or Manufacturers tables.
y MCOs lets you modify an item’s Manufacturers table.
y SCOs let you modify an item’s site-specific BOM or Manufacturers tables.
3. Add the item to the Affected Items table of the change.
4. For ECOs, specify the new revision in the change. SCOs and MCOs do not affect an item’s
revision.
5. Modify the Redline Manufacturers table.
v9.3.1.2 123
Chapter 8
Accessing PLM Metadata with APIName
Field
This chapter includes the following:
About APIName Field.......................................................................................................................................... 123
Assigning Names to APIName Fields.................................................................................................................. 124
APIName Validation Rules .................................................................................................................................. 124
Accessing Metadata Using the APIName Field................................................................................................... 125
About APIName Field
The primary purpose of the APIName field is to facilitate SDK developers' access to internal Agile
metadata when developing SDK applications. Prior to introduction of this field, display names or
numeric IDs defined in the SDK Constants file were used to access Agile internal/metadata of
objects in Classes, Tables, Attributes, Lists, and so on. The negative aspect of this approach is that
numbers are difficult to remember and display names can change. However, an object's APIName
is unique, it is easier to remember, and unlike DisplayName it is not subject to change which can
break your code.
For example, your SDK application can use "AuditResult" which is the APIName of the List instead
of its ID which is 6820, or its display name which is "Audit Result" to look up its internal value.
Figure 7: Accessing attribute value via API Name field
The following paragraphs describe the rules that assign a name to APIName fields and SDK
interfaces that you can use in your SDK applications to access internal data with the APIName field.
Note When upgrading to Release 9.3, it is possible to have duplicate APINames assigned to
previously user defined fields. For example, if you have the user defined field "Foo" on
P2 and P3, the upgrade tool will assign the APIName Foo to both fields. To avoid these
duplications, change the APIName for one of these fields in the Java Client.
SDK Developer Guide - Using Agile APIs
124 Agile Product Lifecycle Management
Assigning Names to APIName Fields
Names are automatically assigned to APIName fields by the PLM application when authorized
users create new data objects in Java Client. Objects that support APIName have the additional
"API Name" field in their Create dialog boxes which PLM immediately populates once a name is
typed in the object's "Name" field.
The PLM assigned APIName converts the contents of the "Name" field using the CamelCase
naming convention. The CamelCase convention is adhered to by Java JDK for all core APIs and
closely resembles the name of the API. For example, the class “Manufacturer Parts” is converted to
“ManufacturerParts" and the list "My new list" is converted to "MyNewList".
Figure 8: API name field
APIName Validation Rules
The APIName naming convention must adhere to the following rules:
à It can contain only characters
à It must be a valid Java/XML identifier
y Allowed characters are a-z, A-Z, 0-9, and _ (underscore)
à It must be between 1 and 255 characters long
à It is case-sensitive
à It must be unique within a context, for example:
y The attribute “Number” can exist in the cover page table for classes “Parts” as well as
“Changes” (Different context, Parts & Changes)
y Two attributes with APIName “Number” cannot exist in the cover page table of “Parts”
(Same context, Parts cover page)
y Two attributes with APIName "Number" cannot exist in Cover Page, Page Two and Page
Three (Cover Page, Page Two and Page Three are a single context)
Chapter 8: Accessing PLM Metadata with APIName Field
v9.3.1.2 125
Accessing Metadata Using the APIName Field
You can use the API name of the Agile Metadata to:
à Access the metadata of Agile PLM (Node, Class, Attribute)
à Access/manipulate the value of the metadata (attributes and table attributes) of a data object
You can view the API name of Nodes, Classes, and Attributes in Java Client. SDK interfaces that
support the APIName field are listed in the following tables.
APIs that Support the APIName Field
API Example
IAdmin
getAgileClass(Object id) getAgileClass("Parts")
getNode(Object id) getNode ("Part.TitleBlock")
IAgileClass
getAttribute (Object key) getAttribute("TitleBlock.number")
or,
getAttribute("number")
getTableAttributes(Object
tableId)
getTableAttributes("TitleBlock")
getTableDescriptor (Object id) getTableDescriptor("TitleBlock")
isSubclassOf(Object cls) isSubclassOf("Parts")
IAgileList
getChild(Object child)
getChild("UNITED_STATES")
UNITED_STATES is the APIName for
entry 'United States' in 'Country'
list
getChildNode(Object child) getChildNode("UNITED_STATES")
setSelection (Object[]
childNodes)
setSelection(new Object[]
{"UNITED_STATES" , "INDIA"})
IAgileSession
createObject(Object objectType,
Object params)
Map map = new HashMap();
String partNumber = "P00001"
map.put("TitleBlock.number",
SDK Developer Guide - Using Agile APIs
126 Agile Product Lifecycle Management
partNumber);
IDataObject dObj = (IDataObject)
(m_session.createObject("Part",
map));
createObject(int objectType,
Object params)
Map map = new HashMap();
String partNumber = "P00001"
map.put("number", partNumber);
IDataObject dObj = (IDataObject)
(m_session.createObject("Part",
map));
getObject(Object objectType,
Object params)
Map map = new HashMap();
map.put("TitleBlock.number", "1000-
01");
IDataObject dObj = (IDataObject)
(m_session.getObject("Part", map));
getObject(int objectType, Object
params)
Map map = new HashMap();
map.put("TitleBlock.number", "1000-
01");
IDataObject dObj =
(IDataObject)(m_session.getObject(II
tem.OBJECT_TYPE, map));
IDataObject
getCell(Object key) getCell("PageTwo.list11") or
getCell("list11")
getTable(Object tableId) getTable("AffectedItems")
getValue(Object attribute) getValue ("PageTwo.list11") or
getValue ("list11")
setValue(Object key,Object value) setValue("PageTwo.text01","test")
saveAs(Object type,Object params) Map params = new HashMap();
params.put("number", number);
IItem part2 = (IItem)
part.saveAs("Document", params);
setValues(Map map) Map map = new HashMap();
map.put("TitleBlock.number", "1000-
01");
part.setValues(map);
ILibrary
getAdminList(Object listId) getAdminList("ActionStatus")
createAdminList(Map map) map.put(IAdminList.ATT_NAME,"My
Chapter 8: Accessing PLM Metadata with APIName Field
v9.3.1.2 127
List");
map.put(IAdminList.ATT_APINAME,
"MyList");
map.put(IAdminList.ATT_DESCRIPTION,
"My desc");
map.put(IAdminList.ATT_ENABLED, new
Boolean(false));
map.put(IAdminList.ATT_CASCADED, new
Boolean(false));
IAdmin admin =
m_session.getAdminInstance();
IListLibrary listLibrary =
admin.getListLibrary();
IAdminList newList =
listLibrary.createAdminList(map);
INode
getChild(Object child) IAdmin admin =
m_session.getAdminInstance();
INode node =
admin.getNode(NodeConstants.NODE_AGI
LE_CLASSES);
INode partsClass =
node.getChild("Parts");
getChildNode(Object child) IAdmin admin =
m_session.getAdminInstance();
INode node =
admin.getNode("AgileClasses");
INode partsClass =
node.getChildNode("Parts");
IProgram
saveAs (Object type, Object[]
tablesToCopy, Object params)
HashMap map = new HashMap();
map.put("name", new_number);
map.put("scheduleStartDate", new
Date());
Object[] objects = new
Object[]{"PageTwo", "PageThree",
"Team"};
IProgram program2 =
(IProgram)program.saveAs("Program",
objects, map);
saveAs(Object type,
Object[]tablesToCopy, Object
HashMap map = new HashMap();
SDK Developer Guide - Using Agile APIs
128 Agile Product Lifecycle Management
params, boolean applyToChildren)
map.put("name", new_number);
map.put("scheduleStartDate", new
Date());
Object[] objects = new
Object[]{"PageTwo", "PageThree",
"Team"};
IProgram program2 =
(IProgram)program.saveAs("Program",
objects, map, true);
IProject
assignSupplier(Object
supplierParams)
HashMap map = new HashMap();
map.put("Responses.itemNumber",
item.getName());
map.put("Responses.supplier",
supplier.getName());
rfq.assignSupplier(map);
IQuery
setResultAttributes (Object[]
attrs)
String[] attrs = new String[3];
attrs[0] = "TitleBlock.number";
attrs[1] = "TitleBlock.description";
attrs[2] =
"TitleBlock.lifecyclePhase";
query.setResultAttributes(attrs);
IRequestForQuote
assignSupplier (Object
supplierParams)
HashMap map = new HashMap();
map.put("Responses.itemNumber",
item.getName());
map.put("Responses.supplier",
supplier.getName());
rfq.assignSupplier(map);
ITable
createRow(Object param) HashMap params = new HashMap();
params.put("itemNumber", "P0001");
params.put("newRev", "A");
ITable affectedItems =
Chapter 8: Accessing PLM Metadata with APIName Field
v9.3.1.2 129
change.getTable("AffectedItems");
IRow affectedItemRow =
affectedItems.createRow(params);
createRows(Object[] rows)
getAvailableValues(Object attr) getAvailableValues("PageTwo.list01")
updateRows (Map rows) HashMap[] mapx = new HashMap[5];
Map rows = new HashMap();
mapx[0] = new HashMap();
mapx[0].put("newRev", "A");
mapx[0].put("text01", "sdk test1");
rows.put(rowArray[0], mapx[0]);
mapx[1] = new HashMap();
mapx[1].put("newRev", "A");
mapx[1].put("text01", "sdk test2");
rows.put(rowArray[1], mapx[1]);
tab.updateRows(rows);
ITableDesc
getAttribute (Object key) getAttribute("number")
SDK APIs that Get the APIName Field
Interface Method
IAdminList
getAPIName()
IAgileClass
getAPIName()
IAgileList
getAPIName()
addChild(Object child, String apiName)
IAttribute
getAPIName()
ICell
getAPIName()
INode
getAPIName()
IProperty
getAPIName()
ITableDesc
getAPIName()
SDK Developer Guide - Using Agile APIs
130 Agile Product Lifecycle Management
API Names of Root Administrator Nodes
The following table lists the API names of the top level Administrator nodes which are not exposed
in Agile Java Client. Top Level Admin Nodes are Admin Nodes that exist on their own. That is, no
other Admin Node must exist in order for these Admin nodes to exist. For example, Class and Roles
are top level nodes, but Life Cycle Phases and Attributes are not because they belong to another
Admin Node. Similarly, Workflow Statuses are not top level nodes because they belong to
Workflow.
Root Node API Name
ACS Responses
ACSResponses
Account Policy
AccountPolicy
Activity Statuses
ActivityStatuses
ActivityHealths
ActivityHealths
Agile Classes
AgileClasses
Agile Workflows
AgileWorkflows
Agile eHubs
AgileEHubs
Attachment Purge Setting
AttachmentPurgeSetting
AutoNumbers
AutoNumbers
Catchers
Catchers
Character Set
CharacterSet
Cluster
Cluster
Company Profile
CompanyProfile
Criteria Library
CriteriaLibrary
Dashboard Management
DashboardManagement
Default Role Settings
DefaultRoleSettings
Destinations
Destinations
Event Handler Types
EventHandlerTypes
Event Handlers
EventHandlers
Event Subscribers
EventSubscribers
Event Types
EventTypes
Events
Events
Example Role/Privilege
ExampleRolePrivilege
Filters
Filters
Full Text Search Settings
FullTextSearchSettings
Import Preference Setting
ImportPreferenceSetting
Chapter 8: Accessing PLM Metadata with APIName Field
v9.3.1.2 131
LDAPConfig
LDAPConfig
LifeCycle Phases
LifeCyclePhases
My Assignments
MyAssignments
Notification Templates
NotificationTemplates
PGC SmartRules
PGCSmartRules
Package File Types
PackageFileTypes
Portals
Portals
Preferences
Preferences
Privileges
Privileges
Process eXtension Library
ProcessEXtensionLibrary
Query Cleanup
QueryCleanup
RFQ Terms and Conditions
RFQTermsAndConditions
Reports
Reports
Roles
Roles
Server Location
ServerLocation
Sign Off Message
SignOffMessage
SmartRules
SmartRules
Subscribers
Subscribers
Task Configuration
TaskConfiguration
UOM Families
UOMFamilies
Viewer and Files
ViewerAndFiles
wCM Servers
WCMServers
API Name Examples
The following example shows how to log in to an Agile PLM server, create two parts, enable Page
Two text 01 and List 20, set values for them, and then add the second part to the BOM Table of the
first part.
Example: Using the APIName field to access metadata
import com.agile.api.*;
import java.util.*;
/**
* This sample code shows how to use the API name.
* It uses some of the SDK APIs with the API name.
SDK Developer Guide - Using Agile APIs
132 Agile Product Lifecycle Management
* For a list of API names for attributes and classes,
* refer to Agile Java Client.
* Some API names in Agile Java Client may differ from the ones
* in this example. This is because a duplicate conflict
* was detected in the API name in the same context.
* If you detect this conflict, be sure to change the API name
* in this sample before compiling and executing the code.
*/
public class APIName
{
public static final String USERNAME = "admin";
public static final String PASSWORD = "agile";
public static final String URL =
"
http://localhost:<>/Agile";
public static IAgileSession session = null;
public static IAdmin admin = null;
public static AgileSessionFactory factory = null;
public static IListLibrary listLibrary = null;
/**
* @param args
*/
public static void main(String[] args) {
try {
// Create an IAgileSession instance
session = connect(session);
admin = session.getAdminInstance();
listLibrary = admin.getListLibrary();
// Create two parts
IItem itemParent = createItem(getAutonumber());
IItem itemChild = createItem(getAutonumber());
// enable Page Two tab for Part
enableP2();
// enable Page Two Text 01 and set value
setP2Text(itemParent);
// create a new AdminList
createAdminList();
// enable Page Two List 20 and set value
setP2List(itemParent);
// Add the child part to the BOM table of the parent part
ITable bomTable = addBOM(itemParent, itemChild);
}
catch (Exception e) {
e.printStackTrace();
}
finally {
session.close();
}
}
/**
Chapter 8: Accessing PLM Metadata with APIName Field
v9.3.1.2 133
* @throws APIException
*/
private static void createAdminList() throws APIException {
Map listParams = new HashMap();
listParams.put(IAdminList.ATT_APINAME, "MY_LIST"); // Specify
the API name of the List
listParams.put(IAdminList.ATT_NAME, "My List");
listParams.put(IAdminList.ATT_ENABLED, new Boolean(true));
IAdminList myList = listLibrary.createAdminList(listParams);
IAgileList values = myList.getValues();
values.addChild("Value A", "VAL_A"); // Specify the API name
along with the value
values.addChild("Value B", "VAL_B");
values.addChild("Value C", "VAL_C");
myList.setValues(values);
System.out.println("Created Admin List " + myList.getName());
}
/**
* @throws APIException
*/
private static void enableP2() throws APIException {
INode p2 = admin.getNode("Part.PageTwo"); // Fully qualified
API name
IProperty visible =
p2.getProperty(PropertyConstants.PROP_VISIBLE);
IAgileList values = visible.getAvailableValues();
values.setSelection(new Object[]{ "Yes" });
visible.setValue(values);
System.out.println("Page two enabled for Part class");
}
/**
* @param itemParent
* @throws APIException
*/
private static void setP2Text(IItem itemParent) throws APIException
{
IAgileClass clazz = itemParent.getAgileClass();
ITableDesc p2TableDesc = clazz.getTableDescriptor("PageTwo");
// 'PageTwo' is the API name of the Page Two tab
IAttribute text01 = p2TableDesc.getAttribute("text01"); //
'text01' is the API name of the Text01 field
IProperty visible =
text01.getProperty(PropertyConstants.PROP_VISIBLE);
IAgileList values = visible.getAvailableValues();
values.setSelection(new Object[]{ "Yes" });
visible.setValue(values);
itemParent.setValue("PageTwo.text01", "SDK test"); //
'PageTwo.text01' is the fully qualified APIName for
ItemConstants.ATT_PAGE_TWO_TEXT01
System.out.println("Set P2 Text01 " +
itemParent.getValue("PageTwo.text01") + " for Part " +
itemParent.getName());
}
/**
* @param itemParent
* @throws APIException
SDK Developer Guide - Using Agile APIs
134 Agile Product Lifecycle Management
*/
private static void setP2List(IItem itemParent) throws APIException
{
IAgileClass clazz = itemParent.getAgileClass();
ITableDesc p2TableDesc = clazz.getTableDescriptor("PageTwo");
// 'PageTwo' is the API name of the Page Two tab
IAttribute text01 = p2TableDesc.getAttribute("list20"); //
'list20' is the API name of the List20 field
IProperty visible =
text01.getProperty(PropertyConstants.PROP_VISIBLE);
IAgileList values = visible.getAvailableValues();
values.setSelection(new Object[]{ "Yes" });
visible.setValue(values);
IAdminList myList = listLibrary.getAdminList("MY_LIST"); //
MY_LIST is the API name of the List 'My List'
IAgileList listValues = myList.getValues();
listValues.setSelection(new Object[] { "VAL_B" } ); // VAL_B
is the API name of the list value 'Value B'
itemParent.setValue("PageTwo.list20", listValues); //
'PageTwo.list20' is the fully qualified APIName for
ItemConstants.ATT_PAGE_TWO_TEXT01
System.out.println("Set P2 List20 " +
listValues.getSelection()[0].getValue() + " for Part " +
itemParent.getName());
}
/**
* <p> Create an IAgileSession instance </p>
* @param session
* @return IAgileSession
* @throws APIException
*/
private static IAgileSession connect(IAgileSession session)
throws APIException {
factory = AgileSessionFactory.getInstance(URL);
HashMap params = new HashMap();
params.put(AgileSessionFactory.USERNAME, USERNAME);
params.put(AgileSessionFactory.PASSWORD, PASSWORD);
session = factory.createSession(params);
return session;
}
/**
* <p> Create a part </p>
* @param parent
* @return IItem
* @throws APIException
*/
private static IItem createItem(String number) throws APIException {
HashMap map = new HashMap();
map.put("TitleBlock.number", number); // 'number' or
'TitleBlock.number' is the APIName for
ItemConstants.ATT_TITLE_BLOCK_NUMBER
map.put("description", "test"); // 'description'
or 'TitleBlock.description' is the APIName for
ItemConstants.ATT_TITLE_BLOCK_DESCRIPTION
String p = "P" + System.currentTimeMillis();
IItem item = (IItem)session.createObject("Part",map); //
'Part' is the API name of the Part class
System.out.println("Created Part " + number);
Chapter 8: Accessing PLM Metadata with APIName Field
v9.3.1.2 135
return item;
}
/**
* <p> Add the child parts to the BOM table of the parent part </p>
* @param itemParent
* @param itemChild1
* @param itemChild2
* @return ITable
* @throws APIException
*/
private static ITable addBOM(IItem itemParent, IItem itemChild)
throws APIException {
ITable table = itemParent.getTable("BOM");
// 'BOM' is APIName for ItemConstants.TABLE_BOM
IRow row1 = table.createRow();
String number =
(String)itemChild.getValue("TitleBlock.number");
row1.setValue("itemNumber", number);
// 'itemNumber' is APIName for 'Item Number' on BOM Table
System.out.println("Added Part " + itemChild.getName() + " to
BOM of the Part " + itemParent.getName());
return table;
}
/**
* @return
* @throws APIException
*/
private static String getAutonumber() throws APIException{
IAgileClass cls = admin.getAgileClass("Part");
// 'Part' is the API name of the Part class
IAutoNumber auto[] = cls.getAutoNumberSources();
String number = null;
if(auto != null && auto.length > 0)
number = auto[0].getNextNumber();
else
number = "PART" + System.currentTimeMillis();
return number;
}
}
v9.3.1.2 137
Chapter 9
Subscribing to Agile PLM Objects
This chapter includes the following:
About User Subscriptions.................................................................................................................................... 137
Getting Subscriptions for an Object..................................................................................................................... 139
Modifying the Subscriptions for an Object........................................................................................................... 141
Making Attributes Available for Subscription .......................................................................................................142
Working with Subscription Tables........................................................................................................................143
About User Subscriptions
When you load an Agile PLM business object, such as an item or change, you can then subscribe
to that object. Once you subscribe to the object, you will receive a Notification whenever a triggering
event occurs for that object. You can specify which events trigger a Notification. Subscription events
can be a lifecycle change, a change to attachment files, or a change to the value of any cell that is
made available for subscription.
You can subscribe to both routable and nonroutable objects. The Agile API provides an interface
called ISubscribable, which enables retrieving and modifying all subscriptions for an object. All
objects that a user has subscribed to are listed on the user’s Subscription table.
Subscription Events
Subscription events vary per object class. The full set of events you can subscribe to are listed in
the following table.
Subscription Event SubscriptionConstants
Status Change (for routable objects)
EVENT_STATUS_CHANGE
Lifecycle Phase Change (for nonroutable objects)
EVENT_LIFECYCLE_CHANGE
Field Change
EVENT_FIELD_CHANGE
Add File
EVENT_ADD_FILE
Delete File
EVENT_DELETE_FILE
Checkin File
EVENT_CHECKIN_FILE
Checkout File
EVENT_CHECKOUT_FILE
Cancel Checkout File
EVENT_CANCELCHECKOUT_FILE
Note There are additional subscription events for Projects Execution objects that are not
supported by the Agile API.
Although most routable and nonroutable objects support the subscription events listed in the table
SDK Developer Guide - Using Agile APIs
138 Agile Product Lifecycle Management
above, there are some exceptions:
à User objects do not support the Lifecycle Change subscription event.
à File Folder objects do not support the Add File and Cancel Checkout File subscription events.
The Field Change subscription event is related to any attribute whose Available To Subscribe
property has been set to “Yes.” Consequently, each class and subclass can have a different set of
subscribable attributes.
Subscribe Privilege
To subscribe to an object, you must have the Subscribe privilege for that class. Many predefined
Agile PLM roles, such as Creator, already have the Subscribe privilege for several object classes.
To change your roles and privileges, see the administrator of your Agile PLM system.
Subscription Notifications
Subscription events trigger two types of Agile PLM Notifications:
à Email – Email Notifications are sent only if the user's Receive Email Notification preference is
set to Yes. For information on user and system preferences, refer to Agile PLM Administrator
Guide.
à Inbox – Inbox Notifications occur automatically regardless of user preferences
A user with Administrator privileges can create and configure these Notifications in Java Client
which provides two very similar dialogs for this purpose. The reason for the two dialogs is due to the
fact that there are two sets of Email and Inbox Notifications:
à Those that the "To" field is grayed out
à Those that the administrator user can select recipients who are notified when the subscription
event is triggered
Sending Notifications with SDK
Notifications are briefly described in the SDK Guide under Event Notifications. SDK exposes the
following API to send Notifications to designated notifiers with the specified template for Agile PLM
objects. For information about Notifications, refer to Agile PLM Administrator Guide.
sendNotification (IDataObject
object
Object the Notification is issued for
String
template
Name of Notification template
Collection
notifiers
List of notifiers
boolean
urgent
True for urgent
String
comments
Comments about the Notification
)
throws APIException
These parameters are defined as follows:
à object – object on which Notification is to be issued
à template – name of the Notification template
Chapter 9: Subscribing to Agile PLM Objects
v9.3.1.2 139
à notifiers – collection containing a list of users as individual IDataObjects such as
IUser and IUserGroup
à urgent – value of true indicates send urgently, set to false otherwise
à comments – comments about the Notification
For more information about these parameters and the API, refer to Javadoc generated HTML files
that document the SDK code. You can find them in the HTML folder in SDK_samples (ZIP file). To
access this file, see the Note in
Client-Side Components on page 2.
The following example uses sendNotification to send a Notification from ECO C0001 to user1
and user2 with Notification Comment and template
Example: Sending a Notification with Agile SDK
IAgileSession session =
AgileSessionFactory.createSessionEx(loginParams);
List notifyList =
new ArrayList();
IDataObject user =
(IDataObject)session.getObject(com.agile.api.IUser.OBJECT_TYPE,"John
Doe");
notifyList.add(user);
user =
(IDataObject)session.getObject(com.agile.api.IUser.OBJECT_TYPE,"Jane
Doe");
notifyList.add(user);
IDataObject agileObject =
(IDataObject)session.getObject(com.agile.api.IChange.OBJECT_TYPE,"C0
001");
boolean urgent = true;
String comment =
"Add ECO approver, Notify CA";
String template =
"Automated SDK process added ECO approver";
session.sendNotification(agileObject,template,notifyList,urgent,comment
);
Deleting Subscribed Objects
You can delete any Agile PLM business object using the IDataObject.delete() method.
However, you can’t delete an object until its subscriptions are removed. Users can remove their
own subscriptions, but not the subscriptions of other users.
SDK Developer Guide - Using Agile APIs
140 Agile Product Lifecycle Management
Getting Subscriptions for an Object
To retrieve the current subscriptions for an object, use ISubscribable.getSubscriptions(),
which returns an array of all ISubscription objects, both enabled and disabled. The following
example shows how to get subscriptions for an object.
Example: Getting subscriptions for an object
public void getSubscriptionStatus(IAgileObject obj) throws APIException
{
ISubscription[] subs =
((ISubscribable)obj).getSubscriptions();
for (int i = 0; i < subs.length; ++i) {
if (subs[i].getId().equals(SubscriptionConstants.EVENT_ADD_FILE)) {
if (subs[i].isEnabled()) {
System.out.println("Add File subscription is enabled");
}
}
else if
(subs[i].getId().equals(SubscriptionConstants.EVENT_CANCELCHECKOUT_F
ILE)) {
if (subs[i].isEnabled()) {
System.out.println("Cancel Checkout File subscription is enabled");
}
}
else if
(subs[i].getId().equals(SubscriptionConstants.EVENT_CHECKIN_FILE)) {
if (subs[i].isEnabled()) {
System.out.println("Checkin File subscription is enabled");
}
}
else if
(subs[i].getId().equals(SubscriptionConstants.EVENT_CHECKOUT_FILE))
{
if (subs[i].isEnabled()) {
System.out.println("Checkout File subscription is enabled");
}
}
else if
(subs[i].getId().equals(SubscriptionConstants.EVENT_DELETE_FILE)) {
if (subs[i].isEnabled()) {
System.out.println("Delete File subscription is enabled");
}
}
else if
(subs[i].getId().equals(SubscriptionConstants.EVENT_FIELD_CHANGE)) {
if (subs[i].isEnabled()) {
IAttribute attr = subs[i].getAttribute();
if (attr != null) {
String attrName = attr.getFullName();
System.out.println("Field Change subscription
Chapter 9: Subscribing to Agile PLM Objects
v9.3.1.2 141
is enabled for " + attrName);
}
}
}
else if
(subs[i].getId().equals(SubscriptionConstants.EVENT_LIFECYCLE_CHANGE))
{
if (subs[i].isEnabled())
System.out.println("Lifecycle Change subscription is enabled");
}
else if
(subs[i].getId().equals(SubscriptionConstants.EVENT_STATUS_CHANGE))
{
if (subs[i].isEnabled())
System.out.println
("Status Change subscription is enabled");
}
else
System.out.println("Unrecognized subscription event: " +
subs[i].getId());
}
}
Modifying the Subscriptions for an Object
You can use the Agile API to modify subscriptions for the current user only. If you change your
subscriptions for a particular business object, other users’ subscriptions for that object remain
unaffected.
The list of subscription events for any object is set at the server and cannot be modified by the Agile
API. However, you can select the fields (attributes) you want subscribed. If you have Administrator
privileges, you can also modify classes to define which fields are available for subscription. For
more information, see the next section.
To work with a subscription, use the following ISubscription methods:
à enable(boolean) – Enables or disables the subscription
à getAttribute() – Returns the IAttribute object associated with a subscription. Only
Field Change subscriptions have associated attributes
à isEnabled() – Returns true if the subscription is enabled, false otherwise
à getId() – Returns the subscription ID, which is equivalent to one of the
SubscriptionConstants
ISubscription is a value object interface. Consequently, when you make changes to a
subscription (for example, by enabling it), it’s not changed in the Agile PLM system until you call
ISubscribable.modifySubscriptions().
The following example shows how to enable the Lifecycle Change and Field Change subscription
events and subscribe to two Page Two fields. All other subscription events are disabled.
Example: Enabling and disabling subscriptions for an object
SDK Developer Guide - Using Agile APIs
142 Agile Product Lifecycle Management
public void setSubscriptions(IAgileObject obj) throws APIException {
ISubscription[] subs = ((ISubscribable)obj).getSubscriptions();
for (int i = 0; i < subs.length; ++i) {
// Enable the Status Change subscription event
if (subs[i].getId().equals(SubscriptionConstants.EVENT_STATUS_CHANGE)) {
subs[i].enable(true);
}
// Enable the Field Change subscription event for Page Two.Text01
and Page Two.List01
else if
(subs[i].getId().equals(SubscriptionConstants.EVENT_FIELD_CHANGE)){
if (subs[i].getAttribute() != null)
System.out.println(subs[i].getAttribute().getFullName() + ": " +
subs[i].getAttribute().getId());
if ((subs[i].getAttribute() != null) &&
((subs[i].getAttribute().getId().equals(CommonConstants.ATT_PAGE_TWO
_LIST01)) ||
(subs[i].getAttribute().getId().equals(CommonConstants.ATT_PAGE_TWO_
TEXT01))) )
subs[i].enable(true);
else
subs[i].enable(false);
}
// Disable all other subscription events
else
subs[i].enable(false);
}
((ISubscribable)obj).modifySubscriptions(subs);
}
Making Attributes Available for Subscription
The attributes that are subscribable vary per Agile PLM class. In general, most Page One (Title
Page, Cover Page, and General Info) attributes are subscribable and can therefore be made
available for subscription. All Page Two attributes, except for ATT_PAGE_TWO_CREATE_USER, and
all Page Three attributes are also subscribable.
When an attribute’s Available To Subscribe property is set to Yes, users can subscribe to the
attribute. When you call ISubscribable.getSubscriptions() for an object, the returned
ISubscription[] array includes an ISubscription object for each subscription event.
Although there is only one Field Change event—whose constant is
SubscriptionConstants.EVENT_FIELD_CHANGE—each subscribed attribute is treated as a
separate event that can trigger a subscription Notification. Depending on how your Agile PLM
system has been configured, there could be dozens of attributes available for subscription for a
particular object.
If an attribute isn’t visible, it also isn’t subscribable even if its Available To Subscribe property has
been set to Yes. Therefore, before setting the Available To Subscribe property to Yes, make sure the
Visible property is also set to Yes. The following example shows how to make all Page Two
Chapter 9: Subscribing to Agile PLM Objects
v9.3.1.2 143
attributes for ECOs available for subscription.
Example: Making Page Two attributes available for subscription
try {
// Get the ECO subclass
IAgileClass classECO = m_admin.getAgileClass("ECO");
// Get Page Two attributes
IAttribute[] attr =
classECO.getTableAttributes(ChangeConstants.TABLE_PAGETWO);
// Make all visible Page Two attributes subscribable
for (int i = 0; i < attr.length; ++i) {
IProperty prop = null;
IAgileList listValues = null;
String strVal = "";
// Check if the attribute is visible
prop = attr[i].getProperty(PropertyConstants.PROP_VISIBLE);
listValues = (IAgileList)prop.getValue();
strVal = listValues.toString();
// If the attribute is visible, make it subscribable
if (strVal.equals("Yes")) {
prop =
attr[i].getProperty(PropertyConstants.PROP_AVAILABLE_FOR_SUBSCRIBE);
if (prop != null) {
listValues = prop.getAvailableValues();
listValues.setSelection(new Object[] { "Yes" });
prop.setValue(listValues);
}
}
}
} catch (APIException ex) {
System.out.println(ex);
}
Parent and Child Attributes
Several read-only attributes have a child relationship with a parent attribute. Child attributes derive
values from their parent attribute. Consequently, parent attributes are available for subscription, but
child attributes are not. Examples of child attributes include BOM table attributes like BOM.Item
List02 and BOM.Item Text01.
SDK Developer Guide - Using Agile APIs
144 Agile Product Lifecycle Management
Working with Subscription Tables
A user’s Subscription table lists all subscriptions the user has made. The Subscription table offers
limited editing capabilities. For example, you can’t add new rows to the table; the only way to add
subscriptions using the Agile API is to call ISubscribable.modifySubscriptions() for a
dataobject. However, you can remove subscriptions from the table.
The following example shows how to retrieve the Subscription table for the current user. It also
shows how to remove a subscription for a part with the number 1000-02.
Example: Removing a subscription
try {
// Get the current user
IUser user = m_session.getCurrentUser();
// Get the Subscription table
ITable tblSubscriptions =
user.getTable(UserConstants.TABLE_SUBSCRIPTION);
Iterator i = tblSubscriptions.iterator();
// Stop subscribing to part 1000-02
while (i.hasNext()) {
IRow row = (IRow)i.next();
String n =
(String)row.getValue(UserConstants.ATT_SUBSCRIPTION_NUMBER);
if (n.equals("1000-02")) {
tblSubscriptions.removeRow(row);
break;
}
}
} catch (APIException ex) {
System.out.println(ex);
}
In addition to removing individual rows from the Subscription table, you can also use the
Collection.clear() method to clear the table.
Example: Clearing the Subscription table
public void clearSubscriptionTable(IUser user) throws APIException {
// Get the Subscription table
ITable tblSubscriptions =
user.getTable(UserConstants.TABLE_SUBSCRIPTION);
// Clear the table
tblSubscriptions.clear();
}
Chapter 9: Subscribing to Agile PLM Objects
v9.3.1.2 145
The Subscription table doesn’t list the events you’ve subscribed to for each object. To find that
information, you need to open each referenced object. The following example shows how to use
ITable.getReferentIterator() to iterate through the referenced objects in the table.
Example: Getting objects referenced in the Subscription table
try {
// Get the current user
IUser user = m_session.getCurrentUser();
// Get the Subscription table
ITable tblSubscriptions =
user.getTable(UserConstants.TABLE_SUBSCRIPTION);
Iterator i = tblSubscriptions.getReferentIterator();
// Get each object referenced in the table
while (i.hasNext()) {
IAgileObject obj = (IAgileObject)i.next();
if (obj instanceof ISubscribable) {
ISubscription[] subscriptions =
((ISubscribable)obj).getSubscriptions();
for (int j = 0; j < subscriptions.length; j++) {
ISubscription subscription =
subscriptions[j];
System.out.println(subscription.getName());
// Add code here to handle each subscription
}
System.out.println(obj.getName());
}
}
} catch (APIException ex) {
System.out.println(ex);
}
v9.3.1.2 147
Chapter 10
Managing Manufacturing Sites
This chapter includes the following:
About Manufacturing Sites................................................................................................................................... 147
Controlling Access to Sites.................................................................................................................................. 147
Creating a Manufacturing Site............................................................................................................................. 148
Loading a Manufacturing Site.............................................................................................................................. 148
Retrieving the Sites Table for an Item ................................................................................................................. 149
Adding a Manufacturing Site to the Sites Table................................................................................................... 149
Selecting the Current Manufacturing Site for an Item.......................................................................................... 150
Disabling a Site....................................................................................................................................................151
About Manufacturing Sites
Companies that practice distributed manufacturing use several different manufacturing sites for their
products. Agile PLM site objects allow companies to maintain site-specific information for a
product’s parts. For example, the various manufacturing locations may have different effectivity
dates for new revisions, different manufacturing instructions due to location, or different
manufacturers from whom they buy components, due to location.
Changes can affect all manufacturing sites of an item or a specific site. The Affected Items table for
a change lets you select the manufacturing sites that are affected. Items may have different
effectivity dates and dispositions at each site. You specify effectivity dates and dispositions on the
Affected Items tab of an ECO or SCO. To create a new revision when you assign the new effectivity
date or disposition, use an ECO. To assign site-specific effectivity dates and dispositions without
incrementing the revision, use an SCO.
For a more detailed overview of Agile PLM’s manufacturing sites functionality, refer to the Agile
PLM Product Collaboration Guide.
Controlling Access to Sites
In order to use manufacturing sites in your organization, the Sites module must be enabled in Agile
Administrator. Your organization's agreement with Oracle determines the modules that are enabled
in Agile PLM.
A user's access to manufacturing sites is controlled by his/her assigned roles and privileges and the
Sites property in the user's profile. Your organization can create an unlimited number of
manufacturing sites, however a user will not have access to every site unless all sites are specified
in his user profile Sites property. Your organization may have implemented the Agile PLM system in
such a way that users can access only the information pertaining to certain sites, as determined by
their user profile Sites property.
To create a site-specific BOM for an item, the item’s subclass must have the Site-specific BOM
SDK Developer Guide - Using Agile APIs
148 Agile Product Lifecycle Management
property set to Allow. Otherwise, items of that subclass have BOMs that are common to all sites. For
information on Sites and enabling sites, refer to the Agile PLM Administrator Guide.
Creating a Manufacturing Site
Manufacturing sites are identified uniquely by name. To create a manufacturing site, use the
IAgileSession.createObject method, specifying both the class and the site name.
All users cannot create manufacturing sites. Only users who have the Create privilege for
manufacturing site objects can create manufacturing sites.
Note When you create a manufacturing site, its Lifecycle Phase is set to Disabled by default.
To use the site, make sure you enable it.
Example: Creating and enabling a manufacturing site
try {
// Create a manufacturing site
HashMap params = new HashMap();
params.put(ManufacturingSiteConstants.ATT_GENERAL_INFO_NAME,
"Taipei");
IManufacturingSite mfrSite =
(IManufacturingSite)m_session.createObject(
ManufacturingSiteConstants.CLASS_SITE,
params);
// Enable the manufacturing site
ICell cell = mfrSite.getCell(
ManufacturingSiteConstants.ATT_GENERAL_INFO_LIFECYCLE_PHASE);
IAgileList values = cell.getAvailableValues();
values.setSelection(new Object[] { "Enabled" });
cell.setValue(values);
} catch (APIException ex) {
System.out.println(ex);
}
Loading a Manufacturing Site
To load an IManufacturingSite object, use one of the IAgileSession.getObject()
methods. The following example shows three different ways to specify the object type for a
manufacturing site.
Example: Loading a manufacturing site
try {
// Load the Hong Kong site
IManufacturingSite siteHK =
(IManufacturingSite)m_session.getObject(ManufacturingSiteConstants.C
LASS_SITE, "Hong Kong");
// Load the Taipei site
IManufacturingSite siteTaipei =
Chapter 10: Managing Manufacturing Sites
v9.3.1.2 149
(IManufacturingSite)m_session.getObject(IManufacturingSite.OBJECT_TY
PE, "Taipei");
// Load the San Francisco site
IManufacturingSite siteSF =
(IManufacturingSite)m_session.getObject("Site", "San Francisco");
} catch (APIException ex) {
System.out.println(ex);
}
Retrieving the Sites Table for an Item
Each item has a Sites table that lists the manufacturing sites where that item can be used. To
retrieve the Sites table for an item, use the DataObject.getTable() method.
Example: Retrieving the Sites table
//Get the Sites table
private static void getSites(IItem item) throws APIException {
IRow row;
ITable table = item.getTable(ItemConstants.TABLE_SITES);
ITwoWayIterator it = table.getTableIterator();
while (it.hasNext()) {
row = (IRow)it.next();
//Add code here to do something with the Sites table
}
}
To determine the manufacturing sites associated with an item, use the
IManufacturingSiteSelectable.getManufacturingSites() method. Of course, you can
also iterate over the Sites table to get the same information, but using the
getManufacturingSites() method is easier and faster. See
Selecting the Current
Manufacturing Site for an Item on page 150 for an example that uses
getManufacturingSites().
Adding a Manufacturing Site to the Sites Table
Each row of the Sites table references a different IManufacturingSite object. To add a
manufacturing site to the Sites table, use the ITable.createRow() method.
If a manufacturing site is not listed on an item’s Sites table, then that item cannot be included in a
parent item’s BOM specific to that manufacturing site. For example, to add item P1001 to another
item’s Taipei-specific BOM, P1001 must have the Taipei site listed on its Sites table.
Example: Adding a row to the Sites table
private static void addSite(String itemNumber, IManufacturingSite site)
throws APIException {
//Load the item
IItem item = (IItem)session.getObject(IItem.OBJECT_TYPE,
itemNumber);
//Get the Sites table
ITable table = item.getTable(ItemConstants.TABLE_SITES);
SDK Developer Guide - Using Agile APIs
150 Agile Product Lifecycle Management
//Add the manufacturing site to the table
IRow row = table.createRow(site);
}
Selecting the Current Manufacturing Site for an Item
BOM and Manufacturers tables (or AMLs) can be different for each manufacturing site used for an
assembly. When you retrieve a BOM or Manufacturers table for an item, you can display
information for all sites or for a specific site. If you choose a specific site, only that site’s information
is included in the table.
The IManufacturingSiteSelectable interface provides methods for getting and setting the
manufacturing site for an item. To get the current manufacturing site selected for an item, use the
IManufacturingSiteSelectable.getManufacturingSite() method.
Example: Getting the currently selected manufacturing site for an item
private static IManufacturingSite getCurrentSite(IItem item)
throws APIException {
IManufacturingSite site = item.getManufacturingSite();
return site;
}
The IManufacturingSiteSelectable.getManufacturingSites() method retrieves all
available manufacturing sites that have been added to an item’s Sites table.
Example: Getting all manufacturing sites associated with an item
private static void getItemSites(IItem item)
throws APIException {
IManufacturingSite[] sites = item.getManufacturingSites();
//Print the name of each site
for (int i = 0; i < sites.length; ++i) {
String siteName = (String)sites[i].getValue(
ManufacturingSiteConstants.ATT_GENERAL_INFO_NAME
);
System.out.println(siteName);
}
}
The IManufacturingSiteSelectable.setManufacturingSite() method sets the current
manufacturing site for an item. You can specify that an item has a specific manufacturing site, is not
site-specific, or uses All Sites. To specify that an item is not site-specific, use
ManufacturingSiteConstants.COMMON_SITE. To specify All Sites, pass the
ManufacturingSiteConstants.ALL_SITES value.
When you set the manufacturing site for an item, the item is updated to reflect site-specific
information. Consequently, your program should update the BOM and Manufacturers tables by
iterating over the rows again to refresh them.
Example: Setting the current manufacturing site for an item
try {
// Load sites
Chapter 10: Managing Manufacturing Sites
v9.3.1.2 151
IManufacturingSite siteSF =
(IManufacturingSite)m_session.getObject("Site", "San Francisco");
IManufacturingSite siteHK =
(IManufacturingSite)m_session.getObject("Site", "Hong Kong");
// Load an item
IItem item = (IItem)m_session.getObject("Part", "1000-02");
// Set the Hong Kong site
item.setManufacturingSite(siteHK);
String desc =
(String)item.getValue(ItemConstants.ATT_TITLE_BLOCK_DESCRIPTION);
System.out.println("Hong Kong description = " + desc);
// Set the San Francisco site
item.setManufacturingSite(siteSF);
desc =
(String)item.getValue(ItemConstants.ATT_TITLE_BLOCK_DESCRIPTION);
System.out.println("San Francisco description = " + desc);
// Set the item to use all sites
item.setManufacturingSite(ManufacturingSiteConstants.ALL_SITES);
desc =
(String)item.getValue(ItemConstants.ATT_TITLE_BLOCK_DESCRIPTION);
System.out.println("All Sites description = " + desc);
// Set the item to be common site (the item is not site-specific)
item.setManufacturingSite(ManufacturingSiteConstants.COMMON_SITE);
desc =
(String)item.getValue(ItemConstants.ATT_TITLE_BLOCK_DESCRIPTION);
System.out.println("Global description = " + desc);
// Set the item to use the user's default site
item.setManufacturingSite(((IAgileList)m_session.getCurrentUser().getVa
lue(
UserConstants.ATT_GENERAL_INFO_DEFAULT_SITE)).getSelection()[0].getValu
e());
desc =
(String)item.getValue(ItemConstants.ATT_TITLE_BLOCK_DESCRIPTION);
System.out.println("User's Default Site description = " + desc);
} catch (APIException ex) {
System.out.println(ex);
}
Disabling a Site
A manufacturing site can have one of two lifecycle phases, enabled or disabled. If a site is disabled,
it can no longer be used to create site-specific BOMs, AMLs, and changes.
To disable a manufacturing site, set the value for the Lifecycle Phase attribute to Disabled.
Example: Disabling a manufacturing site
private static void disableSite(IManufacturingSite site)
SDK Developer Guide - Using Agile APIs
152 Agile Product Lifecycle Management
throws APIException {
// Get the Lifecycle Phase cell
ICell cell = site.getCell(
ManufacturingSiteConstants.ATT_GENERAL_INFO_LIFECYCLE_PHASE
);
// Get available list values for Lifecycle Phase
IAgileList values = cell.getAvailableValues();
// Set the value to Disabled
values.setSelection(new Object[] { "Disabled" });
cell.setValue(values);
}
v9.3.1.2 153
Chapter 11
Working with Lists
This chapter includes the following:
About Lists........................................................................................................................................................... 153
Selecting a List Value.......................................................................................................................................... 157
Selecting a List from the List Library.................................................................................................................... 161
Creating Custom Lists ......................................................................................................................................... 163
Checking the Data Type of a List......................................................................................................................... 169
Modifying a List....................................................................................................................................................169
Printing Contents of IAgileList Objects ................................................................................................................ 173
About Lists
Many attributes in the Agile PLM system are configured as lists. Agile provides two datatypes to
support list fields:
à SingleList – a list in which only one value can be selected.
à MultiList – a list in which multiple values can be selected.
Attributes, properties, and cells can all be lists. The Agile API provides methods for working with
lists in the IAgileList interface, a generalized data structure used for all Agile lists. Because
IAgileList represents a tree structure of available list values, it extends the ITreeNode
interface.
You can use ITreeNode.addChild() to add values to a list. All list values must be unique. After
adding a list value, you can prevent its selection by making it obsolete.
List Library
In Agile Java Client, administrators can define custom lists that can be used for Page Two and
Page Three list attributes. You can also use the Agile API to define custom lists. The
IListLibrary interface provides functionality equivalent to the list library in Agile Java Client. You
can use the IAdminList interface to modify the values or properties of a list.
To retrieve the list library, use the IAdmin.getListLibrary() method. You can then use the
IListLibrary interface to create new custom lists and work with existing lists.
AdminListConstants provide IDs for each list in the list library.
SDK Developer Guide - Using Agile APIs
154 Agile Product Lifecycle Management
Note The Agile API provides support for several internal Agile lists that are not exposed in the
list library in Agile Java Client.
Figure 9: List Library
SingleList Lists
A SingleList attribute or cell presents a list from which only one value can be selected. The following
figure shows a SingleList cell for Part Types in Agile Web Client.
Figure 10: SingleList cell in the Agile Web Client
Chapter 11: Working with Lists
v9.3.1.2 155
Cascading Lists
In Agile Java Client, you can configure a SingleList attribute to have multiple hierarchical levels. A
list with multiple hierarchical levels is called a cascading list. The following figure shows the
Location list, a cascading list, being configured in Agile Java Client. The list has separate levels for
continent, country, and city.
Figure 11: Configuring a cascading list in the Agile Java Client
Note The Location list is the only cascading list that ships with Agile PLM. However, you can
define your own cascading lists.
SDK Developer Guide - Using Agile APIs
156 Agile Product Lifecycle Management
MultiList Lists
A MultiList attribute or cell presents a list from which multiple values can be selected. In Agile Web
Client, you can select values for a MultiList cell using the Multiple Value Selection dialog, shown in
the following figure.
Figure 12: Multiple Value Selection window in the Agile Web Client
Methods that Use IAgileList
The IAgileList interface provides the necessary methods to get and set the selected value(s) of
a list. The IAgileList interface represents a value object with a tree structure, which is why the
interface extends ITreeNode.
The following Agile API methods return an IAgileList object (or an array of IAgileList
objects):
à IAdminList.getValues()
à IAdminList.setValues(IAgileList)
à IAttribute.getAvailableValues()
à IAttribute.setAvailableValues(IAgileList)
à IAgileList.getSelection()
à ICell.getAvailableValues()
à IListLibrary.createAdminList(java.util.Map)
à IListLibrary.getAdminList(java.lang.Object)
à IListLibrary.getAdminLists()
à IProperty.getAvailableValues()
Chapter 11: Working with Lists
v9.3.1.2 157
The following methods either return an IAgileList or require an IAgileList parameter when
the related attribute, cell, or property is a list (the datatype is SingleList or MultiList):
à ICell.getValue() – For SingleList and MultiList cells, the returned Object is an
IAgileList.
à ICell.setValue(java.lang.Object value) – For SingleList and MultiList cells, value
is an IAgileList.
à IProperty.getValue() – For SingleList and MultiList properties, the returned Object is an
IAgileList.
à IProperty.setValue(java.lang.Object value) – For SingleList and MultiList
properties, value is an IAgileList.
à IRow.getValue(java.lang.Object cellId) – For SingleList and MultiList cells, the
returned Object is an IAgileList.
à IRow.getValues() – For each SingleList or MultiList cell in the row, the returned Map object
contains an IAgileList.
à IRow.setValue(java.lang.Object cellId, java.lang.Object value) – If
cellID specifies a SingleList or MultiList cell, value is an IAgileList.
à IRow.setValues(java.util.Map map) – For each SingleList or MultiList cell in the row,
map contains an IAgileList.
Selecting a List Value
To select a list value, whether it is a SingleList or MultiList list, you must first get the available
values for the list. You can then set the selected value. After selecting the list value, save the
selection by setting the value for the cell or property.
The following example shows how to change the value of the Visible property of an attribute. The
Visible property is a SingleList property with two possible values, No and Yes (or 0 and 1).
Note You can use IAgileList getAPIName() to get the available values of a list. For
information, see Accessing PLM Metadata with APIName Field on page 123.
Example: Changing the Visible property of an attribute
try {
// Get the Admin instance
IAdmin admin = m_session.getAdminInstance();
// Get part sub-class
IAgileClass partClass =
admin.getAgileClass(ItemConstants.CLASS_PART);
// Get the "Page Two.List03" attribute
IAttribute attr =
partClass.getAttribute(ItemConstants.ATT_PAGE_TWO_LIST03);
// Get the Visible property
IProperty propVisible =
attr.getProperty(PropertyConstants.PROP_VISIBLE);
// Get all available values for the Visible property
IAgileList values = propVisible.getAvailableValues();
SDK Developer Guide - Using Agile APIs
158 Agile Product Lifecycle Management
// Set the selected list value to "Yes"
values.setSelection(new Object[] { "Yes" });
// Instead of setting the selection to "Yes", you could also
// specify the corresponding list value ID, as in the following line:
// values.setSelection(new Object[] { new Integer(1)});
// Set the value of the property
propVisible.setValue(values);
} catch (APIException ex) {
System.out.println(ex);
}
When you use the IAgileList.setSelection() method, you can specify String[],
Integer[], or IAgileList[] values for the childNodes parameter. When you select a value
from the IAgileList object, you can use its String representation or its Integer ID.
To get the currently selected value for a list, use the IAgileList.getSelection() method. For
a SingleList cell or property, getSelection() returns an array containing one IAgileList
object. For a MultiList cell or property, getSelection() returns an array containing one or more
IAgileList objects.
The following example demonstrates how to use several IAgileList methods, including
getSelection().
Example: Getting the current list value for the Visible property
try {
// Get the Admin instance
IAdmin admin = m_session.getAdminInstance();
// Get the Parts class
IAgileClass partClass =
admin.getAgileClass(ItemConstants.CLASS_PARTS_CLASS);
// Get the "Page Two.List03" attribute
IAttribute attr =
partClass.getAttribute(ItemConstants.ATT_PAGE_TWO_LIST03);
// Get the Visible property
IProperty propVisible =
attr.getProperty(PropertyConstants.PROP_VISIBLE);
// Get the current value of the Visible property
IAgileList value = (IAgileList)propVisible.getValue();
// Print the current value
System.out.println(value); // Prints "Yes"
// Print the list value ID
System.out.println(value.getSelection()[0].getId()); // Prints 1
// Print the list value
System.out.println(value.getSelection()[0].getValue()); // Prints
"Yes"
} catch (APIException ex) {
System.out.println(ex);
}
Chapter 11: Working with Lists
v9.3.1.2 159
Lists can be reused for several attributes, even for attributes of different classes. The following
example reuses the list of available values for a Page Two attribute to set the list of available values
for a Page Three list attribute.
Example: Reusing list values for different attributes
try {
// Get the Admin instance
IAdmin admin = m_session.getAdminInstance();
// Get the Parts class
IAgileClass partClass =
admin.getAgileClass(ItemConstants.CLASS_PARTS_CLASS);
// Get the "Page Two.List01" attribute
IAttribute attr1 =
partClass.getAttribute(ItemConstants.ATT_PAGE_TWO_LIST01);
// Get the "Page Three.List01" attribute
IAttribute attr2 =
partClass.getAttribute(ItemConstants.ATT_PAGE_THREE_LIST01);
// Set the available values for the list, using values from "Page
Two.List01"
attr2.setAvailableValues(attr1.getAvailableValues());
} catch (APIException ex) {
System.out.println(ex);
}
Working with Lifecycle Phase Cells
The Lifecycle Phase attribute is a SingleList datatype. Each subclass in the Agile PLM system can
be defined with different lifecycle phases. Therefore, you must get a Lifecycle Phase cell for a
subclass before you can retrieve the available values for its list. If you use
IAttribute.getAvailableValues() to retrieve the available values for a Lifecycle Phase
attribute instead of a subclass-specific cell, the method returns an empty IAgileList object. The
following example highlights how to work with Lifecycle Phase cells.
Example: Working with Lifecycle Phase cells
private static void setLifecyclePhase(IItem item) throws APIException {
// Get the Lifecycle Phase cell
ICell cell =
item.getCell(ItemConstants.ATT_TITLE_BLOCK_LIFECYCLE_PHASE);
// Get available list values for Lifecycle Phase
IAgileList values = cell.getAvailableValues();
// Set the value to the second phase
values.setSelection(new Object[] { new Integer(1)});
cell.setValue(values);
}
SDK Developer Guide - Using Agile APIs
160 Agile Product Lifecycle Management
Working with Dynamic Lists
The Agile server has both static lists and dynamic lists. Static lists contain a selection of values that
do not change at run time. Dynamic lists contain a selection of values that are updated at run time.
Users with administrator privileges can modify static lists and add new values and make current
values obsolete. Dynamic lists cannot be modified; consequently, the Editable property of dynamic
lists is set to No.
Several dynamic lists are capable of containing thousands of value objects. Items, Changes, and
Users lists are examples of such lists. Although you can use these lists for Page Two and Page
Three fields, you can not enumerate values for these lists.
Enumerable and Non-Enumerable Lists
As such, Agile SDK object lists are either enumerable, or non-enumerable. If a specific list is
enumerable, you can read the contents of that list. If it is non-enumerable, you cannot access the
list directly. For non-enumerable lists, query the Agile class that the object list uses to get the
objects that are referenced by the list. The enumeration property for an object is hard coded on the
server and cannot be changed.
To determine if the values for a dynamic list can be enumerated, use
IAgileList.getChildNodes() as shown in the following example. If getChildNodes()
returns null, the list values cannot be enumerated. However, this does not prevent you from
selecting a value for the list.
Example: Checking whether values for a dynamic list are enumerable
private void setPageTwoListValue(IItem item) throws APIException {
// Get the "Page Two.List01" cell
ICell cell = item.getCell(CommonConstants.ATT_PAGE_TWO_LIST01);
// Get available values for the list
IAgileList values = cell.getAvailableValues();
// If the list cannot be enumerated, set the selection to the current
user
if (values.getChildNodes() == null) {
values.setSelection(new Object[]{m_session.getCurrentUser()});
cell.setValue(values);
}
}
private void setPageTwoMultilistValue(IItem item) throws
APIException {
// Get the "Page Two.Multilist01" cell
ICell cell = item.getCell(CommonConstants.ATT_PAGE_TWO_MULTILIST01);
// Get available values for the list
IAgileList values = cell.getAvailableValues();
// If the list cannot be enumerated, set the selection to an array of
users
if (values.getChildNodes() == null) {
IAgileClass cls = cell.getAttribute().getListAgileClass();
if (cls != null) {
IUser user1 = (IUser)m_session.getObject(cls, "hhawkes");
IUser user2 = (IUser)m_session.getObject(cls, "ahitchcock");
IUser user3 = (IUser)m_session.getObject(cls, "jhuston");
Object[] users = new Object[] {user1, user2, user3};
Chapter 11: Working with Lists
v9.3.1.2 161
values.setSelection(users);
cell.setValue(values);
}
}
}
Non-Enumerable PG&C Lists
The following PG&C lists that were enumerable in earlier releases of the SDK, are no longer
enumerable in this release.
à Declarations
à Substances
à Specifications
à Part Families
à Part Families Commodities
Selecting a List from the List Library
The IListLibrary interface enables working with the library of Agile lists. You can load an
existing list, or create a new one. To load an existing list, use IListLibrary.getAdminList().
You can specify the string name of a list, such as “Disposition.” You can also specify a list, by its ID,
or by an AdminListConstants, such as LIST_DISPOSITION_SELECTION. Before you attempt
to use a list from the list library, make sure the list is enabled.
The following example shows how to configure a Page Two list attribute to use a list called Users.
Example: Configuring an attribute to use an Agile list
try {
IAgileList values = null;
// Get the Admin instance
IAdmin admin = m_session.getAdminInstance();
// Get the List Library
IListLibrary listLib = admin.getListLibrary();
// Get the Parts class
IAgileClass partClass =
admin.getAgileClass(ItemConstants.CLASS_PARTS_CLASS);
// Get the "Page Two.List01" attribute
IAttribute attr =
partClass.getAttribute(ItemConstants.ATT_PAGE_TWO_LIST01);
// Make the list visible
IProperty propVisible =
attr.getProperty(PropertyConstants.PROP_VISIBLE);
values = propVisible.getAvailableValues();
values.setSelection(new Object[] { "Yes" });
propVisible.setValue(values);
// Change the name of the attribute to "Project Manager"
SDK Developer Guide - Using Agile APIs
162 Agile Product Lifecycle Management
IProperty propName = attr.getProperty(PropertyConstants.PROP_NAME);
propName.setValue("Project Manager");
// Get the list property
IProperty propList = attr.getProperty(PropertyConstants.PROP_LIST);
// Use the Users list from the list library.
IAdminList users =
listLib.getAdminList(AdminListConstants.LIST_USER_OBJECTS);
if (users != null ) {
if (users.isEnabled()) {
propList.setValue(users);
} else {
System.out.println("Users list is not enabled.");
}
}
// Specify the Default Value to the current user
IProperty propDefValue =
attr.getProperty(PropertyConstants.PROP_DEFAULTVALUE);
values = propDefValue.getAvailableValues();
values.setSelection(new Object[]{m_session.getCurrentUser()});
propDefValue.setValue(values);
} catch (APIException ex) {
System.out.println(ex);
}
When you select a user-defined list using IListLibrary.getAdminList(), you can specify the
list by name or ID. All list names must be unique. The following example shows how to select an
Agile list called Colors.
Example: Selecting a list named Colors
private void selectColorsList(IAttribute attr, IListLibrary
m_listLibrary) throws APIException {
// Get the List property
IProperty propList = attr.getProperty(PropertyConstants.PROP_LIST);
// Use the Colors list
IAdminList listColors = m_listLibrary.getAdminList("Colors");
if (listColors != null ) {
if (listColors.isEnabled()) {
propList.setValue(listColors);
} else {
System.out.println("Colors list is not enabled.");
}
}
}
Chapter 11: Working with Lists
v9.3.1.2 163
Creating Custom Lists
The Agile API lets you modify list attributes for different classes and configure custom list attributes
for Page Two and Page Three. You can customize these list attributes to create simple lists or
multilists. You can also configure a list to be cascading, that is, have multiple levels.
In Agile Java Client, administrators can configure a library of custom lists by choosing Admin > Data
Settings > Lists. In the Agile API, the IListLibrary interface provides functionality equivalent to
Admin > Data Settings > Lists. The IAdminList interface provides functionality for configuring and
customizing each list.
Creating a Simple List
To create a new list, use the IListLibrary.createAdminList() method, which takes a map
parameter. The map that you pass with createAdminList() must contain values for the following
IAdminList fields:
à ATT_NAME – the String name of the list. This is a required field. The list name must be unique.
à ATT_DESCRIPTION – the String description of the list. This is an optional field; the default
value is an empty string.
à ATT_ENABLED – a Boolean value specifying whether the list is enabled. This is an optional
field; the default value is false.
à ATT_CASCADED – a Boolean value specifying whether the list contains multiple levels. This is
an optional field; the default value is false. The ATT_CASCADED value cannot be changed
after the list is created.
Once the list is created, you can use the IAdminList interface to enable or disable the list and set
values for it.
The following example shows how to create a new list called Colors. This list is a simple list with
only one level.
Example: Creating a simple list
try {
// Get the Admin instance
IAdmin admin = m_session.getAdminInstance();
// Get the List Library
IListLibrary listLib = admin.getListLibrary();
// Create a new Admin list
HashMap map = new HashMap();
String name = "Colors";
map.put(IAdminList.ATT_NAME, name);
map.put(IAdminList.ATT_DESCRIPTION, name);
map.put(IAdminList.ATT_ENABLED, new Boolean(true));
map.put(IAdminList.ATT_CASCADED, new Boolean(false));
IAdminList listColors = listLib.createAdminList(map);
// Add values to the list
SDK Developer Guide - Using Agile APIs
164 Agile Product Lifecycle Management
IAgileList list = listColors.getValues(); //The list is empty at this
point.
list.addChild("Black");
list.addChild("Blue");
list.addChild("Green");
list.addChild("Purple");
list.addChild("Red");
list.addChild("White");
listColors.setValues(list);
} catch (APIException ex) {
System.out.println(ex);
}
Lists that contain String values are case-sensitive. This means that a list can contain uppercase,
lowercase, and mixed-case variations of the same value, which may not be desirable. For example,
the following code snippet adds three variations of each color value to the Colors list.
Example: Adding case-sensitive values to a list
IAgileList list = listColors.getValues(); //The list is empty at this
point.
list.addChild("Black");
list.addChild("BLACK");
list.addChild("black");
list.addChild("Blue");
list.addChild("BLUE");
list.addChild("blue");
list.addChild("Green");
list.addChild("GREEN");
list.addChild("green");
list.addChild("Purple");
list.addChild("PURPLE");
list.addChild("purple");
list.addChild("Red");
list.addChild("RED");
list.addChild("red");
list.addChild("White");
list.addChild("WHITE");
list.addChild("white");
Automatically Creating New Lists by Modifying Existing Lists
Each list attribute must reference an Agile list for its values. If you retrieve an Agile list and modify
its values without saving the list and then use those values for a list attribute, the Agile API
automatically creates a new list. In the following example, the Colors list is retrieved, but before it is
used to populate the values for a list field a new value, “Violet,” is added to the list. When
IAttribute.setAvailableValues() is called, a new list is created.
Chapter 11: Working with Lists
v9.3.1.2 165
Note Lists that are created automatically by the Agile API have a prefix “SDK” followed by a
random number. You can rename such lists, if you prefer.
Example: Creating a new list automatically by modifying an existing list
try {
// Get the Colors list
IAdminList listColors = m_listLibrary.getAdminList("Colors");
// Get the Parts class
IAgileClass partsClass =
admin.getAgileClass(ItemConstants.CLASS_PARTS_CLASS);
// Get the "Page Two.List01" attribute
IAttribute attr =
partsClass.getAttribute(ItemConstants.ATT_PAGE_TWO_LIST01);
// Get the color values
IAgileList values = listColors.getValues();
// Add a new color
values.addChild("Violet");
// Set the available list values for "Page Two.List01". Because the
list
// was modified, a new AdminList is created automatically.
attr.setAvailableValues(values);
} catch (APIException ex) {
System.out.println(ex);
}
Creating a Cascading List
A cascading list is a list with multiple levels. You can configure SingleList attributes and cells using
a cascading list instead of a simple list.
Note Once you set a list to be cascading, you can’t change it to a simple list. You cannot
change the value of IAdminList.ATT_CASCADED after the list is created.
The following example shows how to create a new cascading list called “Field Office.” The list has
two levels.
Important When setting level names for cascading lists, always start with the index 0 for the first
level and increment the index subsequent levels as shown in the following two
examples below.
SDK Developer Guide - Using Agile APIs
166 Agile Product Lifecycle Management
Example: Creating a cascading list
try {
// Get the Admin instance
IAdmin admin = m_session.getAdminInstance();
// Get the List Library
IListLibrary listLib = admin.getListLibrary();
// Create a new Admin list
HashMap map = new HashMap();
String name = "Field Office";
map.put(IAdminList.ATT_NAME, name);
map.put(IAdminList.ATT_DESCRIPTION, name);
map.put(IAdminList.ATT_ENABLED, new Boolean(true));
map.put(IAdminList.ATT_CASCADED, new Boolean(true));
IAdminList listFO = listLib.createAdminList(map);
// Get the empty list
IAgileList list = listFO.getValues();
// Add the list of countries
IAgileList india = (IAgileList)list.addChild("India");
IAgileList china = (IAgileList)list.addChild("China");
IAgileList usa = (IAgileList)list.addChild("USA");
IAgileList australia = (IAgileList)list.addChild("Australia");
// Add the list of cities
india.addChild("Bangalore");
china.addChild("Hong Kong");
china.addChild("Shanghai");
china.addChild("Suzhou");
usa.addChild("San Jose");
usa.addChild("Milpitas");
usa.addChild("Seattle");
usa.addChild("Jersey City");
australia.addChild("Sidney");
// Save the list values
listFO.setValues(list);
Chapter 11: Working with Lists
v9.3.1.2 167
// Set level names starting with index 0 for level 1.
list.setLevelName(0, "Field Office Country");
list.setLevelName(1, "Field Office City");
} catch (APIException ex) {
System.out.println(ex);
}
In cascading lists, level names used by the list must be unique and you cannot share them between
lists. The level names are stored internally, but Agile Java Client and Web Client currently don’t
display them. The level names are needed only if you want to show them in a cascading list UI that
you created.
After you call the IAdminList.setValues() method, a valid ID is assigned to each list value.
Only leaf nodes, that is, nodes on the lowest level of a cascading list, have valid IDs. In the previous
example, the city nodes are leaf nodes. All other nodes have a null ID. You can use the ID to set the
selection of the IAgileList object.
You can add a list value and its parent nodes in one statement instead of adding the parent node
and then its subnodes. Use the | character to separate nodes, which represent levels, in the string.
The following example replaces a portion of the code in the previous example; it shows how to add
the same list values as in the previous example, but using fewer lines of code.
Example: Adding parent nodes and subnodes to a cascading list
// Get the list values
IAgileList list = listFO.getValues(); // The list is empty at this
point.
// Add nodes
list.addChild(“India|Bangalore”);
list.addChild(“Hong Kong|Hong Kong”);
list.addChild(“China|Suzhou”);
list.addChild(“USA|San Jose”);
list.addChild(“USA|Milpitas”);
list.addChild(“USA|Jersey City”);
list.addChild(“Australia|Sidney”);
// Save the list values
listFO.setValues(list);
// Set level names
list.setLevelName(0, “Field Office Country”);
list.setLevelName(1, “Field Office City”);
SDK Developer Guide - Using Agile APIs
168 Agile Product Lifecycle Management
Creating a Criteria-Based List
Criteria-based lists are dynamic lists whose values are defined by the criteria selected from the
Agile Criteria library. These lists are created in Java Client's Create List dialog by selecting the
"Dynamic" List Type in the drop-down list which opens the Agile Criteria library to select the
applicable Criteria.
Figure 13: Creating criteria-based lists in Java Client
Agile SDK supports creating, loading, and modifying Criteria-based lists by exposing the necessary
APIs to:
1. Get the Criteria
2. Create the Criteria-based list
3. Load the Criteria-based list
4. Replace the Criteria-based list
The following examples use the respective APIs to perform these tasks.
Example: Getting the Criteria from the Agile Criteria library
IListLibrary library = m_admin.getListLibrary();
INode lib = m_admin.getNode(NodeConstants.NODE_CRITERIA_LIBRARY);
ICriteria criteria = (ICriteria)lib.getChild("All Change Orders");
Example: Creating the Criteria-based list
HashMap params = new HashMap();
String name = "SDKlist" + System.currentTimeMillis();
params.put(IAdminList.ATT_APINAME, name.toUpperCase());
params.put(IAdminList.ATT_NAME, name.toUpperCase());
params.put(IAdminList.ATT_DESCRIPTION, name.toLowerCase());
params.put(IAdminList.ATT_ENABLED, true);
params.put(IAdminList.ATT_CRITERIA, criteria);
ICriteriaBasedList list =
(ICriteriaBasedList)library.createDynamicAdminList(params);
System.out.println("Created list: "+list.getName());
System.out.println("Criteria:
"+((ICriteriaBasedList)list).getCriteria().toString());
Example: Loading the Criteria-based list
Chapter 11: Working with Lists
v9.3.1.2 169
ICriteriaBasedList list =
(ICriteriaBasedList)m_admin.getListLibrary().getAdminList(name.toUpp
erCase());
System.out.println("Loaded list: "+list.getName());
Example: Replacing the Criteria - Modifying the Criteria-based list
ICriteria criteria = (ICriteria)lib.getChild("All Designs");
list.setCriteria(criteria);
System.out.println("New Criteria:
"+((ICriteriaBasedList)list).getCriteria().toString());
Checking the Data Type of a List
A list can contain objects of any Agile datatype. Therefore, before getting or setting a list value, you
should determine the data type of objects in the list. If you are working with a cascading list, the
data type can vary with each level. There are several ways to determine the data type of a list:
à For predefined lists in the List Library, use IAdminList.getListDataType() to get the
data type.
à For SingleList and MultiList attributes that have only one list level, use the
IAttribute.getListDataType() method to get the data type for the entire list.
à For a level within a cascading list, use the IAgileList.getLevelType() method to get the
data type for a particular level.
Example: Checking the data type of a list
public void setDefaultValue() throws APIException {
// Get the Parts class
IAgileClass partClass =
m_admin.getAgileClass(ItemConstants.CLASS_PARTS_CLASS);
// Get the "Page Two.List01" attribute
IAttribute attr =
partClass.getAttribute(ItemConstants.ATT_PAGE_TWO_LIST01);
switch (attr.getListDataType()) {
case DataTypeConstants.TYPE_OBJECT:
//Add code here to handle Object values
break;
case DataTypeConstants.TYPE_STRING:
//Add code here to handle String values
break;
default:
//Add code here to handle other datatypes
}
}
SDK Developer Guide - Using Agile APIs
170 Agile Product Lifecycle Management
Modifying a List
Once a list has been created, you can modify it in the following ways:
à Add values to a list
à Make list values obsolete
à Set the list name and description
à Set level names for a cascading list
à Enable or disable a list
à Delete a list
à Modify or remove values added to a list
Adding a Value to a List
The following example shows how to add several values to a list. Before adding a value to a list,
use the ITreeNode.getChildNode() method to make sure the value doesn’t already exist.
Example: Adding values to a list
private static void updateProductLinesList() throws APIException {
// Get the Admin instance
IAdmin admin = m_session.getAdminInstance();
// Get the List Library
IListLibrary listLib = admin.getListLibrary();
// Get the Product Lines list
IAdminList listProdLine = listLib.getAdminList("Product Line");
// Add values to the list
IAgileList listValues = listProdLine.getValues();
addToList(listValues, "Saturn");
addToList(listValues, "Titan");
addToList(listValues, "Neptune");
listProdLine.setValues(listValues);
}
Making List Values Obsolete
You can prevent the selection of a list value by making the list entry obsolete. However, when you
invoke the IProperty.getAvailableValues() method, the returned IAgileList object can
include obsolete list values. This is due to the fact that when the list value is marked obsolete, the
server continues to maintain the value in its obsolete list values for existing objects that use these
values.
Chapter 11: Working with Lists
v9.3.1.2 171
The following example shows how to check whether a list value is obsolete and how to make it
obsolete.
Example: Making a list value obsolete
public void checkIfObsolete(IAgileList list) throws APIException {
if (list != null ) {
if (list.isObsolete() == false) {
System.out.println(list.getValue());
}
}
}
public void setObsolete(IAgileList list, String value) throws
APIException {
if (list != null ) {
list.setObsolete(true);
System.out.println(list.getValue() + " is now obsolete.");
}
}
Setting the List Name and Description
To create a list, you must specify a unique name for it. Therefore, when you use
IListLibrary.createAdminList(), you must pass a value for the IAdminList.ATT_NAME
field. Other IAdminList fields, such as ATT_DESCRIPTION, are optional. After the list is created,
you can modify it’s name and description. The following example shows how to set the name and
description of a list.
Example: Setting the list name and description
try {
IAdminList list = m_listLibrary.getAdminList("Packaging Styles");
list.setName("Packaging Color Codes");
list.setDescription("Color codes for product packaging");
} catch (APIException ex) {
System.out.println(ex);
}
Setting Level Names for a Cascading List
Like list names, the level names for a list must be unique. You can’t reuse the level name used by
another cascading list. To check if the list with a given name already exists, use
IListLibrary.getAdminList(). Use one of the following methods to set the level name of a
cascading list:
à IAgileList.setLevelName(int, String) – Sets the level name for a specified level.
à IAgileList.setLevelName(String) – Sets the level name of the current level.
For an example showing how to set the level names of a cascading list, see
Creating a Cascading
List on page 165.
SDK Developer Guide - Using Agile APIs
172 Agile Product Lifecycle Management
Note Level names for cascading lists are not displayed in Agile Java Client or Web Client.
However, you can choose to display them in Clients you create with the Agile SDK.
Enabling or Disabling a List
When you create a custom list, you can use the IAdminList.ATT_ENABLED field to specify
whether it’s enabled. If you omit this field, the list is disabled by default. The following example
shows how to enable and disable a list after it has been created.
Example: Enabling and disabling a list
public void enableList(IAdminList list) throws APIException {
list.enable(true);
System.out.println("List " + list.getName() + " enabled.");
}
public void disableList(IAdminList list) throws APIException {
list.enable(false);
System.out.println("List " + list.getName() + " disabled.");
}
Deleting a List
If a list is not read-only and is not currently being used by an Agile dataobject, you can delete it.
Otherwise, the IAdminList.delete() method throws an exception. Once you delete a list, it is
removed permanently. You cannot undo the deletion.
The following example shows how to delete a list.
Example: Deleting a list
public void deleteList(IAdminList list) throws APIException {
// Make sure the list is not read-only
if (!list.isReadOnly()) {
// Delete the list
list.delete();
System.out.println("List " + list.getName() + " deleted.");
} else {
System.out.println("List " + list.getName() + " is read-only.");
}
}
Modifying and Removing List Values
The SDK provides the following methods to modify String element entries, or remove an entry in an
Agile list:
à The IAgileList.setValue(Object) method to modify String list element entries in an
Agile Admin list.
Note This method only applies to String values. You can only use this method to modify String
entries and not object entries.
Chapter 11: Working with Lists
v9.3.1.2 173
à The IAgileList.clear() and ITree.removeChild(Object) methods to remove any
Agile list entry that is not restricted by the applicable business rules.
The following example uses these methods to modify and clear values in an Agile list.
Example: Renaming and removing Admin list entries
public void exampleClearList() throws Exception {
IAdmin admin = m_session.getAdminInstance();
IListLibrary listLibrary = admin.getListLibrary();
HashMap map = new HashMap();
String name = "Color";
String desc = "Example";
map.put(IAdminList.ATT_NAME, name);
map.put(IAdminList.ATT_DESCRIPTION, desc);
map.put(IAdminList.ATT_ENABLED, new Boolean(true));
map.put(IAdminList.ATT_CASCADED, new Boolean(false));
IAdminList newList = listLibrary.createAdminList(map);
IAgileList list = newList.getValues();
list.addChild("RED");
list.addChild("GREEN");
list.addChild("BLUE");
newList.setValues(list);
list = newList.getValues();
// Removing the selection
IAgileList agList = (IAgileList)list.getChild("BLUE");
Object errorCode = null;
try {
list.removeChild(agList);
}catch(APIException e){
errorCode = e.getErrorCode();
}
// Clear the list
list = newList.getValues();
list.clear();
newList.setValues(list);
// Clean up
newList.delete();
}
SDK Developer Guide - Using Agile APIs
174 Agile Product Lifecycle Management
Printing Contents of IAgileList Objects
When working with an IAgileList object, particularly one with several levels, it’s helpful to print
the entire hierarchy of the list. The following code prints the list nodes contained within an
IAgileList object.
Example: Printing list nodes in an IAgileList object
private void printList(IAgileList list, int level) throws APIException
{
if (list != null ) {
System.out.println(indent(level*4) + list.getLevelName() + ":" +
list.getValue() + ":" + list.getId());
Object[] children = list.getChildren();
if (children != null) {
for (int i = 0; i < children.length; ++i) {
printList((IAgileList)children[i], level + 1);
}
}
}
}
private String indent(int level) {
if (level <= 0) {
return "";
}
char c[] = new char[level*2];
Arrays.fill(c, ' ');
return new String(c);
}
v9.3.1.2 175
Chapter 12
Working with Attachments and File
Folder Objects
This chapter includes the following:
About Attachments and File Folders.................................................................................................................... 175
Working with File Folders .................................................................................................................................... 176
Working with Attachments Table of an Object..................................................................................................... 182
Checking Out a File Folder.................................................................................................................................. 185
Canceling a File Folder Checkout........................................................................................................................185
Adding Files and URLs to the Attachments Table............................................................................................... 186
About Attachments and File Folders
Attachments to objects contain information about the object or a manufacturing process. You can
attach files and URLs by referencing them in a File Folder object. The File Folder object holds
pertinent content, or Attachments. Most primary Agile API objects, such as IItem, IChange,
IManufacturer, IManufacturerPart, IPackage, ITransferOrder, IUser, and
IUserGroup, have an Attachments table (or tab in the Java Client) that lists indirect references to
the files or URLs that are in separate file folders. Each row in an Attachments table can refer to one
file or to all files from a referenced file folder.
The following figure is an example of the way files or URLs contained in a file folder are referenced
indirectly from the Attachments table of multiple business objects, in this case an item and a
change.
Figure 14: How Attachments table rows refer indirectly to File Folder files or URLs
The Agile API does not provide support for viewing or printing an attachment. However, after you
download a file, you can use another application to view, edit, or print the attachment.
SDK Developer Guide - Using Agile APIs
176 Agile Product Lifecycle Management
A File Folder is a business object that specifies one or more files or URLs that are stored in the file
server vault. In addition, a file folder has its own set of tables. This means that you can create and
load an independent file folder and add one or more files to its Files table. You can also search for a
file folder, just as you would search for an Item or Change.
Important Before you try to add Agile PLM attachments and work with file folders, make sure the
File Manager Internal Locator property is set in Agile Java Client. Choose Admin > Settings
> Server Settings > Locations > File Manager > Advanced > File Manager Internal Locator. The
format for the value is
<protocol>://<machinename>:<port>/<virtualPath>/services/FileServer. For example,
http://agileserver.agile.agilesoft.com:8080/Filemgr/services/FileServer is a valid value.
For more information about Agile PLM server settings, refer to the Agile PLM
Administrator Guide.
Working with File Folders
Similar to Attachments, the SDK exposes APIs to perform File Folders-related tasks such as
checking-in and checking-out files associated with objects in the rows of an Attachments table,
adding files and URLs to an Attachments table, and deleting attachments. This section lists and
describes these features, and provides the necessary procedures to use the SDK to perform these
tasks.
File Folder Classes and Subclasses
The File Folder Base Class has two Classes and each of these classes have their own respective
Subclasses. The figure below lists the File Folders Base Class, Classes, and Subclasses. The Agile
PLM administrator can define new file folder subclasses.
Figure 15: File Folders Classes and Subclasses
Chapter 12: Working with Attachments and File Folder Objects
v9.3.1.2 177
A description of these classes and objects appears in the table below.
Base Class Class Subclass Description
Designs Design Objects that permit building model structures in CAD File Folders
File folders File Folder
Markup
Objects that include files or URLs; this class includes all
file folder objects except historical report file folders.
For information about routing these objects, see Checking the State of Agile PLM Objects on page
29.
File Folder Tables and Constants
The File Folder object supports the following tables and corresponding constants:
Table Constant Read/Write Mode
Title Block
TABLE_TITLEBLOCK
Read/Write
Page Two
TABLE_PAGETWO
Read/Write
Page Three
TABLE_PAGETHREE
Read/Write
Files
TABLE_FILES
Read/Write
Structure
TABLE_STRUCTURE
Read/Write
Routing Slip/Workflow
TABLE_WORKFLOW
Read/Write
Relationships
TABLE_RELATIONSHIPS
Read-only
History
TABLE_HISTORY
Read-only
Where Used
TABLE_WHEREUSED
Read/Write
Where Used Design
TABLE_WHEREUSEDDESIGN
Read-only
Creating File Folder Objects
IFileFolder is the interface that corresponds to the file folder business object. The following
example shows how to create a file folder.
Example: Creating a file folder
public void createFileFolder() throws Exception {
IAgileClass attClass =
m_admin.getAgileClass(FileFolderConstants.CLASS_FILE_FOLDER);
IAutoNumber an = cls.getAutoNumberSources()[0];
String attNumber = an.getNextNumber();
IFileFolder ff = (
IFileFolder)m_session.createObject(attClass, attNumber);
ff.checkOutEx();
}
SDK Developer Guide - Using Agile APIs
178 Agile Product Lifecycle Management
Note When you add a file or a URL to the row of the Attachments table of a business object,
you will automatically create automatically a new file folder object that contains the
associated file or URL. See
Creating File Folder Objects by Adding Rows to
Attachments Table on page 180.
The File Folders Design class is similar to the File folder class with the additional Structures table
(Tab in the Java Client UI) for CAD objects. The following examples show how to create a Design
object, adding a Design object to a the Structure tree, and loading a structure table.
Example: Creating a Design object
// autoNum is autoNumber as usual
IFileFolder obj = (IFileFolder) m_session.createObject(
FileFolderConstants.CLASS_DESIGN, autoNum);
Example: Adding Design objects to a Structure tree
IFileFolder obj = // some Design object
IFileFolder childObj1 = // some Design object
IFileFolder childObj2 = // some Design object
obj.checkOutEx();
ITable table = obj.getTable(FileFolderConstants.TABLE_STRUCTURE);
// add row
Object[] vers = childObj1.getVersions();
IRow row = table.createRow(childObj1);
row.setValue(FileFolderConstants.ATT_STRUCTURE_LABEL,
"label modified by creating row 1");
row = table.createRow(childObj2);
row.setValue(FileFolderConstants.ATT_STRUCTURE_LABEL,
"label modified by creating row 2");
obj.checkIn();
Example: Loading a Structure table
public void testLoadingDesignStructureTable() throws Exception {
addCaseInfo("Design Object", "load Structure table", "");
// assuming Design object Design00004 existed with some data in
Structure
IFileFolder obj = (IFileFolder) m_session.getObject(
FileFolderConstants.CLASS_DESIGN, "Design00004");
IAgileClass agileClass = obj.getAgileClass();
// load Structure table
ITable table = obj.getTable(FileFolderConstants.TABLE_STRUCTURE);
Integer tableId = (Integer) table.getTableDescriptor().getId();
// ITable performs related tasks
}
Example: Loading a Structure table as a tree
public void testLoadingDesignStructureTree()
throws Exception
{addCaseInfo("Design Object", "load Structure tree", "");
// assuming Design object Design00004 existed with some data in
Structure
IFileFolder obj = (IFileFolder) m_session.getObject(
FileFolderConstants.CLASS_DESIGN, "Design00004");
IAgileClass agileClass = obj.getAgileClass();
// load Structure table
Chapter 12: Working with Attachments and File Folder Objects
v9.3.1.2 179
ITable table = obj.getTable(FileFolderConstants.TABLE_STRUCTURE);
Integer tableId = (Integer) table.getTableDescriptor().getId();
ITreeNode root = (ITreeNode) table;
Collection topLevelChildren = root.getChildNodes();
Iterator it;
ITreeNode row;
if (topLevelChildren != null) {
it = topLevelChildren.iterator();
int level = 0;
while (it.hasNext()) {
row = (ITreeNode) it.next();
if(row instanceof IRow) {
IRow aRow = (IRow) row;
IDataObject referent =
aRow.getReferent();
if(referent != null) {
System.out.println(
"Row Referent Object ID/row:
"+ referent.getObjectId()+ " / "
+ referent.getName());
}
}
iterateTreeNode(agileClass, true,
tableId, (ITreeNode) row);
count++;
}
}
System.out.println("The number of rows in top level is " + count);
}
private void iterateTreeNode(IAgileClass agileClass, boolean print,
Integer tableId, ITreeNode node) throws APIException {
Collection childNodes = node.getChildNodes();
printRow(agileClass, print, tableId, (IRow) node);
if (childNodes == null || childNodes.size() <= 0) {
return;
}
Iterator it = childNodes.iterator();
ITreeNode childNode;
IRow row;
while (it.hasNext()) {
childNode = (ITreeNode) it.next();
if (childNode instanceof IRow) {
row = (IRow) childNode;
if(row instanceof IRow) {
IDataObject referent =
row.getReferent();
if(referent != null) {
System.out.println
SDK Developer Guide - Using Agile APIs
180 Agile Product Lifecycle Management
("Row Referent Object ID/row:
"+ referent.getObjectId()+ " / "
+ referent.getName());
}
}
iterateTreeNode(agileClass, print, tableId, (ITreeNode) childNode);
}
}
}
Creating File Folder Objects by Adding Rows to Attachments Table
When you add a file or a URL to the row of the Attachments table of a business object, you
automatically create a new file folder that contains the associated file or URL. You can load the
referenced file folder using the IRow.getReferent() method, as shown in the following example.
Example: Creating a file folder by adding a row to the Attachments table
public IFileFolder addRowToItemAttachments
(IItem item, File file) throws Exception
{ITable attTable = item.getTable(ItemConstants.TABLE_ATTACHMENTS);
IRow row = attTable.createRow(file);
IFileFolder ff = (IFileFolder)row.getReferent();
return ff;
}
Working with the Files Table of a File Folder
The Files table of a file folder lists the files and URLs associated with the object. To edit the table,
you must first check out the file folder. You cannot add files or URLs to the Files table or delete
them unless the file folder is checked out.
The following example shows how to check out a file folder and then add files and URLs to the Files
table.
Example: Adding files and URLs to the Files table of a file folder
public void addFiles(IFileFolder ff, File[] files, URL[] urls) throws
Exception {
// Check out the file folder
ff.checkOutEx();
// Get the Files table
ITable filesTable = ff.getTable(FileFolderConstants.TABLE_FILES);
// Add files to the Files table
for (int i = 0; i < files.length; ++i) {
filesTable.createRow(files[i]);
}
// Add URLs to the Files table
for (int i = 0; i < urls.length; ++i) {
filesTable.createRow(urls[i]);
}
Chapter 12: Working with Attachments and File Folder Objects
v9.3.1.2 181
// Check in the file folder
ff.checkIn();
}
Accessing Files in Agile PLM File Vault with IAttachmentFile
IAttachmentFile is the interface that provides generalized access to files stored in the Agile
PLM file vault. This interface is supported by the following Agile API objects:
à File folder – you can class cast IFileFolder to IAttachmentFile.
à A row of the Files table of a file folder – you can class cast IRow from the Files table to
IAttachmentFile.
à A row of the Attachments table of a business object – you can class cast IRow from the Attachments
table to IAttachmentFile.
IAttachmentFile provides the following methods for working with attachments:
à getFile()
à isSecure()
Note IAttachmentFile also has a setFile() method that lets you change the file(s) for
an attachment, but it is supported only for rows of the Attachments table.
The results returned from IAttachmentFile methods vary depending on the object you’re
working with, as shown in the following table.
Calling object getFile() return value isSecure() return value
Row from the Attachments table of
any business object
Returns either a single file InputStream if
the row refers to a specific file from the file
folder or a zipped InputStream with all
the files from the file folder.
true if the referenced file is not URL, or
all the files are not URLs.
FileFolder object Returns a zipped InputStream with all
files from the file folder.
true if all the files contained in the file
folder are not URLs.
Row from the Files table of a file
folder
Returns a single file InputStream that refers to
a specific file from the file folder.
true if the referenced file is not a URL.
Note To read files in a zipped InputStream , use methods of the
java.util.zip.ZipInputStream class.
The following example shows how to use IAttachmentFile.isSecure() and
IAttachmentFile.getFile() from the row of an Attachments table for an item.
Example: Using isSecure() and getFile()
public InputStream getItemAttachment(IItem item) throws Exception {
InputStream content = null;
ITable attachments = item.getTable(ItemConstants.TABLE_ATTACHMENTS);
IRow row = (IRow)attachments.iterator().next();
SDK Developer Guide - Using Agile APIs
182 Agile Product Lifecycle Management
if (((IAttachmentFile)row).isSecure())
content = ((IAttachmentFile)row).getFile();
return content;
}
Working with Attachments Table of an Object
To work with the Attachments table of an object, follow this sequence.
1. Get the object that has the attachment you want.
For example, you can use the IAgileSession.getObject() method to get a particular
object, or you can create a query to return objects.
2. Get the Attachments table. Use the IDataObject.getTable() or
IAttachmentContainer.getAttachments() methods to get the table.
3. Select a row in the Attachments table.
Create an iterator for the table, and then select a particular row. You can use the
ITable.getTableIterator() method to get a bidirectional iterator for the table.
The following example below shows how to retrieve an item, get the Attachments table for the item,
and then select the first attachment.
Example: Getting an attachment for an Item
try {
// Get Item P1000
Map params = new HashMap();
params.put(ItemConstants.ATT_TITLE_BLOCK_NUMBER, "P1000");
IItem item = (IItem)m_session.getObject(IItem.OBJECT_TYPE, params);
// Get the attachment table for file attachments
ITable attTable = item.getAttachments();
// Get a table iterator
ITwoWayIterator it = attTable.getTableIterator();
// Get the first attachment in the table
if (it.hasNext()) {
IRow row = (IRow)it.next();
// Read the contents of the stream
InputSteam stream = ((IAttachmentFile)row).getFile();
}
else {
JOptionPane.showMessageDialog(null, "There are no files listed.",
"Error", JOptionPane.ERROR_MESSAGE);
}
} catch (APIException ex) {
System.out.println(ex);
}
Chapter 12: Working with Attachments and File Folder Objects
v9.3.1.2 183
Checking In and Checking Out Files with ICheckoutable
ICheckoutable is an interface that you can use to check in and check out files that are
associated with an object. This applies only to rows of the Attachments table. You can class cast
IRow from the Attachments table to ICheckoutable.
ICheckoutable provides the following methods for working with attachments:
à cancelCheckout()
à checkIn()
à checkOutEx()
à isCheckedOut()
This example shows how to use the ICheckoutable interface to check out and check in a file
from a row of the Attachments table.
Example: Using ICheckoutable methods to check out and check in an attached file
public InputStream checkOutRow(IRow row) throws APIException {
// Check out the attachment
((ICheckoutable)row).checkOutEx();
// Read the contents of the stream
InputStream stream = ((IAttachmentFile)row).getFile();
return stream;
}
public checkInRow(IRow row, String filePath) throws APIException {
if (row.isCheckedOut()) {
// Set the new file
((IAttachmentFile)row).setFile(new File(filePath));
// Check in the file
((ICheckoutable)row).checkIn();
}
else {
JOptionPane.showMessageDialog(null, "The attachment is not checked
out.",
"Error", JOptionPane.ERROR_MESSAGE);
}
}
Specifying the Revision of the Item
When you are working with items, each revision can have different attachments. If an item has
multiple revisions, your program should allow the user to select a revision. For information about
specifying the revision, see
Getting and Setting the Revision of an Item on page 109.
SDK Developer Guide - Using Agile APIs
184 Agile Product Lifecycle Management
Checking whether the Revision Is Incorporated
When the revision for an item is released, it is possible the revision is also incorporated. The
attachments for an incorporated item are locked and cannot be checked out.
However, you can still view incorporated attachments, but you cannot modify them. To modify an
incorporated attachment, you must either un-incorporate the attachment, or submit a new change
order to create a new revision as shown in the examples below. These two examples are Process
Extensions. For information on Process Extensions, refer to SDK Developer Guide - Developing
PLM Extensions and for information about checking if a revision is incorporated, see
Changing the
Incorporated Status of a Revision on page 111.
Example: Incorporating Attachments
class IncorporateItem implements ICustomAction {
public ActionResult doAction(IAgileSession session, INode
actionNode,
IDataObject affectedObject) {
try {
System.out.println("Workflow action kicked off....");
IItem object = (IItem)affectedObject;
System.out.println("Incorporating...");
IItem loItem = (IItem) session.getObject(IItem.OBJECT_TYPE,
object.getName());
//this will get the latest version. Make sure the latest is against
a MCO
loItem.setIncorporated(true);
//incorporate the attachment
System.out.println("Attachment added.");
String message = ("Incorporated "+object);
return new ActionResult(ActionResult.STRING, message);
} catch (APIException ae) {
ae.printStackTrace();
return new ActionResult(ActionResult.EXCEPTION, ae);
}
}
}
Example: Un-incorporating Attachments
class IncorporateItem implements ICustomAction {
public ActionResult doAction(IAgileSession session, INode
actionNode,
IDataObject affectedObject) {
try {
System.out.println("Workflow action kicked off....");
IItem object = (IItem)affectedObject;
System.out.println("Un-incorporating...");
IItem loItem = (IItem) session.getObject(IItem.OBJECT_TYPE,
object.getName());
//this will get the latest released version
loItem.setIncorporated(false);
System.out.println("Attachment added.");
String message = ("Un-incorporated "+object);
return new ActionResult(ActionResult.STRING, message);
} catch (APIException ae) {
ae.printStackTrace();
Chapter 12: Working with Attachments and File Folder Objects
v9.3.1.2 185
return new ActionResult(ActionResult.EXCEPTION, ae);
}
}
}
Checking Out a File Folder
Before you can add, delete, or modify the files contained in a file folder, you must check out the file
folder. With the appropriate privileges, you can check out a file folder as long as it is not already
checked out by another user. Once a file folder is checked out, no one else can check it out or
modify it.
The user who checked out a file folder, as well as other users who are change analysts or
component engineers, can check it in. If the file folder was checked out to a location on the network,
or to a shared drive or directory, anyone who has access to that network location or to that shared
directory can check in the file folder.
The following example shows how to check out a file folder.
Example: Checking out a file folder
void checkOutFileFolder(IFileFolder ff) throws Exception {
ff.checkOutEx();
}
Note You can also use ICheckoutable.checkOutEx() to check out a row of the
Attachments table. See Checking In and Checking Out Files on page 183.
Canceling a File Folder Checkout
If you check out a file folder and then decide that you don’t want to modify it, or you want to discard
your changes and revert to the original file folder, you can cancel the checkout. When you cancel a
checkout, you also make the file folder available for other users to check out.
Note Only the user who checked out a file folder can cancel the checkout.
This example shows how to cancel a checkout of a file folder.
Example: Canceling checkout of a file folder
void cancelCheckOut(IFileFolder ff) {
// Show a confirmation dialog box
int i = JOptionPane.showConfirmDialog(null,
"Are you sure you want to cancel checkout?",
"Cancel Checkout", JOptionPane.YES_NO_OPTION);
// If the user clicks Yes, cancel checkout
try {
if (i == 0) {
ff.cancelCheckout();
}
SDK Developer Guide - Using Agile APIs
186 Agile Product Lifecycle Management
} catch (APIException ex) {
System.out.println(ex);
}
}
Note You can also use ICheckoutable.cancelCheckout() to cancel checkout of a row
of the Attachments table. See Checking In and Checking Out Files on page 183.
Adding Files and URLs to the Attachments Table
The Agile API lets you add files and URLs to the Attachments table of many types of objects, such
as IItem, IChange, IManufacturerPart, and IManufacturer. An attachment is one or more
physical files or an Internet address (URL). A file is considered a secured attachment because it is
physically stored in the Agile PLM file vault. A URL, on the other hand, is an unsecured attachment.
When you add a file or a URL to the Attachments table of a business object, the server
automatically creates a new file folder containing the associated file or URL. The new row on the
Attachments table references the new file folder.
When you add a URL attachment, the server stores a reference to the Internet location but does not
upload a file. Therefore, you cannot download a URL attachment. The Agile API validates URL
strings that you attempt to check in as an attachment. If a URL is invalid, the Agile API considers
the string a filename instead of a URL.
You cannot add a file or URL to the Attachments table of an item if
à The current revision has a pending or released MCO.
à The current revision is incorporated.
When you use the ITable.createRow(java.lang.Object) method to add a row to the
Attachments table, the param method can be any of the following object types:
à String – adds one file attachment specified by a local path.
à String[] – adds multiple file attachments specified by an array of local paths.
à File – adds one file attachment.
à File[] – adds multiple file attachments.
à InputStream – adds one file attachment.
à InputStream[] – adds multiple file attachments.
à URL – adds one URL attachment.
à URL[] – adds multiple URL attachments.
à IRow (of the Attachments or Files tables) – adds a file or URL attachment.
à IFileFolder – adds all files and URLs for the specified file folder.
à Map – adds one or more files specified by a hash table containing Attachment parameters.
Chapter 12: Working with Attachments and File Folder Objects
v9.3.1.2 187
Note The File object type performs best when adding attachments.
When you add a file or a URL to the row of the Attachments table of a business object, you
automatically create a new file folder that contains the associated file or URL. You can load the
referenced file folder using the IRow.getReferent() method, as shown in the following example.
Example: Creating a file folder by adding a row to the Attachments table
public IFileFolder addRowToItemAttachments
(IItem item, File file) throws Exception
{ITable attTable = item.getTable(ItemConstants.TABLE_ATTACHMENTS);
IRow row = attTable.createRow(file);
IFileFolder ff = (IFileFolder)row.getReferent();
return ff;
}
This example uses several instances of the addAttachment() methods to illustrate the different
ways you can add rows to an Attachments table.
Example: Adding files to the Attachments table
// Add a single file to the Attachments table row by specifying a file
path
public static IRow addAttachment(ITable attTable, String path) throws
APIException {
IRow row = attTable.createRow(path);
return row;
}
// Add a single file to the Attachments table
public static IRow addAttachment(ITable attTable, File file) throws
APIException {
IRow row = attTable.createRow(file);
return row;
}
// Add multiple files to the Attachments table
public static IRow addAttachment(ITable attTable, File[] files) throws
APIException {
IRow row = attTable.createRow(files);
return row;
}
// Add a URL attachment to the Attachments table
public static IRow addAttachment(ITable attTable, URL url) throws
APIException {
IRow row = attTable.createRow(url);
return row;
}
// Add a file folder to the Attachments table
public static IRow addAttachment(ITable attTable, IFileFolder ff)
throws APIException {
IRow row = attTable.createRow(ff);
return row;
SDK Developer Guide - Using Agile APIs
188 Agile Product Lifecycle Management
}
// Add an FileFolder.Files row object or a [BusinessObject].Attachments
row object
// to the Attachments table. The Agile API validates the row object at
run time to
// determine if it is from a valid table (Files or Attachments).
public static IRow addAttachment(ITable attTable, IRow filesRow) throws
APIException {
IRow row = attTable.createRow(filesRow);
return row;
}
// Add a file folder to the Attachments table and specify the version
for all files
public static IRow addAttachmentWithVersion(ITable attTable,
IFileFolder ff) throws APIException {
ff.setCurrentVersion(new Integer(1));
IRow row = attTable.createRow(ff);
return row;
}
Deep Cloning Attachments and Files from One Object to Another
To simplify copying file attachments from one object to another, use the
CommonConstants.MAKE_DEEP_COPY virtual attribute as a Boolean parameter of
ITable.createRow(Object). This parameter allows your program to create a new copy of the
file in the Agile File Manager vault instead of referencing the old file.
Example: Deep cloning an Attachments table row
// Clone an attachment table row and its file from one item to another
public static cloneAttachment(IItem item1, IItem item2, File file)
throws APIException {
// Get the attachments tables of item1 and item2
ITable tblAttach1 = item1.getAttachments();
ITable tblAttach2 = item2.getAttachments();
// Prepare params for the first row
HashMap params = new HashMap();
params.put(CommonConstants.ATT_ATTACHMENTS_CONTENT, file);
// Add the file to the attachments table of item1
IRow row1 = tblAttach1.createRow(params);
// Prepare params for the second row
params.clear();
params.put(CommonConstants.ATT_ATTACHMENTS_CONTENT, row1);
params.put(CommonConstants.MAKE_DEEP_COPY, Boolean.TRUE);
// Add the same file to the attachments table of item2
IRow row2 = tblAttach2.createRow(params);
}
Example: Deep cloning the Files table row of a File Folder
// Clone a Files table row and its file from one File Folder to another
public static cloneFilesRow(IFileFolder folder1, IFileFolder folder2,
File file) throws APIException {
// Check out folder1 and folder2
Chapter 12: Working with Attachments and File Folder Objects
v9.3.1.2 189
folder1.checkOutEx();
folder2.checkOutEx();
// Get the Files tables of folder1 and folder2
ITable tblFiles1 =
folder1.getTable(FileFolderConstants.TABLE_FILES);
ITable tblFiles2 =
folder2.getTable(FileFolderConstants.TABLE_FILES);
// Prepare params for the first row
HashMap params = new HashMap();
params.put(CommonConstants.ATT_ATTACHMENTS_CONTENT, file);
// Add the file to the attachments table of folder1
IRow row1 = tblFiles1.createRow(params);
// Prepare params for the second row
params.clear();
params.put(CommonConstants.ATT_ATTACHMENTS_CONTENT, row1);
params.put(CommonConstants.MAKE_DEEP_COPY, Boolean.TRUE);
// Add the same file to the Files table of folder2
IRow row2 = tblFiles2.createRow(params);
// Check in folder1 and folder2
folder1.checkIn();
folder2.checkIn();
}
Specifying the File Folder Subclass When Adding Attachments
You can set up your Agile PLM system with multiple file folder subclasses. If so, when you add a file
folder to the Attachments table of a business object, you may want to specify which file folder
subclass to use. If you don't specify a subclass, the Agile API uses the default File Folder subclass.
The virtual attribute CommonConstants.ATT_ATTACHMENTS_FOLDERCLASS makes it easier to
specify the required file folder subclass. It enables you to set the attribute to any file folder subclass.
The following example shows how to use the ATT_ATTACHMENTS_FOLDERCLASS attribute to
specify a subclass when you add a file folder to the Attachments table.
Example: Specifying the file folder subclass when adding attachments
IAgileClass ffclass = m_admin.getAgileClass("MyFileFolder");
// init item
IItem item = (IItem)session.createObject(ItemConstants.CLASS_PART,
"P0001");
// get attachments table
ITable tab_attachment = item.getAttachments();
// prepare map
HashMap map = new HashMap();
map.put(CommonConstants.ATT_ATTACHMENTS_CONTENT, new
File("files/file.txt"));
map.put(CommonConstants.ATT_ATTACHMENTS_FOLDERCLASS, ffclass);
// add file
IRow row = tab_attachment.createRow(map);
SDK Developer Guide - Using Agile APIs
190 Agile Product Lifecycle Management
Retrieving Attachment Files
If a file folder is checked out by another user, you can still retrieve a copy of the file folder file(s) and
save it to your local machine. The IAttachmentFile.getFile() method returns the file stream
associated with a row of the Attachments table. The file stream can be for one file or it can be a
zipped file stream for multiple files, depending on how many files the associated file folder has. You
can also use IAttachmentFile.getFile() to get one or more files directly from a file folder
instead of accessing the Attachments table of another business object. If you call getFile() from
the file folder object, you return the zipped file stream for all files listed on the Files table. If you call
getFile() from a row of the Files table of a file folder, you return a file stream for the specific file
associated with that row.
Note When you use IAttachmentFile.getFile(), only file attachments are included in
the returned file stream. URL attachments don’t have files associated with them.
This example shows how to retrieve a copy of an attached file.
Example: Getting attachment files
// Get one or more files associated with the row of an Attachments
table or a Files table
public InputStream getAttachmentFile(IRow row) throws APIException {
InputStream content = ((IAttachmentFile)row).getFile();
return content;
}
// Get all files associated with a file folder
public InputStream getAttachmentFiles(IFileFolder ff) throws
APIException {
InputStream content = ((IAttachmentFile)ff).getFile();
return content;
}
If you use IFileFolder.getFile() to return a zipped file stream for all files contained in a file
folder, you can extract files from the zipped InputStream using methods of the
java.util.zip.ZipInputStream class, as shown in the following example.
Example: Extracting files from a zipped file stream
static void unpack(InputStream zippedStream) throws IOException {
ZipInputStream izs = new ZipInputStream(zippedStream);
ZipEntry e = null;
while ((e = izs.getNextEntry()) != null) {
if (!e.isDirectory()) {
FileOutputStream ofs = new FileOutputStream(e.getName());
byte[] buf = new byte[1024];
int amt;
while ((amt = izs.read(buf)) != -1) {
ofs.write(buf, 0, amt);
}
ofs.close();
}
}
Chapter 12: Working with Attachments and File Folder Objects
v9.3.1.2 191
zippedStream.close();
}
The Agile API provides no direct method for opening an attachment file. However, you can retrieve
a file and then have your program open it in a separate application or display it in a browser
window.
Deleting Attachments and File Folders
To delete a file folder, which may contain multiple files, use the IDataObject.delete() method.
You must have the Delete privilege for file folders to be able to delete them. For more information
about deleting objects, see
Deleting and Undeleting Objects on page 32.
Note Deleting a file folder does not automatically remove its associated files from the file
server. The Agile PLM administrator is responsible for purging deleted files.
To delete a row from the Attachments table of a business object, use the ITable.removeRow()
method. For more information, see
Removing Table Rows on page 78. Removing a row from the
Attachments table does not delete the associated file folder. You cannot delete a row from the
Attachments table in the following situations:
à The parent object is an Item whose revision is incorporated.
à The selected attachment is currently checked out.
Working with Thumbnails
Agile PLM supports adding small static graphical images (thumbnails) to key objects which either
represent graphical objects or require images. For example, documents attached as files such as
Excel worksheets, text files, PDF files, CAD files and so on, can have associated thumbnail
images.. Thumbnails display scaled down versions of these files and, in the case of Part objects,
show how they relate to each other.
The SDK supports the following Thumbnail-related functions:
à Regenerating Thumbnails
à Sequencing Thumbnails
à Setting Master Thumbnails
à Generating Thumbnails while adding Files to Attachments tab
Accessing Thumbnails
Agile SDK provides the IThumbnailContainer interface for generalized access to thumbnail-
related operations for file folder and business objects. This interface is supported by the following
API objects:
à IFileFolder object
à IItem object
à IManufacturerPart object
SDK Developer Guide - Using Agile APIs
192 Agile Product Lifecycle Management
For IFileFolder objects, set the applicable version using IFileFolder.setCurrentVersion
before calling the above APIs. The default version is LATEST_VERSION. For IItem or
IManufacturerPart objects, use the revision that is already set on these objects.
The following example gets thumbnail details from TitleBlock of an IItem or IFileFolder
object .
Example: Getting thumbnail details from TitleBlock of IItem or IFileFolder objects
IItem dataObj =
(IItem)session.getObject(IItem.OBJECT_TYPE, "P00015");
ITable titleBlockTable =
dataObj.getTable(TableTypeConstants.TYPE_PAGE_ONE);
Iterator i =
titleBlockTable.getTableIterator();
while (i.hasNext()) {
IRow row = (IRow)i.next();
Object thumbnailIDDetails =
row.getValue(ThumbnailConstants.ATT_THUMBNAIL_ATTACHMENT_TAB)
;
IAgileList[] nodes =
((IAgileList)thumbnailIDDetails).getSelection();
for(int ii=0; ii<nodes.length; ii++) {
IAgileList childNode = nodes[ii];
IThumbnailID thumbnailID = (IThumbnailID)childNode.getValue();
}
}
Regenerating Thumbnails
Regenerating a thumbnail means generating a thumbnail for an existing (generated) thumbnail for
file folder and item objects. This feature is of particular interest in assembly structures where a
change in the child of the assembly structure is reflected in the thumbnail after the thumbnail is
regenerated.
Agile SDK provides the IThumbnailContainer.generateThumbnail(IThumbnailID) API
for this purpose. When invoked, it will generate and return a new thumbnail. In case of
IFileFolder objects, API will use the current version of the object. For IItem or
IManufacturerPart objects, it will use the current revision of the object. An APIException is
thrown when the API fails to regenerate the thumbnail for the specified thumbnailID parameter.
Example: Regenerating a thumbnail for an IFileFolder object
IFileFolder ff =
(IFileFolder)session.getObject(IFileFolder.OBJECT_TYPE,
"FOLDER00037");
ff.setCurrentVersion(new Integer(1));
IThumbnailID oldThumbnailID = "";
//get this id from row of supported tables like Title Block
ff.generateThumbnail(oldThumbnailID);
Chapter 12: Working with Attachments and File Folder Objects
v9.3.1.2 193
Example: Regenerating a thumbnail for an IItem object
IItem itemObj =
(IItem)session.getObject(IItem.OBJECT_TYPE, "P00015");
IThumbnailID oldThumbnailID = "";
//get this id from row of supported tables like Title Block
itemObj.generateThumbnail(oldThumbnailID);
Setting Master Thumbnails
In Agile PLM, a file folder object is represented by a thumbnail file which can contain several files in
its Files tab. Using SetMasterThumbnail, a user can decide which row in the Files tab will
represent the selected thumbnail's file folder.
SDK provides the setMasterThumbnail API to set master thumbnails on file folder objects. An
exception is thrown if the function fails to set the master thumbnail represented by the parameter
masterRow.
Example: Setting a master thumbnail
IFileFolder ff =
(IFileFolder)session.getObject(IFileFolder.OBJECT_TYPE,
"FOLDER00037");
ff.setCurrentVersion(new Integer(1));
ITable attachmentTable =
ff.getTable(FileFolderConstants.TABLE_FILES);
Iterator i =
attachmentTable.getTableIterator();
while (i.hasNext()) {
IRow row = (IRow)i.next();
IRow masterRow = null;
//set one of the rows as the master row
}
ff.setMasterThumbnail(masterRow);
Replacing Thumbnails
You can replace an Agile PLM generated thumbnail with a user provided image for file folder and
item objects. The SDK provides the following API for this purpose.
IThumbnailID replaceThumbnail (IThumbnailID oldThumbnailID, byte[] bytes)
throws APIException
This API will replace the thumbnail referred to in oldThumbnailID with the image file referred to in
the input stream. That is, it will return the thumbnailID of the replaced thumbnail.
For IFileFolder objects, the API will use the version that is already set on the object. For IItem
or IManufacturerPart objects, it will use the revision that is already set on the object. An
APIException is thrown if it fails to replace the thumbnail specified in the oldThumbnailID
parameter.
Example: Replacing a thumbnail for an IFileFolder object
IFileFolder ff =
(IFileFolder)session.getObject(IFileFolder.OBJECT_TYPE,
"FOLDER00037");
SDK Developer Guide - Using Agile APIs
194 Agile Product Lifecycle Management
ff.setCurrentVersion(new Integer(1));
IThumbnailID oldThumbnailID = "";
//get this id from row of supported tables like Title Block
String filePath = "C:\\Earth.bmp";
File file1_tmp = new File(filePath);
byte[] b1 = new byte[(int)file1_tmp.length()];
FileInputStream fileInputStream = new FileInputStream(file1_tmp);
fileInputStream.read(b1);
IThumbnailID newThumbnailID = ff.replaceThumbnail(oldThumbnailID, b1);
Example: Replacing a thumbnail for an IItem object
IItem itemObj =
(IItem)session.getObject(IItem.OBJECT_TYPE, "P00015");
IThumbnailID oldThumbnailID = "";
//get this id from row of supported tables like Title Block
String filePath = "C:\\Earth.bmp";
File file1_tmp = new File(filePath);
byte[] b1 = new byte[(int)file1_tmp.length()];
FileInputStream fileInputStream = new FileInputStream(file1_tmp);
fileInputStream.read(b1);
IThumbnailID newThumbnailID = itemObj.replaceThumbnail(oldThumbnailID,
b1);
Sequencing Thumbnails
When Web Client users add attachment files to business objects, they can also set the order
(sequence) of their appearance in the Thumbnail Navigator. Agile PLM provides the
setThumbnailSequence API to enable this feature in the SDK. For IItem or
IManufacturerPart objects, the API will use the revision that is already set on the object. The
API will sort (sequence) the order of appearance using the thumbnailIDs parameter. An
exception is thrown if the function fails to set the master thumbnail.
Example: Sequencing thumbnails
IItem itemObj =
(IItem)session.getObject(IItem.OBJECT_TYPE, "P00015");
IThumbnailID[] thumbnailIDs = null;
//get this id from row of Title Block table
IThumbnailID[] newSeqOfThumbnailIDs = null;
//generate new order using thumbnail IDs
itemObj.setThumbnailSequence(newSeqOfThumbnailIDs);
Generating Thumbnails while Adding Files to Attachments Tab
There are no APIs specifically for this purpose. When you add a file to the Attachments tab of an
Item, a thumbnail is generated for that file provided thumbnail support is enabled in the Web Client.
Chapter 12: Working with Attachments and File Folder Objects
v9.3.1.2 195
Working with Design Objects
A Design object is a business object that specifies one or more URLs or files stored in Agile PLM's
File Management Server. It contains information about the binary files attached to it. Similar to other
Agile PLM business objects, Design objects appear in Agile PLM's class hierarchy as a separate
base class.
Design class objects are used with Agile PLM's Engineering Collaboration (EC ) module which is
used to manage CAD data in Agile PLM. Objects created in this class have many of the same
properties and behaviors of File folders. In Java Client, users with administrator privileges can
enable other users to open and work with Design objects. Agile PLM users can then access and
work exclusively with these objects in Web Client.
Agile SDK supports the following Design object-related functions:
à Managing (adding, removing, getting, and editing) version specific Relationships between two
Design objects
à Using where-used queries for Design object deployments in Agile PLM Class structures. For
information about where-used queries, see
Creating a Where-Used Query on page 61.
Adding and Loading Design Objects
To create or get an IDesign object, you can use IAgileSession.createObject() or
IAgileSession.getObject(). The following examples show the different methods provided by
the SDK to create and get Design objects.
Example: Creating a Design by class name
IDesign des = (IDesign)
m_session.createObject("Design", "DESIGN00133");
Example: Creating a Design by class ID
IDesign des = (IDesign)
m_session.createObject(FileFolderConstants.CLASS_DESIGN,
"DESIGN00133");
Example: Creating a Design by IAgileClass reference:
IDesign des = (IDesign)
m_session.createObject(desClass, "DESIGN00133");
Example: Loading a Design object
IDesign des = (IDesign)
m_session.getObject(IDesign.OBJECT_TYPE, "DESIGN00133");
Managing Version Specific Relationships between Design Objects
Agile SDK supports the following version specific Relationships functions between Design objects:
Note These version specific functions only apply to Design objects.
à Adding version specific relationships between Design objects
à Removing version specific relationships between Design objects
à Getting version specific relationships for specific versions of Design objects
SDK Developer Guide - Using Agile APIs
196 Agile Product Lifecycle Management
à Editing version specific relationships for Design objects
Adding Relationships for Specific Versions of Design Objects
The SDK provides the following API to add relationships between two specific versions of Design
objects:
IDesign.addVersionSpecificRelationship(Object versionNum, IDesign
relatedDesign, Object relatedVersionNum)
The parameters are:
à versionNum – This an integer showing the version number of this Design object.
à relatedDesign – The Design object you are creating the Relationships for.
à relatedVersionNum – This an integer showing the version number of the Design object you
are creating the Relationship for.
An APIException is thrown if the version specific relationship between the two Design objects was
not created.
Alternatively, you can load the object's RelationshipsTable and call createRow(Object
params) with the following params:
HashMap params = new HashMap();
params.put(DesignConstants.ATT_RELATIONSHIPS_REV_VERSION, versionNum);
params.put(DesignConstants.ATT_RELATIONSHIPS_NAME, relatedDesign);
params.put(DesignConstants.ATT_DESIGN_VERSION, relatedVersionNum);
Removing Relationships for Specific Versions of Design Objects
To remove Version Specific Relationships for IDesign:
IDesign des1 = (IDesign)session.getObject(IFileFolder.OBJECT_TYPE,
"DESIGN00001");
des1.setCurrentVersion(new Integer(4));
ITable relationshipTable = des1.getRelationship();
relationshipTable.removeRow(row);
Getting Relationships for Specific Versions of Design Objects
To get the Relationships for a specific version of IDesign:
IDesign des1 = (IDesign)session.getObject(IFileFolder.OBJECT_TYPE,
"DESIGN00001");
des1.setCurrentVersion(new Integer(4)); //set desired version
ITable relationshipTable = des1.getRelationship();
Chapter 12: Working with Attachments and File Folder Objects
v9.3.1.2 197
Editing Relationships for Specific Versions of Design Objects
To edit the Relationships for a specific version of the IDesign object.
IDesign des1 = (IDesign)session.getObject(IFileFolder.OBJECT_TYPE,
"DESIGN00001");
des1.setCurrentVersion(new Integer(4));
ITable relationshipTable = des1.getRelationship();
HashMap mapForUpdate=new HashMap();
HashMap rowUpdateMap = new HashMap();
rowUpdateMap.put(DesignConstants.ATT_DESIGN_VERSION, new Integer(1));
mapForUpdate.put(row1, rowUpdateMap);
relationshipTable.updateRows(mapForUpdate);
Purging Specific Versions of Design Objects
The SDK provides the IDesign.purgeVersions(Object[] versions) API for purging
specific versions of Design objects and relevant versions of its child objects. The versions
parameter, an integer value, specifies the version number you want purged. An exception is thrown
if the API fails to purge the object.
Searching Design Object Deployments with Where-Used Queries
The Structure tab for Design objects enables users to create structures of different Design objects
having different versions. The SDK supports searching for Design object usage in Agile PLM Class
Structures for the latest checked in versions and all checked in versions with the following queries
and query constants:
à WHERE_USED_IN_STRUCTURE_ONE_LEVEL_LATEST_CHECKEDIN – This WHERE_USED query
returns the LATEST version of the immediate parent of the Design object which uses the input
Design object as a child in the design structure. The constant
QueryConstants.WHERE_USED_IN_STRUCTURE_ONE_LEVEL_LATEST_CHECKEDIN
supports this search.
à WHERE_USED_IN_STRUCTURE_ALL_LEVEL_LATEST_CHECKEDIN – This WHERE_USED query
returns ALL versions of the immediate parent of the Design object which uses the input Design
object as a child in the design structure. The constant
QueryConstants.WHERE_USED_IN_STRUCTURE_ONE_LEVEL_ALL_CHECKEDIN supports
this search.
You can find code samples using QueryConstants in SDK_samples.zip folder. To access this file,
see the Note in
Client-Side Components on page 2. These are the Javadoc generated HTML files in
the documentation folder.
SDK Developer Guide - Using Agile APIs
198 Agile Product Lifecycle Management
The two searches and their respective results are explained with the aid of the following illustration.
It shows the Design objects and level one structures. The search parameter Title
Block.Number includes the number 11.
Figure 16: Design objects and search results
v9.3.1.2 199
Chapter 13
Importing and Exporting Data with SDK
This chapter includes the following:
About Importing and Exporting Data.................................................................................................................... 199
Validating Import Data and Importing Data.......................................................................................................... 199
Exporting Data from the SDK .............................................................................................................................. 202
About Importing and Exporting Data
You can use the SDK to import and export data from external databases into the PLM system. The
source can be an Agile database, a third party Product Data Management (PDM) system, or an
Enterprise Resource Planning (ERP) system. The following paragraphs provide background
information, procedures, and examples to perform these tasks using the agile SDK.
Validating Import Data and Importing Data
When you import data, you have the option to validate the data, or ignore this step. The purpose of
import validation is to check the data for compliance with applicable server rules such as length
tolerances, allowable values, and other constraints. The validation process informs you of the data
that will fail to import before initiating the process.
The SDK exposes two methods to programmatically perform the following import-related tasks:
à The IImportManager.validateData(byte[], String, byte[], byte[],
String[], List) method to validate the imported data for compliance with server business
rules. This action is performed before importing the data to identify the invalid items in the input
source data.
à The IImportManager.importData(byte[], String, byte[], byte[], String[],
List) method supports importing data into the PLM databases. This action is performed after
running the IImportManager.validateData() method to select the data that meets the
server business rules and is importable into the PLM system.
For more information about importing data, refer to Agile Integration Services Developer Guide and
Agile Import and Export Guide.
The following example uses these methods to validate the imported data for compliance and import
it into the PLM system upon validation.
Validating Data and Importing Data with SDK
Example: Validating and Importing Data into PLM
import com.agile.api.*;
import java.util.*;
import java.io.ByteArrayInputStream;
SDK Developer Guide - Using Agile APIs
200 Agile Product Lifecycle Management
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
public class ImportClient {
public static IAgileSession session = null;
public static AgileSessionFactory factory;
public static void main(String[] args) {
try {
String _url="
http://localhost/Agile";
String _user="admin";
String _pwd="agile";
String srcFilePath="bom.txt";
/* Supported file types: aXML,IPC2571, ExcelFile, DelimitedTextFile
* The value of "-f" parameter is the same
* in Import AIS sample command
*/
String srcFileType="DelimitedTextFile";
// Null implies loading the default mapping
String mappingPath="NewMapFile.xml";
// Null implies do not transform
String transformPath=null;
/* The value used by operations is the
same as the value of the "-t" parameter in the import AIS sample
command.
all supported
operations:"items.bom","items.aml","items.attachments",
"items.relationships", "manufacturers",
"manufacturers.relationships",
"manufacturers.attachments", "manufacturerParts",
"manufacturerParts.relationships",
"manufacturerParts.attachments" "partgroups",
"partgroups.relationships",
"partgroups.attachments", "productServiceRequests"
"productServiceRequests.affectedItems",
"productServiceRequests.relatedPSR"
"productServiceRequests.relationships"
"productServiceRequests.attachments" "qualityChangeRequests"
"qualityChangeRequests.affectedItems"
"qualityChangeRequests.relationships"
"qualityChangeRequests.attachments"
*/
String [] operations=new String[]{"items", "items.bom","items.aml"};
/* The value used by options is the
* same as the "-n" parameter in the import AIS sample command
*/
List options=new ArrayList();
options.add("BusinessRuleOptions|ChangeMode=Authoring");
Chapter 13: Importing and Exporting Data with SDK
v9.3.1.2 201
options.add("BusinessRuleOptions|BehaviorUponNonExistingObjects=Acce
pt");
String _output="log.xml";
FileOutputStream fop=new FileOutputStream(_output);
// Create an instance of IAgileSession
session = connect(_url,_user,_pwd);
IImportManager imgr = (IImportManager)
session.getManager(IImportManager.class);
byte[] logData=null;
/* Sample code to import data
* Remove comments to run the importData example.
* byte[]logData=imgr.importData(stream2byte
* (new FileInputStream(srcFilePath)),
* srcFileType, convertFiletoStream(mappingPath),
* convertFiletoStream(transformPath),
* operations, options);
* Sample code to validate data
* Remove comments to run the validateData example
* logData=imgr.validateData(stream2byte
* (new FileInputStream(srcFilePath)),
* srcFileType, convertFiletoStream(mappingPath),
* convertFiletoStream(transformPath), * operations, options);
* byte buf[]=new byte[1024*4];
int n=0;
InputStream logStream=byte2stream(logData);
while((n=logStream.read(buf))!=-1){
fop.write(buf, 0, n);
}
fop.close();
}
catch (Exception e) {e.printStackTrace();
}
finally {session.close();
}
}
/*
* <p> Create an IAgileSession instance </p>
*
* @return IAgileSession
* @throws APIException
*/
private static IAgileSession connect(String _url,String _user,String
_pwd) throws APIException {
factory = AgileSessionFactory.getInstance(_url);
HashMap params = new HashMap();
params.put(AgileSessionFactory.USERNAME, _user);
params.put(AgileSessionFactory.PASSWORD, _pwd);
session = factory.createSession(params);
return session;
}
private static byte[] stream2byte(InputStream stream) throws
IOException {
ByteArrayOutputStream outStream=new ByteArrayOutputStream();
SDK Developer Guide - Using Agile APIs
202 Agile Product Lifecycle Management
byte buf[]=new byte[1024*4];
int n=0;
while((n=stream.read(buf))!=-1){
outStream.write(buf, 0, n);
}
byte[] data=outStream.toByteArray();
outStream.close();
return data;
}
private static InputStream byte2stream(byte[] data) throws
IOException{
ByteArrayInputStream stream=new ByteArrayInputStream(data);
return stream;
}
private static byte[] convertFiletoStream(String path) throws
IOException{
if(path==null || path.equals(""))
return null;
return stream2byte(new FileInputStream(path));
}
}
Exporting Data from the SDK
The SDK exposes the exportData()method to programmatically export data from PLM
databases. This method is designed to overcome performance and memory issues that are
encountered when loading large BOMs into the SDK programs. To overcome this issue, you can
invoke the export functionality to load the BOM. The SDK programs can then read and export the
data from the extracted XML files.
For more information about exporting data, refer to the Agile Integration Services Developer Guide
and Agile Import and Export Guide.
Invoking SDK's Export Function
Use the following call to invoke the export function of the SDK.
public byte[] exportData (Object[], Integer, String[])
In this call,
à exportData – Is the method that returns the exported data in an array of bytes. The byte
array represents a ZIP file that contains the export XML file in aXML or PDX formats and any
file attachments that are included in the exported package.
à Object[]– Is the array of objects that are exported from PLM to the external system. These
objects are passed as IDataObject objects.
à Integer – Is the indicator (constants that are provided in ExportConstants.java) to
identify whether the output export format should be aXML or PDX. These are the two formats
that the SDK supports.
à String[] – Is the array of ACS filter names that are used for the export. The filter names are
Chapter 13: Importing and Exporting Data with SDK
v9.3.1.2 203
not case sensitive and must match the names of filters defined by the Admin tool for ACS.
The conditions that wil cause the exportData method to throw an exception and the respective
exceptions are:
à Invalid Data Format – The method was called with an unrecognized value for the export data
format. Only aXML (provide constant label) and PDX (provide constant label) values are valid.
à No Filter Specified – The method was called but no filters were specified. At least one valid filter
must be provided.
à Specified Filter Not Found – The method was called with specified filter which was not found in the
system
Example: Exporting data from PLM using the SDK
... //
IItem item = (IItem) session.getObject(IItem.OBJECT_TYPE, "P0001");
if (item == null) {
... // throw an error, the part wasn't found
}
IDataObject[] expObjs = {item};
String[] filters = {"Default Item Filter"};
...
IExportManager eMgr = (IExportManager)
session.getManager(IExportManager.class);
try {
byte[] exportData = eMgr.exportData(expObjs,
ExportConstants.EXPORT_FORMAT_PDX, filters);
if (exportData != null) {
String fileName = createOutputFileName();
FileOutputStream outputFile = new FileOutputStream(fileName);
outputFile.write(exportData);
outputFile.close();
System.out.println("Data exported to file: " + fileName);
}
} catch (Throwable t) {
... // error handling
}
...
v9.3.1.2 205
Chapter 14
Managing Workflow
This chapter includes the following:
About Workflow....................................................................................................................................................205
Selecting a Workflow........................................................................................................................................... 207
Adding and Removing Approvers........................................................................................................................ 208
Approving or Rejecting Change........................................................................................................................... 217
Approving or Rejecting a Change Without Password.......................................................................................... 218
Commenting a Change........................................................................................................................................ 219
Auditing a Change............................................................................................................................................... 219
Changing the Workflow Status of an Object........................................................................................................ 220
Sending an Agile Object to Selected Users......................................................................................................... 223
Sending an Agile Object to User Groups............................................................................................................. 223
About Workflow
Agile has electronic routing, Notification, and signoff capabilities, thus automating the change
control process and providing a simplified but powerful Workflow mechanism. With these Workflow
features, you can
à Route changes automatically to the users who need to approve or observe the change.
à Send email alerts automatically to approvers and observers to notify them that a change has
been routed to them.
à Approve or reject changes online.
à Attach comments to changes.
The Change Control Process
The change control process can vary for each Workflow defined for a routable object. The table
below lists the sequences for the default Workflows for each type of routable object. For changes
the first four steps in the sequence are identical and only the final step is different.
Workflow Default sequence
Default Activities Not Started > In Process > Complete
Default Attachments Review
Default Audits Prepared > Initiated > Audited > Issued > Corrected > Validated > Closed
Default CAPAs Identified > Acknowledged > Investigated > Implemented > Validated > Closed
Default Change Orders Pending > Submitted > CCB > Released > Implemented
Default Change Requests Pending > Submitted > CCB > Released > Closed
SDK Developer Guide - Using Agile APIs
206 Agile Product Lifecycle Management
Workflow Default sequence
Default CTOs Pending> Review > Released > Complete
Default Declarations Pending > Open to Supplier > Submit to Manager > Review > Released > Implemented
Default Deviations Pending > Submitted > CCB > Released > Expired
Default Gates Closed > In Review > Open
Default Manufacturer Orders Pending > Submitted > CCB > Released > First Article Complete
Default Non-Conformance Reports Pending > Submitted > Review > Released > Closed
Default Packages Pending > Submitted > Review > Accepted > Closed
Default Price Change Orders Pending > Submitted > Price Review > Released > Implemented
Default Problem Reports Pending > Submitted > Review > Released > Closed
Default Sites Change Orders Pending > Submitted > CCB > Released > Implemented
Default Stop Ships Pending > Submitted > CCB > Released > Resumed
Dynamics of Workflow Functionality
The Workflow functionality available to each user for a particular routable object depends on the
status of the routable object and the user’s privileges. Your Agile API program should take these
Workflow dynamics into account and, where possible, adjust your program accordingly.
How the Status of a Change Affects Workflow Functionality
The Workflow actions available for a pending change are different from those for a released
change. To check the status of a change to determine whether it’s pending or released, use the
IRoutable.getStatus() method. The getStatus() method returns an IStatus object for
the Workflow status. IStatus extends the INode interface and provides helpful methods for
working with status nodes. The following example shows how to use getStatus() to determine
whether a change is released.
Example: Getting the status of a change object
private static boolean isReleased(IChange change) throws APIException {
return
(change.getStatus().getStatusType().equals(StatusConstants.TYPE_RELE
ASED);
}
How User Privileges Affect Workflow Functionality
Agile privileges determine the types of Workflow actions a user can perform on a change. The Agile
system administrator assigns roles and privileges to each user. The table below lists privileges
needed to perform Workflow actions.
Privilege Related API
Change Status
IRoutable.changeStatus()
Chapter 14: Managing Workflow
v9.3.1.2 207
Privilege Related API
Comment
IRoutable.comment()
Send
DataObject.send()
To determine at run time whether a user has the appropriate privileges to perform an action, use the
IUser.hasPrivilege() method. You can adjust your program’s UI based on the user’s
privileges. The following example shows how to check whether a user has the privilege to change
the status of a change before calling the IRoutable.changeStatus() method.
Example: Checking the privileges of a user before changing the status of a change
private void goToNextStatus(IChange change, IUser user) throws
APIException {
// Check if the user can change status
if(user.hasPrivilege(UserConstants.PRIV_CHANGESTATUS, change)) {
IUser[] approvers = new IUser[] { user };
IStatus nextStatus = change.getDefaultNextStatus();
change.changeStatus(nextStatus, true, "", true, true, null,
approvers, null, false);
} else {
System.out.println("Insufficient privileges to change status.");
}
}
Selecting a Workflow
When you create a new change, package, product service request, or quality change order, you
must select a Workflow. Otherwise, the object is in an unassigned state and cannot progress
through a Workflow process. Your Agile system can have multiple Workflows defined for each type
of routable object. To retrieve the valid Workflows for an object, use the
IRoutable.getWorkflows() method. If a routable object has not been assigned a Workflow
yet, you can use the IRoutable.getWorkflows() method to select a Workflow.
As long as a change is in the Pending status, you can select a different Workflow. Once a change
moves beyond the Pending status, you can’t change the Workflow.
Example: Selecting a Workflow
private IChange createECO(IAgileSession session) throws APIException {
// Get an Admin instance
IAdmin admin = session.getAdminInstance();
// Create a change
IAgileClass ecoClass =
admin.getAgileClass(ChangeConstants.CLASS_ECO);
IAutoNumber[] autoNumbersPart = ecoClass.getAutoNumberSources();
IChange change = (IChange)m_session.createObject(ecoClass,
autoNumbersPart[0]);
// Get the current Workflow (a null object,
// since the Workflow has not been set yet)
IWorkflow wf = change.getWorkflow();
SDK Developer Guide - Using Agile APIs
208 Agile Product Lifecycle Management
// Get all available Workflows
IWorkflow[] wfs = change.getWorkflows();
// Set the change to use the first Workflow
change.setWorkflow(wfs[0]);
// Set the change to use the second Workflow
change.setWorkflow(wfs[1]);
return change;
}
If a change is still in the Pending status type, you can deselect a Workflow to make the change
“unassigned.” To make a change unassigned, use the IRoutable.setWorkflow() method and
specify null for the Workflow parameter.
Example: Making a change unassigned
private void unassign(IChange change) throws APIException {
change.setWorkflow(null);
}
Adding and Removing Approvers
After a change is routed and the online approval process is initiated, it is sometimes necessary to
add or remove people from the list of approvers or observers. To add or remove approvers or
observers, a user must have the Route privilege.
You don’t need to load the Workflow table to modify the list of approvers. Once you have a routable
object, such as an ECO, you can modify its list of approvers using the
IRoutable.addApprovers() and IRoutable.removeApprovers() methods. When you
use addApprovers() or removeApprovers(), you specify the lists of approvers and observers,
whether the Notification is urgent, and an optional comment. The Agile API provides overloaded
addApprovers() and removeApprovers() methods for adding or removing a user or a user
group from the list of approvers. For more information, refer to the API Reference files at Oracle®
E-Cloud Web site (
http://edelivery.oracle.com/).
If any users you select as approvers or observers do not have appropriate privileges to view a
change, your program throws an APIException. To avoid the possible exception, check the
privileges of each user before adding him to the approvers or observers list.
The following example shows how to add and remove approvers for a change.
Example: Adding and removing approvers and observers
public void modifyApprovers(IChange change) {
try {
// Get current approvers for the change
IDataObject[] currApprovers =
change.getApproversEx(change.getStatus());
// Get current observers for the change
Chapter 14: Managing Workflow
v9.3.1.2 209
IDataObject[] currObservers =
change.getObserversEx(change.getStatus());
// Add hhawkes to approvers
IUser user = (IUser)m_session.getObject(IUser.OBJECT_TYPE,
"hhawkes");
IUser[] approvers = new IUser[]{user};
// Add flang to observers
user = (IUser)m_session.getObject(IUser.OBJECT_TYPE, "flang");
IUser[] observers = new IUser[]{user};
// Add approvers and observers
change.addApprovers(change.getStatus(), approvers, observers, true,
"Adding hhawkes to approvers and flang to observers");
// Add skubrick to approvers
user = (IUser)m_session.getObject(IUser.OBJECT_TYPE, "skubrick");
approvers[0] = user;
// Add kwong to observers
user = (IUser)m_session.getObject(IUser.OBJECT_TYPE, "kwong");
observers[0] = user;
// Remove skubrick from approvers and kwong from observers
change.removeApprovers(change.getStatus(), approvers, observers,
"Removing skubrick from approvers and kwong from observers");
} catch (APIException ex) { System.out.println(ex);
}
}
If you want to modify only the list of approvers or the list of observers for a change, you can pass a
null value for the parameter you don’t want to change. The following example shows how to add
the current user to the approvers list without changing the list of observers.
Example: Adding approvers without changing observers
public void addMeToApprovers(IChange change) {
try {
// Get the current user
IUser user = m_session.getCurrentUser();
// Add the current user to the approvers list for the change
IUser[] approvers = new IUser[]{user};
change.addApprovers(change.getStatus(), approvers, null, true,
"Adding current user to approvers list");
} catch (APIException ex) {
System.out.println(ex);
}
}
Setting the “Signoff User Dual Identification” Preference
The “Signoff User Dual Identification” feature is a systemwide preference that controls whether
approval/rejection signoff requires a dual identification, or a “second signoff.” This feature is
required by FDA-regulated companies and can benefit companies with a corporate policy requiring
double authentication of user identity when approving or rejecting change orders. For more
information, refer to the latest release of the Agile PLM Administrator Guide.
SDK Developer Guide - Using Agile APIs
210 Agile Product Lifecycle Management
The following paragraphs list and describe the APIs that support the Signoff User Dual Identification
feature and provide code samples that use these methods.
Approving a Routable Object
The approve() method informs users if the object is approved by the approver, or when the
approver is approving the object on behalf of one or more user groups. You can also use this
method to specify the secondSignature, escalations, transfers, or signoffForSelf
parameters as they are set in the server’s Preferences settings.
// Approving a user
/*
Parameters:
password: User's approval password
secondSignature: User's second signature for approval
comment: A character string for user comments (4000 characters
maximum)
notifyList: List of users and user groups to notify
approveForGroupList: List of user groups to approve for
escalations: Escalated from other users and user groups to approve
for
transfers: From other users and user groups to approve for
signoffForSelf: True to signoff for self and False otherwise
APIException:
Thrown if the method fails to approve the routable object
*/
public void approve (String password, String secondSignature,
String comment, Collection notifyList,
Collection approveForGroupList, Collection escalations,
Collection transfers, boolean signoffForSelf)
throws APIException;
The following code example approves a routing object requiring Dual identification. Other conditions
are:
à Display User ID when Sever Settings > Preferences Signoff User Dual Identification is selected.
à Set the Workflow Settings for Workflow Status CCB: Default Change Orders Dual Identification
Required to Yes.
à Create a change object and add a user, for example admin as approver to the CCB Status
and the Released Status.
Example: Approving a routable object
// Admin approves the change by supplying approval password and "User
// ID" as the second signature
String chgNo = “ECO-12345”;
IChange chg = (IChange) session.getObject(ChangeConstants.CLASS_ECO,
chgNo);
String userName = session.getCurrentUser().getName();
chg.approve ("agile", userName, "OK, Approved", null, null, null,
null, true);
Chapter 14: Managing Workflow
v9.3.1.2 211
Rejecting a Routable Object
This reject() method informs users that the routable object is rejected by the approver, or when
the approver is rejecting the object on behalf of one or more user groups. You can also use this
method to specify the secondSignature, escalations, transfers, or SignoffForSelf
parameters as they are set in server’s Preferences settings.
// Rejecting a user
/*
Parameters
password: User's approval password
secondSignature: User's second signature for approval
comment: A character string for user comments
(4000 characters maximum)
notifyList: List of users and user groups to notify
approveForGroupList: List of user groups to approve for
escalations: Escalated from other users and user groups
to approve for
transfers: From other users and user groups to approve for
signoffForSelf: True to signoff for self and False otherwise
APIException
Thrown if the method fails to approve the routable object
*/
public void reject(String password, String secondSignature,
String comment, Collection notifyList,
Collection approveForGroupList, Collection escalations,
Collection transfers, boolean signoffForSelf)
throws APIException;
The following code sample requires Dual identification to reject a routing object. Other conditions
are:
à Display User ID when Sever Settings > Preferences Signoff User Dual Identification is selected.
à Set the Workflow Settings for Workflow Status CCB: Default Change Orders Dual Identification Required
to Yes.
à Create a change object and add a user, for example admin as an approver of the CCB Status
and the Released Status.
Example: Rejecting a routable object
// Admin rejects the change by supplying approval password and "User
// ID" as the second signature
String chgNo = “ECO-12345”;
IChange chg = (IChange) session.getObject(ChangeConstants.CLASS_ECO,
chgNo);
String userName = session.getCurrentUser().getName();
chg.reject("agile", userName, "Rejected", null, null, null, null,
true);
SDK Developer Guide - Using Agile APIs
212 Agile Product Lifecycle Management
Adding User Groups of Approvers and Users to Approve Routable
Objects
The getPossibleUserGroupsForSignoff() method is designed to retrieve an array of user
groups that is added as approvers for a particular Workflow status and the current user/approver is
also a group member.
/*
Parameters
status: A node corresponding to the desired Workflow status. You can
retrieve the current status using getStatus(). To retrieve the
default next status, use getDefaultNextStatus().
APIExceptions and Returns
- throws APIException if the method fails
- returns an array of IUserGroup objects
*/
public IDataObject[] getPossibleUserGroupsForSignoff(IStatus status)
throws APIException;
The following code sample adds a user group that approves the ECO at the CCB status and
contains the current user as its member. In addition to Dual identification, the following conditions
are also required:
à Display User ID when Sever Settings > Preferences Signoff User Dual Identification is selected.
à Set the Workflow Settings for Workflow Status CCB: Default Change Orders Dual Identification Required
to Yes.
Example: Adding User Groups of Approvers with Current User as a Member of the “User
Group”
IChange change;
//Add the User Group as approver for CCB
Object[] appr=new Object[] {user_group};
IStatus current=change.getStatus();
StatusConstants type=current.getStatusType();
m_session.disableWarning(new Integer(574));
while(!(type == (StatusConstants.TYPE_REVIEW))){
IStatus nextstatus=change.getDefaultNextStatus();
change.changeStatus(nextstatus,true,"",true,true,(Object[])null,(
Object[])null,(Object[])null,false);
current=change.getStatus();
type=change.getStatus().getStatusType();
}
m_session.enableWarning(new Integer(574));
change.addApprovers(current, appr, (Object [])null, false, "");
//Get one of the possible signoff groups and have current user signoff
//in their behalf
IDataObject[] u = change.getPossibleUserGroupsForSignoff(current);
Collection gl = new ArrayList();
gl.add(u[0]);
change.approve("agile", session.getCurrentUser().getName(),
"ESIGN-FIRST", null, gl, null, null, false);
Chapter 14: Managing Workflow
v9.3.1.2 213
Approving a Routable Object by Users on behalf of “Transferred from
Users”
The getPossibleTransferredFromUsers() method is designed to retrieve an array of users
that is added as transfer authorities for the current user and for a particular Workflow status.
/*
Parameters
status: A node corresponding to the desired Workflow status. You can
retrieve the current status using getStatus(). To retrieve the
default next status, use getDefaultNextStatus().
APIExceptions and Returns
- throws APIException if the method fails
- returns an array of IUserGroup objects
*/
public IDataObject[] getPossibleTransferredFromUsers(IStatus status)
throws APIException;
The following code sample sets up a Transfer Authority from user A to user B, creates an ECO, and
adds user A as an approver of the CCB status.
Note The getPossibleTransferredFromUsers(IStatus status) return value for
user B 's CCB status is the array of Users whose Sign-off authority is transferred to user
B.
In addition to Dual identification, the following conditions are also required:
à Display User ID when Sever Settings > Preferences Signoff User Dual Identification is selected.
à Set the Workflow Settings for Workflow Status CCB: Default Change Orders Dual Identification Required
to Yes.
Example: Setting up a Transfer of Authority from one user to another user
//Log in and execute the following code as User B
IChange change;
IStatus current = change.getStatus();
IDataObject [] usrs =
change.getPossibleTransferredFromUsers(current);
// Prepare the collection
Collection col = new ArrayList ();
for (int i=0; i < usrs.length; i++){
col.add(usrs[i]);
}
// approve the change
chg.approve(“agile”, userName, “OK, Approved”, null, null, null,
col, false);
SDK Developer Guide - Using Agile APIs
214 Agile Product Lifecycle Management
Adding Active Escalations for Current Users to a Approve Routable
Object
The getPossibleEscalatedFromUsers() method is designed to retrieve an array of users that
serve as active escalations for the current user for a particular Workflow status. This method will
override the settings in the Allow Escalation Designation Approval attribute on the user’s cover
page.
/*
Parameters
status: A node corresponding to the desired Workflowstatus. You can
retrieve the current status using getStatus(). To retrieve the
default next status, use getDefaultNextStatus().
APIExceptions and Returns
- throws APIException if the method fails
- returns an array of IUser and IUserGroup objects
*/
public IDataObject[] getPossibleEscalatedFromUsers(IStatus status)
throws APIException;
The following code sample sets up an Escalation from user A to user B, creates an ECO, and adds
user A as an approver of the CCB status.
Note The getPossibleEscalatedFromUsers(IStatus status) for user B for the CCB
status will return the array of Users whose escalations are set to user B.
In addition to Dual identification, the following conditions are also required:
à Display User ID when Sever Settings > Preferences Signoff User Dual Identification is selected.
à Set the Workflow Settings for Workflow Status CCB: Default Change Orders Dual Identification Required
to Yes.
Example: Setting up an escalation for a user
// Log in and execute the following code as “User B”
IChange change;
IStatus current = change.getStatus();
IDataObject [] usrs = change.getPossibleEscalatedFromUsers(current);
// Prepare the collection
Collection col = new ArrayList ();
for (int i=0; i < usrs.length; i++){
col.add(usrs[i]);
}
// approve the change
chg.approve("agile", userName, "OK, Approved", null, null, null, col,
false);
Chapter 14: Managing Workflow
v9.3.1.2 215
Specifying a Second Signature to Approve a Routable Object
The isSecondSignatureRequired() method is designed to verify if a second signature is
required to approve a routable object. Use this method in combination with the methods
documented in
Adding User ID as Second Signature to Approve a Routable Object on page 216
(which also has the secondSignature) parameter and
Approving a Routable Object on page 210
and
Rejecting a Routable Object on page 210.
Examples
/*
Parameters
Status: The status (IStatus) of the object checked for the next
Workflowstatus.
Returns
true if a second signature is required, false otherwise
*/
public boolean isSecondSignatureRequired(IStatus status)
throws APIException;
The following code sample sets the system preference “Signoff User Dual Identification Type” to
“User ID”, sets the Default Change Orders workflow CCB status property “Dual Identification
Required” to “Yes”, and prints the value of the “Second Signature Required Property” for the various
states of the workflow. The isSecondSignatureRequired (IStatus status) for the CCB
status will return true.
Example: Specifying a second signature to approve a routable object
// set the "Signoff User Dual Identification Type" preferences Node
IAdmin admin = session.getAdminInstance();
INode node = admin.getNode(NodeConstants.NODE_PREFERENCES);
// Node Properties
IProperty propSecondSignature = node.getProperty("Signoff User Dual
Identification Type");
IAgileList lst = propSecondSignature.getAvailableValues();
lst.setSelection(new Object [] {"User ID"});
propSecondSignature.setValue(lst);
// set the "Dual Identification Required" property for "Workflow Status
CCB: Default Change Orders" to "Yes"
INode root=admin.getNode(NodeConstants.NODE_AGILE_WORKFLOWS);
INode CCBStatus=(INode)root.getChildNode("Default Change
Orders/Status List/CCB");
IProperty propDualIdentification = CCBStatus.getProperty("Dual
Identification Required");
IAgileList lst = propDualIdentification.getAvailableValues();
lst.setSelection(new Object [] {"Yes"});
propDualIdentification.setValue(lst);
// Get and print the "Second Signature Required Property" for the
// various states of a workflow
IChange change;
IWorkflow [] wfs = change.getWorkflows();
IWorkflow wf = wfs[0];
change.setWorkflow(wf);
IStatus [] sts = wf.getStates();
SDK Developer Guide - Using Agile APIs
216 Agile Product Lifecycle Management
for (int i=0; i< sts.length; i++) {
IStatus st = sts[i];
System.out.println("Status Name =" + st.getName());
System.out.println("IS Second Signature Reqd = "+
change.isSecondSignatureRequired(st));
System.out.println("IS Second Signature UserId = " +
change.isSecondSignatureUserId(st));
}
Adding User ID as Second Signature to Approve a Routable Object
The isSecondSignatureUserId() method is designed to set the user's ID as the second
signature to approve a routable object. Use this method in combination with methods documented
in
Specifying a Second Signature to Approve a Routable Object on page 214. These methods
have the secondSignature parameter. See
Approving a Routable Object on page 210 and
Rejecting a Routable Object on page 210.
/*
Parameters
Status: The status (IStatus) of the object checked for the next
Workflow status.
Returns true if a second signature required is User ID, false
otherwise.
*/
public boolean isSecondSignatureUserId(IStatus status)
throws APIException;
The following code sample creates an ECO chg (change order). The
chg.isSecondSignatureRequired (IStatus status) for the CCB status will return true.
In addition to Dual identification, the following conditions are also required:
à Display User ID when Sever Settings > Preferences Signoff User Dual Identification Type is selected.
à Set the Workflow Settings for Workflow Status CCB: Default Change Orders Dual Identification Required
to Yes.
Example: Specifying User ID as the second signature
// Get and print the “Second Signature Is User Id Property” for the
// various states of a workflow
IChange change;
IWorkflow [] wfs = change.getWorkflows();
IWorkflow wf = wfs[0];
change.setWorkflow(wf);
IStatus [] sts = wf.getStates();
for (int i=0; i< sts.length; i++) {
IStatus st = sts[i];
System.out.println(“Status Name =" + st.getName());
System.out.println("IS Second Signature Reqd = "+
change.isSecondSignatureRequired(st));
System.out.println("IS Second Signature UserId = " +
change.isSecondSignatureUserId(st));
}
Chapter 14: Managing Workflow
v9.3.1.2 217
Approving or Rejecting Change
After a change is routed to a group of approvers, the online approval process begins. Users listed in
the Workflow table for a change can approve or reject the change.
When you approve a change, the Agile system records the approval on the Workflow table. When
all approvers have approved the change, the system sends an email Notification to the change
analyst or component engineer indicating that the change is ready to be released.
Note To approve or reject a change, users must have the correct privileges. For more
information, refer to Agile PLM Administrator Guide.
When you use the IRoutable.approve() method, you specify the user’s approval password and
an optional comment. approve() methods allow you to specify a Notification list and a collection of
user groups for which you’re approving; refer to the API Reference files at Oracle® E-Cloud Web
site (
http://edelivery.oracle.com/) for details.
The following paragraphs document approving or rejecting a given routable object. The APIs that
support approving or rejecting a change object when a second signature is required are described
in detail in
Setting the “Signoff User Dual Identification” Preference on page 209.
The following example shows how to approve a change.
Example: Approving a change
public void approveChange(IChange change) {
try {
change.approve("agile", "Looks good to me");
} catch (APIException ex) {
System.out.println(ex);
}
}
If a change has a fundamental flaw, users listed on the Workflow table may reject it. When you
reject a change, the system records the rejection on the Workflow tab for the change and sends an
email Notification to the change analyst or component engineer. The change analyst or component
engineer may decide to return the rejected change to the originator, thus reverting its status to
Pending.
When you use the IRoutable.reject() method, you must specify the userNotifications
approval password and optional comments. An overloaded reject() method allows you to
specify a Notification list and a collection of user groups for which you’re approving; refer to the API
Reference files at Oracle® E-Cloud Web site (
http://edelivery.oracle.com/) for more information.
SDK Developer Guide - Using Agile APIs
218 Agile Product Lifecycle Management
The following example shows how to reject a change.
Example: Rejecting a change
public void rejectChange(IChange change) {
try {
change.reject("agile", "Incorrect replacement part!");
} catch (APIException ex) {
System.out.println(ex);
}
}
Approving or Rejecting a Change Without Password
Agile PLM's Java Client provides the option to configure Workflow Settings to enable the approval
or rejection of a change with or without typing a password. Users with the Administrator role and
privileges configure this option by selecting the Yes or No option in the Password Required field shown
in the following illustration.
Figure 17: Configuring workflow settings without a password
The following example uses the Agile SDK to programmatically configure this requirement.
Example: Approving or rejecting change without a password
// Workflow settings - Password Required
Iadmin admin = session.getAdminInstance();
INode root = admin.getNode(NodeConstants.NODE_AGILE_WORKFLOWS);
INode CCBStatus = (INode)root.getChildNode("Default Change
Orders/Status List/CCB/Status Properties");
Chapter 14: Managing Workflow
v9.3.1.2 219
IProperty PwdReq =
CCBStatus.getProperty(PropertyConstants.PROP_WORKFLOW_PASSWORD_REQUI
RED);
PwdReq.setValue(“No”);
// Approve change without passing password
change.approve(null, null, "Approve", null, null, null, null, true);
Commenting a Change
When you comment a change, you send a comment to other CCB reviewers during the online
approval process. In addition to the comment, you can specify whether to notify the originator, the
change analyst, and the change control board. An overloaded comment() method allows you to
specify a Notification list. For more information, refer to the API Reference files at Oracle® E-Cloud
Web site (
http://edelivery.oracle.com/).
The following example shows how to comment a change.
Example: Commenting a change
public void commentChange(IChange change) {
try {
change.comment(true, true, true, "Change flagged for transfer to
ERP.");
} catch (APIException ex) {
System.out.println(ex);
}
}
Auditing a Change
At any point in a change’s workflow, you can audit it to determine if any required entry cells are not
completed or if the change violates any Agile SmartRules. When you use the
IRoutable.audit() method, the method returns a Map object containing ICell objects as
keys and a List of APIException objects as values. The ICell key can be null if there are no
problems with the change. The APIException object describes a problem with the associated
entry cell.
The Map object returned by the audit() method may also contain null objects as keys. The
APIException object associated with a null object describes a problem unrelated to data cells.
The following example shows how to audit a change.
Example: Auditing a change
public void auditChange(IChange change) {
try {
// Audit the release
Map results = change.audit();
// Get the set view of the map
Set set = results.entrySet();
// Get an iterator for the set
SDK Developer Guide - Using Agile APIs
220 Agile Product Lifecycle Management
Iterator it = set.iterator();
// Iterate through the cells and print each cell name and exception
while (it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
ICell cell = (ICell)entry.getKey();
if(cell != null) {
System.out.println("Cell : " + cell.getName());
} else {
System.out.println("Cell : No associated data cell");
}
//Iterate through exceptions for each map entry.
//(There can be multiple exceptions for each data cell.)
Iterator jt = ((Collection)entry.getValue()).iterator();
while (jt.hasNext()) {
APIException e = (APIException)jt.next();
System.out.println("Exception : " + e.getMessage());
}
}
} catch (APIException ex) {
System.out.println(ex);
}
}
Changing the Workflow Status of an Object
The IRouteable.changeStatus() method is a general purpose method for changing the status
of an Agile object. For example, you can use changeStatus() to submit, release, or cancel a
change. In instances such as failed audits, it throws the compound exception
ExceptionConstants.API_SEE_MULTIPLE_ROOT_CAUSES. You can disable this exception by
modifying the code that caught the exception. See the example below.
Example: Throwing compound exception s
while (true) {
try {
change.changeStatus(
wf.getStates(expectStatus)[0],
false,
"comment",
false,
false,
null,
null,
null,
false
);
} catch (APIException ae) {
try {
Chapter 14: Managing Workflow
v9.3.1.2 221
if
(ae.getErrorCode().equals(ExceptionConstants.API_SEE_MULTIPLE_ROOT_CAUS
ES)){
Throwable[] causes = ae.getRootCauses();
for (int i = 0; i < causes.length; i++) {
m_session.disableWarning(
(Integer)((APIException)causes[i]).getErrorCode()
);
}
} else {
m_session.disableWarning((Integer)ae.getErrorCode());
}
} catch (Exception e) {
throw ae;
}
continue;
}
break;
}
In general, you release a change after it is signed off by CCB members. In addition to modifying the
status of a change, you can also use changeStatus() to specify a Notification list, optional
comments, and whether to notify the originator and change control board.
Depending on the overloaded changeStatus() method you use, the notifyList parameter is
an array of IUser or IUserGroup objects that should be notified about the change in status;
refer to the API Reference files at Oracle® E-Cloud Web site (
http://edelivery.oracle.com/) for
details. To use the default Notification list for the Workflow status, specify a null value. To indicate
that no users should be notified, specify an empty array.
For both the approvers and observers parameters of the changeStatus() method, you
must explicitly pass an array of users or user groups. If you pass null, no approvers or observers
are used. To get the default approvers and observers for a particular Workflow status, use
getApproversEx() and getObserversEx(), respectively.
The following example shows how to check the Workflow status of a change.
Example: Checking the status of a change
void checkStatus(IChange change) {
try {
// Get current workflow status (an IStatus object)
IStatus status = change.getStatus();
System.out.println("Status name = " + status.getName());
// Get next available Workflow statuses
IStatus[] nextStatuses = change.getNextStatuses();
for (int i = 0; i < nextStatuses.length; i++) {
System.out.println("nextStatuses[" + i +"] = " +
nextStatuses[i].getName());
}
// Get next default Workflow status
SDK Developer Guide - Using Agile APIs
222 Agile Product Lifecycle Management
IStatus nextDefStatus = change.getDefaultNextStatus();
System.out.println("Next default status = " +
nextDefStatus.getName());
} catch (APIException ex) {
System.out.println(ex);
}
}
The following example shows how to change the status of a change.
Example: Changing the status of a change
public void nextStatus(IChange change, IUser[] notifyList,
IUser[] approvers, IUser[] observers) {
try {
// Check if the user has privileges to change to the next status
IStatus nextStatus = change.getDefaultNextStatus();
if (nextStatus == null) {
System.out.println("Insufficient privileges to change status.");
return;
}
// Change to the next status
else {
change.changeStatus(nextStatus, true, "", true, true, notifyList,
approvers, observers, false);
}
} catch (APIException ex) {
System.out.println(ex);
}
}
The following example shows how to use the default approvers and observers when you change
the status of a routable object.
Example: Changing the status and routing to the default approvers and observers
public void changeToDefaultNextStatus(IChange change) throws
APIException {
// Get the next status of the change
IStatus nextStatus = change.getDefaultNextStatus();
// Get default approvers for the next status
IDataObject[] defaultApprovers = change.getApproversEx(nextStatus);
// Get default observers for the next status
IDataObject[] defaultObservers = change.getObserversEx(nextStatus);
// Change to the next status
change.changeStatus(nextStatus, false, "", false, false, null,
defaultApprovers,
defaultObservers, false);
}
Chapter 14: Managing Workflow
v9.3.1.2 223
Sending an Agile Object to Selected Users
You can send any Agile object to a selected group of users. When you send an object, such as an
ECO, there is no signoff required. The selected recipients receive an email message with an
attached link to the object. When you use the IDataObject.send() method, you can specify an
array of Agile users and an optional comment. Unlike other Workflow commands, the send()
method is not limited to routable objects. You can use it to send any type of Agile dataobject,
including an item.
The following example shows how to send an object to all users.
Example: Sending an Agile object to selected users
public void sendToAll(IDataObject object) {
try {
// Get all users
IQuery q = (IQuery)m_session.createObject(IQuery.OBJECT_TYPE,
"select * from [Users]");
ArrayList userList = new ArrayList();
Iterator i = q.execute().getReferentIterator();
while (i.hasNext()) {
userList.add(i.next());
}
IUser[] users = new IUser[userList.size()];
System.arraycopy(userList.toArray(), 0, users, 0, userList.size());
// Send the object to all users
object.send(users, "Please read this important document.");
} catch (APIException ex) {
System.out.println(ex);
}
}
Sending an Agile Object to User Groups
You can send an Agile change object or an item object to a user group. When you send an object,
such as an ECO, there is no signoff required. The selected recipients receive an email message
with an attached link to the object. When you use the IDataObject.send(IDataObject[] to,
String Comment) method, you can specify an array of Agile User Groups and an optional
comment. The IDataObject parent interface represents the IUserGroup Agile object. Unlike
other Workflow commands, the send() method is not limited to routable objects. You can use it to
send any type of Agile dataobject, including an item.
SDK Developer Guide - Using Agile APIs
224 Agile Product Lifecycle Management
The following example shows how to send an object to all User Groups.
Example: Sending an Agile object to selected user groups
public void sendToAll(IDataObject[] object) {
try {
// Get all user groups
IQuery q = (IQuery)m_session.createObject(IQuery.OBJECT_TYPE,
"select * from [UserGroup]");
ArrayList usergroupList = new ArrayList();
Iterator i = q.execute().getReferentIterator();
while (i.hasNext()) {
usergroupList.add(i.next());
}
IUserGroup[] group = (IUserGroup[])(usergroupList.toArray());
// Send the object to all user groups
object.send(usergroups, "Please read this important document.");
} catch (APIException ex) {
System.out.println(ex);
}
}
v9.3.1.2 225
Chapter 15
Managing and Tracking Quality
This chapter includes the following:
About Quality Control...........................................................................................................................................225
Working with Customers...................................................................................................................................... 226
Working with Product Service Requests.............................................................................................................. 228
Working with Quality Change Requests.............................................................................................................. 231
Using Workflow Features with PSRs and QCRs................................................................................................. 233
About Quality Control
The Agile PLM system provides tools that allow companies to track and manage the following
quality-related items:
à customer complaints
à product and manufacturing quality issues
à enhancement and corrective action requests
The corrective action process in the Agile PLM system is flexible and can be implemented in many
different ways. For example, one way to customize the Agile PLM system is to use the Agile API to
integrate the system with a Customer Relationship Management (CRM) system.
Quality-Related API Objects
The Agile API includes the following new interfaces:
à ICustomer – interface for the Customer class. A customer is anyone that uses a company’s
product(s). In some Agile PLM implementations, customers and problem reports will be
imported directly from Customer Relationship Management (CRM) systems.
à IServiceRequest – interface for the ServiceRequest class. IServiceRequest is a
subinterface of IRoutable; it lets you create two types of service requests, problem reports
and nonconformance reports (NCRs).
à IQualityChangeRequest – interface for the QualityChangeRequest class, which is
similar to an ECR and other types of change requests. It represents a closed loop Workflow
process that addresses quality problems. Audit and CAPA (Corrective Action/Preventive
Action) are subclasses of QualityChangeRequest.
SDK Developer Guide - Using Agile APIs
226 Agile Product Lifecycle Management
Quality-Related Roles and Privileges
To create, view, and modify problem reports, NCRs, CAPAs, and Audits, you must have the
appropriate privileges. The Agile PLM system has two default user roles that provide users with
privileges to work with these quality-related objects:
à Quality Analyst – role for users who manage problem reports, and NCRs.
à Quality Administrator – role for users who manage audits and CAPAs.
For more information about roles and privileges, refer to the Agile PLM Administrator Guide.
Working with Customers
This section describes how to create, load, and save ICustomer objects.
About Customers
The ICustomer object stores contact information about a customer. What role does a customer
have in the Agile PLM system? Customers provide feedback on your company’s products, alerting
you to quality issues or problems they encounter.
This object can originate in another system, such as a CRM system. You can use the Agile API to
import customer data and problem reports from CRM systems into the Agile PLM system.
Creating a Customer
To create a customer, use the IAgileSession.createObject() method. At a minimum, you
should specify values for the General Info.Customer Name and General Info.Customer
Number attributes.
Example: Creating a customer
try {
//Create a Map object to store parameters
Map params = new HashMap();
//Initialize the params object
params.put(CustomerConstants.ATT_GENERAL_INFO_CUSTOMER_NUMBER,
"CUST00006");
params.put(CustomerConstants.ATT_GENERAL_INFO_CUSTOMER_NAME, "Western
Widgets");
//Create a new customer
ICustomer cust1 =
(ICustomer)m_session.createObject(CustomerConstants.CLASS_CUSTOMER,
params);
} catch (APIException ex) {
System.out.println(ex);
}
Chapter 15: Managing and Tracking Quality
v9.3.1.2 227
Loading a Customer
To load a customer, use the IAgileSession.getObject() method. To uniquely identify a
customer, specify the value for the General Info | Customer Number attribute.
Example: Loading a customer
try {
// Load a customer by specifying a CustomerNumber
ICustomer cust =
(ICustomer)m_session.getObject(ICustomer.OBJECT_TYPE, "CUST00006");
} catch (APIException ex) {
System.out.println(ex);
}
Saving a Customer as Another Customer
To save a customer as another customer, use the IDataObject.saveAs() method, which has
the following syntax:
public IAgileObject saveAs(java.lang.Object type, java.lang.Object
params)
For the params parameter, specify the General Info | Customer Name and General Info | Customer
Number attributes.
Example: Saving a customer to another customer
try {
// Load an existing customer
ICustomer cust1 =
(ICustomer)m_session.getObject(ICustomer.OBJECT_TYPE, "CUST00006");
//Create a Map object to store parameters
Map params = new HashMap();
//Initialize the params object
params.put(CustomerConstants.ATT_GENERAL_INFO_CUSTOMER_NUMBER,
"CUST00007");
params.put(CustomerConstants.ATT_GENERAL_INFO_CUSTOMER_NAME, "Wang
Widgets");
// Save the customer
ICustomer cust2 =
(ICustomer)cust1.saveAs(CustomerConstants.CLASS_CUSTOMER, params);
} catch (APIException ex) {
System.out.println(ex);
}
SDK Developer Guide - Using Agile APIs
228 Agile Product Lifecycle Management
Working with Product Service Requests
This section describes how to work with the two classes of Product Service Requests: Problem
Reports and Nonconformance Reports
About Problem Reports
A problem report describes a problem or an issue that occurred with a product from the customer’s
perspective. A problem report can be submitted by a customer, sales representative, or customer
service representative.
Because a problem report usually originates with a customer, it may not accurately describe the
actual cause of the problem. To understand the root cause of a problem, a Quality Analyst must
investigate the problem.
Problem reports can be routed for investigation. The investigating team, consisting of Quality
Analysts, determines the root cause of the problem and decides whether to escalate the problem
into an issue.
About Nonconformance Reports
A nonconformance report (NCR) is used to report material damages, failure modes, or defects in a
product received by a customer or supplier. An NCR is typically identified when a product shipment
is inspected after receipt from a supplier. A product is nonconforming if it does not meet customer
requirements or specifications. Such products are generally rejected or segregated to await
disposition. A nonconformance report may require that a Quality Analyst investigate the problem
and determine whether corrective action is required.
NCRs can be routed for review. Typically, the review is used for additional information gathering
rather than approval and rejection.
Creating a Product Service Request
To create a problem report or nonconformance report, use the
IAgileSession.createObject() method. The only required attribute value you must specify is
the object’s number. The following example shows how to create problem reports and NCRs.
Example: Creating a problem report or NCR
public IServiceRequest createPR(String strNum) throws APIException {
IServiceRequest pr = (IServiceRequest)m_session.createObject(
ServiceRequestConstants.CLASS_PROBLEM_REPORT, strNum);
return pr;
}
public IServiceRequest createNCR(String strNum) throws APIException {
IServiceRequest ncr = (IServiceRequest)m_session.createObject(
ServiceRequestConstants.CLASS_NCR, strNum);
return ncr;
}
Chapter 15: Managing and Tracking Quality
v9.3.1.2 229
Assigning a Product Service Request to a Quality Analyst
To assign a problem report or NCR to a Quality Analyst, set the value for the Cover Page | Quality
Analyst field, which is a list field. The available values for the list field consists of Agile PLM users.
The following example shows how to set the value for the Cover Page.Quality Analyst field
for a problem report or NCR.
Example: Assigning a problem report or nonconformance report
void assignServiceRequest(IServiceRequest sr) throws APIException {
Integer attrID;
//Set attrID equal to the Quality Analyst attribute ID
attrID = ServiceRequestConstants.ATT_COVER_PAGE_QUALITY_ANALYST;
//Get the Cover Page.Quality Analyst cell
ICell cell = sr.getCell(attrID);
//Get available list values for the list
IAgileList values = cell.getAvailableValues();
//Set the value to the current user
IUser user = m_session.getCurrentUser();
values.setSelection(new Object[] { user });
cell.setValue(values);
}
Adding Affected Items to a Product Service Request
To associate a problem report or nonconformance report with one or more items, you add items to
the Affected Items table. Each Product Service Request can be associated with many items.
Note If Product Service Requests have been added to the Related PSR table, the Affected
Items table cannot be modified.
Example: Adding an affected item to a Product Service Request
void addAffectedItem(IServiceRequest sr, String strItemNum) throws
APIException {
//Get the class
IAgileClass cls = sr.getAgileClass();
//Attribute variable
IAttribute attr = null;
//Get the Affected Items table
ITable affItems =
sr.getTable(ServiceRequestConstants.TABLE_AFFECTEDITEMS);
//Create a HashMap to store parameters
HashMap params = new HashMap();
//Set the Item Number value
params.put(ServiceRequestConstants.ATT_AFFECTED_ITEMS_ITEM_NUMBER,
strItemNum);
//Set the Latest Change value
SDK Developer Guide - Using Agile APIs
230 Agile Product Lifecycle Management
attr =
cls.getAttribute(ServiceRequestConstants.ATT_AFFECTED_ITEMS_LATEST_CHAN
GE);
IAgileList listvalues = attr.getAvailableValues();
listvalues.setSelection(new Object[] { new Integer(0)});
params.put(ServiceRequestConstants.ATT_AFFECTED_ITEMS_LATEST_CHANGE,
listvalues);
//Set the Affected Site value
attr =
cls.getAttribute(ServiceRequestConstants.ATT_AFFECTED_ITEMS_AFFECTED_SI
TE);
IAgileList listvalues = attr.getAvailableValues();
listvalues.setSelection((new Object[] { "Hong Kong" });
params.put(ServiceRequestConstants.ATT_AFFECTED_ITEMS_AFFECTED_SITE,
listvalues);
//Create a new row in the Affected Items table
IRow row = affItems.createRow(params);
}
Adding Related PSRs to a Product Service Request
A Product Service Request can be used to aggregate multiple problem reports or NCRs into one
master. To do this, create a new Product Service Request and don’t add items to the Affected Items
table. Instead, select the Related PSR table and add a row for each related Product Service
Request. The single PSR you create is the Parent PSR. All the added PSRs on the Related PSR
tab are child PSRs.
Note SmartRules settings control whether a PSR can be associated with both affected items
and related PSRs, or only affected items or related PSRs. Depending on
enabling/disabling the "PSR contains Items and Related PSRs" SmartRule setting, you
can enable/disable the Affected Items tab after you add Related PSRs. For information
on SmartRules and PSRs, refer to Agile PLM Product Quality Management User Guide
and Agile PLM Administrator Guide. The following example assumes SmartRules are set
properly.
Example: Adding related PSRs to a Product Service Request
void addRelatedPSRs(IServiceRequest sr, String[] psrNum) throws
APIException {
//Get the Related PSR table
ITable relPSR =
sr.getTable(ServiceRequestConstants.TABLE_RELATEDPSR);
//Create a HashMap to store parameters
HashMap params = new HashMap();
//Add PSRs to the Related PSR table
for (int i = 0; i < psrNum.length; i++)
{
//Set the PSR Number value
params.put(ServiceRequestConstants.ATT_RELATED_PSR_PSR_NUMBER,
psrNum[i]);
Chapter 15: Managing and Tracking Quality
v9.3.1.2 231
//Create a new row in the Related PSR table
IRow row = relPSR.createRow(params);
//Reset parameters
params = null;
}
}
Working with Quality Change Requests
A Quality Change Request, or QCR, allows a Quality Analyst to manage quality records that contain
aggregated problems related to products, documents, suppliers, and customers. You can route the
QCR for review and approval, driving the issue(s) to closure using a corrective or preventive action
(CAPA). This may result in changes to a product, process, or supplier by initiating an ECO or MCO.
QCRs also provide an audit trail between problems, corrective and preventive actions, and
engineering changes.
Agile PLM provides two classes of Quality Change Requests:
à CAPA – Stands for Corrective Action/Preventive Action, which addresses defects that
(generally) surfaced from problem reports. By the time a problem reaches the CAPA stage, the
team has figured out which specific items must be fixed. Consequently, the affected item for a
CAPA may be different from the affected item of its related problem report. For example, say a
customer reported a problem with a DVD-ROM drive. A CAPA is initiated and the root-cause is
identified to be a defect in the IDE controller. Therefore, the CAPA and its related problem
report have different affected items.
à Audit – Systematic, independent and documented processes for obtaining evidence and
evaluating it objectively to determine the extent to which criteria are fulfilled. Audits can be
initiated against items for which no problems have been reported.
Creating a Quality Change Request
To create a QCR, use the IAgileSession.createObject() method. The only required
attribute value you must specify is the object’s number. The example below shows how to create
both CAPA and Audit QCRs.
Example: Creating a QCR
public IQualityChangeRequest createCAPA(String strNum) throws
APIException {
IQualityChangeRequest capa =
(IQualityChangeRequest)m_session.createObject(
QualityChangeRequestConstants.CLASS_CAPA, strNum);
return capa;
}
public IQualityChangeRequest createAudit(String strNum) throws
APIException {
IQualityChangeRequest audit =
(IQualityChangeRequest)m_session.createObject(
SDK Developer Guide - Using Agile APIs
232 Agile Product Lifecycle Management
QualityChangeRequestConstants.CLASS_AUDIT, strNum);
return audit;
}
Assigning a Quality Change Request to a Quality Administrator
To assign a QCR to a Quality Administrator, you set the value for the Cover Page | Quality
Administrator field. This process is similar to the way you assign a Product Service Request to a
Quality Analyst.
Example: Assigning a QCR
void assignQCR(IQualityChangeRequest qcr) throws APIException {
Integer attrID;
//Set attrID equal to the Quality Administrator attribute ID
attrID =
QualityChangeRequestConstants.ATT_COVER_PAGE_QUALITY_ADMINISTRATOR;
//Get the Cover Page.Quality Administrator cell
ICell cell = qcr.getCell(attrID);
//Get available list values for the list
IAgileList values = cell.getAvailableValues();
//Set the value to the current user
IUser user = m_session.getCurrentUser();
values.setSelection(new Object[] { user });
cell.setValue(values);
}
Saving a Quality Change Request as a Change
You can use the IDataObject.saveAs() method to save a QCR as another QCR or as an ECO
(or another type of change order). When you save a QCR as an ECO, the items affected by the
QCR are not automatically transferred to the Affected Items tab of the ECO. If you want to transfer
affected items from the QCR to the ECO, you must write the code in your program to provide that
functionality. Workflow is a required input parameter for using saveAs()on QCRs.
Note If you try to save a QCR to an object that is not a subclass of either the Quality Change
Request or Change superclasses, the Agile API throws an exception.
Example: Saving a QCR as an ECO
public IChange saveQCRasECO(IAgileSession session,
IQualityChangeRequest qcr) throws APIException {
// Get the ECO class
IAgileClass cls = m_admin.getAgileClass(ChangeConstants.CLASS_ECO);
// Get autonumber sources for the ECO class
IAutoNumber[] numbers = cls.getAutoNumberSources();
// Get Workflow for the ECO class
IWorkflow ecoWf =
((IRoutableDesc)session.getAdminInstance().getAgileClass(ChangeConst
ants.CLASS_ECO)).getWorkflows()[0];
Chapter 15: Managing and Tracking Quality
v9.3.1.2 233
// Save the QCR as an ECO
HashMap map = new HashMap();
map.put(ChangeConstants.ATT_COVER_PAGE_NUMBER, numbers[0]);
map.put(ChangeConstants.ATT_COVER_PAGE_WORKFLOW, ecoWf);
IChange eco = (IChange)qcr.saveAs(ChangeConstants.CLASS_ECO, map);
// Add code here to copy affected items from the QCR to the ECO
return eco;
}
Using Workflow Features with PSRs and QCRs
PSRs and QCRs derive all Workflow functionality from the IRoutable interface. The following
table lists the Workflow commands you can use to manage product quality objects.
Feature Equivalent API(s)
Audit a PSR or QCR
IRoutable.audit()
Change the status of a PSR or QCR
IRoutable.changeStatus()
Send a PSR or QCR to another user
IDataObject.send()
Approve a PSR or QCR
IRoutable.approve()
Reject a PSR or QCR
IRoutable.reject()
Comment on a PSR or QCR
IRoutable.comment()
Add or remove approvers for a PSR or
QCR
IRoutable.addApprovers()
IRoutable.removeApprovers()
Selecting Workflows for PSRs and QCRs
When you create a new Product Service Request or a Quality Change Request, you must select a
workflow. Your Agile PLM system can have multiple workflows defined for each type of Product
Service Request and Quality Change Request. To retrieve the valid workflows for an object, use
IRoutable.getWorkflows(). If a Workflow has not been assigned yet, you can use
IRoutable.getWorkflows() to select a workflow, as shown in the following example.
Example: Selecting a workflow
public static IServiceRequest createPSR() throws APIException {
// Create a problem report
IAgileClass prClass =
admin.getAgileClass(ServiceRequestConstants.CLASS_PROBLEM_REPORT);
IAutoNumber[] numbers = prClass.getAutoNumberSources();
IServiceRequest pr =
(IServiceRequest)m_session.createObject(prClass, numbers[0]);
// Get the current Workflow (a null object, since the Workflow has
not been set yet)
SDK Developer Guide - Using Agile APIs
234 Agile Product Lifecycle Management
IWorkflow wf = pr.getWorkflow();
// Get all available workflows
IWorkflow[] wfs = pr.getWorkflows();
// Set the problem report to use the first workflow
pr.setWorkflow(wfs[0]);
return pr;
}
You can also set the Workflow for a Product Service Request or a Quality Change Request by
selecting a value for the Cover Page.Workflow field, as shown in the following example.
Example: Selecting a Workflow by setting the value of the “Cover Page.Workflow” attribute
void selectWorkflow(IServiceRequest psr) throws APIException {
int nAttrID;
//Set nAttrID equal to the Workflow attribute ID
nAttrID = ServiceRequestConstants.ATT_COVER_PAGE_WORKFLOW;
//Get the Workflow cell
ICell cell = psr.getCell(nAttrID);
//Get available list values for the list
IAgileList values = cell.getAvailableValues();
//Select the first workflow
values.setSelection(new Object[] {new Integer(0));
cell.setValue(values);
}
v9.3.1.2 235
Chapter 16
Creating and Managing Projects
This chapter includes the following:
About Projects and Project Objects..................................................................................................................... 235
Differences in the Behavior of Project Objects.................................................................................................... 236
Creating Projects................................................................................................................................................. 236
Adding Rules for PPM Objects............................................................................................................................ 238
Loading Projects.................................................................................................................................................. 239
Adding "FileFolder" to Project's Content Tab....................................................................................................... 239
Using Project Templates......................................................................................................................................241
Scheduling Projects............................................................................................................................................. 244
Setting Start and End Timestamps for PPM Date Attributes............................................................................... 247
Working with Projects Baselines.......................................................................................................................... 248
Delegating Ownership of a Projects to Another User.......................................................................................... 249
Adding Resources to a Projects Team................................................................................................................ 249
Substituting Project Resources............................................................................................................................252
Locking or Unlocking Projects ............................................................................................................................. 253
Working with Discussions.................................................................................................................................... 253
Note In Release 9.3, the name of the Program Base Class was changed to Projects and
Projects to Sourcing Projects. However the interface for the Projects Base Class is still
called IProgram in the SDK Guide and in Javadoc references.
About Projects and Project Objects
You can use the project management features of Agile Product Portfolio Management (PPM) to
define a project and its associated elements such as activity schedules, deliverables, and
discussions. These capabilities enable you to determine the availability of the required resources,
assigning resources to tasks, identifying bottlenecks, and responding to over- and under-allocated
resource conditions. You can also create and reuse project templates.
The Project object is used to schedule and execute projects. Each project, in addition to schedule
information, contains attachments, discussions and actions items, resources and roles, and history
and content of related activities. For management visibility, data is rolled up to higher levels by rules
and parent-child relationships.
The Agile API provides support for creating, loading, and working with Projects. The IProgram
interface represents all Project objects, including programs, phases, tasks, and gates.
Similar to other Agile PLM business objects, the IProgram interface implements IRoutable,
which means it uses the same IRouteable.changeStatus() method to change a Projects’
Workflow status and to route it to other users. For more information, see
Changing the Workflow
Status of an Object on page 220.
SDK Developer Guide - Using Agile APIs
236 Agile Product Lifecycle Management
Differences in the Behavior of Project Objects
The IProgram interface implements several interfaces commonly used by other Agile PLM
objects. However, it also provides the following distinct functionality that separates Project objects
from other objects.
à The Project object is a container of other underlying Project objects, such as Phases, Tasks,
and Gates. The underlying Project objects are related to the parent object, usually the Projects,
through the Schedule table.
à Projects have baselines that allow you to track changes in the schedule. Therefore, the
IProgram interface provides methods that let you create, get, or remove a baseline.
à Projects can be archived. If you archive the root Projects, the entire Projects tree is soft-deleted
from the system.
à Projects can be locked or unlocked.
Creating Projects
Use the IAgileSession.createObject() method to create Projects. When you specify the
Project's parameters, you must specify the Project subclass (for example, Program, phase, task, or
gate). For Programs, phases, and tasks, you must also specify following required Project attributes:
à General Info.Name
à General Info.Schedule Start Date
à General Info.Schedule End Date
à General Info.Duration Type
For gates, only two attributes are required, General Info.Name and General Info.Schedule
End Date.
The following example shows how to create new Projects and specify the required attributes.
Example: Creating Projects
try {
// Create a Map object to store parameters
Map params = new HashMap();
// Set Projects name
String name = "APOLLO PROJECTS";
// Set Projects start date
Date start = new Date();
start.setTime(1);
// Set Projects end date
Date end = new Date();
end.setTime(1 + 2*24*60*60*1000);
// Set Projects duration type
Chapter 16: Creating and Managing Projects
v9.3.1.2 237
IAttribute attr =
m_admin.getAgileClass(ProgramConstants.CLASS_PROGRAM).
getAttribute(ProgramConstants.ATT_GENERAL_INFO_DURATION_TYPE);
IAgileList avail = attr.getAvailableValues();
avail.setSelection(new Object[] {"Fixed"});
// Initialize the params object
params.put(ProgramConstants.ATT_GENERAL_INFO_NAME, name);
params.put(ProgramConstants.ATT_GENERAL_INFO_SCHEDULE_START_DATE,
start);
params.put(ProgramConstants.ATT_GENERAL_INFO_SCHEDULE_END_DATE, end);
params.put(ProgramConstants.ATT_GENERAL_INFO_DURATION_TYPE, avail);
// Create Projects
IProgram program =
(IProgram)m_session.createObject(ProgramConstants.CLASS_PROGRAM,
params);
} catch (APIException ex) {
System.out.println(ex);
}
Projects contain other types of activities, such as phases, tasks, and gates. A gate is a special
milestone—a task with an end date but no duration—that denotes the completion of a set of related
phases, tasks, or Projects. The following figure shows the hierarchy of Project objects.
Figure 18: Program hierarchy
You can use the IAgileSession.createObject() method to create phases, tasks, and gates
in the same way that you create other Project objects. Once you create these different types of
activities, you can add them to the Schedule table of a Projects object. For more information, see
Scheduling Projects on page 244.
SDK Developer Guide - Using Agile APIs
238 Agile Product Lifecycle Management
Adding Rules for PPM Objects
In PLM, any object that is assigned a lifecycle phase or a workflow can be added as a deliverable.
The only exceptions are Discussions, Users, and User groups.
Rules in PPM ensure an activity will not complete before the completion of the preceding activity as
set in the workflow, or lifecycle phase. For example, if you want to ensure the completion of an
activity before a Gate is opened, you can add that activity as a deliverable for the Gate to open. You
can even restrict one Gate from opening before another by adding the prior Gate as a deliverable
for the subsequent Gate to open. For more information, refer to the Agile PLM Product Portfolio
Management User Guide.
The SDK supports this function with IProgram interface as shown in the following example.
Example: Setting rules for PPM objects
try{
//Get Program
IProgram pgm =
(IProgram)session.getObject
(ProgramConstants.CLASS_PROGRAM,"PGM00239");
//Get Object and add as relationship under Content tab
IChange eco = (IChange)session.getObject
(ChangeConstants.CLASS_ECO,"C00060");
ITable table = pgm.getTable
(ProgramConstants.TABLE_RELATIONSHIPS);
IRow row = table.createRow(eco);
//Get the Control object status
IStateful state = (IStateful)pgm;
IStatus[] statuses = state.getStates();
IStatus ctl_status = null;
for(int i=0; i<statuses.length; i++){
if(statuses[i].getName().equals("In Process")){
ctl_status = statuses[i];
break;
}
}
//Get the Affected object status
state = (IStateful)eco;
statuses = state.getStates();
IStatus aff_status = null;
for(int i=0; i<statuses.length; i++){
if(statuses[i].getName().equals("Submitted")){
aff_status = statuses[i];
break;
}
}
//Add Rule
HashMap map = new HashMap();
map.put(CommonConstants.ATT_RELATIONSHIPS_RULE_CONTROLOBJECT, pgm);
map.put(CommonConstants.ATT_RELATIONSHIPS_RULE_AFFECTEDOBJECT, eco);
map.put(CommonConstants.ATT_RELATIONSHIPS_RULE_CONTROLOBJECTSTATUS,
ctl_status);
map.put(CommonConstants.ATT_RELATIONSHIPS_RULE_AFFECTEDOBJECTSTATUS,
aff_status);
Chapter 16: Creating and Managing Projects
v9.3.1.2 239
row.setValue(CommonConstants.ATT_RELATIONSHIPS_RULE, map);
System.out.println(row.getCell
(CommonConstants.ATT_RELATIONSHIPS_RULE));
}catch (APIException ex) {
System.out.println(ex);
}
Loading Projects
To load Projects, use the IAgileSession.getObject() method. To uniquely identify a Project
object, specify the value for the General Info.Number attribute. You can also load a Projec
object by searching for it by name, and then selecting it from the search results.
Note The IProgram.getName() method actually returns the value of the General
Info.Number attribute, not General Info.Name.
Example: Loading Projects
public IProgram loadProgram(String number) throws APIException {
IProgram program =
(IProgram)m_session.getObject(IProgram.OBJECT_TYPE, number);
return program;
}
Note The News table for Projects is disabled by default. To enable it, log in to the Java Client
as an Administrator and make the News tab visible.
Adding "FileFolder" to Project's Content Tab
You can add FileFolders to the Content tab of a Project using the IProgram API. The following
example shows how to perform this task.
Example: Adding FileFolder to the Content tab of a Project
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.agile.api.*;
public class Sample {
public static void main(String[] args) {
try{
Sample sample = new Sample();
String url = "
http://localhost:8888/web";
String userName = "admin";
SDK Developer Guide - Using Agile APIs
240 Agile Product Lifecycle Management
String password = "agile";
AgileSessionFactory instance =
AgileSessionFactory.getInstance(url);
HashMap params = new HashMap();
params.put(AgileSessionFactory.USERNAME, userName);
params.put(AgileSessionFactory.PASSWORD, password);
IAgileSession session =
instance.createSession(params);
IFileFolder ff = createFileFolder(session);
System.out.println(ff.getName());
// Add file to Files table
addFile2FileFolder(session,ff);
// Add filefolder to contents tab
sample.uploadFile(session,ff.getName());
}catch(Throwable th){
th.printStackTrace();
}
}
/**
* Upload attachment to Contents tab of a Program
*
* @param session
* @throws APIException
*/
private void uploadFile(IAgileSession session,String foldname)
throws APIException {
IProgram program = (IProgram)
session.getObject(IProgram.OBJECT_TYPE, "PGM00041");
IFileFolder ff = (IFileFolder)
session.getObject(IFileFolder.OBJECT_TYPE, foldname);
//Upload filefolder to Conents table
ITable table =
program.getTable(ProgramConstants.TABLE_RELATIONSHIPS);
table.createRow(ff);
}
/**
* Upload attachment to FileFolder
*
* @param session
* @param foldername
* @throws APIException
*/
private static void addFile2FileFolder(IAgileSession session,
IFileFolder ff) throws APIException {
Chapter 16: Creating and Managing Projects
v9.3.1.2 241
ff.checkOut();
ITable table = ff.getTable(FileFolderConstants.TABLE_FILES);
String path = "C:\\temp\\out3.txt";
File file = new File(path);
table.createRow(file);
ff.checkIn();
System.out.println("Finish");
}
private static IFileFolder createFileFolder(IAgileSession session)
throws APIException {
IAgileClass objClass =
session.getAdminInstance().getAgileClass(
FileFolderConstants.CLASS_FILE_FOLDER);
IAutoNumber autoNumber = objClass.getAutoNumberSources()[0];
IFileFolder obj = (IFileFolder)session.createObject(
FileFolderConstants.CLASS_FILE_FOLDER,
autoNumber);
return obj;
}
}
Using Project Templates
Project templates make it easy to define a new Project object, activity, or task. A template is a
Project with the General Info.Template attribute set to “Template”. You can use a template to
create a new Project by loading it and then using the IProgram.saveAs() method.
This special version of the saveAs() method enables to use the SDK to:
à Create a new Project from a template and specify the tables that you want copied over
à Change the owner of the Project and the owner of the children
à Create a new Project template by saving a Project as a template
Creating New Projects Using Templates
You can use this special version of the saveAs() method to specify the Project tables that you
want to copy from the original Project to the new Project. You don’t need to specify all tables. The
General Info, Schedule, Dependencies - Dependent Upon, Dependencies - Required For, and
Workflow tables are copied automatically. The Discussion, News, and History tables cannot be
copied. Generally, you should copy Page Two, Page Three (if it’s used), and the Team table, as
shown in the example below.
Example: Creating a new Project from a template
try {
// Get the Project template whose number is PGM00004
SDK Developer Guide - Using Agile APIs
242 Agile Product Lifecycle Management
IProgram template =
(IProgram)m_session.getObject(IProgram.OBJECT_TYPE, "PGM00004");
if (template != null) {
// Create a hash map of the program attributes to use for the new
program
HashMap map = new HashMap();
String name = "Scorpio Program";
IAttribute att =
m_admin.getAgileClass(ProgramConstants.CLASS_PROGRAM).getAttribute(
ProgramConstants.ATT_GENERAL_INFO_TEMPLATE);
IAgileList templateList = att.getAvailableValues();
// Note: Available values for the Template attribute are Active,
Proposed, and Template
templateList.setSelection(new Object[] {"Active"});
map.put(ProgramConstants.ATT_GENERAL_INFO_NAME, name);
map.put(ProgramConstants.ATT_GENERAL_INFO_SCHEDULE_START_DATE, new
Date());
map.put(ProgramConstants.ATT_GENERAL_INFO_TEMPLATE, templateList);
// Define the tables to copy to the new program from the template
Integer pagetwo = ProgramConstants.TABLE_PAGETWO;
Integer pagethree = ProgramConstants.TABLE_PAGETHREE;
Integer team = ProgramConstants.TABLE_TEAM;
Object[] tables = new Object[]{pagetwo, pagethree, team};
// Save the template as a new program
IProgram program =
(IProgram)template.saveAs(ProgramConstants.CLASS_PROGRAM,t
ables, map);
}
} catch (APIException ex) {
System.out.println(ex);
}
Creating Projects and Changing Ownerships
When you create a Project from a template using the saveAs() API call, you can change the
ownership of the Project and propagate the change to the children of the Project. In SDK, the
exposed API is used to accomplish this:
public IAgileObject saveAs(Object type, Object[] tablesToCopy,Object
params, boolean applyToChildren)
throws APIException;
This is done by specifying a value for both the ProgramConstants and the OWNER attributes. The
value for the OWNER attribute is required in order to change the Project's ownership. Set the
Boolean applyToChildren to true if you want to apply the OWNER value to all children.
In the UI, when you create a Project from a template, you have the option to change ownership of
the Project and apply the change to the children. In this situation, the SDK mirrors the UI. However,
the original Project must be a Template to create a Project from a template via SDK's
saveAs()API.
Note In the SDK, a Project is a template when the value of the General Info.Template
attribute in the original program is set to Template.
Chapter 16: Creating and Managing Projects
v9.3.1.2 243
Example: Creating a Project from a template, change owner, and propagate change
public IProgram saveTemplateAndSetOwner (IProgram template, String
userID, boolean applyToChildren) throws APIException {
/* "template" is a program template
userID -- The "userID" of the user that
is specified as the owner of the Saved program object
applyToChildren -- true or false.
If "true" the "specified owner" will be the owner of the entire
program tree
If "false", the specified owner will be the owner of the Root Parent
object only
*/
HashMap map = new HashMap () ;
String newPgmName =
"PROG" + System.currentTimeMillis() ; // Generate a random name for
the Saved Program object
IUser user =
session.getObject(UserConstants.CLASS_USER, userID) ;
map.put(ProgramConstants.ATT_GENERAL_INFO_NAME, newPgmName);
map.put(ProgramConstants.ATT_GENERAL_INFO_OWNER, user);
map.put(ProgramConstants.ATT_GENERAL_INFO_SCHEDULE_START_DATE, new
Date());
// Define the tables to copy from the template
// If you do not want any tables to be copied,
// specify "null" for the "tables" param
Integer pageTwo = ProgramConstants.TABLE_PAGETWO ;
Integer pageThree = ProgramConstants.TABLE_PAGETHREE ;
Integer team = ProgramConstants.TABLE_TEAM ;
Object[] tables =
{ pageTwo, pageThree, team } ;
IProgram pgm =
(IProgram) root.saveAs(ProgramConstants.CLASS_PROGRAM, tables, map,
applyToChildren);
System.out.println
("New Program Number = " + pgm.getName()) ;
System.out.println
("Owner Value = " +
pgm.getValue(ProgramConstants.ATT_GENERAL_INFO_OWNER).toString())
return pgm ;
}
Saving Projects as Templates
When you create a Project, you can specify that it’s a template by setting the value of the Template
attribute (ProgramConstants.ATT_GENERAL_INFO_TEMPLATE) to “Template”. You can only do
this when you create a Project or when you save it as a new Project. Existing Projects cannot be
changed from the “Active” or “Proposed” state to “Template”.
SDK Developer Guide - Using Agile APIs
244 Agile Product Lifecycle Management
The following example shows how to open a Project object and save it as a template.
Example: Saving a Projects object as a template
try {
// Get the program whose number is PGM00005
IProgram program =
(IProgram)m_session.getObject(IProgram.OBJECT_TYPE, "PGM00005");
if (program != null) {
// Create a hash map of the program attributes to use for the new
program
HashMap map = new HashMap();
String name = "Rapid Development");
IAttribute att =
m_admin.getAgileClass(ProgramConstants.CLASS_PROGRAM).getAttribute(P
rogramConstants.ATT_GENERAL_INFO_TEMPLATE);
IAgileList templateList =
att.getAvailableValues();
// Note: Available values for the Template attribute
are Active, Proposed, and Template
templateList.setSelection(new Object[] {"Template"});
map.put(ProgramConstants.ATT_GENERAL_INFO_NAME, name);
map.put(ProgramConstants.ATT_GENERAL_INFO_SCHEDULE_START_DATE, new
Date());
map.put(ProgramConstants.ATT_GENERAL_INFO_TEMPLATE, templateList);
//Define the tables to copy to the template
Integer pagetwo =
ProgramConstants.TABLE_PAGETWO;
Integer pagethree =
ProgramConstants.TABLE_PAGETHREE;
Integer team =
ProgramConstants.TABLE_TEAM;
Object[] tables =
new Object[]{pagetwo, pagethree, team};
// Save the program as a template
IProgram program =
(IProgram)template.saveAs(ProgramConstants.CLASS_PROGRAM,
tables, map);
}
} catch (APIException ex) {
System.out.println(ex);
}
Scheduling Projects
To schedule Projects, edit the Schedule table, which lets you add, edit, and remove schedule items.
To add a new row to the Schedule table, use the ITable.createRow() method and specify an
IProgram object for the parameter.
Example: Modifying the Schedule table
try {
// Define a row variable
Chapter 16: Creating and Managing Projects
v9.3.1.2 245
IRow row = null;
// Set the date format
DateFormat df = new SimpleDateFormat("MM/dd/yy");
// Get a Project
IProgram program =
(IProgram)m_session.getObject(ProgramConstants.CLASS_PROGRAM,
"PGM00012");
if (program != null) {
// Get the Schedule table
ITable schedule =
program.getTable(ProgramConstants.TABLE_SCHEDULE);
Iterator i = schedule.iterator();
// Find task T000452 and remove it
while (i.hasNext()) {
row = (IRow)i.next();
String num =
(String)row.getValue(ProgramConstants.ATT_GENERAL_INFO_NUMBER);
if (num.equals("T000452")) {
schedule.removeRow(row);
break;
}
}
// Add a phase
HashMap info = new HashMap();
info.put(ProgramConstants.ATT_GENERAL_INFO_NAME, "Specifications
phase");
info.put(ProgramConstants.ATT_GENERAL_INFO_SCHEDULE_START_DATE,
df.parse("06/01/05"));
info.put(ProgramConstants.ATT_GENERAL_INFO_SCHEDULE_END_DATE,
df.parse("06/10/05"));
IAttribute attr =
m_admin.getAgileClass(ProgramConstants.CLASS_PHASE).
getAttribute(ProgramConstants.ATT_GENERAL_INFO_DURATION_TYPE);
IAgileList list = attr.getAvailableValues();
list.setSelection(new Object[] {"Fixed"});
info.put(ProgramConstants.ATT_GENERAL_INFO_DURATION_TYPE, list);
IProgram phase =
(IProgram)m_session.createObject(ProgramConstants.CLASS_PHASE,
info);
row = schedule.createRow(phase);
// Add a task
info = null;
list = null;
info.put(ProgramConstants.ATT_GENERAL_INFO_NAME, "Write
specifications");
info.put(ProgramConstants.ATT_GENERAL_INFO_NUMBER, "T000533");
info.put(ProgramConstants.ATT_GENERAL_INFO_SCHEDULE_START_DATE,
df.parse("06/01/05"));
info.put(ProgramConstants.ATT_GENERAL_INFO_SCHEDULE_END_DATE,
df.parse("06/05/05"));
attr = m_admin.getAgileClass(ProgramConstants.CLASS_TASK).
getAttribute(ProgramConstants.ATT_GENERAL_INFO_DURATION_TYPE);
list = attr.getAvailableValues();
list.setSelection(new Object[] {"Fixed"});
info.put(ProgramConstants.ATT_GENERAL_INFO_DURATION_TYPE, list);
IProgram task =
(IProgram)m_session.createObject(ProgramConstants.CLASS_TASK, info);
row = schedule.createRow(task);
SDK Developer Guide - Using Agile APIs
246 Agile Product Lifecycle Management
// Add a gate
info = null;
info.put(ProgramConstants.ATT_GENERAL_INFO_NAME, "Specifications
complete");
info.put(ProgramConstants.ATT_GENERAL_INFO_SCHEDULE_END_DATE,
df.parse("06/10/05"));
IProgram gate =
(IProgram)m_session.createObject(ProgramConstants.CLASS_GATE, info);
row = schedule.createRow(gate);
}
} catch (APIException ex) {
System.out.println(ex);
}
Once a Project's schedule is defined, you can reschedule it using the IProgram.reschedule()
method. The reschedule() method takes a couple of parameters, the IProgram.RESCHEDULE
constant and the new value for that schedule option. Here are the list of IProgram.RESCHEDULE
constants you can use:
à STARTDATE – This moves the scheduled start date to the specified date.
à ENDDATE – This moves the scheduled end date to the specified date.
à BACKWARDDAYS – This moves the schedule backward by the specified number of days.
à FORWARDDAYS – This moves the schedule forward by the specified number of days.
Example: Rescheduling Projects
try {
// Get a Project
IProgram program =
(IProgram)m_session.getObject(IProgram.OBJECT_TYPE,
"PGM00012");
if (program != null) {
// Define new start and end dates
String startDate = "02/01/2005 GMT";
String endDate = "06/01/2005 GMT";
SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy z");
Date start = df.parse(startDate);
Date end = df.parse(endDate);
// Change the schedule start date
program.reschedule(IProgram.RESCHEDULE.STARTDATE, start);
// Change the schedule end date
program.reschedule(IProgram.RESCHEDULE.ENDDATE, end);
// Move the schedule backward three days
program.reschedule(IProgram.RESCHEDULE.BACKWARDDAYS, new
Integer(3));
// Move the schedule forward two days
program.reschedule(IProgram.RESCHEDULE.FORWARDDAYS, new Integer(2));
}
} catch (Exception ex) {
System.out.println(ex);
}
Chapter 16: Creating and Managing Projects
v9.3.1.2 247
Setting Start and End Timestamps for PPM Date
Attributes
Start and End timestamps are automatically set for PPM Date attributes when the end user creates
or edits a scheduled PPM task. You can schedule PPM tasks in Working Time, which is
configurable in the agile.properties file. When creating or editing PPM objects, the end user
must specify a valid date for Working Time within the Start and End values set in
agile.properties file for the following PPM Date attributes:
à Schedule
à Estimated
à Actual
Note If the specified time for the above Date attributes is not within the Start and End values
set in agile.properties, PPM will not complete the end user's operation. For
example, if the Start and End values in agile.properties are 8:00 AM and 6:00 PM
and those specified by the user are different, PPM will not complete the applicable
operation.
The environment variable (flag) called ppm.date.appendtime automatically sets the appropriate
time for PPM's Schedule, Estimated, or Actual dates before sending these values to the Agile
server to update the Date attribute. When the flag is turned on, the existing time in the date value
for Schedule, Estimated, or Actual dates is ignored and is automatically set according to the
following rules:
à If the attribute is Schedule Start Date, Estimated Start Date or Actual Start Date, then the start
working time of the day set in agile.properties is appended. For example, if the working
time in agile.properties is configured as 8:00:00-12:00:00, 13:00:00-17:00:00, then the
start working time for the day is 8 AM. The time portion in the date value for start date attributes
is set to 8 AM.
à If the attribute is Schedule End Date, Estimated End Date or Actual End Date, then the end
working time of the day set in agile.properties is appended. For example, if the working
time in agile.properties is configured as 8:00:00-12:00:00, 13:00:00-17:00:00, then the
end working time for the day is 5 PM. The time portion in the date value for end date attributes
is set to 5 PM.
By default, the value of the ppm.date.appendtime flag is set to True. This is to ensure backward
compatibility of PPM SDK so that SDK Clients compiled in earlier releases can execute without
recompilation.
Example: To set timestamp for PPM date attributes in SDK Client:
You have the following options:
à Set the ppm.date.appendtime flag to False using syntax such as java -
Dppm.date.appendtime=false <SDK Program Name>
OR,
à Set an environment variable called ppm.date.appendtime and execute the SDK program.
SDK Developer Guide - Using Agile APIs
248 Agile Product Lifecycle Management
Note This is a global setting and the setting will apply to all SDK programs that are running on
the given platform.
Working with Projects Baselines
Project baselines allow you to compare actual progress with your original plans. When you create a
baseline, a snapshot of your Project's schedule is preserved. The original estimates contained in
the baseline are permanent reference points against which you can compare the updated task
structure, schedule, and actual dates.
Baselines can be created only for the root Project object. You can save multiple baselines, and
retrieve them later for comparison. The IProgram interface provides the following methods for
creating, retrieving, and removing baselines:
à createBaseline(java.lang.Object)
à getBaseline()
à getBaselines()
à removeBaseline(java.lang.Object)
à selectBaseline(java.lang.Object)
Example: Creating and retrieving baselines
try {
// Get a Project
IProgram program =
(IProgram)m_session.getObject(IProgram.OBJECT_TYPE, "PGM00012");
if (program != null) {
// Create a baseline
Object baseline = program.createBaseline("august 8 baseline");
// Get all baselines
Map map = program.getBaselines();
// Get the first baseline
Set keys = map.keySet();
Object[] objs = keys.toArray();
baseline = map.get(objs[0]);
// Remove the first baseline
program.removeBaseline(baseline);
// Get all baselines again
map = program.getBaselines();
// Select the first baseline
If (map.size() > 0) {
keys = map.keySet();
Chapter 16: Creating and Managing Projects
v9.3.1.2 249
objs = keys.toArray();
baseline = map.get(objs[0]);
program.selectBaseline(baseline);
}
}
} catch (APIException ex) {
System.out.println(ex);
}
Delegating Ownership of a Projects to Another User
The owner or manager of a Project object can assign the ownership of the Project to other users by
delegating it. The delegated user receives a request that he can accept or decline. If he accepts,
the delegated user becomes owner of the task. A delegated owner is automatically given the
Project Manager role for the delegated Project object.
To delegate ownership of a Project, use the IProgram.delegateOwnership() method. When
you delegate ownership of a Project, you automatically update the Delegated Owner field, which is
read-only. The delegateOwnership() method lets you specify whether delegated ownership
also applies to the Project's children.
Example: Delegating ownership of a Project object
try {
// Get the task whose number is T00012
IProgram task = (IProgram)m_session.getObject(IProgram.OBJECT_TYPE,
"T00012");
if (task != null) {
// Get a user
IUser user1 = (IUser)m_session.getObject(UserConstants.CLASS_USER,
"kkieslowski");
if (user1 != null) {
// Delegate the task to the user
task.delegateOwnership(user1, false);
}
}
} catch (APIException ex) {
System.out.println(ex);
}
Adding Resources to a Projects Team
The Team table lets you manage the team member list for a Project object. You can add or remove
team members, change team members’ roles, and change their allocation. You must have the
appropriate privileges to modify a Project's Team table.
When you add a resource to the Team table, you specify what roles the user or user group has for
that Project object. The roles available are not the complete set of Agile PLM roles; they are roles
specifically related to Project functionality. Here is the list of roles you can assign to team members:
SDK Developer Guide - Using Agile APIs
250 Agile Product Lifecycle Management
à Executive
à Change Analyst
à Program Team Member
à Program Manager
à Resource Pool Owner
à Program Administrator
For a description of each of these roles, refer to the Agile PLM Administrator Guide.
The Team table has two attributes that require special mention:
à ProgramConstants.ATT_TEAM_NAME
à ProgramConstants.ATT_TEAM_ROLES.
These are SingleList and MultiList attributes, respectively. To get the available values for these
attributes, use ITable.getAvailableValues() instead of
IAttribute.getAvailableValues(). Otherwise, the IAgileList object returned from the
method may contain invalid list values.
Example: Adding resources to a Project team
try {
// Get users
IUser user1 = (IUser)session.getObject(UserConstants.CLASS_USER,
"daveo");
IUser user2 = (IUser)session.getObject(UserConstants.CLASS_USER,
"yvonnec");
IUser user3 = (IUser)session.getObject(UserConstants.CLASS_USER,
"albertl");
IUser user4 = (IUser)session.getObject(UserConstants.CLASS_USER,
"brians");
// Get a resource pool (user group)
IUserGroup pool =
(IUserGroup)session.getObject(IUserGroup.OBJECT_TYPE, "Development");
// Add all four users to the resource pool
ITable usersTable =
pool.getTable(UserGroupConstants.TABLE_USERS);
usersTable.createRow(user1);
usersTable.createRow(user2);
usersTable.createRow(user3);
usersTable.createRow(user4);
// Get a Project
IProgram program =
(IProgram)session.getObject(IProgram.OBJECT_TYPE, "PGM02423");
if (program != null) {
Chapter 16: Creating and Managing Projects
v9.3.1.2 251
// Get the Team table of the program
ITable teamTable = program.getTable(ProgramConstants.TABLE_TEAM);
// Get Roles attribute values (use ITable.getAvailableValues)
IAgileList attrRolesValues =
teamTable.getAvailableValues(ProgramConstants.ATT_TEAM_ROLES);
// Create a hash map to hold values for row attributes
Map map = new HashMap();
// Add the first user to the team
attrRolesValues.setSelection(new Object[]{"Change
Analyst","Projects Manager"});
map.put(ProgramConstants.ATT_TEAM_NAME, user1);
map.put(ProgramConstants.ATT_TEAM_ROLES, attrRolesValues);
IRow row1 = teamTable.createRow(map);
// Add the second user to the team
attrRolesValues.setSelection(new Object[]{"Projects
Administrator"});
map.put(ProgramConstants.ATT_TEAM_NAME, user2);
IRow row2 = teamTable.createRow(map);
// Add the resource pool to the team
attrRolesValues.setSelection(new Object[]{"Projects Team Member"});
map.put(ProgramConstants.ATT_TEAM_NAME, pool);
IRow row3 = teamTable.createRow(map);
}
In Agile Web Client, when you add a resource pool to the Team table, you can replace the pool with
one or more resources contained within it. In other words, instead of assigning the entire resource
pool, you can assign select users from the pool. The IProgram.assignUsersFromPool()
method reproduces this functionality. To use assignUsersFromPool(), you must specify a user
group that has already been added to the Project's Team table.
Example: Assigning users from a resource pool
public void replaceUserGroupWithUser(IProgram program) throws Exception
{
// Get the Team table
ITable teamTable = program.getTable(ProgramConstants.TABLE_TEAM);
// Get a table iterator
Iterator it = teamTable.iterator();
// Find a user group and replace it with one of its members, kwong
while(it.hasNext()){
IRow row = (IRow)it.next();
IDataObject object = row.getReferent();
if(object instanceof IUserGroup){
IUserGroup ug = (IUserGroup)object;
ITable users = ug.getTable(UserGroupConstants.TABLE_USERS);
Iterator ref_it = users.getReferentIterator();
while(ref_it.hasNext()){
IUser user = (IUser)ref_it.next();
if(user.getName().equals("kwong")) {
SDK Developer Guide - Using Agile APIs
252 Agile Product Lifecycle Management
program.assignUsersFromPool(new IUser[]{user}, ug, true);
break;
}
}
}
}
}
Substituting Project Resources
A resource’s availability can frequently change due to overloading, reassignments, vacation, and
illness. You can substitute an existing resource for another resource. The current resource’s role is
assigned to the substituted resource, but only for that Project. To substitute Project resources, use
the IProgram.substituteResource() method.
When you substitute resources, you can specify users as well as user groups. You can also specify
whether the resource assignment applies to the Project's children.
Example: Substituting Project resources
try {
// Get a Project
IProgram program =
(IProgram)m_session.getObject(IProgram.OBJECT_TYPE, "PGM00012");
if (program != null) {
// Get users
IUser u1 =
(IUser)m_session.getObject(UserConstants.CLASS_USER, "akurosawa");
IUser u2 =
(IUser)m_session.getObject(UserConstants.CLASS_USER, "creed");
IUser u3 =
(IUser)m_session.getObject(UserConstants.CLASS_USER, "dlean");
IUser u4 =
(IUser)m_session.getObject(UserConstants.CLASS_USER, "jford");
// Get a user group
IUserGroup ug =
(IUserGroup)m_session.getObject(IUserGroup.OBJECT_TYPE,
"Directors");
// Substitute u1 with u3 and do not apply to children
program.substituteResource(u1, u3, false);
// Substitute u2 with u4 and apply to children
program.substituteResource(u2, u4, true);
// Substituete u4 with a user group, and apply to children
program.substituteResource(u4, ug, true);
}
} catch (APIException ex) {
System.out.println(ex);
}
Chapter 16: Creating and Managing Projects
v9.3.1.2 253
Locking or Unlocking Projects
The owner of Project can lock or unlock the Project object. When a Projects is locked, its schedule
cannot be modified. To lock or unlock a Project, use the IProgram.setLock() method.
Note Projects are automatically locked when you use the Gantt Chart or the Microsoft Project
integration functionality in Agile Web Client.
Example: Locking Projects
try {
// Get a Program
IProgram program =
(IProgram)m_session.getObject(IProgram.OBJECT_TYPE, "PGM00012");
if (program != null) {
// Lock it
program.setLock(true);
}
} catch (APIException ex) {
System.out.println(ex);
}
Working with Discussions
During the course of a project, issues arise that require users to collaborate and exchange
information. Agile PLM provides threaded discussion functionality that allows team members to
reply with their feedback, providing a record of their thoughts and ideas. Discussions are
asynchronous; that is, they do not require a simultaneous connection from all discussion
participants. People can reply to any thread of the discussion independently. To close issues, action
items can be assigned to team resources. The Discussion object is used to manage both threaded
discussions and the action items related to them.
Discussion objects, unlike Projects, are not routable objects. Therefore, discussions do not have
workflows associated with them.
Note The Action Items, Cover Page, and Replies tables appear on the Discussion tab in Agile
PLM clients. The Page Two table appears on the Details tab in Agile PLM clients. The
Where Used table is not supported, its functionality is replaced by General
Info.Related To field.
Creating a Discussion
To create a discussion, use the IAgileSession.createObject() method. When you specify
discussion parameters, you must specify the discussion subclass and the following required
discussion attributes:
à Cover Page.Number
à Cover Page.Subject
SDK Developer Guide - Using Agile APIs
254 Agile Product Lifecycle Management
In addition, you must also specify data for the Cover Page.Notify List and Cover Page.Message attributes.
Otherwise, the discussion does not have a Notification list, or a message that users can respond to.
The following example shows how to create a new discussion and add it to the Discussion table of a
Project.
Example: Creating a discussion
try {
// Create a hash map variable
Map map = new HashMap();
// Set the Number field
IAgileClass discussionClass =
m_session.getAdminInstance().getAgileClass(
DiscussionConstants.CLASS_DISCUSSION);
String number =
discussionClass.getAutoNumberSources()[0].getNextNumber();
// Set the Subject field
String subject = "Packaging issues";
// Make the Message field visible
IAttribute attr =
discussionClass.getAttribute(DiscussionConstants.ATT_COVER_PAGE_MESSAGE
);
IProperty propVisible =
attr.getProperty(PropertyConstants.PROP_VISIBLE);
IAgileList list = propVisible.getAvailableValues();
list.setSelection(new Object[] { "Yes" });
// Set the Message field
String message = "We still have problems with the sleeves and
inserts." +
"Let's resolve these things at the team meeting on
Friday.";
// Set the Notify List field
IUser user1 = m_session.getCurrentUser();
IUser user2 = (IUser)m_session.getObject(UserConstants.CLASS_USER,
"jdassin");
attr =
discussionClass.getAttribute(DiscussionConstants.ATT_COVER_PAGE_NOTIFY_
LIST);
list = attr.getAvailableValues();
list.setSelection(new Object[] {user1, user2});
// Put the values into the hash map
map.put(DiscussionConstants.ATT_COVER_PAGE_NUMBER, number);
map.put(DiscussionConstants.ATT_COVER_PAGE_SUBJECT, subject);
map.put(DiscussionConstants.ATT_COVER_PAGE_MESSAGE, message);
map.put(DiscussionConstants.ATT_COVER_PAGE_NOTIFY_LIST, list);
// Create a Discussion object
IDiscussion discussion = (IDiscussion)m_session.createObject(
Chapter 16: Creating and Managing Projects
v9.3.1.2 255
DiscussionConstants.CLASS_DISCUSSION, map);
// Get a Projects
IProgram program =
(IProgram)m_session.getObject(IProgram.OBJECT_TYPE, "PGM00012");
if (program != null) {
// Get the Discussion table
ITable discTable =
program.getTable(ProgramConstants.TABLE_DISCUSSION);
// Add the new discussion to the table
discTable.createRow(discussion);
}
} catch (APIException ex) {
System.out.println(ex);
}
Replying to a Discussion
Team members or notified users—that is, users listed in the Cover Page.Notified List field of a
discussion—can reply to discussions. When you reply to a discussion, you create another nested
table in the Replies table.
Example: Replying to a discussion
private void replyToDiscussion() throws Exception {
Iterator it;
IDiscussion discussion;
// Get a Project
IProgram program =
(IProgram)m_session.getObject(IProgram.OBJECT_TYPE, "PGM00012");
// Get the Discussion table
ITable discTable =
program.getTable(ProgramConstants.TABLE_DISCUSSION);
// Get the first Discussion listed
if (discTable.size()!=0) {
it = discTable.iterator();
if (it.hasNext()) {
IRow row = (IRow)it.next();
discussion = (IDiscussion)row.getReferent();
}
// Get the Replies table
ITable repliesTable =
discussion.getTable(DiscussionConstants.TABLE_REPLIES);
// Iterate to the only row of the Replies table and send a reply
it = repliesTable.iterator();
if (it.hasNext()) {
IRow row = (IRow)it.next();
IMessage message = (IMessage)row;
HashMap response = new HashMap();
// Set the Subject field (use the same Subject as the parent)
response.put(MessageConstants.ATT_COVERPAGE_SUBJECT,
SDK Developer Guide - Using Agile APIs
256 Agile Product Lifecycle Management
row.getValue(DiscussionConstants.ATT_REPLIES_SUBJECT));
// Make the Message field visible
IAgileClass discussionClass =
m_session.getAdminInstance().getAgileClass(DiscussionConstants.CL
ASS_DISCUSSION);
IAttribute attr =
discussionClass.getAttribute(DiscussionConstants.ATT_COVER_PAGE_M
ESSAGE);
IProperty propVisible =
attr.getProperty(PropertyConstants.PROP_VISIBLE);
IAgileList list =
propVisible.getAvailableValues();
list.setSelection(new Object[] { "Yes" });
// Set the Message field
response.put(MessageConstants.ATT_COVERPAGE_MESSAGE,
"The spec needs to be updated to reflect the latest decisions.");
// Send a reply
message.reply(response);
}
}
}
The previous example showed how to reply to the root discussion. But what if a discussion has
several replies and you want to reply to the latest one? That is a little more complicated, and
requires further understanding of the Replies table.
The Replies table of a discussion is different from other Agile PLM tables. It contains only one row,
even if there are multiple replies. If the discussion has multiple replies, they are contained within a
series of nested tables. To select the latest reply, expand the Replies table to its last nested table.
The following figure shows an expanded Replies table in Agile Web Client.
Figure 19: Expanded Replies table
You can use a recursive method (one that calls itself) to expand all levels of the Replies table, as
shown in the following example. Subsequent levels of the Replies table are obtained by getting the
value of the Child Table attribute (DiscussionConstants.ATT_REPLIES_CHILD_TABLE).
Example: How to expand the Replies table
// Read the Replies table
public void readRepliesTable(IDiscussion discussion) throws Exception {
ITable replies =
discussion.getTable(DiscussionConstants.TABLE_REPLIES);
browseReplies(0, replies);
}
// Recursively browse through all levels of the Replies table
void browseReplies(int indent, ITable replies) throws Exception {
Iterator i = replies.iterator();
while (i.hasNext()) {
IRow row = (IRow) i.next();
Chapter 16: Creating and Managing Projects
v9.3.1.2 257
System.out.print(indent(indent*4));
readRow(row);
System.out.println();
ITable followup =
(ITable)row.getValue(DiscussionConstants.ATT_REPLIES_CHILD_TABLE);
browseReplies(indent + 1, followup);
}
}
// Read each cell in the row and print the attribute name and value
static protected void readRow(IRow row) throws Exception {
ICell[] cells = row.getCells();
for (int j = 0; j < cells.length; ++j) {
Object value = cells[j].getValue();
System.out.print( "\t" + cells[j].getAttribute().getName() + "="+
value);
}
}
// Indent text
private String indent(int level) {
if (level <= 0) {
return "";
}
char c[] = new char[level*2];
Arrays.fill(c, ' ');
return new String(c);
}
Joining a Discussion
Agile Web Client allows users to join a discussion by clicking the Discussion tab of a Project, and
then clicking the Join button. When you join a discussion, your username is added to the Notify List
field of the Discussion object. To join a discussion using the Agile API, simply add yourself to the
Notify List field. You can join a discussion only if you are a team member of the Project.
Note If you are not on the Notify List of a Discussion object, you cannot read the replies.
However, anyone listed on the Team table of a Projects can join a discussion associated
with that Project.
Example: Joining a discussion
try {
// Get a Project
IProgram program =
(IProgram)m_session.getObject(ProgramConstants.CLASS_PROGRAM,
"PGM00012");
if (program != null) {
// Get the Discussion table
ITable discTable =
program.getTable(ProgramConstants.TABLE_DISCUSSION);
// Get the first discussion
IRow row =
(IRow)discTable.iterator().next();
IDiscussion discussion =
SDK Developer Guide - Using Agile APIs
258 Agile Product Lifecycle Management
(IDiscussion)row.getReferent();
// Add yourself and another user to the Notify List field
IUser user1 =
m_session.getCurrentUser();
IUser user2 =
(IUser)m_session.getObject(UserConstants.CLASS_USER, "owelles");
ICell cell =
discussion.getCell(DiscussionConstants.ATT_COVER_PAGE_NOTIFY_LIST);
IAgileList list =
(IAgileList)cell.getAvailableValues();
list.setSelection(new Object[] {user1, user2});
}
} catch (APIException ex) {
System.out.println(ex);
}
Creating an Action Item
Action items can be created as part of a Discussion object. If a discussion raises an issue that
requires someone to perform an action, you can assign that action to another user. Action items
have a subject, status, due date, and an assigned user. When you create an action item, it appears
in the Notifications & Requests Inbox of the assigned user.
To create an action item, use the ITable.createRow() method to add a row to the Action Items
table of a Project object. Make sure the map object used to initialize the row contains parameters
for the Subject, Assigned To, and Due Date fields.
Example: Creating an action item
private void replyToDiscussion() throws Exception {
// Get a Project
IProgram program =
(IProgram)m_session.getObject(IProgram.OBJECT_TYPE, "PGM00012");
if (program != null) {
// Create a hash map for Action Item parameters
HashMap map = new HashMap();
// Set the Subject field
String subj = "Update packaging requirements";
map.put(ProgramConstants.ATT_ACTION_ITEMS_SUBJECT, subj);
// Set the Assigned To field
IUser user1 = (IUser)m_session.getObject(UserConstants.CLASS_USER,
"akurosawa");
IAttribute attr = m_session.getAdminInstance().getAgileClass(
ProgramConstants.CLASS_PROGRAM).getAttribute(
ProgramConstants.ATT_ACTION_ITEMS_ASSIGNED_TO);
IAgileList list = attr.getAvailableValues();
list.setSelection(new Object[] {user1});
map.put(ProgramConstants.ATT_ACTION_ITEMS_ASSIGNED_TO, list);
Chapter 16: Creating and Managing Projects
v9.3.1.2 259
// Set the Due Date field
DateFormat df = new SimpleDateFormat("MM/dd/yy");
map.put(ProgramConstants.ATT_ACTION_ITEMS_DUE_DATE,
df.parse("03/30/05"));
// Get the Action Items table
Table table = program.getTable(ProgramConstants.TABLE_ACTIONITEMS);
// Add the new Action Item to table
table.createRow(map);
}
} catch (APIException ex) {
System.out.println(ex);
}
v9.3.1.2 261
Chapter 17
Working with Product Cost Management
This chapter includes the following:
Overview.............................................................................................................................................................. 261
Working with Price Objects..................................................................................................................................262
Working with Suppliers........................................................................................................................................ 266
Working with Sourcing Projects........................................................................................................................... 268
Overview
The Product Sourcing module of the Agile PLM supports, enhances, and simplifies the handling of
all product cost-related data throughout the product lifecycle. This enables you to effectively
manage and manipulate Sourcing content, collaborate with suppliers to establish new Sourcing
content, and analyze the data. Product Sourcing supports the following functions:
à Create Sourcing Projects
à Gather and prepare product content
à Leverage pricing contracts and history
à Create Request for Quote (RFQ) objects
à Manage supplier RFQ responses and negotiate pricing (Not supported by PCM SDK)
à Conduct Sourcing Project analysis
The Agile API supports the following Product Sourcing objects:
à IChange – This interface is for the Change class, which includes Price Change Orders
(PCOs).
à IPrice – This interface is for the Price class, which handles both published prices and
historical prices.
à IProject – This interface is for the Sourcing Projects class, which is the container used
for product Sourcing data.
à IRequestForQuote – This interface is for the RequestForQuote class, which represents
an RFQ for a Sourcing Project.
à ISupplier – This interface is for the Supplier class.
Except for the ISupplierResponse object, the Agile API allows you to read and modify all
Product Sourcing objects. The following table lists the create, read, and modify rights for Product
Sourcing objects.
SDK Developer Guide - Using Agile APIs
262 Agile Product Lifecycle Management
Object Create Read Modify
IChange (including PCO)
Yes Yes Yes
IPrice
Yes Yes Yes
IProject
Yes Yes Yes
IRequestForQuote
Yes Yes Yes
ISupplier
Yes Yes Yes
Working with Price Objects
Agile PLM’s price management solution replaces inefficient manual systems, where prices are often
stored in files, spreadsheets, or databases in disparate locations. The Agile PLM system allows you
to create and centrally manage prices and terms for items and manufacturer parts.
There are two out-of-the-box Price classes provided with the system:
à Historical Quotes – This is a historical Quote object that contains price quotes from previous
Sourcing projects or legacy data.
à Published Prices – This is a historical Published Price that contains published prices or contract
prices on current items and manufacturer parts.
These are the basic steps used to define pricing for an item or manufacturer part:
1. Users with the appropriate role can create a new Price object, specifying the Number,
Description, Item or Manufacturer Part, Supplier, Site, and Customer.
2. After creating a Price object, users can build out a price/terms matrix for each associated item
or manufacturer part. The price and terms matrix includes Effectivity Dates, Quantity, Price,
and Cancellation Windows.
3. The Price object is submitted and goes through a Workflow approval process. Other users can
approve or reject the object.
4. Users with the appropriate role can create a Price Change Order (PCO) to modify a Price
object that has been released. The updated Price object is again submitted for approval.
Loading a Price Object
To load a Price object, use the IAgileSession.getObject() method. To uniquely identify a
Price object, specify the value for the Title Block | Number attribute.
Example: Loading a Price object
public IPrice getPrice() throws Exception {
IPrice price = (IPrice)m_session.getObject(IPrice.OBJECT_TYPE,
"PRICE10008");
return price;
}
For a list of Price object tables, refer to the Javadoc generated HTML files that document the SDK
Chapter 17: Working with Product Cost Management
v9.3.1.2 263
code. You can find them in the HTML folder in SDK_samples (ZIP file). To access this file, see the
Note in
Client-Side Components on page 2.
Adding Price Lines
The Price Lines table of a Price object is where you define the prices and terms for the related item
or manufacturer part. When you add a row to the Price Lines table, you must initialize the row with
values. At a minimum, you must specify values for the following attributes:
à ATT_PRICE_LINES_SHIP_FROM
à ATT_PRICE_LINES_SHIP_TO
à ATT_PRICE_LINES_PRICE_EFFECTIVE_FROM_DATE
à ATT_PRICE_LINES_PRICE_EFFECTIVE_TO_DATE
à ATT_PRICE_LINES_QTY
If you fail to specify a value for one of these attributes, the Price Lines row won’t be created.
Example: Adding price lines
public void addPriceLines(IPrice price) throws Exception {
DateFormat df = new SimpleDateFormat("MM/dd/yy");
IAgileClass cls = price.getAgileClass();
ITable table = price.getTable(PriceConstants.TABLE_PRICELINES);
IAttribute attr = null;
IAgileList listvalues = null;
HashMap params = new HashMap();
//Set Ship-To Location (List field)
attr = cls.getAttribute(PriceConstants.ATT_PRICE_LINES_SHIP_TO);
listvalues = attr.getAvailableValues();
listvalues.setSelection(new Object[] { "San Jose" });
params.put(PriceConstants.ATT_PRICE_LINES_SHIP_TO, listvalues);
//Set Ship-From Location (List field)
attr = cls.getAttribute(PriceConstants.ATT_PRICE_LINES_SHIP_FROM);
listvalues = attr.getAvailableValues();
listvalues.setSelection(new Object[] { "Hong Kong" });
params.put(PriceConstants.ATT_PRICE_LINES_SHIP_FROM, listvalues);
//Set Effective From (Date field)
params.put(PriceConstants.ATT_PRICE_LINES_PRICE_EFFECTIVE_FROM_DATE,
df.parse("10/01/03"));
//Set Effective To (Date field)
params.put(PriceConstants.ATT_PRICE_LINES_PRICE_EFFECTIVE_TO_DATE,
df.parse("10/31/03"));
//Set Quantity (Number field)
params.put(PriceConstants.ATT_PRICE_LINES_QTY, new Integer(1000));
//Set Currency Code (List field)
attr =
cls.getAttribute(PriceConstants.ATT_PRICE_LINES_CURRENCY_CODE);
listvalues = attr.getAvailableValues();
listvalues.setSelection(new Object[] { "USD" });
params.put(PriceConstants.ATT_PRICE_LINES_CURRENCY_CODE,
listvalues);
//Set Total Price (Money field)
SDK Developer Guide - Using Agile APIs
264 Agile Product Lifecycle Management
params.put(PriceConstants.ATT_PRICE_LINES_TOTAL_PRICE, new
Money(new Double(52.95), "USD"));
//Set Total Material Price (Money field)
params.put(PriceConstants.ATT_PRICE_LINES_TOTAL_MATERIAL_PRICE, new
Money(new Double(45.90), "USD"));
//Set Total Non-Materials Price (Money field)
params.put(PriceConstants.ATT_PRICE_LINES_TOTAL_NON_MATERIAL_PRICE,
new Money(new Double(7.05),
"USD"));
//Set Lead Time (Number field)
params.put(PriceConstants.ATT_PRICE_LINES_LEAD_TIME, new Integer(5));
//Set Transportation Time (List field)
attr =
cls.getAttribute(PriceConstants.ATT_PRICE_LINES_TRANSPORTATION_TIME);
listvalues = attr.getAvailableValues();
listvalues.setSelection(new Object[] { "FOB" });
params.put(PriceConstants.ATT_PRICE_LINES_TRANSPORTATION_TIME,
listvalues);
//Set Country of Origin (List field)
attr =
cls.getAttribute(PriceConstants.ATT_PRICE_LINES_COUNTRY_OF_ORIGIN);
listvalues = attr.getAvailableValues();
listvalues.setSelection(new Object[] { "United States" });
params.put(PriceConstants.ATT_PRICE_LINES_COUNTRY_OF_ORIGIN,
listvalues);
//Create a new Price Lines row and initialize it with data
IRow row = table.createRow(params);
}
Creating a Price Change Order
Price objects such as published prices and contracts have a revision history. To modify a released
Price object, you must first create a Price Change Order (PCO) and adding the Price object to the
Affected Prices table. The PCO is then submitted for approval. Any changes made to the Price
object take effect when the PCO completes its Workflow approval process.
A PCO is similar to other Change objects, such as ECOs and ECRs. You can create a PCO using
the IAgileSession.createObject() method.
Example: Creating a PCO
public void createPCO(IPrice price) throws Exception {
//Get the PCO class
IAgileClass cls =
m_admin.getAgileClass(ChangeConstants.CLASS_PCO);
//Get autonumber sources for the PCO class
IAutoNumber[] numbers =
cls.getAutoNumberSources();
//Create the PCO
IChange pco =
Chapter 17: Working with Product Cost Management
v9.3.1.2 265
(IChange)m_session.createObject(ChangeConstants.CLASS_PCO,
numbers[0]);
//Get the Affected Prices table
ITable affectedPrices =
pco.getTable(ChangeConstants.TABLE_AFFECTEDPRICES);
//Add the Price object to the Affected Prices table
IRow row = affectedPrices.createRow(price);
}
Creating a Price Object
There are several steps to create a Price object. First, specify the object class and the unique
identifying attributes, and then use IAgileSession.createObject() to return the new Price
object.
Price objects are more complex than other Agile API objects because they have several key
attributes that must be specified. Most other Agile API objects have only one key object, such as the
object’s number. With a Price object, you must specify a number, customer, item or manufacturer
part, revision (for items), Program, site, and supplier. If any one of these attributes is missing, an
exception will be thrown and the Price object won’t be created.
Note If you are not dealing with site-specific information, specify the Global site for the
Manufacturing Site attribute.
After you create a Price object, you can further define it by setting values for Cover Page, Page
Two, and Page Three fields. To define prices and terms for items and manufacturer parts, add rows
to the Price Lines table. If there are files or documents to attach, add them to the Attachments table.
Defaults
To create a price with Program==All and Customer==All, you do not need to pass values for
PriceConstants.ATT_GENERAL_INFORMATION_CUSTOMER and
PriceConstants.ATT_GENERAL_INFORMATION_Program during price creation. By default, the
price will be created with Progam==All and Customer==All.
Specifying Item Revision
When you specify the item revision during price creation, you need to pass the change number,
instead of the revision number.
Example: Specifying Item Revision by Passing the Change Number
//Pass the change number
params.put(Priceconstants.ATT_GENERAL_INFORMATION_ITEM_REV, "CO-
35884");
//Instead of the revision number
params.put(PriceConstants.ATT_GENERAL_INFORMATION_ITEM_REV, "B")
SDK Developer Guide - Using Agile APIs
266 Agile Product Lifecycle Management
Creating a Published Price
The following example shows how to create a published price.
Example: Creating a published price
public void createPublishedPrice(ICustomer customer, ISupplier
supplier) throws Exception {
HashMap params = new HashMap();
IAgileClass cls =
m_admin.getAgileClass(PriceConstants.CLASS_PUBLISHED_PRICE);
IAutoNumber an =
cls.getAutoNumberSources()[0];
params.put(PriceConstants.ATT_GENERAL_INFORMATION_NUMBER, an);
params.put(PriceConstants.ATT_GENERAL_INFORMATION_CUSTOMER,
customer);
params.put(PriceConstants.ATT_GENERAL_INFORMATION_ITEM_NUMBER,
"1000-02");
params.put(PriceConstants.ATT_GENERAL_INFORMATION_ITEM_REV, "CO-
35884");
params.put(PriceConstants.ATT_GENERAL_INFORMATION_PROGRAM,
"PROGRAM0023");
params.put(PriceConstants.ATT_GENERAL_INFORMATION_MANUFACTURING_SITE
, "San Jose");
params.put(PriceConstants.ATT_GENERAL_INFORMATION_SUPPLIER,
supplier);
IPrice price = (IPrice)m_session.createObject(cls, params);
}
Working with Suppliers
The Agile PLM system comes with five out-of-the-box supplier classes:
à Broker
à Component Manufacturer
à Contract Manufacturer
à Distributor
à Manufacturer Rep
There are two primary key attributes that uniquely identify each supplier: GENERAL_INFO_NUMBER
and GENERAL_INFO_NAME.
Loading a Supplier
To load a supplier, use the IAgileSession.getObject() method. To uniquely identify the
supplier, specify the General Info | Number attribute.
Example: Loading a supplier
public ISupplier getSupplier() throws APIException {
ISupplier supplier =
(ISupplier)m_session.getObject(ISupplier.OBJECT_TYPE, "SUP20013");
return supplier;
}
Chapter 17: Working with Product Cost Management
v9.3.1.2 267
Note The Agile API does not support adding new rows to Supplier tables.
Modifying Supplier Data
The Agile API lets you read and update all read/write Supplier fields. For General Info, Page One,
and Page Three fields, you can access the cells directly. To access cells on multirow tables like the
Contact Users table, you must first load the table and select a particular row.
Example: Modifying supplier data
public void updateSupplierGenInfo(ISupplier supplier) throws Exception
{
ICell cell = null;
IAgileList listvalues = null;
//Update Name (Text field)
cell = supplier.getCell(SupplierConstants.ATT_GENERAL_INFO_NAME);
cell.setValue("Global Parts");
//Update URL (Text field)
cell = supplier.getCell(SupplierConstants.ATT_GENERAL_INFO_URL);
cell.setValue("http://wwww.globalpartscorp.com");
//Update Corporate Currency (List field)
cell =
supplier.getCell(SupplierConstants.ATT_GENERAL_INFO_CORPORATE_CURRENCY)
;
listvalues = cell.getAvailableValues();
listvalues.setSelection(new Object[] { "EUR" });
cell.setValue(listvalues);
}
public void updateSupplierContactUsers(ISupplier supplier) throws
Exception {
ICell cell = null;
IAgileList listvalues = null;
//Load the Contact Users table
ITable contactusers =
supplier.getTable(SupplierConstants.TABLE_CONTACTUSERS);
//Get the first row
ITwoWayIterator i = contactusers.getTableIterator();
IRow row = (IRow)i.next();
//Update Email (Text field)
cell = row.getCell(SupplierConstants.ATT_CONTACT_USERS_EMAIL);
cell.setValue("[email protected]");
}
SDK Developer Guide - Using Agile APIs
268 Agile Product Lifecycle Management
Working with Sourcing Projects
A Sourcing Project is where you prepare content for Sourcing tasks, such as Requests for Quotes
(RFQs) and Sourcing analysis. Sourcing Project is a centralized, collaborative solution. Multiple
users can add data to a Sourcing Project and perform analysis of Sourcing results. Because
Sourcing projects serve as the home for all Sourcing activities, they are linked to many classes of
objects, including Supplier, RequestForQuote (RFQ), and SupplierResponse.
You can use the Agile API to:
à Load an existing Sourcing Project
à Create Sourcing Projects by quantity breaks
à Create Sourcing Projects by price periods
à Open and close a Sourcing Project
à Add items, including AMLs to Sourcing Project items
à Access and modify objects, tables, and attributes in Sourcing Projects
à Access and modify Sourcing Project status
à Update Sourcing Project AMLs
à Update Page 1, Page 2, and Page 3 in Sourcing projects
à Read and update a nested Pricing table in Sourcing projects
à Set quantity for an item in Sourcing Projects
à Update the target price for items in Sourcing Projects
à Set partners for items in Sourcing Projects
à Perform quantity Rollups in Sourcing Projects
à Set a response designated as best in Sourcing Projects
Unlike the Web Client which provides additional functionality for Sourcing projects, the Agile API
exposes Sourcing projects for simple data extraction and updating. Consequently, the Agile API
does not support the following functions:
à Validation for items, commodities, or manufacturer parts.
à Filter Sourcing Project tables
à Modify the price scenario for Sourcing Projects (change quantity breaks and effectivity periods)
Chapter 17: Working with Product Cost Management
v9.3.1.2 269
Supported API Methods
The SDK supports the following API methods for Sourcing projects. For information on these
interfaces, refer to the Javadoc generated HTML files that document the SDK code. You can find
them in the HTML folder in SDK_samples (ZIP file). To access this file, see the Note in
Client-Side
Components on page 2.
à IAgileSession.createObject(Object, Object)
à IAgileSession.createObject(int, Object)
à IAgileSession.getObject(Object, Object)
à IAgileSession.getObject(int, Object)
à IProject.assignSupplier (Object partnerParams)
à IProject.Costrollup()
à IProject.lookupPrices()
à IProject.rollupQuantity()
à IProject.getName()
à IProject.changeStatusToOpen()
à IProject.changeStatusToClose()
à IProject.getTable(Object)
à IRow.getValue(Object)
à IRow.setValue(Object, Object)
à ITable.iterator()
à ITable.getName()
à ITable.getTableDescriptor()
à ITable.size()
à ITable.createRow(Object)
Note The PCM SDK does not support the IRow.getReferent() method.
Loading an Existing Sourcing Project
To load existing Sourcing Projects, use the IAgileSession.getObject() method. To uniquely
identify the Sourcing Projects, specify the value for the Cover Page | Number attribute.
Example: Loading Sourcing Projects
public IProject getProject() throws APIException {
String prjnum = "PRJACME_110";
IProject prj = (IProject)m_session.getObject(IProject.OBJECT_TYPE,
prjnum);
SDK Developer Guide - Using Agile APIs
270 Agile Product Lifecycle Management
return prj;
}
Creating Sourcing Projects by Quantity Breaks
Defining Sourcing projects uses the generic IAgileSession method.
Example: Creating Sourcing Projects
IAgileObject createObject (Object objectType, Object params)
throws APIException;
Creating Sourcing Projects requires specifying one of the following set of parameters:
à Sourcing Project number and quantity breaks
Or,
à Sourcing Project number, quantity breaks, and price period information
Note Quantity breaks is a required parameter and is always specified. The example below
creates a Sourcing Project using the quantity break parameter.
Example: Creating Sourcing Projects by quantity breaks
IAgileClass agClass =
m_admin.getAgileClass(ProjectConstants.CLASS_SOURCING_PROJECT);
IAutoNumber number = agClass.getAutoNumberSources()[0];
HashMap map = new HashMap();
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_NUMBER, number);
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_NUMBER_OF_QTY_BREAKS,
new Integer(4));
IProject prj = (IProject) m_session.createObject(agClass, map);
Important Do not pass numbers that are greater than two digits to the QUANTITY_BREAK
attribute.
Creating Sourcing Projects by Quantity Breaks and Price Periods
Alternatively, you can create Sourcing Projects by specifying quantity breaks and price period
information such as the number of periods, period type, and start date. Example below creates a
Sourcing Project using these parameters.
Note When you create a Sourcing Project with price period information set to period type, you
must specify the Period Type attribute. The supported values are Monthly, Quarterly,
Semi-Annually, and Yearly. However, Period Type is not correctly returned afterwards
when you check the value of period type, for example, by invoking
getValue(ProjectConstants.ATT_GENERAL_INFORMATION_PERIOD_TYPE).
That is, instead of returning the value that you set when creating the Sourcing Project,
the future returned value is always “Weekly”. This is not an error. It is normal SDK
behavior and the specified period type value is not altered, because it is for internal use
only.
Example: Creating a Sourcing Project by quantity breaks and price periods
/*
Chapter 17: Working with Product Cost Management
v9.3.1.2 271
Descriptions
ATT_GENERAL_INFORMATION_PERIOD_TYPE is described in ProjectConstants
Name: Period Type
Description: Period Type indicates the recurrence of price periods
in a Sourcing Project.
Type: List
List: Period Type List
List Id: 4565
List Valid Values: {Monthly, Quarterly, Semi-Annually, Yearly}
Restrictions: Required, Read Only. Used only when creating Sourcing
Projects. Internal use only. Not available through Agile UI clients.
ATT_GENERAL_INFORMATION_PERIOD_START_DATE is described in
ProjectConstants
Name: Period Start Date
Description: Period Start Date indicates the start date for price
periods in a Sourcing Project
Type: Date
Valid Values: any Date object.
Restrictions: Required, Read only, Used only when creating Sourcing
Projects, Internal use only /Not available through Agile UI clients
*/
IAgileClass agClass =
m_admin.getAgileClass(ProjectConstants.CLASS_SOURCING_PROJECT);
IAutoNumber number =
agClass.getAutoNumberSources()[0];
HashMap map =
new HashMap();
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_NUMBER, number);
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_NUMBER_OF_QTY_BREAK
S, new Integer(4));
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_NUMBER_OF_PERIODS,
new Integer(4));
IAgileList list =
agClass.getAttribute(PERIODTYPE).getAvailableValues();
String TYPE = “Monthly”;
list.setSelection(new Object[]{TYPE});
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_PERIOD_TYPE, list);
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_PERIOD_START_DATE,
(new GregorianCalendar()).getTime());
IProject prj =
(IProject) m_session.createObject(agClass, map);
Accessing and Modifying Objects, Tables, and Attributes
You can use the generic IDataObject method with standard calls such as getObject,
getTable, getValue, setValue to access and subsequently modify objects, tables, and
attributes as follows:
à Read Page 1 or Cover Page, Page 2, Page 3, Items, AML, Analysis, and nested pricing tables
à Update Page 1 or Cover Page, Page 2, Page 3, and AML tables
à Add items including AML to Items table
à Read RFQ table
SDK Developer Guide - Using Agile APIs
272 Agile Product Lifecycle Management
à Load RFQ table
The com.agile.api.ProjectConstants.java file contains information about classes, tables,
and attributes.
The SDK does not support the following table operations:
à Sourcing Projects class
y Sorting PCM specific tables that have a default sorting order. These tables are Sourcing
Project Item, Sourcing Project AML, Sourcing Project Changes, Sourcing Project Analysis,
and Sourcing Project RFQ, RFQ Response, RFQ Changes, Supplier Response, and
Supplier Changes.
à Request for quote and RFQ responses classes
y Responses and Changes tables
à Removing items from RFQ Response and Sourcing Projects tables because the PCM SDK
does not support ITable.clear() or ITable.removeRow()
Setting Cover Page Values for Sourcing Projects
You can read and update all read/write Sourcing Projects cells. The following example updates the
cells on a Sourcing project’s Cover Page (Page 1).
Example: Setting values for a Sourcing project’s Cover Page
public void updateProjectGenInfo (IProject project) throws Exception {
ICell cell = null;
IAgileList listvalues = null;
//Update Customer (List field)
cell =
project.getCell(ProjectConstants.ATT_GENERAL_INFORMATION_CUSTOMER);
listvalues =
cell.getAvailableValues();
listvalues.setSelection(new Object[] { "CUST00010" });
cell.setValue(listvalues);
//Update Description (Text field)
cell =
project.getCell(ProjectConstants.ATT_GENERAL_INFORMATION_DESCRIPTION
);
cell.setValue("Sourcing Projects for Odyssey III");
//Update Manufacturing Site (List field)
cell =
project.getCell(ProjectConstants.ATT_GENERAL_INFORMATION_MANUFACTURI
NG_SITE);
listvalues =
cell.getAvailableValues();
listvalues.setSelection(new Object[] { "Global" });
cell.setValue(listvalues);
//Update Ship To Location (List field)
cell =
Chapter 17: Working with Product Cost Management
v9.3.1.2 273
project.getCell(ProjectConstants.ATT_GENERAL_INFORMATION_SHIP_TO_LOC
ATION);
listvalues =
cell.getAvailableValues();
listvalues.setSelection(new Object[] { "San Jose" });
cell.setValue(listvalues);
}
Understanding Nested Tables in PCM
A nested table is a table within a table. They are used to accesses and modify data in multi-level
objects such as BOMs and Items with AMLs. The way the SDK fulfills this function is to treat the cell
values in a nested table as a table. For example, when the SDK finds the next level in a cell in a
BOM table, it treats and processes the cell as a table. Nested tables are unique to the PCM SDK.
Sourcing Projects' Parent Table and Nested Child Table Constants
The list of parent Sourcing Projects table and the corresponding nested child table constants
appear in the Parent Sourcing Projects Table Constants and the Corresponding Nested Sourcing
Projects Tables.
Parent Table Constant Nested Child Table Constant Read/Write Mode
TABLE_ITEMS ATT_ITEMS_AML
Read/Write
TABLE_ITEMS ATT_ITEMS_PRICING
Read/Write
TABLE_AML ATT_AML_PRICETABLE
Read/Write
TABLE_ITEM ATT_ITEM_PRICE_TABLE
Read/Write
TABLE_ITEM ATT_ITEM_BOM_TABLE
Read
TABLE_ANALYSIS ATT_ANALYSIS_AML
Read
TABLE_ANALYSIS ATT_ANALYSIS_PRICING
Read
Accessing and Modifying Nested Tables in Sourcing Projects or RFQs
The example below is a Read mode example that accesses a nested table. To modify/update a
nested table, see the Example entitled "Nested RFQ table update" in
RFQ Parent Table and Nested
Child Table Constants on page 291.
Note The Money type attribute in nested PCM Pricing tables always uses “USD” as the default
currency unit. This applies even if the buyer specifies a different currency unit. In this
case, the “United State Dollar” is the default and only supported currency.
Example: Accessing a nested table
Row row = (IRow) table.iterator.next();
ITable nested_table =
(ITable)row.getValue(ProjectConstants.ATT_ITEMS_AML);
SDK Developer Guide - Using Agile APIs
274 Agile Product Lifecycle Management
Viewing Updates after Modifying a Nested Table
After modifying a nested table, it is necessary to reload the table as shown in the previous example
for changes to take effect, otherwise, the old data will reappear and the new values are not
displayed.
Accessing and Modifying the Status of Sourcing Project
Because Sourcing Projects do not have a Workflow connected to them, their status change is
controlled internally. They control their status with a set of methods. This is a special case for some
PCM objects such as Sourcing Projects and Requests for Quote. This release supports changing
the status of a Sourcing Project from Draft to Open and Open to Close.
You can access the status of Sourcing Projects using the standard IDataObject method for the
lifecycle phase field on the Cover Page (Page 1). You can modify the status of Sourcing Projects
with IProject methods which enable you to open, modify, and close a Sourcing Project. You
must set the Ship to Location parameter in order to open a Sourcing Project, as shown in the
following example.
Example: Setting values for a Sourcing project’s Cover Page
// add Ship To //
String sj = “San Jose”;
IAgileList ship2List =
(IAgileList)prj.getValue(ProjectConstants.ATT_GENERAL_INFORMATION_SH
IP_TO_LOCATION);
ship2List.setSelection(new Object[]{sj});
prj.setValue(ProjectConstants.ATT_GENERAL_INFORMATION_SHIP_TO_LOCATION,
ship2List);
// open Sourcing Project //
prj.changeStatusToOpen();
// close Sourcing Project //
prj.changeStatusToClose();
Managing Data in Sourcing Projects
The following paragraphs provide descriptions and examples to prepare a Souring Project to issue
an RFQ. You can then use the SDK to complete the RFQ-related tasks.
Note The Sourcing Project Start date that you specify is converted to the GMT format for
storage in the PLM database. Due to this conversion, the date value returned by
IProject.getValue(ProjectConstants.ATT_GENERAL_INFORMATION_PERIOD
_START_DATE) is not guaranteed to be the same that the user may expect.
Setting Quantity for Items in Sourcing Projects
You can use the SDK to set the required quantity for the an Item object in a Sourcing Project. The
code sample below sets this value in the Item table, under the Items tab, for a single price target.
The end user can specify the target price using the displayed name which is QuantityBreak2 in
the following example.
Chapter 17: Working with Product Cost Management
v9.3.1.2 275
Example: Setting quantity for Items
// Setting Quantity for an Item //
ITable tab_item = dObj.getTable(ProjectConstants.TABLE_ITEM);
IRow row = (IRow) tab_item.iterator().next()
ITable priceTable =
row.getValue(ProjectConstants.ATT_ITEM_PRICE_TABLE);
for (Iterator iterator = priceTable.iterator(); iterator.hasNext();) {
IRow row = (IRow) iterator.next();
String name = row.getName();
if(name.equals("QuantityBreak2")){
row.setValue(ProjectConstants.ATT_PRICEDETAILS_QUANTITY, new
Double(123));
}
}
Note For items, quantity is only set at the root level. Thus, if an item is not a root, the
exception ExceptionConstants.PCM_PROJECT_ITEM_IS_NOT_ROOT is thrown.
In addition, because priceTable is a nested table, you must reload the table to get the updated
value of Quantity. This is shown in the following example.
Example: Reloading a nested table to get an updated value
// Getting the updated value //
priceTable = row.getValue(ProjectConstants.ATT_ITEM_PRICE_TABLE);
for (Iterator iterator = priceTable.iterator(); iterator.hasNext();) {
IRow iRow = (IRow) iterator.next();
String name = iRow.getName();
if(name.equals("QuantityBreak2")){
Object qty =
row.getValue(ProjectConstants.ATT_PRICEDETAILS_QUANTITY));
}
}
Adding Items to Sourcing Projects with BOM Filters
The PLM Web Client supports setting up BOM filters to selectively add Items to Sourcing Projects.
This filtering applies to all enabled attributes on the Cover page, P2, and BOM tabs of the Item
object and includes the Parts and Documents fields in the Cover page. These attributes are enabled
using the Java Client. For background information and procedures on BOM filtering, refer to Agile
PLM Product Cost Management User Guide. To enable Item object attributes, refer to Agile PLM
Administrator Guide.
The SDK enables replicating this Web Client feature programmatically. SDK filter operators that
support this feature are implemented in the OperatorConstants class. The following code
samples show how BOM filters are applied to Item object's numeric, multilist, money, and mass
attributes. As indicated above, these attributes must be enabled in the Java Client by an Admin
user.
SDK Developer Guide - Using Agile APIs
276 Agile Product Lifecycle Management
Example: Applying BOM filter operators located in the OperatorConstants class
IProject prj = (IProject)m_session.getObject(IProject.OBJECT_TYPE,
"PRJ00001");
IItem assembly = (IItem)m_session.getObject(IItem.OBJECT_TYPE,
"P00001");
//Applying BOM filter to numeric attributes
ProjectItemFilter itemfilter = new ProjectItemFilter();
itemfilter.addCriteria(ItemConstants.ATT_BOM_BOM_NUMERIC03,
OperatorConstants.RELOP_EQ, new Integer(10));
itemfilter.addCriteria(ItemConstants.ATT_BOM_BOM_NUMERIC04,
OperatorConstants.RELOP_GE, new Integer(100));
Map params = new HashMap();
params.put(ProjectConstants.ATT_ITEM_NUMBER, assembly);
params.put(ProjectConstants.ATT_ITEM_FILTER, itemfilter);
ITable ITEM = prj.getTable(ProjectConstants.TABLE_ITEM);
IRow row = ITEM.createRow(params);
//Applying BOM filter to multilist attributes
ProjectItemFilter itemfilter = new ProjectItemFilter();
IAttribute list03 =
m_session.getAdminInstance().getAgileClass(ItemConstants.CLASS_PARTS
_CLASS).getAttribute(ItemConstants.ATT_PAGE_TWO_MULTILIST01);
IAgileList list3 = list03.getAvailableValues();
list3.setSelection(new Object[]{"Austria","India"});
itemfilter.addCriteria(ItemConstants.ATT_PAGE_TWO_MULTILIST01,
OperatorConstants.RELOP_CONTAINS_ALL_VALUE, list3);
Map params = new HashMap();
params.put(ProjectConstants.ATT_ITEM_NUMBER, assembly);
params.put(ProjectConstants.ATT_ITEM_FILTER, itemfilter);
ITable ITEM = prj.getTable(ProjectConstants.TABLE_ITEM);
IRow row = ITEM.createRow(params);
//Applying BOM filter to money attributes
Money mny = new Money(new Double(15.3), "USD");
ProjectItemFilter itemfilter = new ProjectItemFilter();
itemfilter.addCriteria(ItemConstants.ATT_PAGE_TWO_MONEY01,
OperatorConstants.RELOP_EQ, mny);
Map params = new HashMap();
params.put(ProjectConstants.ATT_ITEM_NUMBER, assembly);
params.put(ProjectConstants.ATT_ITEM_FILTER, itemfilter);
ITable ITEM = prj.getTable(ProjectConstants.TABLE_ITEM);
IRow row = ITEM.createRow(params);
//Applying BOM filter to mass attributes
IUnitOfMeasureManager uomm
=(IUnitOfMeasureManager)m_session.getManager(IUnitOfMeasureManager.c
lass);
IUnitOfMeasure uom = uomm.createUOM(10.1,"Gram");
ProjectItemFilter itemfilter = newProjectItemFilter();
itemfilter.addCriteria(ItemConstants.ATT_TITLE_BLOCK_MASS,OperatorCo
nstants.RELOP_NEQ, uom);
Map params = new HashMap();
params.put(ProjectConstants.ATT_ITEM_NUMBER, assembly);
params.put(ProjectConstants.ATT_ITEM_FILTER, itemfilter);
ITable ITEM = prj.getTable(ProjectConstants.TABLE_ITEM);
IRow row = ITEM.createRow(params);
Performing Quantity Rollup in Sourcing Projects
Quantity rollups generate data related the quantity values for the selected Item in a Sourcing
Project. In the SDK, you can use the following API to invoke a Quantity rollup in a Sourcing Project.
Chapter 17: Working with Product Cost Management
v9.3.1.2 277
public void rollupQuantity() throws APIException, RemoteException,
Exception;
This code sample uses rollupQuantity() to do a Quantity rollup.
Example: Quantity Rollup
IProject prj =
(IProject)m_session.getObject(ProjectConstants.CLASS_SOURCING_PRO
JECT,"PRJ00001");
prj.rollupQuantity();
Note To get the updated value of Quantity, it is necessary to invoke rollupQuantity() on
the Sourcing Project similar to the example in Modifying Spplier Data on page 267. This
is necessary because getValue() does not return the updated value of the affected
item after setting Quantity.
Performing Cost Rollup in Sourcing Projects
Cost Rollup (Rollup cost) generates an Assembly Cost Report (ACR) based on available prices. In
this process, it picks up the lowest costs from filtered data, performs Set as Best (on user defined or
default parameters) and costed BOM rollup (aggregation) to generate the ACR. In the UI, Rollup
cost provides an intuitive mechanism for non PCM users to cost a BOM without going through PCM
steps.
Note Cost Rollup runs on existing Sourcing Project prices. If Cost Rollup needs to run on
looked up prices, lookupPrices() must be invoked prior to running costRollup().
If there are no assemblies in the Sourcing Project, the
ExceptionConstants.PCM_NO_ASSEMBLY_IN_PROJECT is thrown.
The PCM SDK supports the Cost Rollup function with the following API.
public void costRollup()
throws APIException, RemoteException, Exception;
Example: Using the costRollup API
IProject prj = (IProject)
m_session.getObject(ProjectConstants.CLASS_SOURCING_PROJECT,
"PRJ0001");
prj.costRollup();
Note If you need to run quantity rollup immediately after cost rollup, be sure to provide some
delay (For example as in Thread.currentThread().sleep(10000);) to allow the
results of the cost rollup to be refreshed in the database.
Performing Price Lookup in Sourcing Projects
You can use the SDK to verify the existence of a price scenario for a specified period and quantity
in the Item Master. You can either use the price information of the Item, or modify the price
information and send the RFQ to suppliers for requote.
In Agile PCM, there are three types of price objects:
à Contracts – Predefined agreements with suppliers for Item prices over a specified time period
SDK Developer Guide - Using Agile APIs
278 Agile Product Lifecycle Management
à Published Prices – The Item price information that has been published from other Sourcing
projects
à Quote Histories – Quoted prices that were previously received for an Item
For information about price objects and price lookups in Sourcing projects, refer to the Agile PLM
Product Cost Management User Guide.
Price Lookup API and Price Lookup Options
à Supported API
The SDK supports price lookups with the following API in IProject.
public void lookupPrices(Object lookupParams)
throws APIException, RemoteException, Exception;
à Price lookup options
This API performs price lookups from Price history and price lookups from another Sourcing
Project.
Note lookupPrices()looks for an Item or an MPN one object at a time. To run lookup
for multiple Items/MPNs, you must run the API one Item or one MPN at a time.
The following examples show price lookups from the Sourcing Project History and from another
Sourcing Project. In addition, applicable parameters are grouped and listed as those that are
specific to the price lookup type and necessary in the price lookup type.
Parameters for Price Lookup from History or Another Sourcing Project
This example shows a price lookup from Sourcing Project History and from another Sourcing
Projects. It provides a list of specific and required parameters for the two price lookups.
Example: Price lookup from History and another Sourcing Projects
ArrayList priceTypes = new ArayList();
priceTypes.add(PriceConstants.CLASS_PUBLISHED_PRICE);
priceTypes.add(PriceConstants.CLASS_QUOTE_HISTORY);
priceTypes.add(PriceConstants.CLASS_CONTRACT);
ArrayList suppliers = new ArrayList();
suppliers.add(supplier1);
suppliers.add(supplier2);
//supplier1, supplier2 are objects of ISupplier or String
ArrayList customers = new ArrayList();
customers.add(customer1);
customers.add(customer2);
//customer1, customer2 are objects of ICustomer or String
ArrayList programs = new ArrayList();
programs.add(program1);
programs.add(program2);
//program1, program2 are objects of IProgram or String
Chapter 17: Working with Product Cost Management
v9.3.1.2 279
String shipTo = "berlin";
HashMap itemMap = new HashMap();
itemMap.put("IPN1","REV1");//itemMap.put("IPN1", null) if no revision
or
itemMap.put(item); //item is an object of IItem
HashMap mpnMap = new HashMap();
mpnMap.put("MPN1","MFR1");
or
mpnMap.put(mfrPart); //mfrPart is and object of IManufacturerPart
IProject srcPrj = (IProject)
m_session.getObject(ProjectConstants.CLASS_SOURCING_PROJECT,
"PRJ_SRC");
Boolean isLookupFromPrice = new Boolean(false);
String priceScenario = null;
Map priceScenarios = new HashMap();
//if lookup from price history
priceScenario = "QuantityBreak1";
//if lookup from Sourcing project
String destPricePoint1 = "QuantityBreak1";
String destPricePoint2 = "QuantityBreak2";
String srcPricePoint1 = "QuantityBreak1";
String srcPricePoint2 = "QuantityBreak2";
priceScenarios.put(destPricePoint2,srcPricePoint1);
priceScenarios.put(destPricePoint1,srcPricePoint2);
Boolean ignoreQtyRange = new Boolean(true);
Double qtyPercentRange = new Double(15);
Boolean ignoreDateRange = new Boolean(true);
Integer dateRange = new Integer(20);
HashMap map = new HashMap();
map.put(PriceConstants.ATT_GENERAL_INFORMATION_PRICE_TYPE,priceTypes);
map.put(ProjectConstants.ATT_ANALYSIS_SUPPLIER,suppliers);
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_CUSTOMER,customers);
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_PROGRAM,programs);
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_SHIP_TO_LOCATION,shipT
o);
map.put(ProjectConstants.ATT_ITEMS_NUMBER,itemMap);
map.put(ProjectConstants.ATT_ITEMS_AML,mpnMap);
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_NUMBER,srcPrj);
map.put(LookupConstants.FLAG_IGNORE_ITEM_REVISION,ignoreItemRev);
map.put(LookupConstants.FLAG_CONSIDER_BEST_PRICES,considerBestPrices);
map.put(LookupConstants.FLAG_ALL_PRICE_SCENARIOS,allPriceScenarios);
map.put(LookupConstants.FIELD_PRICE_SCENARIO,priceScenario);
SDK Developer Guide - Using Agile APIs
280 Agile Product Lifecycle Management
map.put(LookupConstants.FIELD_PRICE_SCENARIOS,priceScenarios);
map.put(LookupConstants.FLAG_IGNORE_QUANTITY,ignoreQtyRange);
map.put(LookupConstants.FIELD_QUANTITY_RANGE,qtyPercentRange);
map.put(LookupConstants.FLAG_IGNORE_DATE_RANGE,ignoreDateRange);
map.put(LookupConstants.FIELD_DATE_RANGE,dateRange);
map.put(LookupConstants.FIELD_SELECT_RESPONSE_BY,
LookupConstants.OPTION_LOWEST_PRICE);
map.put(LookupConstants.FIELD_LOOKUP_TYPE,
LookupConstants.OPTION_LOOKUP_FROM_PRICE);
prj.lookupPrices(map);
Parameters specific to price lookups from price history
PriceConstants.ATT_GENERAL_INFORMATION_PRICE_TYPE
ProjectConstants.ATT_GENERAL_INFORMATION_CUSTOMER
ProjectConstants.ATT_GENERAL_INFORMATION_PROGRAM
ProjectConstants.ATT_GENERAL_INFORMATION_SHIP_TO_LOCATION
LookupConstants.FLAG_ALL_PRICE_SCENARIOS
LookupConstants.FIELD_PRICE_SCENARIO
LookupConstants.FLAG_IGNORE_QUANTITY
LookupConstants.FIELD_QUANTITY_RANGE
LookupConstants.FLAG_IGNORE_DATE_RANGE
LookupConstants.FIELD_DATE_RANGE
LookupConstants.FIELD_SELECT_RESPONSE_BY
Parameters specific to price lookups from Sourcing Projects
ProjectConstants.ATT_GENERAL_INFORMATION_NUMBER
LookupConstants.FLAG_ALL_PRICE_SCENARIOS
LookupConstants.FLAG_IGNORE_ITEM_REVISION
LookupConstants.FLAG_CONSIDER_BEST_PRICES
Note The remaining parameters are common to both cases.
Parameters required for price lookups from price history
PriceConstants.ATT_GENERAL_INFORMATION_PRICE_TYPE
ProjectConstants.ATT_ITEMS_NUMBER or ProjectConstants.ATT_ITEMS_AML
LookupConstants.FIELD_QUANTITY_RANGE if
LookupConstants.FLAG_IGNORE_QUANTITY is ‘false’
LookupConstants.FIELD_DATE_RANGE if
LookupConstants.FLAG_IGNORE_DATE_RANGE is ‘false’
LookupConstants.FIELD_PRICE_SCENARIO if
LookupConstants.FLAG_ALL_PRICE_SCENARIOS is ‘false’
Parameters required for price lookups from Sourcing Projects
ProjectConstants.ATT_GENERAL_INFORMATION_NUMBER
LookupConstants.FLAG_ALL_PRICE_SCENARIOS
ProjectConstants.ATT_ITEMS_NUMBER or ProjectConstants.ATT_ITEMS_AML
Chapter 17: Working with Product Cost Management
v9.3.1.2 281
Note Parameters that are not required in one of the price lookups, for example, History, may
be optional in price lookup from another Sourcing Project. Comparing the list of required
parameters above, the LookupConstants.FLAG_ALL_PRICE_SCENARIOS parameter
is optional when performing a price lookup from History. You can either omit the optional
parameters, or set them to null.
Setting the price lookup from History or Sourcing Projects
Set LookupConstants.FIELD_LOOKUP_TYPE for lookup from history or Sourcing Projects as
follows:
à For lookup from price history – LookupConstants.OPTION_LOOKUP_FROM_PRICE
à For lookup from an existing Sourcing Project –
LookupConstants.OPTION_LOOKUP_FROM_PROJECT
Settings for Quantity Breaks in price lookups
You can set quantity breaks in a price lookup by cost, date, or leadtime by setting
LookupConstants.FIELD_SELECT_RESPONSE_BY as follows:
à For break tie by cost – LookupConstants.OPTION_LOWEST_PRICE
à For break tie by date – LookupConstants.OPTION_MOST_RECENT_RESPONSE
à For break tie by leadtime– LookupConstants.OPTION_SHORTEST_LEAD_TIME
Impact of improper parameter settings
If the following parameters are not set, or are improperly set, the API will take the following actions:
à LookupConstants.FIELD_LOOKUP_TYPE will default to
LookupConstants.OPTION_LOOKUP_FROM_PRICE which corresponds to the lookup from
price history
à LookupConstants.FLAG_IGNORE_QUANTITY or
LookupConstants.FLAG_IGNORE_DATE_RANGE will default to true.
à LookupConstants.FIELD_SELECT_RESPONSE_BY will default to
LookupConstants.OPTION_LOWEST_PRICE which corresponds to the break tie by cost
à LookupConstants.FLAG_IGNORE_ITEM_REVISION or
LookupConstants.FLAG_CONSIDER_BEST_PRICES will default to false
à LookupConstants.LookupConstants.FLAG_ALL_PRICE_SCENARIOS is not set it will be
defaulted to ‘true’.
à ExceptionConstants.APDM_ADMIN_MISSINGREQUIREDFIELD exception is thrown when
a required parameter is missing
à ExceptionConstants.API_INVALID_PARAM exception is thrown when the datatype or the
value of a parameter is incorrectly set
SDK Developer Guide - Using Agile APIs
282 Agile Product Lifecycle Management
For RFQ lookup:
The settings are similar to Sourcing Project lookup from price history. Following is a code sample.
HashMap map = new HashMap();
map.put(PriceConstants.ATT_GENERAL_INFORMATION_PRICE_TYPE,priceTypes);
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_CUSTOMER,customers);
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_PROGRAM,programs);
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_SHIP_TO_LOCATION,shipT
o);
map.put(ProjectConstants.ATT_ITEMS_NUMBER,itemMap);
map.put(ProjectConstants.ATT_ITEMS_AML,mpnMap);
map.put(LookupConstants.FLAG_ALL_PRICE_SCENARIOS,allPriceScenarios);
map.put(LookupConstants.FIELD_PRICE_SCENARIO,priceScenario);
map.put(LookupConstants.FLAG_IGNORE_QUANTITY,ignoreQtyRange);
map.put(LookupConstants.FIELD_QUANTITY_RANGE,qtyPercentRange);
map.put(LookupConstants.FLAG_IGNORE_DATE_RANGE,ignoreDateRange);
map.put(LookupConstants.FIELD_DATE_RANGE,dateRange);
map.put(LookupConstants.FIELD_SELECT_RESPONSE_BY,LookupConstants.OPTION
_LOWEST_PRICE);
map.put(LookupConstants.FLAG_EXCLUDE_AUTH_SUPPLIER,excludeAuthSupplier)
;
rfq.lookupPrices(map);
Following is the list of the required parameters for the RFQ lookup:
PriceConstants.ATT_GENERAL_INFORMATION_PRICE_TYPE
ProjectConstants.ATT_ANALYSIS_SUPPLIER,suppliers
ProjectConstants.ATT_ITEMS_NUMBER or ProjectConstants.ATT_ITEMS_AML
LookupConstants.FIELD_QUANTITY_RANGE if
LookupConstants.FLAG_IGNORE_QUANTITY is ‘false’
LookupConstants.FIELD_DATE_RANGE if
LookupConstants.FLAG_IGNORE_DATE_RANGE is ‘false’
LookupConstants.FIELD_PRICE_SCENARIO if
LookupConstants.FLAG_ALL_PRICE_SCENARIOS is ‘false’
Note If you do not set the value of LookupConstants.FLAG_EXCLUDE_AUTH_SUPPLIER, it
will default to false.
Generating the Assembly Cost Report for Sourcing Projects
The PLM Web Client supports generating the Assembly Cost Report to help understand the total
cost of a BOM, including the material and non-material costs. To simplify this operation, the Web
Client provides a wizard to locate and select the required Sourcing Project, including the necessary
parameters. See
Understanding Assembly Cost Report Parameters on page 284 for a description
of these parameters.
Chapter 17: Working with Product Cost Management
v9.3.1.2 283
A sample report is shown in the following screen shot. Once the report is prepared, the PLM user
can invoke the Export command and send the data from the PLM to an external device in a
supported format, for example, to an Excel worksheet.
Figure 20: Assembly Cost Report for Sourcing Projects
The SDK supports this Web Client feature by enhancing the ProductReport.execute() API.
The extent of the SDK operation does not include invoking the Export command. The following is a
code sample that uses the ProductReport.execute() API and the required parameters to
programmatically generate this report.
Example: Generating Assembly Cost Reports
String[] items = new String[1];
items[0] = "P00001";
String[] suppliers = new String[2];
suppliers[0] = "-101"; //to include data for best suppliers
suppliers[1] = "EMS1 COMPONENT SUPPLIER";
String[] priceScenarios = new String[1];
priceScenarios[0] = "QuantityBreak1";
Boolean doCostRollup = new Boolean(true);
HashMap map = new HashMap();
map.put(ProductReportConstants.REPORTPARAM_REPORT_TYPE,ProductReport
Constants.REPORT_PROJECT_ASSEMBLY_COST);
map.put(ProductReportConstants.REPORTPARAM_REPORT_CATEGORY, "data");
map.put(ProductReportConstants.PROJECT_NUMBER, "PRJ00001");
map.put(ProductReportConstants.PROJECT_ITEMS, items);
map.put(ProductReportConstants.PROJECT_SUPPLIERS, suppliers);
map.put(ProductReportConstants.PROJECT_PRICEPOINTS, priceScenarios);
map.put(ProductReportConstants.PROJECT_DO_COST_ROLLUP,
doCostRollup);
SDK Developer Guide - Using Agile APIs
284 Agile Product Lifecycle Management
try{
IProductReport report =
(IProductReport)m_session.createObject(IProductReport.OBJECT_TYPE, "My
Reports");
String result =report.execute(map);
}
catch (Exception e){
e.printStackTrace();
}
Note The returned value of the ProductReport.execute()API represents either the XML
data of the Assembly Cost Report or the XML schema. To get the schema, you must set
the values of the first two parameters in the map where the value of the parameter
REPORTPARAM_REPORT_CATEGORY is set to “schema”.
Understanding Assembly Cost Report Parameters
The Assembly Cost Report parameters supported by ProductReport.execute()are defined as
follows:
à items – The array of top level assembly items: "<itemNumber>::<revNumber>" if there is a
revision, and "<itemNumber>" if there are no revisions.
à suppliers – The array of supplier names along with the optional indicators for the "Best of
Suppliers": "-101" or the “Best Of Suppliers/Partners"
à pricescenarios – The array of price scenarios names
à doCostRollup – The flag to run the cost Rollup option for the report
If you want to generate a report for all assemblies, all suppliers/partners, or all price scenarios
without specifying their names, you must provide the following corresponding parameters:
à String[] items = new String[1];
items[0] = "all";
à String[] suppliers = new String[2];
suppliers[0] = "-101";
suppliers[1] = “all";
à String[] priceScenarios = new String[0];
priceScenarios[0] = "all";
Modifying the Target Price for Items in Sourcing Projects
Target Price is the market cost per unit of the item or the manufacturer part. It is specified when
items are ordered. For each Item and for each Pricepoint, Target Price is set in the Items table,
under the AML tab. A Pricepoint is the Target price quoted for a given quantity for an Item. For
example, price quoted for X number of tires, which can be different for Y number of the same tires.
Chapter 17: Working with Product Cost Management
v9.3.1.2 285
Note The Target price is always a positive number. Setting a negative value for Target price
will throw the ExceptionConstants.PCM_NEGATIVE_TARGET_PRICE exception.
Target Price is set at the Item level only. You cannott set a Target Price the AML level. The end
user specifies a Pricepoint using the name displayed for the Pricepoint. In the following example,
QuantityBreak2 is the Pricepoint.
Example: Setting the Target price in Sourcing Projects
ITable tab_item = dObj.getTable(ProjectConstants.TABLE_ITEMS);
IRow row = (IRow) tab_item.iterator().next();
ITable priceTable = row.getValue(ProjectConstants.ATT_ITEMS_PRICING);
for (Iterator iterator = priceTable.iterator(); iterator.hasNext();) {
IRow row = (IRow) iterator.next();
String name = row.getName();
if(name.equals("QuantityBreak2")){
row.setValue(ProjectConstants.ATT_PRICEDETAILS_TARGET_COST,
new Money(new Double(1.23), "USD") );
}
}
Because priceTable is a nested table, you must reload this table to get the updated value of the
Target price as shown in the following example. This is similar to the example in
Setting Quantity
for Items in Sourcing Projects on page 274.
Example: Reloading the priceTable to get the updated value of the target price
priceTable = row.getValue(ProjectConstants. ATT_ITEMS_PRICING);
for (Iterator iterator = priceTable.iterator(); iterator.hasNext();) {
IRow iRow = (IRow) iterator.next();
String name = iRow.getName();
if(name.equals("QuantityBreak2")){
Object qty =
row.getValue(ProjectConstants.ATT_PRICEDETAILS_TARGET_COST));
}
}
Setting the Best Response for Items in Sourcing Projects
The Best Response is set in the Analysis table under the Analysis tab for both the Item and
Manufacturer Part number objects. The end user specifies three of these parameters: Lowest Cost,
Lowest Cost Within Lead Time Constraint, Shortest Lead Time, Supplier Rating, and AML Preferred
status. For more information, refer to Agile Product Lifecycle Management - Product Cost
Management Supplier Guide.
You can use the SDK to find the best response for an Item Part Number (IPN), a Manufacturer Part
Number (MPN), and for an IPN and an MPN as shown in the following code samples.
Example: Setting the Best Response for an IPN
//set best response for ipn //
ITable table_analysis = prj.getTable(ProjectConstants.TABLE_ANALYSIS);
Iterator it = table_analysis.iterator();
while(it.hasNext()) {
SDK Developer Guide - Using Agile APIs
286 Agile Product Lifecycle Management
IRow row = (IRow) it.next();
String itemName =
row.getValue(ProjectConstants.ATT_ANALYSIS_NUMBER);
String suppName =
row.getValue(ProjectConstants.ATT_ANALYSIS_SUPPLIER);
if (itemName.equals("IPN1") && suppName.equals("suppName1
(suppNumber1)")) {
row.setValue(ProjectConstants.ATT_ANALYSIS_BEST_RESPONSE
, “Yes”);
}
}
Example: Setting the Best Response for an MPN
ITable table_aml =
(ITable) row.getValue(ProjectConstants.ATT_ANALYSIS_AML);
Iterator _it =
table_aml.iterator();
while(it.hasNext()){
String itemName =
row.getValue(ProjectConstants.ATT_ANALYSIS_NUMBER);
String suppName =
row.getValue(ProjectConstants.ATT_ANALYSIS_SUPPLIER);
String mfrName = row.getValue(ProjectConstants.
ATT_ANALYSIS_MANUFACTURER);
if (itemName.equals("MPN1") && suppName.equals("suppName1
(suppNumber1)"
&& mfrName.equals("MFR1"))) {
row.setValue(ProjectConstants.ATT_ANALYSIS_BEST_RESPONSE, "Yes");
}
}
Note Because you can only set the Best Response to Yes, if you pass any value other than
Yes, the ExceptionConstants.API_INVALID_PARAM exception is thrown.
Example: Getting the Best Response for an IPN and an MPN
String bResp =
row.getValue(ProjectConstants.ATT_ANALYSIS_BEST_RESPONSE).toString();
Setting Partners in Sourcing Projects
Partners can view complete Sourcing Project BOMs in RFQs. You can assign partners to an item in
the Sourcing Project when you add the item to the RFQ that will be sent to the partners. If multiple
partners are selected, you can split the quantity among the partners by specifying what percentage
of an item you want to receive from each supplier. For example, if two partners supply the same
item, you can add both partners to the list and then assign a certain percentage to each, for
example, 50%-50%, or 60%-40%, and so on.
In the SDK, the following API is used to set partners for an item in a Sourcing Project and split the
percentage among the partners.
public void assignSupplier(Object partnerParams) throws APIException,
RemoteException, Exception;
Chapter 17: Working with Product Cost Management
v9.3.1.2 287
The behavior of this API and its use cases are similar to
IRequestForQuote.assignSupplier(). However, when you add new partners for an item
with this API, you will override the existing ones. Thus, to avoid removing existing partners, it is
necessary to once again add the existing partners and set the split (Percentage for each) level for
each one. This only occurs in the SDK, the GUI does not require adding the existing partners when
you add new partners. You cannot remove a partner for an item, but assigning a split = 0,
(Percentage of ownership/participation) will remove the partner. For more information on the GUI
behavior, refer to the latest release of Agile Product Lifecycle Management - Product Cost
Management Supplier Guide.
The following code sample sets partners and splits the percentages among the assigned partners.
Example: Setting partners and splitting percentages among partners
HashMap map = new HashMap();
HashMap supplierSplit = new HashMap();
HashMap partnerMap = new HashMap();
map.put(ProjectConstants.ATT_ITEM_NUMBER, item);
Double split1 =
new Double(55);
Double split2 =
new Double(75);
supplierSplit.put(supplier1, split1);
supplierSplit.put(supplier2, split2);
partnerMap.put(ProjectConstants.ATT_PARTNERS_PARTNER, supplierSplit);
map.put(ProjectConstants.ATT_ITEM_PARTNER_TABLE, partnerMap);
prj.assignSupplier(map);
An item or supplier can be an IItem object, a ISupplier object, or a String object.
Partners can be assigned to any Item Part Number (IPN), but not a Manufacturer Part Number
(MPN). If the item is not in the Sourcing Project, the
ExceptionConstants.PCM_ERROR_INVALID_PROJECT_ITEM is thrown.
Split percentages can be any object representing a number. If it is not a number, the
ExceptionConstants.API_INVALID_PARAM exception is thrown.
To get data about a given partner, you can use the Items or AML tabs as shown below.
Example: Getting partner data using Item or AML
ITable tab_item =
prj.getTable(ProjectConstants.TABLE_ITEMS);
IRow row = (
IRow) tab_item.iterator().next();
ITable partnerTable =
(ITable) row.getValue(ProjectConstants.ATT_ITEMS_PARTNERS);
Or,
ITable tab_item =
prj.getTable(ProjectConstants.TABLE_ITEM);
IRow row =
(IRow) tab_item.iterator().next();
ITable partnerTable =
(ITable) row.getValue(ProjectConstants.ATT_ITEM_PARTNER_TABLE);
SDK Developer Guide - Using Agile APIs
288 Agile Product Lifecycle Management
for (Iterator iterator =
partnerTable.iterator(); iterator.hasNext();) {
IRow iRow =
(IRow) iterator.next();
String partner =
iRow.getValue(ProjectConstants.ATT_PARTNERS_PARTNER).toString();
String split =
iRow.getValue(ProjectConstants.ATT_PARTNERS_PARTNER_SPLIT).toString(
);
}
Working with RFQs
Requests for Quotes (RFQs) allow users to request pricing information from suppliers. RFQs serve
as the instrument to negotiate pricing and terms for items or manufacturer parts. RFQs are defined
for Sourcing projects. Thus, to define an RFQ, you must first create the Sourcing Project and then
create the required RFQs for that Sourcing Project.
A single Sourcing Project can generate several RFQs. RFQs support a one-to-many relationship
with suppliers. That is, one RFQ may generate several responses from suppliers.
The Agile API supports the following RFQ-related tasks.
à Create an RFQ for Sourcing a Project
à Load and modify RFQ objects, tables, and attributes
à Access and modify the Page 1, Page 2, and RFQ Response tables
à Add items to the RFQ Response table from the RFQ’s Sourcing Project
à Read and update the nested tables in the Page 1, Page 2, and RFQ Response table
à Assign suppliers to items or manufacturer parts in the RFQ Response table
For a list of API methods that support these RFQ functions, see
Supported API Methods on page
288.
Note The PCM SDK RFQ objects do not have a Page three, and no Page three RFQ constant
is supported. Do not invoke these constants because the RFQ will not produce the
expected result.
Supported API Methods
The SDK supports the following APIs for RFQs. For information on these interfaces, refer to the
Javadoc generated HTML files that document the SDK code. You can find them in the HTML folder
in SDK_samples (ZIP file). To access this file, see the Note in
Client-Side Components on page 2.
à IAgileSession.createObject(Object, Object)
à IAgileSession.createObject(int, Object)
à IAgileSession.getObject(Object, Object)
à IAgileSession.getObject(int, Object)
Chapter 17: Working with Product Cost Management
v9.3.1.2 289
à IRequestForQuote.getName()
à IRequestForQuote.assignSupplier(Object)
à IRequestForQuote.getTable(Object)
à IRequestForQuote.lookupPrices(Object)
à ITable.iterator()
à ITable.getTableDescriptor()
à ITable.size()
à ITable.createRow(Object)
à IRow.getValue(Object)
à IRow.setValue(Object, Object)
Creating RFQs for Sourcing Projects
RFQs are defined for a specific Sourcing Project. Creating an RFQ uses the generic
IAgileSession method.
Similar to Sourcing Projects (see
Creating RFQs for Sourcing Projects on page 289), you can use
IDataObject with standard calls such as getObject, getTable, getValue, setValue to
access and modify objects, tables, and attributes as follows:
à Read Page 1 or Cover Page and Page 2 tables
à Update Page 1 or Cover Page and Page 2 tables
Example: Creating an object
IAgileObject createObject(Object objectType, Object params)
throws APIException;
To create an RFQ, you must open the Sourcing Project. However, to open the Sourcing Project, it is
necessary to first set the ship to location. See the code example in Accessing and Modifying the
Status of Sourcing Projects.
You cannot create an RFQ by specifying the Sourcing Project number only. You must also specify
the related Sourcing Project as this is a required parameter. This is shown in the example below.
Example: Creating an RFQ for a Sourcing Project
IAgileClass rfqClass =
m_admin.getAgileClass(RequestForQuoteConstants.CLASS_RFQ);
IAutoNumber rfqNumber = rfqClass.getAutoNumberSources()[0];
HashMap map = new HashMap();
map.put(RequestForQuoteConstants.ATT_COVERPAGE_RFQ_NUMBER, rfqNumber);
map.put(RequestForQuoteConstants.ATT_COVERPAGE_PROJECT_NUMBER,
pnumber);
IRequestForQuote rfq =
(IRequestForQuote) m_session.createObject(rfqClass, map);
SDK Developer Guide - Using Agile APIs
290 Agile Product Lifecycle Management
Loading Existing RFQs
You can load an existing RFQ using the IAgileSession.getObject() method, or select it from
the RFQ table of the Sourcing Project object.
To load an RFQ, use the IAgileSession.getObject() method. To uniquely identify an RFQ,
specify the value for the Cover Page | RFQ Number attribute.
Example: Loading an RFQ
public IRequestForQuote getRFQ() throws APIException {
IRequestForQuote rfq =
(IRequestForQuote)m_session.getObject(IRequestForQuote.OBJECT_TYPE,
"RFQ01004");
return rfq;
}
Loading RFQs from Sourcing Project's RFQ Table
In addition to loading an RFQ using IAgileSession.getObject(), you can also select an RFQ
from the RFQ table of the Sourcing Project object.
Example: Loading an RFQ from the Sourcing Project RFQ table
ITable table = prj.getTable(ProjectConstants.TABLE_RFQS);
Iterator it = table.iterator();
IRow row1 = (IRow) it.next();
IDataObject obj1 = (IDataObject)
m_session.getObject(IRequestForQuote.OBJECT_TYPE,
row1.getValue(ProjectConstants.ATT_RFQS_RFQ_NUMBER));
Note The getReferent() method does not support the PCM SDK, including the RFQ
tables. A list of supported RFQ tables appears in the table below.
Supported RFQ Tables
The supported RFQ tables and their respective constants are listed in the table below.
Table Constant Read/Write Mode
Cover Page
TABLE_COVERPAGE
Read/Write
Page Two
TABLE_PAGETWO
Read/Write
Responses
TABLE_RESPONSES
Read/Write
Note The Agile API does not support adding new rows to RFQ tables. However, you can add
new rows to the RFQ response table.
Chapter 17: Working with Product Cost Management
v9.3.1.2 291
Accessing and Modifying RFQ Objects, Tables, Nested Tables, and
Attributes
You can access RFQ objects, tables, and attributes using the generic IAgileSession and
IDataObject methods and standard calls such as getObject, getValue, setValue.
Information about these classes, tables, and attributes is provided in the
com.agile.api.RequestForQuoteConstants.java file in the API HTML reference files. See
Client-Side Components on page 2 to access these files.
RFQ Parent Table and Nested Child Table Constants
The list of parent RFQ table and the corresponding nested child table constants appears in the
table below.
Parent Table Constant Nested Child Table
Constant
Read/Write Mode
TABLE_RESPONSES ATT_RESPONSES_AML
Read/Write
TABLE_RESPONSES ATT_RESPONSES_PRICING
Read/Write
Similar to Sourcing Projects, nested RFQ tables are accessed by treating their cell value as a table.
See
Accessing and Modifying Nested Tables in Sourcing Projects or RFQ on page 273. The
following example updates a nested table.
Note Do not use Project.ATT_RFQ_RFQ_STATE to get the status of an RFQ, because it is
not exposed to the SDK and will not render the correct value of the RFQ row. To get the
status of an RFQ, you must first load the RFQ, and then get the status from the RFQ
itself.
Example: Nested RFQ table update
ITable subtab1 =
(ITable)row.getValue(RequestForQuoteConstants.ATT_RESPONSES_PRICING)
;
IRow pricing1 =
(IRow)subtab1.iterator().next();
Integer nest =
ProjectConstants.ATT_PRICEDETAILS_MATERIAL_PRICE;
Object nre =
pricing1.getValue(nest);
Money tc =
new Money(new Integer(100), “USD”);
pricing1.setValue(nest, (Object)tc);
Note You must assign the supplier before updating an RFQ response table entry.
SDK Developer Guide - Using Agile APIs
292 Agile Product Lifecycle Management
Performing Price Lookup in RFQs
Similar to Performing Price Lookup in a Sourcing Project on page 277, you can verify the existence
of a price scenario for a specified period and quantity for RFQs. If they exist, you do not have to
create an RFQ for the specified item. You can either use the price information of the item, or you
can modify the price information and send the RFQ to suppliers for requote. This is shown in the
following code sample.
Example: Price lookup from history and from another Sourcing Project
HashMap map = new HashMap();
map.put(PriceConstants.ATT_GENERAL_INFORMATION_PRICE_TYPE,priceTypes);
map.put(ProjectConstants.ATT_ANALYSIS_SUPPLIER,suppliers);
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_CUSTOMER,customers);
map.put(ProjectConstants.ATT_GENERAL_INFORMATION_PROGRAM,programs);
map.put(ProjectConstants.
ATT_GENERAL_INFORMATION_SHIP_TO_LOCATION,shipTo);
map.put(ProjectConstants.ATT_ITEMS_NUMBER,itemMap);
map.put(ProjectConstants.ATT_ITEMS_AML,mpnMap);
map.put(LookupConstants.FLAG_ALL_PRICE_SCENARIOS,allPriceScenarios);
map.put(LookupConstants.FIELD_PRICE_SCENARIO,priceScenario);
map.put(LookupConstants.FLAG_IGNORE_QUANTITY,ignoreQtyRange);
map.put(LookupConstants.FIELD_QUANTITY_RANGE,qtyPercentRange);
map.put(LookupConstants.FLAG_IGNORE_DATE_RANGE,ignoreDateRange);
map.put(LookupConstants.FIELD_DATE_RANGE,dateRange);
map.put(LookupConstants.
FIELD_SELECT_RESPONSE_BY,LookupConstants.OPTION_LOWEST_PRICE);
map.put(LookupConstants.FLAG_EXCLUDE_AUTH_SUPPLIER,excludeAuthSupplier)
;
rfq.lookupPrices(map);
Required parameters for an RFQ price lookup
PriceConstants.ATT_GENERAL_INFORMATION_PRICE_TYPE
ProjectConstants.ATT_ANALYSIS_SUPPLIER,suppliers
ProjectConstants.ATT_ITEMS_NUMBER or ProjectConstants.ATT_ITEMS_AML
LookupConstants.FIELD_QUANTITY_RANGE if
LookupConstants.FLAG_IGNORE_QUANTITY is ‘false’
LookupConstants.FIELD_DATE_RANGE if
LookupConstants.FLAG_IGNORE_DATE_RANGE is ‘false’
LookupConstants.FIELD_PRICE_SCENARIO if
LookupConstants.FLAG_ALL_PRICE_SCENARIOS is ‘false’
Impact of Improper parameter settings
LookupConstants.FLAG_EXCLUDE_AUTH_SUPPLIER will default to false if not set.
Chapter 17: Working with Product Cost Management
v9.3.1.2 293
Working with RFQ Responses
The PCM SDK supports the following operations for RFQ responses, nested table of items
responses, and Child AML responses:
à Read RFQ tables with different views (price scenarios, currency modes)
This is supported through generic SDK API.
à Add items to RFQs
à Add Response lines (Assign Suppliers)
PCM RFQ provides the following method for assigning suppliers to items or manufacturer
parts.
public void assignSupplier(Object supplierParams)
throws APIException, RemoteException, Exception;
You can assign supplier data such as Manufacturer Part Number (mpn) or supplier name as a
String or an Object to the RFQ response.
Example: Adding supplier data as String constants
IRequestForQuote dObj =
(IRequestForQuote)m_session.getObject(RequestForQuoteConstants.CLASS
_RFQ, number);
ITable tab =
dObj.getTable(RequestForQuoteConstants.TABLE_RESPONSES);
Map mp = new HashMap();
mp.put(ProjectConstants.ATT_RESPONSES_NUMBER, “P00007”);
mp.put(ProjectConstants.ATT_RESPONSES_SUPPLIER, “SDKSUP”);
dObj.assignSupplier(mp);
Example: Adding supplier data as Objects
You can also add an item as an IItem object as shown below.
mp.put(ProjectConstants.ATT_RESPONSES_NUMBER, itemObject);
If you are assigning a supplier to an mpn, you must specify the mpn as an IManufacturerPart
Object, or as a pair of Objects. One for the mpn name and one for mfr name.
mp.put(RequestForQuoteConstants.ATT_RESPONSES_NUMBER, mpnObject);
Or,
mp.put(RequestForQuoteConstants.ATT_RESPONSES_NUMBER, mpnName);
mp.put(RequestForQuoteConstants.ATT_RESPONSES_MANUFACTURER, mfrName);
SDK Developer Guide - Using Agile APIs
294 Agile Product Lifecycle Management
Caution When you invoke RequestForQuote.TABLE_RESPONSE to assign suppliers to item
components, the table size may change if there is more than one supplier for that item
component. That is, if an item has a single supplier, each item and the corresponding
supplier will occupy their own distinct separate rows in the TABLE_RESPONSE table.
However, if the item has more than one supplier, then the row for this item component
is split into the number of suppliers, thus changing TABLE_RESPONSE by increasing
the number of rows in the table. It is therefore necessary to immediately reload the
ITERATOR to reflect the change in TABLE_RESPONSE table. This is not an SDK
defect and is due to SUN J2SE ITERATOR behavior.
à Update Response Lines
The PCM SDK supports the RFQ response table through generic SDK API. It does not support
the RFQ Response Class or Supplier Response.
Note The response currency in the RFQ response line is determined by the response
currency attribute. This causes the server to ignore the currency parameter in the
material price. Buyers can modify the response currency in the response line and it
will be applied to all pricing attributes in the response line. The supplier RFQ
response currency is set to your RFQ currency preference and cannot be modified
in the supplier responses. Once the response line is opened to suppliers, the
response line must be locked before buyers can modify them.
v9.3.1.2 295
Chapter 18
Managing Product Governance &
Compliance
This chapter includes the following:
About Agile Product Governance and Compliance ............................................................................................. 295
Agile PG&C Interfaces and Classes.................................................................................................................... 296
Agile PG&C Roles ............................................................................................................................................... 296
Creating Declarations, Specifications, and Substances ......................................................................................297
Creating Substances ........................................................................................................................................... 299
Adding Items, Manufacturer Parts, and Part Groups to Declarations.................................................................. 301
Adding Substances to Declarations..................................................................................................................... 302
Adding Substances to a Specification .................................................................................................................308
Adding Specifications to a Declaration................................................................................................................ 309
Routing Declarations ........................................................................................................................................... 310
Completing a Declaration .................................................................................................................................... 311
Submitting Declarations to Compliance Managers.............................................................................................. 312
Publishing a Declaration...................................................................................................................................... 313
Getting and Setting Weight Values...................................................................................................................... 313
Adding Substance Compositions for Manufacturer Parts.................................................................................... 314
Rolling Up Compliance Data................................................................................................................................316
About Agile Product Governance and Compliance
Agile Product Governance & Compliance (PG&C) addresses the growing number of environmental
regulations and corporate environmental policies that impact product definition and the import,
export, and disposal of restricted substances. Agile PG&C is designed to help OEM manufacturers
audit the amount of regulated substances used in their products, and show that they responsibly
dispose of, recycle or reuse electronics containing those substances.
Agile PG&C allows companies to cost-effectively comply with environmental regulations.
Companies can use Agile PG&C to obtain compliance data for parts from their suppliers. This
allows companies to
à Meet substance restrictions
à Satisfy reporting requirements for regulations
à Design recyclable products
à Minimize compliance costs
à Eliminate noncompliance on future products
Agile PG&C is a communication vehicle between the Compliance Manager and suppliers. The
Compliance Manager ensures that a company’s products adhere to government regulations and
company policy. As the Material Provider, the supplier completes and signs off on material
SDK Developer Guide - Using Agile APIs
296 Agile Product Lifecycle Management
declarations, thereby disclosing which hazardous substances are contained within the components
and subassemblies it provides. For a more detailed overview of Agile PG&C features, refer to the
Product Governance & Compliance User Guide.
Agile PG&C Interfaces and Classes
The following table lists Agile PG&C-related interfaces and classes:
Object Interface Constants Class
Declaration
IDeclaration DeclarationConstants
Specification
ISpecification SpecficationConstants
Substance
ISubstance SubstanceConstants
Part Groups
ICommodity PartGroupConstants
Items, Manufacturer Parts, and Part Groups are objects that are also related to Agile PG&C. They
have Specifications, Compositions, and Substances tables that are populated with data when
declarations are released. For Manufacturer Parts, you can edit the Compositions and Substances
tables directly without submitting a declaration.
Note The terms “part group” and “commodity” are used interchangeably in this guide to refer
to any ICommodityobject. ICommodity represents the Part Group base class, which
includes the Commodity and Part Family subclasses.
Of course, other common Agile API interfaces, such as ITable, IDataObject, and ICell, are
also used to work with Agile PG&C objects.
Agile PG&C Roles
Agile PLM provides two out-of-the-box roles designed for Agile PG&C users:
à Compliance Manager – This provides privileges needed to create and manage Agile PG&C
objects, such as Declarations, Substances, and Specifications, and run Agile PG&C reports.
Compliance Managers are responsible for routing material declarations to suppliers.
à (Restricted) Material Provider – This provides privileges needed to create and modify declarations,
as well as read all other types of Agile PG&C objects. This role is typically assigned to supplier
users, who have restricted access to the Agile PLM system. Material Providers are responsible
for completing and signing off on material declarations.
To use Agile PG&C APIs mentioned in this chapter, make sure you log in as a user assigned either
the Compliance Manager role, or the (Restricted) Material Provider role. For more information about
Agile PLM roles, refer to the Agile PLM Administrator Guide.
Chapter 18: Managing Product Governance & Compliance
v9.3.1.2 297
Note The Discover Change privilege mask is not included in the Compliance Manager role. If
you only have the Compliance Manager role, then you do not have sufficient privileges to
use the API to set the calculated compliance of a part in a Declaration, and pass the
Change Number to the SDK call. To pass the Change Number in the SDK call, you must
have the Discover Change privilege mask for that object in the Change Orders class. For
more information, see
Setting Values in the Calculated Compliance Field for Declaration
Objects on page 320.
Creating Declarations, Specifications, and Substances
The following paragraphs provide definitions and procedures to define and manage these PG&C
classes.
Creating Declarations
A Declaration object is the main record of Agile PG&C. It tracks the substances and materials that
are used for items, manufacturer parts, and part groups. When you release a declaration, the
information gathered from it is published to the product record, thereby updating the Composition
data contained within the items, manufacturer parts, and part groups listed by the declaration.
There are seven declaration subclasses provided with Agile PLM:
à Homogeneous Material Declaration – A homogeneous material composition declaration that
uses material-level specifications.
à IPC 1752-1 Declaration – A material composition declaration for electronic products that
conforms to IPC standards and uses only one part-level specification.
à IPC 1752-2 Declaration – A homogeneous material composition declaration for electronic
products that conforms to IPC standards and uses only one material-level specification.
à JGPSSI Declaration – A material composition declaration that follows the Japanese Green
Procurement (JGP) standard and uses part-level specifications.
à Part Declaration – A material composition declaration that uses part-level or material-level
specifications.
à Substance Declaration – A material composition declaration for each substance within part-
level specifications.
à Supplier Declaration of Conformance – A questionnaire to assess supplier compliance with
specifications from customers and government agencies. The survey addresses compliance at
a general company level. Can be used for CSR type declarations.
The procedure for creating a declaration is the same for all declaration subclasses. You must
specify the declaration subclass as well as values for the Cover Page.Name and Cover Page.Supplier
attributes. Other declaration attributes are optional.
By default, the Cover Page.Name field uses an Autonumber format with the prefix “MD” (for “Material
Declaration”). Although the Autonumber format isn’t required, it makes sense to use the same prefix
for all declarations to make it easier to search for them.
SDK Developer Guide - Using Agile APIs
298 Agile Product Lifecycle Management
Note The case required for the Cover Page.Name field depends on the selected character set for
the field. For more information about defining and modifying character sets, Refer to the
Agile PLM Administrator Guide.
Supplier users with the (Restricted) Material Provider role can also create declarations. However, in
this case, only the Cover Page.Name attribute is required to create the object. The Cover Page.Supplier
attribute is filled in automatically with the user’s supplier organization.
The following example shows how to create a JGPSSI declaration.
Example: Creating a JGPSSI Declaration
public void CreateJGPSSIDeclaration(String num, ISupplier supplier)
throws Exception {
// Create a Map object to store parameters
Map params = new HashMap();
// Initialize the params object
params.put(DeclarationConstants.ATT_COVER_PAGE_NAME, num);
params.put(DeclarationConstants.ATT_COVER_PAGE_SUPPLIER, supplier);
// Get the JGPSSI Declaration subclass
IAgileClass declClass = m_session.getAdminInstance().getAgileClass(
DeclarationConstants.CLASS_JGPSSI_DECLARATION);
// Create a new JGPSSI declaration
IDeclaration object =
(IDeclaration)m_session.createObject(declClass, params);
}
Creating Specifications
Specifications are used to state the criteria that a product is expected to meet or exceed. They are
generally used to limit the amount of restricted substances contained in a product. Specifications
can be internal documents issued by a company or industry, or, more commonly, they are
regulations issued by a governing body. Here are some examples of government regulations:
à Restrictions on the Use of Certain Hazardous Substances in Electrical and Electronic
Equipment (RoHS) Directive, issued by the European Union
à Waste Electrical and Electronic Equipment (WEEE) Directive, issued by the European Union
à Food Allergen Labeling and Consumer Protection Act (FALCPA), issued by the U.S.A. Food
and Drug Administration (FDA)
A specification defines a list of substances, the parts-per-million (PPM) threshold for each
substance, and whether a particular substance is restricted. Compliance Managers can use
specifications to pre-populate material declarations with appropriate substances to ensure
compliance.
The only required attribute you must specify when you create a specification is General Info.Name.
The name must be unique. The name is case-insensitive, which means “ROHS” is treated the same
as “Rohs”.
The General Info.Validation Type attribute is important because it determines whether the specification
is Part Level (the default) or Homogeneous Material Level, which affects the types of declarations
that can be used with the specification. Another optional attribute is General Info.Lifecycle Phase.
Chapter 18: Managing Product Governance & Compliance
v9.3.1.2 299
When you create a specification, the default lifecycle phase is Active. To make the specification
obsolete, change the value of its lifecycle phase attribute to Obsolete.
Example: Creating a specification
public void createSpecification(String name) throws Exception {
ISpecification spec =
(ISpecification)
m_session.createObject(SpecificationConstants.CLASS_SPECIFICATION,
name);
}
Creating Substances
There are four substance subclasses provided with Agile PLM:
à Subpart – a subunit of a component manufacturer part. The Composition table of a subpart can
have other subparts, materials, substance groups, and substances.
à Material – a compound consisting of several substances. The Composition table of a material
can have substance groups or substances.
à Substance Group – a group of substances. The Composition table of a substance group can
have only substances.
à Substance – a single element, such as lead, chromium, or cadmium. Substances do not have a
Composition table.
These substance subclasses comprise the hierarchy of objects that can appear on a Composition
table, also known as the Bill of Substances.
Creating a Subpart
A subpart object is a subunit of a component that is tracked in Agile PLM. Subparts are parts
without a part number that are used to create a bill of material of manufacturer parts or parts within
a composition.
Example: Creating a subpart
public void createSubpart(String num) throws Exception {
// Create a Map object to store parameters
Map params = new HashMap();
// Initialize the map object
params.put(SubstanceConstants.ATT_GENERAL_INFO_NAME, num);
// Get the Subpart subclass
IAgileClass subsClass =
m_session.getAdminInstance().getAgileClass(SubstanceConstants.CLASS_
SUBPART);
// Create a new Subpart
ISubstance sub =
(ISubstance)m_session.createObject(class, params);
}
SDK Developer Guide - Using Agile APIs
300 Agile Product Lifecycle Management
Creating a Substance Group
A substance group object is a group of multiple substances tracked in Agile PLM that have a
common base substance. Every substance within the group has a conversion factor used to convert
the weight of the base substance of the group.
Example: Creating a substance group
public void createSubstanceGroup(String num, ISubstance sub) throws
Exception {
// Create a Map object to store parameters
Map params = new HashMap();
// Initialize the map object
params.put(SubstanceConstants.ATT_GENERAL_INFO_NAME, num);
params.put(SubstanceConstants.ATT_GENERAL_INFO_BASE_SUBSTANCE, sub);
// Get the Substance Group subclass
IAgileClass subsClass =
m_session.getAdminInstance().getAgileClass(SubstanceConstants.CLASS_
SUBSTANCE_GROUP);
// Create a new Substance Group
ISubstance sub =
(ISubstance)m_session.createObject(subsClass, params);
}
Creating a Material
When you create a material object, the only attribute you need to specify is the General Info.Name
attribute, which is equivalent to the substance number. After you create a material object, you can
add substances to its Composition table.
Example: Creating a material object and adding substances to it
public void createMaterial(String num, ISubstance[] substances) throws
Exception {
// Create a Map object to store parameters
Map params = new HashMap();
// Initialize the params object
params.put(SubstanceConstants.ATT_GENERAL_INFO_NAME, num);
// Create a new material
ISubstance material =
(ISubstance)m_session.createObject(SubstanceConstants.CLASS_MATERIAL
, params );
// Get the Composition table
ITable composition =
material.getTable(SubstanceConstants.TABLE_COMPOSITION);
// Add substances to the Composition table
for (int i = 0; i < substances.length; ++i) {
IRow row = composition.createRow(substances[i]);
}
}
Chapter 18: Managing Product Governance & Compliance
v9.3.1.2 301
Creating a Substance
Like material objects, the only attribute you need to specify to create a substance is the General
Info.Name attribute, which is equivalent to the substance number. You can also specify other optional
attributes, such as General Info.CAS Number.
Example: Creating a substance
public void createSubstance(String num, String casNumber) throws
Exception {
// Create a Map object to store parameters
Map params = new HashMap();
// Initialize the params object
params.put(SubstanceConstants.ATT_GENERAL_INFO_NAME, num);
params.put(SubstanceConstants.ATT_GENERAL_INFO_CAS_NUMBER,
casNumber);
// Get the Substance subclass
IAgileClass subsClass =
m_session.getAdminInstance().getAgileClass(SubstanceConstants.CLASS_
SUBSTANCE);
// Create a new substance
ISubstance substance =
(ISubstance)m_session.createObject(subsClass, params);
}
Adding Items, Manufacturer Parts, and Part Groups to
Declarations
Each declaration has separate tables for items, manufacturer parts, and part groups. Each of these
also has an associated composition table: Item Composition, Manufacturer Part Composition, and
Part Group Composition.
When you add an item to the Items table of a declaration, the latest released revision of the item is
used. If the item does not have a released revision, the Introductory revision is used.
The following example shows how to add items, manufacturer parts, and part groups to a
declaration.
Example: Adding items, manufacturer parts, and part groups to a declaration
public void addDecObjects(IDeclaration dec) throws APIException {
try {
HashMap params = new HashMap();
//Add an Item to the Items table
ITable tblItems =
dec.getTable(DeclarationConstants.TABLE_ITEMS);
params.clear();
params.put(DeclarationConstants.ATT_ITEMS_ITEM_NUMBER, "1000-02");
IRow rowItems =
tblItems.createRow(params);
//Add a Manufacturer Part to the Manufacturer Parts table
SDK Developer Guide - Using Agile APIs
302 Agile Product Lifecycle Management
ITable tblMfrParts =
dec.getTable(DeclarationConstants.TABLE_MANUFACTURERPARTS);
params.clear();
params.put(DeclarationConstants.ATT_MANUFACTURER_PARTS_MFR_PART_NUMB
ER, "Widget103");
params.put(DeclarationConstants.ATT_MANUFACTURER_PARTS_MFR_NAME,
"ACME");
IRow rowMfrParts = tblMfrParts.createRow(params);
//Add a Commodity to the Part Groups table
ITable tblPartGroups =
dec.getTable(DeclarationConstants.TABLE_PARTGROUPS);
params.clear();
params.put(DeclarationConstants.ATT_PART_GROUPS_NAME, "RES");
IRow rowPartGroups =
tblPartGroups.createRow(params);
} catch (APIException ex) {
System.out.println(ex);
}
}
Adding Substances to Declarations
You can add substances to the Item Composition, Manufacturer Part Composition, and Part Group
Composition tables contained within a declaration. To publish substances into items, manufacturer
parts, and part groups, you release the declaration. When the declaration is released, the
substances get added automatically to the Substances tables of the corresponding items,
manufacturer parts, and part groups.
The composition tables for a declaration are mapping tables; they map parts to their substances. If
there are no substances for the parent object, the composition table has no rows.
To add a row to the composition tables of a declaration, use the ITable.createRow() method.
Because the composition tables are mapping tables, you cannot pass an ISubstance object to
create the row. Instead, specify a Map object containing attribute-value pairs.
Important The Substances and Composition tables for items and part groups are read-only.
They get populated with data only when declarations are released.
To add a substance to one of the Composition tables of a declaration:
1. Add an item, manufacturer part, or part group to the Items, Manufacturer Parts, or Part Groups
tables of a declaration, respectively.
2. Add a substance row to the Composition table that references the parent row on the Items,
Manufacturer Parts, or Part Groups table. Use the virtual attribute
DeclarationConstants.ATT_PARENT_ROW to specify the parent row. When you add a
substance, specify the substance name and substance type.
Important For the Agile SDK, Composition tables for declarations list all parent objects
contained in the Items, Manufacturer Parts, and Part Groups tables. Agile Web
Client represents Composition tables differently. It shows a separate
Composition table for each parent object.
Chapter 18: Managing Product Governance & Compliance
v9.3.1.2 303
When you create a row in the Composition tables, you pass a Map object containing attribute-value
pairs. The following table lists the attributes the Map object must contain:
Composition
Table
Required Attributes DeclarationConstants
Item Composition Item Row
Substance Name
ATT_PARENT_ROW
ATT_ITEM_COMPOSITION_SUBSTANCE_NAME
Manufacturer Part
Composition
Manufacturer Part Row
Substance Name
ATT_PARENT_ROW
ATT_MANUFACTURER_PART_COMPOSITION_SUBSTANCE_N
AME
Part Group
Composition
Part Group Row
Substance Name
ATT_PARENT_ROW
ATT_PART_GROUP_COMPOSITION_SUBSTANCE_NAME
Structure of Bill of Substances
When you add substances to the Composition tables of a declaration, you can structure them in
multiple levels. The number of levels you can use depends on the type of declaration.
à Homogeneous Materials Declaration – You can create a multilevel Bill of Substances with
subparts, materials, substance groups, and substances. The composition must contain either a
subpart or a material as a direct child. It can also include substances and substance groups,
but they must be attached to a subpart or material.
à Substance Declaration/JGPSSI Declaration – Users can add substances or substance groups
to the Composition tables.
à Part Declaration/Supplier Declaration of Conformance – These declarations do not have
Composition tables.
The following figure shows the hierarchy for a Bill of Substances (Composition) with four child
levels.
SDK Developer Guide - Using Agile APIs
304 Agile Product Lifecycle Management
Rules for Adding Substances
Follow these rules when adding substances to a Composition table:
à Parent objects must be added before their children.
à Subparts can have the following children: other Subparts, Materials, Substance Groups, or
Substances.
y A Subpart cannot contain Subparts, Materials, Substance Groups, and Substances all at
the same level.
y A Subpart can contain other Subparts and Material at the same level.
y A Subpart can contain Substance Groups and Substances at the same level.
à Material can have the following children: Substance Groups or Substances.
à Substance Groups can have the following children: Substances only.
Adding Subparts and Materials that Do Not Exist
When you add substances to a Composition table of a declaration, you can specify “dummy”
subparts and materials that do not exist in the Agile PLM system. Such subparts and materials will
be visible only within the Composition table. When you add “dummy” subparts and materials to the
Composition table, you must specify the Substance Type attribute:
à ATT_ITEM_COMPOSITION_SUBSTANCE_TYPE
à ATT_MANUFACTURER_PART_COMPOSITION_SUBSTANCE_TYPE
à ATT_PART_GROUP_COMPOSITION_SUBSTANCE_TYPE
The following example shows how to add a dummy subpart or material to the Manufacturer Part
Composition table. Because the Substance Type field is a list field, the value passed for it is an
IAgileList.
Example: Adding a dummy subpart or material to the Manufacturer Part Composition table
public IRow addDummy(IDeclaration dec, IRow parentRow,
String dummyName, IAgileList subtype)
throws APIException {
try {
HashMap params = new HashMap();
ITable tblMfrPartComp =
dec.getTable(DeclarationConstants.TABLE_MANUFACTURERPARTCOMPOSITION)
;
params.put(DeclarationConstants.ATT_PARENT_ROW, parentRow);
params.put(DeclarationConstants.ATT_MANUFACTURER_PART_COMPOSITION_SU
BSTANCE_NAME, dummyName);
params.put(DeclarationConstants.ATT_MANUFACTURER_PART_COMPOSITION_SU
BSTANCE_TYPE, subtype);
IRow dummyRow = tblMfrPartComp.createRow(params);
return dummyRow;
} catch (APIException ex) {
System.out.println(ex);
}
}
Chapter 18: Managing Product Governance & Compliance
v9.3.1.2 305
Examples of Adding Substances
The following examples show how to add:
à Substances to the Manufacturer Part Composition Table of a Homogeneous Material
Declaration
à Substances to the Manufacturer Part Composition Table of a Substance Declaration
Adding Substances to Manufacturer Part Composition Table of
Homogeneous Material Declarations
The following example shows how to add substances to a Manufacturer Part Composition table of a
Homogeneous Material Declaration. The table has four levels: subparts, materials, substance
groups, and substances. When you add a substance row to the table, we recommend that you pass
a substance object (ISubstance) instead of a substance name (String) as the input parameter.
Example: Adding Homogeneous Material Level substances to a Manufacturer Part
Composition table
public void addHomogeneousMaterialComp(IAgileSession m_session) throws
APIException {
try {
HashMap params = new HashMap();
// Create a Declaration
String num =
"MDTEST001";
ISupplier supplier =
(ISupplier)m_session.getObject(ISupplier.OBJECT_TYPE,
"DISTRIBUTOR00007");
params.put(DeclarationConstants.ATT_COVER_PAGE_NAME, num);
params.put(DeclarationConstants.ATT_COVER_PAGE_SUPPLIER, supplier);
IAgileClass declClass =
m_session.getAdminInstance().getAgileClass(DeclarationConstants.CLAS
S_HOMOGENEOUS_MATERIAL_DECLARATION);
IDeclaration dec =
(IDeclaration)m_session.createObject(declClass, params);
// Add a Homogeneous Material Level spec to the Specifications table
ITable tblSpec =
dec.getTable(DeclarationConstants.TABLE_SPECIFICATION);
params.clear();
ISpecification spec =
(ISpecification)m_session.getObject(ISpecification.OBJECT_TYPE,
"Lead Homogeneneous Material Level");
IRow rowSpec = tblSpec.createRow(spec);
// Add a Manufacturer Part to the Manufacturer Parts table
ITable tblMfrParts =
dec.getTable(DeclarationConstants.TABLE_MANUFACTURERPARTS);
params.clear();
params.put(DeclarationConstants.ATT_MANUFACTURER_PARTS_MFR_PART_NUMB
ER, "Widget103");
params.put(DeclarationConstants.ATT_MANUFACTURER_PARTS_MFR_NAME,
"ACME");
IManufacturerPart mfrPart =
SDK Developer Guide - Using Agile APIs
306 Agile Product Lifecycle Management
(IManufacturerPart) m_session.
getObject(IManufacturerPart.OBJECT_TYPE, params);
IRow rowMfrParts =
tblMfrParts.createRow(mfrPart);
// Add a subpart to the Composition table
ITable tblMfrPartComp =
dec.getTable(DeclarationConstants.TABLE_MANUFACTURERPARTCOMPOSITION)
;
ISubstance subpart =
(ISubstance)m_session.getObject(SubstanceConstants.CLASS_SUBPART,
"Steel Casing");
params.clear(); params.put(DeclarationConstants.ATT_PARENT_ROW,
rowMfrParts);
params.put(DeclarationConstants.ATT_MANUFACTURER_PART_COMPOSITION_SU
BSTANCE_NAME, subpart);
IRow rowSubpart =
tblMfrPartComp.createRow(params);
// Add a material
ISubstance material =
(ISubstance)m_session.getObject(SubstanceConstants.CLASS_MATERIAL,
"Steel");
params.clear();
params.put(DeclarationConstants.ATT_PARENT_ROW, rowSubpart);
params.put(DeclarationConstants.ATT_MANUFACTURER_PART_COMPOSITION_SU
BSTANCE_NAME, material);
IRow rowMaterial =
tblMfrPartComp.createRow(params);
// Add a substance group
ISubstance sg =
(ISubstance)m_session.getObject(SubstanceConstants.CLASS_SUBSTANCE_G
ROUP,"Lead Compounds");
params.clear(); params.put(DeclarationConstants.ATT_PARENT_ROW,
rowMaterial);
params.put(DeclarationConstants.ATT_MANUFACTURER_PART_COMPOSITION_SU
BSTANCE_NAME, sg);
IRow rowSubGroup =
tblMfrPartComp.createRow(params);
// Add a substance
ISubstance sub =
(ISubstance)m_session.getObject(SubstanceConstants.CLASS_SUBSTANCE,"
Lead");
params.clear();
params.put(DeclarationConstants.ATT_PARENT_ROW, rowSubGroup);
params.put(DeclarationConstants.ATT_MANUFACTURER_PART_COMPOSITION_SU
BSTANCE_NAME, sub);
IRow rowSubs =
tblMfrPartComp.createRow(params);
} catch (APIException ex) { System.out.println(ex);
}
}
Chapter 18: Managing Product Governance & Compliance
v9.3.1.2 307
Adding Substances to Manufacturer Part Composition Table of
Substance Declarations
The following example shows how to add substances to a Manufacturer Part Composition table of a
Substance Declaration. The table has two levels: substance groups and substances.
Example: Adding Part Level substances to a Manufacturer Part Composition table
public void addSubstanceComp(IAgileSession m_session) throws
APIException {
try {
HashMap params = new HashMap();
//Create a Declaration
String num =
"MDTEST001";
ISupplier supplier =
(ISupplier)m_session.getObject(ISupplier.OBJECT_TYPE,
"DISTRIBUTOR00007");
params.put(DeclarationConstants.ATT_COVER_PAGE_NAME, num);
params.put(DeclarationConstants.ATT_COVER_PAGE_SUPPLIER, supplier);
IAgileClass declClass =
m_session.getAdminInstance().getAgileClass(DeclarationConstants.C
LASS_SUBSTANCE_DECLARATION);
IDeclaration dec =
(IDeclaration)m_session.createObject(declClass, params);
//Add a Specification to the Specifications table
ITable tblSpec =
dec.getTable(DeclarationConstants.TABLE_SPECIFICATION);
params.clear();
// Part Level
ISpecification spec =
(ISpecification)m_session.getObject(ISpecification.OBJECT_TYPE,
"Lead Part Level");
IRow rowSpec =
tblSpec.createRow(spec);
//Add a Manufacturer Part to the Manufacturer Parts table
ITable tblMfrParts =
dec.getTable(DeclarationConstants.TABLE_MANUFACTURERPARTS);
params.clear();
params.put(DeclarationConstants.ATT_MANUFACTURER_PARTS_MFR_PART_N
UMBER, "Widget103");
params.put(DeclarationConstants.ATT_MANUFACTURER_PARTS_MFR_NAME,
"ACME");
IManufacturerPart mfrPart =
(IManufacturerPart)
m_session.getObject(IManufacturerPart.OBJECT_TYPE, params);
IRow rowMfrParts =
tblMfrParts.createRow(mfrPart);
//Add a substance group
ITable tblMfrPartComp =
dec.getTable(DeclarationConstants.TABLE_MANUFACTURERPARTCOMPOSITI
ON);
ISubstance sg =
(ISubstance)m_session.getObject(SubstanceConstants.CLASS_SUBSTANC
E_GROUP,"Lead Compounds");
params.clear();
params.put(DeclarationConstants.ATT_PARENT_ROW, rowMfrParts);
SDK Developer Guide - Using Agile APIs
308 Agile Product Lifecycle Management
params.put(DeclarationConstants.ATT_MANUFACTURER_PART_COMPOSITION_SU
BSTANCE_NAME, sg);
IRow rowSubGroup =
tblMfrPartComp.createRow(params);
//Add a substance
ISubstance sub =
(ISubstance)m_session.getObject(SubstanceConstants.CLASS_SUBSTANC
E,"Lead");
params.clear();
params.put(DeclarationConstants.ATT_PARENT_ROW, rowSubGroup);
params.put(DeclarationConstants.ATT_MANUFACTURER_PART_COMPOSITION_SU
BSTANCE_NAME, sub);
IRow rowSubs =
tblMfrPartComp.createRow(params);
} catch (APIException ex) { System.out.println(ex);
}
}
Adding Substances to a Specification
The Substances table of a specification is important to Agile PG&C because it identifies which
substances are restricted and their threshold mass parts per million (PPM). Only substances and
substance groups can be added to the Substances table of a Specification. To add a substance to
the Substances table, use the ITable.createRow() method. You can pass an ISubstance or
a Map object to create the new row.
Example: Adding a substance to a specification
public void addSubstanceToSpec(ISpecification spec, ISubstance
substance)
throws Exception {
IRow row = null;
//Add a substance to the Substances table
ITable tableSub =
spec.getTable(SpecificationConstants.TABLE_SUBSTANCES);
row = tableSub.createRow(substance);
if (row!=null){
//Set value of Restricted
ICell cell =
row.getCell(SpecificationConstants.ATT_SUBSTANCES_RESTRICTED);
IAgileList list = (IAgileList)cell.getAvailableValues();
list.setSelection(new Object[] {"Yes"});
cell.setValue(list);
//Set value of Threshold Mass PPM
row.setValue(SpecificationConstants.ATT_SUBSTANCES_THRESHOLD_MASS_PPM,
new Integer(10));
}
}
Chapter 18: Managing Product Governance & Compliance
v9.3.1.2 309
Adding Specifications to a Declaration
The Specifications table of a declaration lists specifications related to the items, manufacturer parts,
and part groups contained in the declaration. The purpose of a declaration is to the ensure that
suppliers comply with any restrictions stated in the specifications.
Rules for Adding Specifications
Specifications are optional for declarations. If you submit a declaration without a specification, it
means you intend to collect raw data (mass or PPM) at the substance level. The supplier must
provide information on all materials and substances.
If you add a specification to a declaration, note that declaration classes support different types of
specifications. The following table lists the specification requirements for each type of declaration:
Declaration Type Supported Specification Validation Types
Homogeneous Material Declaration Homogeneous Material Level
IPC 1752-1 Declaration Part Level
IPC 1752-2 Declaration Homogeneous Material Level
JGPSSI Declaration Part Level
Part Declaration Part Level and Homogeneous Material Level
Substance Declaration Part Level
Supplier Declaration of Conformance Part Level and Homogeneous Material Level
Specifications may concern many substances, including those not used by the parts contained in
the declaration. When the declaration is opened to the supplier, any relevant substances from the
specifications are automatically added to the Item Composition, Manufacturer Part Composition,
and Part Group Composition tables. This ensures that you are properly tracking any restricted
substances contained in parts listed in the declaration.
Example: Adding specifications to the Specification table
private void addSpecifications(IDeclaration dec, ISpecification[]
specs) throws Exception {
ITable tableSpecs =
dec.getTable(DeclarationConstants.TABLE_SPECIFICATION);
for (int i = 0; i < specs.length; ++i) {
ISpecification spec = specs[i];
IRow row = tableSpecs.createRow(spec);
}
}
SDK Developer Guide - Using Agile APIs
310 Agile Product Lifecycle Management
Routing Declarations
The Default Declarations Workflow follows a straightforward process flow, as shown in the following
figure.
Figure 21: Default Declarations workflow
The following table describes each status in the Default Declarations workflow.
Status Description
Pending The Compliance Manager creates a new declaration, adding new items, manufacturer parts, or
part groups. He also adds specifications to the declaration.
Open To Supplier The Compliance Manager opens the declaration to the supplier, asking him to confirm whether
parts comply with specifications.
When the Workflow status of a declaration is changed from “Pending” to “Open To Supplier,”
the Agile PLM server automatically populates the declaration’s Substances tables with any
substances listed on its specifications.
Submit to Manager The supplier electronically “signs” and submits the declaration back to the Compliance
Manager.
Review The Compliance Manager and other reviewers verify and approve the contents of the
declaration.
Released The Compliance Manager releases the declaration, thereby publishing the materials into the
product record.
Implemented Once the parts are manufactured and disseminated in the field, the Compliance Manager
implements the declaration, thereby completing the workflow.
Before you can route a declaration, you should set values for the following three Cover Page
fields:
à Cover Page.Compliance Manager
à Cover Page.Workflow
à Cover Page.Due Date
Chapter 18: Managing Product Governance & Compliance
v9.3.1.2 311
Technically, only the Compliance Manager and Workflow fields are required to route the
declaration. The Due Date field is optional but should be specified for tracking purposes. The
following example shows how to set values for these three fields.
Example: Setting values for the Compliance Manager, Workflow, and Due Date fields
public void setFieldsNeededForRouting(IDeclaration dec) throws
Exception {
//Set the Compliance Manager field
IUser user = m_session.getCurrentUser();
dec.setValue(DeclarationConstants.ATT_COVER_PAGE_COMPLIANCE_MANAGER,
user);
//Set the Workflow field
IWorkflow workflow = dec.getWorkflows()[0];
dec.setWorkflow(workflow);
//Set the Due Date field
DateFormat df = new SimpleDateFormat("MM/dd/yy");
dec.setValue(DeclarationConstants.ATT_COVER_PAGE_DUE_DATE,
df.parse("05/01/05"));
}
To change the status of a declaration, use the IRoutable.changeStatus() method. Once a
declaration is opened to a supplier, only the supplier’s contact users can edit it. For other users,
including the Compliance Manager, the declaration becomes read-only. The following example
shows how the Compliance Manager can change the status of a declaration to “Open To Supplier.”
Example: Opening a declaration to a supplier
public void openToSupplier(IDeclaration dec) throws Exception {
IStatus status = null;
// Get the Open to Supplier status type
IStatus[] stats = dec.getNextStatuses();
for (int i = 0; i < stats.length; i++) {
if (stats[i].toString().equals("Open To Supplier")) {
status = stats[i];
break;
}
}
// Change to the Open to Supplier status
dec.changeStatus(status, false, null, false, false, null, null, null,
false);
}
For more information about Agile APIs that support Workflow processes, see
Managing Workflow
on page
205.
SDK Developer Guide - Using Agile APIs
312 Agile Product Lifecycle Management
Completing a Declaration
When a declaration is opened to a supplier, the supplier is responsible for completing the
declaration and disclosing if any restricted substances are contained in the components and
subassemblies it provides and whether those substances comply with specifications. To complete
and sign off on declarations, one or more contact users for the supplier must be assigned the
(Restricted) Material Provider role.
The Material Provider user should do the following to complete a declaration:
à Fill in the Mass and Declared PPM fields or the Declared Compliance field for every substance listed
on the Item Composition, Manufacturer Part Composition, and Part Group Composition tables,
particularly for substances that are restricted by specifications.
à Complete other flex fields on the Composition tables as necessary.
à Add or remove substances from the declaration.
When the declaration is complete, the Material Provider user can sign off and submit the declaration
to the Compliance Manager, described below.
Submitting Declarations to Compliance Managers
When the supplier changes the status of the declaration from “Open to Supplier” to “Submit to
Manager,” he must sign-off on the declaration. Therefore, he must use the changeStatus()
method that has an additional password parameter:
changeStatus(IStatus newStatus, boolean auditRelease, String comment,
boolean notifyOriginator, boolean notifyCCB, Object[] notifyList,
Object[] approvers, Object[] observers, boolean urgent, String
password)
The following example shows how the supplier can sign off and submit the declaration to the
Compliance Manager.
Example: Signing off and submitting a declaration to the Compliance Manager
public void submitToCM(IDeclaration dec) throws Exception {
IStatus status = null;
// Get the Submit to Manager status type
IStatus[] stats = dec.getNextStatuses();
for (int i = 0; i < stats.length; i++) {
if (stats[i].toString().equals("Submit To Manager")) {
status = stats[i];
break;
}
}
// Change to the Submit to Manager status (signoff password is "agile")
dec.changeStatus(status, false, null, false, false, null, null,
null, false, "agile");
}
Chapter 18: Managing Product Governance & Compliance
v9.3.1.2 313
Publishing a Declaration
The Agile API does not provide a method to publish a material declaration to the product record.
Instead, a declaration is automatically published when it is released. Therefore, as far as the API is
concerned, the substances table for an item, manufacturer part, or part group always reflects the
last released declarations. However, Agile Web Client allows you to select an later declaration and
publish it, thereby updating the substances information in the product record.
Getting and Setting Weight Values
Unit of Measure fields have been implemented in Agile PLM to support mass (weight) values for
Agile PG&C objects. The Unit of Measure datatype is a compound datatype that includes a numeric
value and a unit, for example, grams or ounces.
You can configure and manage weight fields using the following interfaces:
à IMeasure
à IUnit
à IUnitOfMeasure
à IUnitOfMeasureManager
Although the Agile PLM administrator can define new measures from the UOM node in Agile Java
Client, the Agile API supports only the Weight measure for Agile PG&C objects. You cannot use the
Agile API to define new measures.
In Agile 9.2.1, the Title Block.Weight field for items was changed to Title Block.Mass.
However, the Agile API constant for the field is still ItemConstants.TITLE_BLOCK_WEIGHT.
The following example shows how to get and set values for the Title Block.Mass field of an item.
Example: Getting and setting the mass (weight) value for an item
private IUnitOfMeasure getMassValue(IItem item) throws APIException {
IUnitOfMeasure uom =
(IUnitOfMeasure)item.getValue(ItemConstants.ATT_TITLE_BLOCK_WEIGH
T);
System.out.println("Value: " + uom.getValue());
System.out.println("Unit: " + uom.getUnit().toString());
return uom;
}
private void setMassValue(IItem item, double value, String unit) throws
APIException {
IUnitOfMeasure uom = null;
IUnitOfMeasureManager uomm =
(IUnitOfMeasureManager)m_session.getManager(IUnitOfMeasureManager
.class);
uom = uomm.createUOM(value, unit);
item.setValue(ItemConstants.ATT_TITLE_BLOCK_WEIGHT, uom);
System.out.println("Value: " + uom.getValue());
System.out.println("Unit: " + uom.getUnit().toString());
SDK Developer Guide - Using Agile APIs
314 Agile Product Lifecycle Management
}
If you create a query to search for items by mass, only the numeric value is searched, not the unit.
The server converts mass values to the standard unit before returning query results. For example,
the following query returns all items whose mass value is between 1.0 and 2.0 grams (the default
standard unit). Items with a mass between 1000 and 2000 milligrams would also be included in the
search results.
Example: Searching for items by mass
try {
IQuery query = (IQuery)m_session.createObject(IQuery.OBJECT_TYPE,
"select * from [Items] where [Title Block.Weight] between (1.0,
2.0)"
);
ITable results = query.execute();
} catch (APIException ex) {
System.out.println(ex);
Adding Substance Compositions for Manufacturer
Parts
With appropriate privileges, you can modify the Specifications, Compositions, and Substances
tables of a manufacturer part directly without submitting a declaration. This feature is useful for
manufacturing partners that want to specify composition information for their parts. To add a row to
the Specifications, Compositions, and Substances tables, use the ITable.createRow(Object)
method.
Note Once a row has been added to the Compositions and Substances tables of a
Manufacturer Part, you cannot update or remove it.
The procedure for adding rows to the Substances table of a Manufacturer Part is similar to the way
you add rows to the composition tables for a declaration. Follow these steps to add substance
compositions into a manufacturer part:
1. Optionally, add a specification to the Specifications table.
2. Add a row to the Compositions table. You must specify a value for the
ManufacturerPartConstants.ATT_COMPOSITIONS_COMPOSITION_TYPE attribute.
3. Add one or more rows to the Substances table. Each row must reference the parent row from
the Compositions table. Use the virtual attribute
ManufacturerPartConstants.ATT_PARENT_ROW to specify the parent row. When you add
a substance, specify the substance name and substance type.
For additional rules about adding substances to the Substances table, see
Rules for Adding
Substances on page 303.
The Composition Type attribute for the parent row determines the types of substances you can add
to the Substances table. There are three possible Composition Type values:
à Homogeneous Material Composition – You can create a multilevel Bill of Substances with subparts,
Chapter 18: Managing Product Governance & Compliance
v9.3.1.2 315
materials, substance groups, and substances. The composition must contain either a subpart
or a material as a direct child. It can also include substances and substance groups, but they
can only be attached to a subpart or material.
à Substance Composition – The Substances table can contain only substance groups and
substances.
à Part Composition – You can’t add rows to the Substances table.
Specifications that you reference in a row in the Compositions table must match the Composition
Type attribute for that row. For example, if the Composition Type for the row is Homogeneous
Material Composition, the validation type for a specification referenced in that row must be
Homogeneous Material Level.
The following example shows how to define a Homogeneous Material composition for a
manufacturer part. The Substances table has four levels: subparts, materials, substance groups,
and substances.
Example: Adding specifications, compositions, and substances to a Manufacturer Part
public void addMfrPartSubs(IAgileSession m_session) throws APIException
{
try {
// Create a Manufacturer Part
HashMap params = new HashMap();
params.put(ManufacturerPartConstants.ATT_GENERAL_INFO_MANUFACTURER_P
ART_NUMBER,"Widget");
params.put(ManufacturerPartConstants.ATT_GENERAL_INFO_MANUFACTURER_N
AME, "ACME");
IManufacturerPart mfrPart =
(IManufacturerPart)
m_session.createObject(ManufacturerPartConstants.CLASS_MANUFACTURER_
PART, params);
// Add a Specification to the Specifications table
ITable tblSpec =
mfrPart.getTable(ManufacturerPartConstants.TABLE_SPECIFICATIONS);
ISpecification spec =
(ISpecification)m_session.getObject(ISpecification.OBJECT_TYPE,"Lead
Spec");
// Add Spec
IRow rowSpec =
tblSpec.createRow(spec);
// Get the Compositions table and Set as Homogeneous Material Level
ITable tblComp =
mfrPart.getTable(ManufacturerPartConstants.TABLE_COMPOSITIONS);
// Add a row to the Compositions table that references the
specification
params.clear();
params.put(ManufacturerPartConstants.ATT_COMPOSITIONS_SPECIFICATION,
spec.getName());
params.put(ManufacturerPartConstants.ATT_COMPOSITIONS_COMPOSITION_TY
PE,
"Homogeneous Material Composition");
IRow rowComp =
tblComp.createRow(params);
SDK Developer Guide - Using Agile APIs
316 Agile Product Lifecycle Management
// Get the Substances table
ITable tblSubs =
mfrPart.getTable(ManufacturerPartConstants.TABLE_SUBSTANCES);
// Add a subpart
ISubstance subpart =
(ISubstance)m_session.
getObject(SubstanceConstants.CLASS_SUBPART,
"Steel Casing");
params.clear();
params.put(ManufacturerPartConstants.ATT_PARENT_ROW, rowComp);
params.put(ManufacturerPartConstants.ATT_SUBSTANCES_SUBSTANCE_NAME,
subpart);
IRow rowSubpart =
tblSubs.createRow(params);
// Add a material
ISubstance material =
(ISubstance)m_session.getObject(SubstanceConstants.CLASS_MATERIAL,
"Steel");
params.clear();
params.put(ManufacturerPartConstants.ATT_PARENT_ROW, rowSubpart);
params.put(ManufacturerPartConstants.ATT_SUBSTANCES_SUBSTANCE_NAME,
material);
IRow rowMaterial =
tblSubs.createRow(params);
// Add a substance group
ISubstance sg =
(ISubstance)m_session.getObject(SubstanceConstants.CLASS_SUBSTANCE_G
ROUP, "Lead Compounds");
params.clear();
params.put(ManufacturerPartConstants.ATT_PARENT_ROW, rowMaterial);
params.put(ManufacturerPartConstants.ATT_SUBSTANCES_SUBSTANCE_NAME,
sg);
IRow rowSubGroup =
tblSubs.createRow(params);
// Add a substance
ISubstance sub =
(ISubstance)m_session.getObject(SubstanceConstants.CLASS_SUBSTANCE,"
Lead");
params.clear();
params.put(ManufacturerPartConstants.ATT_PARENT_ROW, rowSubGroup);
params.put(ManufacturerPartConstants.ATT_SUBSTANCES_SUBSTANCE_NAME,
sub);
IRow rowSubs =
tblSubs.createRow(params);
} catch (APIException ex) {
System.out.println(ex);
}
}
Chapter 18: Managing Product Governance & Compliance
v9.3.1.2 317
Rolling Up Compliance Data
After gathering compliance data for items, manufacturer parts, and part groups, compliance
managers review the completed declarations to determine if the data is ready for publication into the
product record. Once declarations are published with the data written through to parts and part
groups on BOMs, compliance managers must examine and test BOMs to ensure the assemblies
and products are compliant. This process is called compliance validation and is fulfilled through
compliance rollups. Rollups are built into the system. They are easy to use and rollup results are
available on the UI. For more information on rolling up compliance data and the business logic
behind this process, refer to the Agile Product Governance & Compliance User Guide.
The SDK supports calling the PG&C Rollup function on the server side. This is the same rollup
function that is called by the UI. The IPGCRollup interface supports this feature.
Understanding the IPGCRollup Interface
The IPGCRollup interface provides the following methods to support rolling up compliance data:
à rollup()
à rollup(Date)
One of these methods has no parameters and the other has Date as a parameter. The Date
parameter in the rollup API is used by the system to set the timestamp for the rollup, when it is
done.
Example: IPGCRollup methods
public interface IPGCRollup {
public void rollup()
throws APIException;
public void rollup(Date rollupDate)
throws APIException;
}
Note After invoking rollup(Date), it is necessary to call IDataObject.refresh() to
make sure the rollup function has taken effect. Otherwise, the system will display the
results obtained in the previous rollup if the timestamp of the recent rollup is the same as
the Date parameter.
Passing the Date Parameter
If you do not pass the date, the system will use the current time provided by the system. When a
rollup is performed on a set of items, if the timestamp of the recent rollup on an item is the same as
the passed Date parameter, the system will not repeat the rollup process on that item. Instead, it will
display the results obtained in the previous rollup. You may want to use this date feature if there is a
large number of items to rollup and you want to use the SDK to call all of them. In this case, you will
get the current date first, and then the pass that date for the subsequent SDK Rollup(Date) call.
For example, you want to use the SDK to roll up data for Assembly 1 and Assembly 2. In this case,
the SDK is called twice. The first instance, to roll up data for Assembly 1, and the second instance,
to rollup data for Assembly 2. With the date parameter already inside the rollup when performing the
rollup on Assembly 2, the system will reuse the previous rollup data obtained for Item1.
SDK Developer Guide - Using Agile APIs
318 Agile Product Lifecycle Management
Assembly 1
Item1
Iitem2
Assembly 2
Item1
Item3
Using the IPGCRollup Interface
The following examples roll up the assembled data on Items and Manufacturer Parts:
à Item (latest released ECO or MCO)
à MPN (latest released ECO or MCO)
Rolling Up Assembled Data on Items
This example calls an API using the SDK to identify the top level parent of a given Item (its latest
released ECO or MCO). Next, it will call the rollup API on the top level parent returned by the
previous API to ensure the assemblies and products are compliant.
Example: Identifying the top level parent for an Item
public void itemRollup(String itemStr) throws Exception{
try {
IItem item =
(IItem)m_session.getObject(IItem.OBJECT_TYPE, itemStr);
IQuery query =
(IQuery)m_session.createObject(IQuery.OBJECT_TYPE,
ItemConstants.CLASS_ITEM_BASE_CLASS);
// IQuery query = (IQuery)
m_session.createObject(IQuery.OBJECT_TYPE, ItemConstants.CLASS_PART);
query.setSearchType(QueryConstants.WHERE_USED_TOP_LEVEL);
query.setCriteria("[1001] Equal To '"+item.getName()+"'");
//
query.setCriteria("["+SDKWrapper.getString("TITLE_BLOCK")+"."+SDKWrappe
r.getString("IQuery_Number")+"] Equal To '"+item.getName()+"'");
ITable results=query.execute();
if (results.size() > 0) {
Iterator it =
results.getReferentIterator();
if (it.hasNext()) {
IItem obj =
(IItem)it.next();
Chapter 18: Managing Product Governance & Compliance
v9.3.1.2 319
IItem tlaItem =
(IItem)m_session.getObject(IItem.OBJECT_TYPE, obj.getName());
tlaItem.rollup();
}
}
else {
item.rollup();
}
} catch (APIException e) {
throw e;
}
return;
}
Rolling Up Assembled Data on MPNs
This example calls an API using the SDK to identify the top level parent of a given MPN (its latest
released ECO or MCO). Next, it will call the rollup API on the top level parent returned by the
previous API to ensure the assemblies and products are compliant.
Example: Identifying the top level parent for an MPN
public void testMfrPartRollup() throws Exception{
IManufacturerPart mfrp =
(IManufacturerPart)
m_session.getObject(IManufacturerPart.OBJECT_TYPE,
"HARRIS::IS82C55A96");
ITable whereused =
mfrp.getTable(ManufacturerPartConstants.TABLE_WHEREUSED);
Iterator it =
whereused.iterator();
while(it.hasNext())
{
IRow r = (IRow)it.next();
// read item number
String itemStr =
r.getValue(ManufacturerPartConstants.ATT_WHERE_USED_ITEM_NUMBER).toS
tring();
try {
itemRollup(itemStr);
} catch (APIException e) {
int error =
((Integer)e.getErrorCode()).intValue();
}
}
return;
}
SDK Developer Guide - Using Agile APIs
320 Agile Product Lifecycle Management
Setting Values in the Calculated Compliance Field for Item Objects
Use the following API to set the value of the Calculated Compliance field on the Specifications table
of Item and ManufacturerPart objects:
Public void setCalculatedComplianceForPartSpec(Object specName, Object
complianceEntryValue) throws APIException
In this API, the specName parameter is the name of the Specification object, and the
complianceEntryValue parameter is the actual value of the Calculated Compliance field,
which can be any entry in the Calculated Compliance list. Both parameters are of type String.
When this value is set by the SDK Client, it is never overwritten during the Rollup. This API allows
users to set the calculated compliance value based on their own defined logic, instead of using the
system’s default logic.
Example: Setting the value of the Calculated Compliance field for Item objects
// COMPLIANT, the actual value of the Calculated Compliance field shows
the Specification is compliant or not, based on customized calculated
compliance result
String COMPLIANT = "Compliant";
// spec_num is the Specification Name in Item object’s Specification
Table
String spec_num =
row.getValue(ItemConstants.ATT_SPECIFICATIONS_SPECIFICATION).toSt
ring();
item.setCalculatedComplianceForPartSpec(spec_num, COMPLIANT);
Setting Values in the Calculated Compliance Field for Declaration
Objects
This is similar to the previous API that enabled setting the Calculated Compliance field for Item
objects. You can use this API to set the value of the Calculated Compliance field in Item table and
Manufacturer Part table for Declaration objects.
Public void setCalculatedComplianceForMDOPartSpec (Object partName, Object
partClassName, Object changeNumber, Object specName, Object
complianceEntryValue)) throws APIException
The system recognizes that the SDK Client has set this value and will use the new setting in the
subsequent response during Rollup. In this API, the parameter changeNumber is optional. When
the Declaration object has only one revision of an item, you can set the value of changeNumber to
null. If the Declaration object has more than one revision of an item, you must set the value of
changeNumber for the proper execution of the API.
Chapter 18: Managing Product Governance & Compliance
v9.3.1.2 321
Similar to the previous API, when this value is set by the SDK Client, it is never overwritten during
the Rollup within the declaration. This API allows users to set the calculated compliance value
based on their own defined logic, instead of using the system’s default logic.
Note If the SDK developer intends to pass the changeNumber field to
setCalculatedComplianceForDeclarationPartSpec(), the developer must
have the Discover Change privilege mask for that change.
Example: Setting the value of the Calculated Compliance field for Declaration objects
// complianceValue -- This is the customized calculated compliance
value and shows if the part is compliant to a Spec
String ComplianceValue = "Compliant";
// partName is the Item/Mfr Part name in Declaration’s Item/MfrPart
table. If it is a mfr part, it should be like “MfrName::MfrPartName
String partName =”P00001”; String partClassName = “Parts”;
// If the added part in Declaration is an Item, the changeName should
be the
Change number corresponding to the Item’s revision.
// If the added part in Declaration is a Mfr Part, the
changeName should be “null”
String changeName = “C00001”;
// spec_num is the Specification Name in Declaration object’s
Specification Table
String specName = “Rohs”;
Declaration.setCalculatedComplianceForDeclarationPartSpec
(partName, partClassName, changeName, specName, complianceValue);
v9.3.1.2 323
Chapter 19
Handling Exceptions
This chapter includes the following:
About Exceptions................................................................................................................................................. 323
Exception Constants............................................................................................................................................324
Getting Error Codes............................................................................................................................................. 324
Disabling and Enabling Error Codes with Bulk APIs............................................................................................324
Getting Error Messages....................................................................................................................................... 325
Disabling and Enabling Warning Messages........................................................................................................ 326
Checking if APIException is Warning and not Error ............................................................................................ 327
Saving and Restoring State Enabled and Disabled Warnings............................................................................. 327
Warnings on Deleting Objects Automatically Disabled by Agile API ...................................................................328
About Exceptions
Errors that cause a problem in a Java program are called exceptions. When Java throws an
exception that is not caught, your program may quit, or errors may appear onscreen. To handle an
exception gracefully, your program must:
à Protect code that contains a method that might throw an exception by putting it in a try block.
à Test for and handle any exceptions that are thrown inside a catch block.
The Agile API provides a subclass of Exception called APIException. This is a general-
purpose exception class that is used throughout the Agile API to handle Agile PLM runtime errors.
In the Agile API HTML reference, each method indicates the types of exceptions it throws.
Generally, any Agile API method that requires interaction with the Agile Application Server throws
APIException. The table below lists the APIException class methods for handling exceptions:
Method Description
getErrorCode()
Returns the number of the error code associated with the APIException.
getMessage()
Returns the error message associated with the APIException.
getRootCause()
Returns the root cause of the APIException, if any.
getType()
Returns the type of exception.
SDK Developer Guide - Using Agile APIs
324 Agile Product Lifecycle Management
Exception Constants
The ExceptionConstants class contains String constants for all Agile Application Server and
Agile API runtime error and warning codes. For a description of each of these constants, refer to the
API Reference files at
http://edelivery.oracle.com/.
Several of ExceptionConstants are for exceptions that are used to display an Agile PLM
warning message before completing an action. All constants for warning messages end with the
suffix WARNING. If you don’t want to use Agile PLM warning messages in your code, you can
disable them. For more information, see
Disabling and Enabling Warning Messages on page 326.
Getting Error Codes
To properly trap warning errors, you may need to retrieve the error code of the exception and then
handle it appropriately. Generally, this involves displaying a confirmation dialog box to let the user
choose whether to complete the action. The following example shows how to check for the error
code of an exception in the catch block.
Example: Getting Agile PLM error codes
private void removeApprover(IChange change, IUser[] approvers, IUser[]
observers, String comment) {
try {
// Remove the selected approver
change.removeApprovers(change.getStatus(), approvers, observers,
comment);
} catch (APIException ex) {
if
(ex.getErrorCode().equals(ExceptionConstants.APDM_RESPONDEDUSERS_WAR
NING))
JOptionPane.showMessageDialog(null, ex.getMessage(), "Warning",
JOptionPane.YES_NO_OPTION);
}
}
Disabling and Enabling Error Codes with Bulk APIs
The SDK supports the following bulk operations in IAgileSession to disable/enable all error
codes or for a given set of error codes:
à IAgileSession.enableWarnings(Integer[])
à IAgileSession.disableWarnings(Integer[])
à IAgileSession.enableAllWarnings()
à IAgileSession.disableAllWarnings()
Chapter 19: Handling Exceptions
v9.3.1.2 325
The process is similar to the previous example. The following example shows how to use these bulk
APIs to suppress warnings while releasing a Change.
Example: Disabling and enabling error codes in the bulk mode
public static void releseECO(IAgileSession session, IChange change)
throws Exception {
// Set workflow
IWorkflow workflow = change.getWorkflows()[0];
change.setWorkflow(workflow);
IStatus submit = getStatus(workflow, StatusConstants.TYPE_SUBMIT);
IStatus ccb = getStatus(workflow, StatusConstants.TYPE_REVIEW);
IStatus released = getStatus(workflow,
StatusConstants.TYPE_RELEASED);
session.disableWarnings(new Integer[] {
ExceptionConstants.APDM_WFL_ATLEASTONECHGANALYST_WARNING,
ExceptionConstants.APDM_MISSINGFIELDS_WARNING });
// instead you can use session.disableAllWarnings()
// route to SUBMIT
change.changeStatus(submit, false, null, false, false, new
Object[]{}, new Object[]{}, new Object[] {}, false);
// Change status to CCB
change.changeStatus(ccb, false, null, false, false, new Object[]{},
new Object[]{}, new Object[]{}, false);
// route from CCB to release
change.changeStatus(released, false, "release", false, false, new
Object[]{}, new Object[]{}, new Object[]{}, false);
session.enableWarnings(new Integer[] {
ExceptionConstants.APDM_WFL_ATLEASTONECHGANALYST_WARNING,
ExceptionConstants.APDM_MISSINGFIELDS_WARNING });
// instead you can use session.enableAllWarnings()
}
public static IStatus getStatus(IWorkflow workflow, StatusConstants
status)
throws Exception {
IStatus[] states = workflow.getStates(status);
IStatus state = states[0];
return state;
}
Getting Error Messages
If your program throws an APIException, which indicates an Agile PLM runtime error, you may
want to display an error message. You can use the getMessage() method to return the error
message string and then display it in a message dialog box, as shown in the following example.
Example: Getting an error message
// Display an error message dialog
void errorMessage(APIException ex) {
try {
JOptionPane.showMessageDialog(null, ex.getMessage(), "Error",
JOptionPane.ERROR_MESSAGE);
} catch (Exception e) {}
SDK Developer Guide - Using Agile APIs
326 Agile Product Lifecycle Management
}
For a list of Agile PLM error messages, refer to the API Reference files (at
http://edelivery.oracle.com/) under ExceptionConstants.
Disabling and Enabling Warning Messages
Several Agile PLM error messages are warnings that give you the option to stop or continue with an
operation. By default, most error messages, including warning messages, are enabled. If you try to
perform an action that triggers a warning, an exception will be thrown. To avoid the exception, you
can disable the warning message before performing the action.
The following example shows how to check whether attempting to release a change causes an
exception to be thrown. If the error code for the exception is
ExceptionConstants.APDM_UNRESPONDEDCHANGE_WARNING, the program displays a warning.
The user can click Yes in the warning dialog box to release the change.
Example: Disabling and enabling error codes
private void releaseChange(IAgileSession m_session, IChange chgObj) {
IStatus nextStatus = null;
try {
// Get the default next status
nextStatus = chgObj.getDefaultNextStatus();
// Release the Change
chgObj.changeStatus(nextStatus, false, "", false, false, null, null,
null, false);
} catch (APIException ex) {
// If the exception is error code
// ExceptionConstants.APDM_UNRESPONDEDCHANGE_WARNING,
// display a warning message
if (ex.getErrorCode() ==
ExceptionConstants.APDM_UNRESPONDEDCHANGE_WARNING) {
int i =
JOptionPane.showConfirmDialog(null, ex.getMessage(),
"Warning", JOptionPane.YES_NO_OPTION);
if (i == 0) {
// If the user clicks Yes on the warning, disable the error code and
release the change
try {
// Disable the warning
m_session.disableWarning(ExceptionConstants.APDM_UNRESPONDEDCHANGE_W
ARNING);
// Release the Change
chgObj.changeStatus(nextStatus, false, "", true, true, null, null,
null, false);
// Enable all warnings
m_session.enableWarning(ExceptionConstants.APDM_UNRESPONDEDCHANGE_WA
RNING);
} catch (APIException exc) {}
}
}
}
Chapter 19: Handling Exceptions
v9.3.1.2 327
}
Checking if APIException is Warning and not Error
As noted above, if you try to perform an operation that triggers a warning, an exception will be
thrown. Warning messages are helpful for interactive GUI clients, like Agile Web Client, but you
may not want to use them in your Agile API program, particularly if it performs batch processes.
You can use APIException.isWarning() to check whether an Agile PLM exception is a
warning. If so, you can disable the warning to continue the operation.
Example: Checking if an APIException is a warning
private void checkIfWarning(IAgileSession m_session) {
boolean gotWarning = true;
while (gotWarning) {
try {
// Add some API code here that throws an exception
m_session.doNothing();
gotWarning = false;
} catch (APIException e) {
try {
if (e.isWarning())
m_session.disableWarning((Integer)e.getErrorCode());
} catch (Exception ex) {}
continue;
}
break;
}
}
Saving and Restoring State Enabled and Disabled
Warnings
Rather than keep track of which warning messages are disabled or enabled before beginning a
particular operation, you can use IAgileSession.pushWarningState() to save the current
state of enabled and disabled warnings. After completing the operation, you can restore the
previous state of enabled and disabled warnings using IAgileSession.popWarningState().
Example: Using pushWarningState() and popWarningState()
private void pushPopWarningState(IAgileSession m_session, IItem item)
throws APIException {
// Save the current state of enabled/disabled warnings
m_session.pushWarningState();
// Disable two AML warnings
m_session.disableWarning(ExceptionConstants.APDM_WARN_MFRNAMECHANGE_
WARNING);
m_session.disableWarning(ExceptionConstants.APDM_ONEPARTONEMFRPART_W
ARNING);
SDK Developer Guide - Using Agile APIs
328 Agile Product Lifecycle Management
// Get the Manufacturers table
ITable aml = item.getTable(ItemConstants.TABLE_MANUFACTURERS);
// Create a new row and set a value for the row
HashMap amlEntry = new HashMap();
amlEntry.put(ItemConstants.ATT_MANUFACTURERS_MFR_NAME, "MFR_TEST3");
amlEntry.put(ItemConstants.ATT_MANUFACTURERS_MFR_PART_NUMBER,
"MFR_PART3");
IRow rowAML1 = aml.createRow(amlEntry);
rowAML1.setValue(ItemConstants.ATT_MANUFACTURERS_REFERENCE_NOTES,
"new note");
// Restore the previous state of enabled/disabled warnings
m_session.popWarningState();
}
Warnings on Deleting Objects Automatically Disabled
by Agile API
In the Agile Web Client, when you try to delete an object a warning message appears. These
warning messages are not appropriate for batch processes in an Agile API program. Therefore, the
Agile API implicitly disables the following warnings, which saves you the trouble of disabling them in
your code.
à ExceptionConstants.APDM_HARDDELETE_WARNING
à ExceptionConstants.APDM_SOFTDELETE_WARNING
For more information about deleting objects, see
Deleting and Undeleting Objects on page 32.
v9.3.1.2 329
Chapter 20
Performing Administrative Tasks
This chapter includes the following:
About Agile PLM Administration.......................................................................................................................... 329
Privileges Required to Administer Agile PLM ...................................................................................................... 330
Administrative Interfaces ..................................................................................................................................... 330
Getting an IAdmin Instance .................................................................................................................................331
Working with Nodes............................................................................................................................................. 331
Managing Agile PLM Classes.............................................................................................................................. 336
Working with Attributes........................................................................................................................................ 340
Working with Properties of Administrative Nodes................................................................................................344
Managing Users................................................................................................................................................... 345
Managing User Groups........................................................................................................................................ 350
About Agile PLM Administration
Agile Java Client provides administrative functionality that lets you manage the Agile Application
Server. It lets you quickly and easily adapt your Agile PLM system to fit the way you do business.
You can customize the Agile PLM system in several ways:
à Modify Agile PLM database properties
à Define object classes and subclasses
à Set preferences
à Create and configure user accounts
à Define user groups
à Define roles and privileges
à Define SmartRules, which set how you manage your change control process
The Agile API provides read/write access to all nodes of Agile PLM’s administrative functionality.
This means you can create Agile API programs that let users read and modify Agile PLM
subclasses, and add, modify, or delete Agile PLM users. The Agile API does not allow you to create
new nodes in the administrative tree structure. Therefore, you can’t create workflows, criteria, and
roles. However, you can create users and user groups because those objects have been
implemented as data objects; IUser and IUserGroup both extend IDataObject.
SDK Developer Guide - Using Agile APIs
330 Agile Product Lifecycle Management
Privileges Required to Administer Agile PLM
Before you can administer the Agile Application Server, you must have proper privileges. For
access to administrative functionality, you should have the Administrator privilege. The
Administrator role grants the Administrator privilege to all administrative functionality available on
the server. The User Administrator role grants the Administrator privilege for functionality related to
users and user groups.
Without the Administrator privilege, you cannot modify administrative nodes, users, and user
groups. If you have not yet been granted Administrator rights to the Agile PLM system, contact the
Agile PLM administrator.
To create users and user groups, you need the Create privilege for those objects. Several roles
supplied with the Agile PLM system, such as the Administrator, User Administrator, and Change
Analyst roles, include the Create privilege for users and user groups.
Administrative Interfaces
The following table lists interfaces related to Agile PLM’s administrative functionality.
Interface Description
IAdmin
Interface that lets you get Agile PLM classes, nodes, users, or user groups
IAgileClass
Class definition used to identify the category to which an object belongs
IAgileList
A general-purpose list interface for all SingleList or MultiList attributes and properties
IAttribute
Provides detailed information about a particular data member in an object
IAutoNumber
An AutoNumber source, which is a predefined, consecutive number series used to automatically number
Agile PLM objects
ICriteria
A reusable set of search criteria used primarily for queries and Workflows
INode
A node in the administrative hierarchy. Each node is equivalent to an Admin node in the Agile Java Client
IProperty
A property of an Agile PLM administrative node
IRoutableDesc
Metadata that describes any object that implements the IRoutable interface, you can use
IRoutableDesc to get the workflows for a class without instantiating an object of that class
ITableDesc
Metadata that describes an Agile PLM table, you can use ITableDesc to get table attributes without
loading a table
ITreeNode
A generic node in a hierarchical tree structure. Several administrative interfaces, such as INode and
IFolder, are subinterfaces of ITreeNode and therefore inherit its functionality
Note: There is also a deprecated ITree interface which provides similar functionality to ITreeNode.
Be sure to use ITreeNode instead.
IUser
An Agile PLM user
IUserGroup
A user group. Use user groups to define project teams, site-related groups, departments, or global groups
Chapter 20: Performing Administrative Tasks
v9.3.1.2 331
Interface Description
IWorkflow
A Workflow node
Getting an IAdmin Instance
The IAdmin interface provides access to most administrative functionality for the Agile Application
Server. To use the IAdmin interface, you first get an instance of IAdmin from the current session.
The following example shows how to log in to the Agile Application Server and get an IAdmin
instance.
Example: Getting an IAdmin instance
public IAgileSession m_session;
public IAdmin m_admin;
public AgileSessionFactory m_factory;
try {
HashMap params =
new HashMap();
params.put(AgileSessionFactory.USERNAME, "jdassin");
params.put(AgileSessionFactory.PASSWORD, "agile");
m_factory =
AgileSessionFactory.getInstance("
http://agileserver/virtualPath");
m_session =
m_factory.createSession(params);
m_admin =
m_session.getAdminInstance();
} catch (APIException ex) {
System.out.println(ex);
}
Once you have an IAdmin instance, you can:
à Traverse the server nodes
à Traverse the folder hierarchy
à Get Agile PLM classes and subclasses
Working with Nodes
The INode object represents a single node or object within Agile PLM’s administrative tree. Similar
to the Windows Explorer interface, each INode can be expanded to show child nodes. This simple
hierarchy lets you navigate the administrative tree structure on the Agile Application Server.
Examples of nodes are the root node (also called the Database node), Classes, Preferences,
Roles, Privileges, and SmartRules.
SDK Developer Guide - Using Agile APIs
332 Agile Product Lifecycle Management
This table shows the mapping of Agile Java Client nodes to Agile API administrative functionality.
Agile Java Client node Agile API equivalent
Data Settings
Classes
NodeConstants.NODE_AGILE_CLASSES
Character Sets
NodeConstants.NODE_CHARACTER_SETS
Lists Not supported
Process Extensions Not supported
AutoNumbers
NodeConstants.NODE_AUTONUMBERS
Criteria
NodeConstants.NODE_CRITERIA_LIBRARY
Workflow Settings
Workflows
NodeConstants.NODE_AGILE_WORKFLOWS
User Settings
Account Policy Not supported
Users Create a query of users
User Groups Create a query of user groups
Supplier Groups Not supported
Roles
NodeConstants.NODE_ROLES
Privileges
NodeConstants.NODE_PRIVILEGES
User Monitor Not supported
Deleted Users Not supported
Deleted User Groups Not supported
System Settings
SmartRules
NodeConstants.NODE_SMARTRULES
Viewer & Files
NodeConstants.NODE_VIEWER_AND_FILES
Notifications
NodeConstants.NODE_NOTIFICATION_TEMPLATES
Full Text Search Not supported
UOM Not supported
Company Profile Not supported
Currency Exchange Rates
IAdmin.getConversionRates()
Commodities Not supported
Product Cost Management
Chapter 20: Performing Administrative Tasks
v9.3.1.2 333
Agile Java Client node Agile API equivalent
Ship To Locations Not supported
Project Portfolio Management
Projects Health Not supported
Cost Status Not supported
Quality Status Not supported
Resource Status Not supported
Dashboard Management Not supported
Default Role Not supported
Agile Content Service
Subscribers
NodeConstants.NODE_SUBSCRIBERS
Destinations
NodeConstants.NODE_DESTINATIONS
Events
NodeConstants.NODE_EVENTS
Filters
NodeConstants.NODE_FILTERS
Package Services Not supported
Response Services Not supported
Product Governance & Compliance
Sign Off Message Not supported
Server Settings
Locations
NodeConstants.NODE_SERVER_LOCATION
Database
NodeConstants.ROOT
Preferences
NodeConstants.NODE_PREFERENCES
Licenses
NodeConstants.NODE_SERVER_LICENSES
NodeConstants.NODE_USER_LICENSES
Task Monitor Not supported
Task Configuration Not supported
Example
Example Roles Not supported
Example Privileges Not supported
Example Criteria Not supported
Agile Web Client allows you to view and edit system and user settings by choosing Admin and
Settings from the menu, respectively. The following table identifies how Agile Web Client
administrative functionality maps to the Agile API.
SDK Developer Guide - Using Agile APIs
334 Agile Product Lifecycle Management
Agile Web Client Node Agile API equivalent
Tools > My Settings
User Profile User.General Info page
Change Password IUser.changeLoginPassword() and
IUser.changeApprovalPassword()
Transfer Authority Not supported
Organize Bookmarks My-Inbox folder
Organize Searches Searches folder
Organize Reports Not supported
Personal Groups My-Inbox folder
Deleted Personal Groups Not supported
Personal Criteria Not supported
Personal Supplier Groups Not supported
Tools > Administration > Web Client Settings
Themes Not supported
Tools > Administrator > User Settings
Users Create a query of users
User Groups Create a query of user groups
Supplier Groups Not supported
Deleted Users Not supported
Deleted User Groups Not supported
Dashboard Configuration Not supported
Admin nodes in Agile PLM Clients do not have names that match up identically to their respective
NodeConstants. For example, the Notifications node in Agile Java Client is equivalent to
NodeConstants.NODE_NOTIFICATION_TEMPLATES. Similarly, the hierarchy of nodes that are
represented in the Agile PLM database does not exactly match Agile Java Client node hierarchy.
If your Agile API program provides a tree view of the Agile PLM administrative nodes, you can use
the view to interactively retrieve INode objects. From each INode object you can get the child
nodes. If you continue to traverse the administrative node hierarchy, you can reach all node levels.
The following example shows how to retrieve the root node and its children, thus displaying the top-
level nodes on the Agile Application Server.
Example: Retrieving top-level nodes
private void getTopLevelNodes() throws APIException {
INode root =
m_admin.getNode(NodeConstants.ROOT);
if (null != root) {
System.out.println(root.getName() + ", " + root.getId());
Chapter 20: Performing Administrative Tasks
v9.3.1.2 335
Collection childNodes =
root.getChildNodes();
for (Iterator it =
childNodes.iterator();it.hasNext();) {
INode node =
(INode)it.next();
System.out.println(node.getName() + ", " + node.getId());
}
}
}
Note When you call getChildNodes() on the root node, the results include several
undocumented Agile PLM nodes. Any undocumented nodes are not supported by the
Agile API.
For faster access, you can also retrieve a node by specifying its node ID constant. The
NodeConstants class lists all administrative nodes that are directly accessible. The following
example shows how to retrieve the SmartRules node and its properties.
Example: Retrieving SmartRules values
private void getSmartRules() throws APIException {
//Get the SmartRules node in Agile Administrator
INode node = m_admin.getNode(NodeConstants.NODE_SMARTRULES);
System.out.println("SmartRules Properties");
//Get SmartRules properties
IProperty[] props = (IProperty[])node.getProperties();
for (int i = 0; i < props.length; i++) {
System.out.println("Name : " + props[i].getName());
Object value = props[i].getValue();
System.out.println("Value : " + value);
}
}
Another way to get a node is to locate a parent node and then get one of its children using the
ITreeNode.getChildNode() method. The getChildNode() method lets you specify a node
by name or ID. You can also specify the path to a subnode, separating each node level with a slash
character (/). The following example shows how to use the getChildNode() method to retrieve a
node.
Example: Retrieving nodes using ITreeNode.getChildNode()
private INode getChildNode(INode node, String childName) throws
APIException {
Node child = (INode)(node.getChildNode(childName)); return child;
}
SDK Developer Guide - Using Agile APIs
336 Agile Product Lifecycle Management
Working with the Classes Node
The Classes node and its subnodes are similar to the IAgileClass objects that are returned by
the IAdmin.getAgileClasses() method. The difference is that getAgileClasses() returns
several virtual classes, such as Item and Change, that are not represented as nodes. To modify the
properties of the attribute of a particular node, Agile recommends using the
IAdmin.getAgileClasses() or IAdmin.getAgileClass() methods. Although it’s possible
to modify a subclass by traversing the Classes node and its subnodes, it is much easier to work
with IAgileClass objects. For more information, see
Managing Agile PLM Classes on page 336.
Managing Agile PLM Classes
The Agile Classes node provides a framework for classifying Agile PLM objects, such as parts,
changes, and packages. Using Agile Java Client, you can define new subclasses for your
organization. Although you can’t use the Agile API to create new subclasses, you can read or
modify any of the existing subclasses. For example, you can customize a subclass by defining the
attributes that are visible in each table or on each page.
The Agile PLM classes framework is based on the types of objects that are created in Agile PLM.
The objects that are available on your Agile PLM system depend on the Agile PLM agreement with
Oracle.
Each Agile PLM class has at least one subclass. The following table lists Agile PLM base classes,
classes, and Agile-supplied subclasses. Your Agile PLM system may include other user-defined
subclasses.
Base Class Classes Predefined Subclasses
Changes Change Orders ECO
Change Requests ECR
Deviations Deviation
Manufacturer Orders MCO
Price Change Orders PCO
Site Change Orders SCO
Stop Ships Stop Ship
Customers Customers Customer
Declarations Homogeneous Material Declarations Homogeneous Material Declaration
IPC 1752-1 Declarations IPC 1752-1 Declaration
IPC 1752-2 Declarations IPC 1752-2 Declaration
JGPSSI Declarations Japan Green Procurement Survey
Standardization Initiative Declaration
Part Declarations Part Declaration
Substance Declarations Substance Declaration
Chapter 20: Performing Administrative Tasks
v9.3.1.2 337
Base Class Classes Predefined Subclasses
Supplier Declarations of Conformance Supplier Declaration of Conformance
Discussions Discussions Discussion
File Folders File Folders File Folder
Historical Report File Folders Schedule Generated
User Saved
Items Documents Document
Parts Part
Manufacturer Parts Manufacturer Parts Manufacturer Part
Manufacturers Manufacturers Manufacturer
Packages Packages Package
Prices Published Prices Contract
Published Price
Quote Histories Quote History
Product Service Requests Non-Conformance Reports NCR
Problem Reports Problem Report
Projects Activities Phase
Program
Task
Gates Gate
Quality Change Requests Audits Audit
Corrective and Preventive Actions CAPA
Reports1 Custom Reports Custom Report
External Reports External Report
Standard Reports Administrator Report
Standard Report
Requests for Quote Requests for Quote RFQ
RFQ Responses RFQ Responses RFQ Response
Sites Sites Site
Sourcing Projects Sourcing Projects Sourcing Project
Specifications Specifications Specification
Substances Materials Material
Subparts Subpart
SDK Developer Guide - Using Agile APIs
338 Agile Product Lifecycle Management
Base Class Classes Predefined Subclasses
Substance Groups Substance Group
Substances Substance
Suppliers Suppliers Broker
Component Manufacturer
Contract Manufacturer
Distributor
Manufacturer Representative
Transfer Orders Automated Transfer Orders ATO
Content Transfer Orders CTO
User Groups User Groups User Group
Users Users User
Note Report objects are not supported by the Agile API.
Concrete and Abstract Classes
Agile PLM super classes, such as Item and Change, are abstract classes that serve as the parent
classes for other abstract classes, such as Parts Class, Documentation Class, and Engineering
Change Order Class. Abstract superclasses and classes cannot be instantiated.
Concrete classes are user-defined subclasses that can be instantiated by the Agile API. Examples
of concrete classes are Part, Document, ECO, and ECR.
When you load an object using the IAgileSession.getObject() method, you can specify
either a concrete or an abstract Agile PLM class. For example, all of the following methods load the
same specified part.
Example: Loading an object using abstract or concrete classes
try {
IItem item;
// Load a part using the Item base class
item =
(IItem)m_session.getObject(ItemConstants.CLASS_ITEM_BASE_CLASS,
"1000-02");
// Load a part using the Parts class
item =
(IItem)m_session.getObject(ItemConstants.CLASS_PARTS_CLASS, "1000-
02");
// Load a part using the Part subclass
item =
(IItem)m_session.getObject(ItemConstants.CLASS_PART, "1000-02");
} catch (APIException ex) {
System.out.println(ex);
Chapter 20: Performing Administrative Tasks
v9.3.1.2 339
}
To get an array of classes, use the IAgileClass.getAgileClasses() method. You can
specify a range of classes to return. For example, specify IAdmin.CONCRETE for the range
parameter to return only concrete classes or IAdmin.ALL to return all classes.
Example: Getting classes
private void getConcreteClasses() throws APIException {
IAgileClass[] classes =
m_admin.getAgileClasses(IAdmin.CONCRETE);
for (int i = 0; i < classes.length; i++) {
System.out.println("Class Name : " + classes[i].getName());
System.out.println("ID : " + classes[i].getId());
}
}
void getAllClasses() throws APIException {
IAgileClass[] classes =
m_admin.getAgileClasses(IAdmin.ALL);
for (int i = 0; i < classes.length; i++) {
System.out.println("Class Name : " + classes[i].getName());
System.out.println("ID : " + classes[i].getId());
}
}
When you create a new object using the IAgileSession.createObject() method, you must
specify a concrete Agile PLM class, that is, one of the user-defined subclasses. Remember,
abstract classes cannot be instantiated. The following example shows how to create an object of
the Part subclass.
Example: Creating a part
try {
Map params =
new HashMap();
params.put(ItemConstants.ATT_TITLE_BLOCK_NUMBER, "1000-02");
IItem item =
(IItem)m_session.createObject(ItemConstants.CLASS_PART, params);
} catch (APIException ex) {
System.out.println(ex);
}
Referencing Classes
You can reference Agile PLM classes in the following ways:
à by object (an IAgileClass)
à by class ID constant, such as ItemConstants.CLASS_PART or
ChangeConstants.CLASS_ECO. All Agile API constants are contained in classes that have a
suffix name “Constants.” For example, ItemConstants contains all constants related to
IItem objects.
à by class name, such as “Part” or “ECO”.
SDK Developer Guide - Using Agile APIs
340 Agile Product Lifecycle Management
In general, avoid referencing classes by name for the following reasons:
à Class names can be modified.
à Class names are not necessarily unique. It’s possible to have duplicate class names.
Consequently, if you reference a class by name you may inadvertently reference the wrong
class.
à Class names are localized; that is, the names are different for different languages.
Identifying the Target Type of a Class
Each class has a specified target type, which is the type of Agile PLM object that the class can
create. For example, the target type for the Part subclass is IItem.OBJECT_TYPE. You can use
the target type to classify the user-defined subclasses that have been defined in your Agile PLM
system. For example, if you want to create a user interface that displays item classes, you can list
the classes at run time by selecting those with the target type IItem.OBJECT_TYPE.
Example: Getting the target type for a class
private void getConcreteItemClasses() throws APIException {
IAgileClass[] classes =
m_admin.getAgileClasses(IAdmin.CONCRETE);
for (int i = 0; i < classes.length; i++) {
if (classes[i].getTargetType()
== IItem.OBJECT_TYPE) {
System.out.println("Class Name : " + classes[i].getName());
System.out.println("ID : " + classes[i].getId());
}
}
}
There are two predefined concrete classes for the Item class, Document and Part. If your company
hasn’t added any Item subclasses to the Agile PLM system, the code in the previous example
should print the following results:
Class Name : Document
ID : 9141
Class Name : Part
ID : 10141
Working with Attributes
Each object that you can retrieve in an Agile API program has a set of attributes. An attribute
represents metadata for a particular business object. It defines the properties and values of the
object. For example,
Title Block.Number, Title Block.Description, and Title Block.Part Category
are three of the Title Block attributes for a Part.
When you create an instance of an object in your program, each IAttribute in your object
classes is equivalent to a field, or an ICell object. IAttribute objects directly correspond with
ICell objects for an object that you created or opened in your program. For more information
about ICell objects, see
Working with Data Cells on page 89.
Chapter 20: Performing Administrative Tasks
v9.3.1.2 341
Referencing Attributes
You can reference Agile PLM attributes in the following ways:
à by object (an IAttribute)
à by attribute ID constants
All Agile API constants, including attribute ID constants, are contained in classes that have the
suffix “Constants.” For example, ItemConstants contains all constants related to IItem
objects.
à by fully qualified name, such as "Title Block.Number" or "Cover Page.Change Category"
à by short name, such as “Number”. However, attribute short names are not unique in Agile PLM.
If you are referencing multiple attributes, you may run into a conflict if two different attributes
have the same short name.
Note Because attribute names can be modified and referencing attributes by ID number or
constant is difficult to identify or remember, Agile recommends using the APIName field
for this purpose. For information and procedures, see
Accessing PLM Metadata with
APIName Field on page 123. Many of the examples in this manual reference attributes
by name because they were constructed before the introduction of this field.
The following example shows how to reference an attribute ID constant.
Example: Referencing an attribute ID constant
Integer attrID =
ItemConstants.ATT_TITLE_BLOCK_DESCRIPTION;
try {
v = item.getValue(attrID);
} catch (APIException ex) {
System.out.println(ex);
}
A fully qualified attribute name is a string with the following format:
TableName.AttributeName
TableName is the name of the table in which the attribute appears. AttributeName is the
current value for the Name property of an attribute. All attributes have default names, but the names
can be changed. In particular, Page Two and Page Three attributes that have been made visible in
your Agile PLM system are likely to have been assigned more meaningful names than “Text01,”
“List01,” and “Date01.”
“Cover Page.Reason for Change” and “Title Block.Number” are two examples of fully qualified
attribute names.
The following example shows how to reference to a fully qualified attribute name.
Example: Referencing an attribute name
Object v;
String attrName = "Title Block.Description";
try {
v = item.getValue(attrName);
SDK Developer Guide - Using Agile APIs
342 Agile Product Lifecycle Management
} catch (APIException ex) {
System.out.println(ex);
}
Note Attribute names are case-sensitive.
Retrieving Attributes
IAttribute objects are associated with a particular subclass. For example, the attributes for a
Part are different from those of an ECO. Therefore, if you know the subclass of an object you can
retrieve the list of attributes for it. The following table lists methods that can be used to retrieve
attributes.
Method Description
IAgileClass.getAttribute()
Retrieves the specified IAttribute object for a class
IAgileClass.getAttributes()
Retrieves an array of IAttribute objects for all tables of a class
IAgileClass.getTableAttributes()
Retrieves an array of IAttribute objects for a specified table of
the class
ITable.getAttributes()
Retrieves an array of IAttribute objects for a table
ICell.getAttribute()
Retrieves the IAttribute object for a cell
The following example shows how to retrieve BOM table attributes.
Example: Retrieving BOM table attributes for the Part subclass
try {
// Get the Part subclass
IAgileClass partClass =
(IAgileClass)m_admin.getAgileClass(ItemConstants.CLASS_PART);
// Get the collection of BOM table attributes for the Part subclass
IAttribute[] attrs =
partClass.getTableAttributes(ItemConstants.TABLE_BOM);
} catch (APIException ex) {
System.out.println(ex);
}
Another way to retrieve the attributes for a particular table is to first get the table, then get its
attributes using the ITable.getAttributes() method.
Example: Retrieving the collection of BOM table attributes from the table
try {
// Get Part P200
IItem item =
(IItem)m_session.getObject(IItem.OBJECT_TYPE, "P200");
// Get the BOM table
ITable bomTable =
item.getTable(ItemConstants.TABLE_BOM);
// Get BOM table attributes
IAttribute[] attrs =
bomTable.getAttributes();
Chapter 20: Performing Administrative Tasks
v9.3.1.2 343
} catch (APIException ex) {
System.out.println(ex);
}
Retrieving Individual Attributes
If you know the attribute you want to retrieve, you can get it by using the
IAgileClass.getAttribute() method. The following example shows how to get the “Cover
Page.Reason Code” attribute for an ECO.
Example: Retrieving the “Cover Page.Reason Code” attribute
try {
// Get the ECO subclass
IAgileClass classECO =
m_admin.getAgileClass("ECO");
// Get the "Cover Page.Reason Code" attribute
IAttribute attr =
classECO.getAttribute(ChangeConstants.ATT_COVER_PAGE_REASON_CODE);
// Get available values for Reason Code
IAgileList availValues =
attr.getAvailableValues();
} catch (APIException ex) {
System.out.println(ex);
}
Editing the Property of an Attribute
Agile PLM classes have attributes, and attributes have properties. To modify the properties of an
attribute for a particular subclass, follow these steps:
1. Use the IAdmin.getAgileClass() method to get an Agile PLM class.
2. Use the IAgileClass.getAttribute() method to get an attribute for the class.
3. Use the IAttribute.getProperty() method to get a property for the attribute.
4. Use the IProperty.getValue() method to get the current value for the property.
5. Use the IProperty.setValue() method to set a new value for the property.
Working with User-Defined Attributes
For each Agile PLM subclass, you can define additional attributes on the Page Two and Page
Three tables. These user-defined attributes, also known as customer flex fields, behave the same
as predefined Agile PLM attributes. You can retrieve them and edit their properties.
User-defined attributes are custom extensions to the Agile PLM system. Consequently, their IDs are
not included in the CommonConstants class. However, you can view the base ID for any attribute,
including user-defined attributes, in Agile Java Client. You can also write a procedure to
programmatically retrieve the ID for a user-defined attribute at run time, or use the API name.
SDK Developer Guide - Using Agile APIs
344 Agile Product Lifecycle Management
Working with Properties of Administrative Nodes
If you use the Agile API to retrieve an INode object, you can also view the INode’s property
values. An IProperty object represents a single property for an administrative node. To return an
array of all properties for a node, use the INode.getProperties() method.
The following example shows how to get the property value for the Reminder/Escalation Weekend
Setting preference. The last part of this example converts the available list values for this SingleList
property to a comma-delimited string.
Example: Getting Property values
private void getReminderEscalationWeekendProp() throws APIException {
//Get the General Preferences node
INode node =
m_admin.getNode(NodeConstants.NODE_PREFERENCES);
//Get the Reminder/Escalation Weekend Setting property
IProperty prop =
node.getProperty(PropertyConstants.PROP_REMINDER_ESCALATION_WEEKE
ND_SETTING);
//Get the Reminder/Escalation Weekend Setting property value
Object value =
prop.getValue();
System.out.println("Reminder/Escalation Weekend Setting : " +
value);
IAgileList avail =
prop.getAvailableValues();
if (avail != null) {
String strAvail =
listToString(avail);
System.out.println("Available Values : " + strAvail);
}
}
private String listToString(IAgileList list) throws APIException {
String strList = "";
Collection children =
list.getChildNodes();
for (Iterator it =
children.iterator();it.hasNext();) {
IAgileList childList =
(IAgileList)it.next();
strList =
strList + childList.getValue();
if (it.hasNext()) {
strList = strList + ", ";
}
}
return strList;
}
The SingleList and MultiList properties are different from other types of properties. You
cannot use the IProperty.getValue() and IProperty.setValue() methods to directly
modify a property that contains a list of values. Instead, you use the IAgileList.setSelection
() method to select a list node, and then use the IProperty.setValue() method to set the
Chapter 20: Performing Administrative Tasks
v9.3.1.2 345
value. For more information about how to modify SingleList and MultiList properties, see
Getting
and Setting List Values on page 96.
Managing Users
Users are data objects that you can create, like items and changes. Consequently, you can work
with users directly without traversing the administrative node hierarchy. If you have the proper Agile
PLM privileges, you can create, modify, and delete users. For example, you could create a program
that periodically synchronizes Agile PLM users with data available from a corporate directory.
Getting All Users
To retrieve all Agile PLM users, run a query for User objects. The following example retrieves all
users and prints the username, first name, and last name for each user.
Example: Getting all users
private void getAllUsers() throws APIException {
IQuery q =
(IQuery)m_session.createObject(IQuery.OBJECT_TYPE, "select * from
[Users]");
ArrayList users =
new ArrayList();
Iterator itr =
q.execute().getReferentIterator();
while (itr.hasNext()) {
users.add(itr.next());
}
for (int i = 0; i < users.size(); i++) {
IUser user =
(IUser)users.get(i);
System.out.println(
user.getValue(UserConstants.ATT_GENERAL_INFO_USER_ID) + ", " +
user.getValue(UserConstants.ATT_GENERAL_INFO_FIRST_NAME) + ", " +
user.getValue(UserConstants.ATT_GENERAL_INFO_LAST_NAME)
);
}
}
Creating a User - 9.3.1.2
A user is like other data objects that you can create with the Agile API. To create a user, you define
the user’s parameters and pass them to the IAgileSession.createObject() method. The
required parameters you must specify are username and login password. You can also specify
other user attributes, which are listed in the UserConstants class.
Note If an LDAP directory server is used to authenticate users for your Agile PLM system, you
can create only supplier users through the SDK that have restricted access to the Agile
PLM system. You must create and maintain other users on the directory server.
SDK Developer Guide - Using Agile APIs
346 Agile Product Lifecycle Management
The passwords you specify for a new user are default values. If you specify an approval password,
it must be different from the login password unless the
UserConstants.ATT_GENERAL_INFO_USE_LOGIN_PASSWORD_FOR_APPROVAL cell is set to
“Yes.” The user can change passwords later.
Example: Creating a user
private void userTest() {
try {
//Add code here to log in to the Agile Application Server
//After logging in, create a new user by invoking the createUser method
below
IUser user = createUser("akurosawa");
} catch (APIException ex) {
System.out.println(ex);
}
}
private IUser createUser(String newUser) throws APIException {
//Create the new user
Map params =
new HashMap();
params.put(UserConstants.ATT_GENERAL_INFO_USER_ID, newUser);
params.put(UserConstants.ATT_LOGIN_PASSWORD, "agile");
IUser user =
(IUser)session.createObject
(UserConstants.CLASS_USER, params);
return user;
}
By default, when you create a new user it’s assigned the Concurrent user category and the My User
Profile role, a combination that allows the user to only view their own profile. To create and modify
objects, the user must be assigned roles with the appropriate create and modify privileges. For an
example showing how to change a user’s Role settings, see
Configuring User Settings on page
348.
Creating Users and Requiring Password Modification at Login
When creating a user, you can require the new user to change the assigned password, which is
usually temporary, for a new and more secure one at login. To create such a user, it is necessary to
define the user’s parameters as explained in
Creating a User on page 345 and pass a flag to force
password change at login. This is illustrated in the following code sample.
Example: Creating a user and requiring password modification at login
String username = "USER" + System.currentTimeMillis();
HashMap params = new HashMap();
params.put(UserConstants.ATT_GENERAL_INFO_USER_ID, username);
params.put(UserConstants.ATT_GENERAL_INFO_FIRST_NAME, username);
params.put(UserConstants.ATT_GENERAL_INFO_LAST_NAME, username);
params.put(UserConstants.ATT_LOGIN_PASSWORD, "agile");
params.put(UserConstants.ATT_APPROVAL_PASSWORD, "agile2");
params.put(UserConstants.ATT_MUST_CHANGE_PWD_AT_LOGON, "true");
IUser user = (IUser) session.createObject(UserConstants.CLASS_USER,
params);
System.out.println("Created user: " + user.getName());
Chapter 20: Performing Administrative Tasks
v9.3.1.2 347
Creating a Supplier User
Supplier users are assigned to the Restricted user category by default, which restricts their access
to the Agile PLM system. The Restricted user category allows supplier users to respond to RFQs
and use other features of Agile Product Cost Management (PCM).
To create a supplier user, define the user’s parameters and pass them to the
IAgileSession.createObject() method. You must specify the username, login password,
and supplier name. You can also specify other user attributes, which are listed in the
UserConstants class.
Example: Creating a supplier user
private IUser createSupplierUser(String userName, String supplier)
throws APIException {
HashMap userParams =
new HashMap();
userParams.put(UserConstants.ATT_GENERAL_INFO_USER_ID, userName);
userParams.put(UserConstants.ATT_LOGIN_PASSWORD, "agile");
userParams.put(UserConstants.ATT_SUPPLIER, supplier);
return (IUser)m_session.createObject(UserConstants.CLASS_USER,
userParams);
}
Saving a User to a New User
You can use the IDataObject.saveAs() method to save an existing user to a new user. The
saveAs() method serves as a handy shortcut because it allows you to assign a new user the
same roles, privileges, and sites as an existing user. When you use the saveAs() method to save
a user, you must specify parameters for the new user’s user name and login password.
Example: Saving an object as a new object
private void saveAsUser(IUser user, String newUserName) {
try {
//Set parameters for the new user
Map params =
new HashMap();
params.put(UserConstants.ATT_GENERAL_INFO_USER_ID, newUserName);
params.put(UserConstants.ATT_LOGIN_PASSWORD, "agile");
// Save the new user
user.saveAs(UserConstants.CLASS_USER, params);
} catch (APIException ex) {
System.out.println(ex);
}
}
SDK Developer Guide - Using Agile APIs
348 Agile Product Lifecycle Management
Checking for Expired Passwords
An administrator can manually require a password change in Java Client. When a user’s login
password expires, the user cannot log in to the Agile Application Server. If the login password has
expired, the Agile API program can prompt the user to specify a new password. The following
example shows how to check for an Agile API error related to an expired password.
Example: Checking for Expired Passwords
HashMap params = new HashMap();
params.put(AgileSessionFactory.USERNAME, user.getName());
params.put(AgileSessionFactory.PASSWORD, "agile");
params.put(AgileSessionFactory.URL,"
http://localhost/Agile");
// Pass one element array to get the login exception
APIException[] exception = new APIException[1];
params.put(AgileSessionFactory.STATUS, exception);
IAgileSession session=AgileSessionFactory.createSessionEx(params);
System.out.println(exception[0].getErrorCode());
// When error code is ExceptionConstants.APDM_PWDNOCHANGE
If(exception[0].getErrorCode() ==
ExceptionConstants.APDM_PWDNOCHANGE) {
String oldPassowrd = "agile";
String newPassowrd = "oracle";
// Prompt for new password and change the passsword
Session.getUser().changeLoginPassword (oldPassword, newPassword);
}
Configuring User Settings
An IUser object, unlike administrative nodes, is a dataobject. Therefore, an IUser object has data
cells, not properties, and you use the ICell interface to configure a user’s settings. The following
example shows how to get visible cells on the General Info and Page Two tables for a user. To
access cells on other user tables, use the IDataObject.getTable() method to load the table.
Example: Getting user cells for General Info and Page Two
private void getUserCells(IUser user) throws APIException {
ICell[] cells = user.getCells();
for (int i = 0; i < cells.length; i++) {
System.out.println(cells[i].getName() + " : " +
cells[i].getValue());
}
}
Two important settings for a user are User Category and Roles. The User Category setting defines
the broad range of actions a user can perform on the Agile PLM system. Select from one of the
following User Category values:
à Power – User can log in to the server at any time with unrestricted use of the Agile PLM system.
Power users are not subject to the limited number of concurrent users.
à Concurrent – User can log in to the server only if a concurrent user agreement is available.
Note Licenses are controlled by your agreement with Oracle.
Chapter 20: Performing Administrative Tasks
v9.3.1.2 349
à Restricted – User has restricted access to the Agile PLM system. Supplier users are by default
assigned the Restricted category, which allows them to respond to RFQs and use other
features of Agile Product Cost Management (PCM). Restricted users are not subject to the
limited number of concurrent users.
The Roles setting further defines the capabilities of a user, assigning roles and privileges. A user
won’t be able to create objects without the proper roles and privileges. For more information about
Agile PLM user roles, and privileges, refer to the Agile PLM Administrator Guide.
The following example shows how to set a user’s User Category and Roles settings.
Example: Setting the User Category and Roles settings for a user
private void setCategory(IUser user) throws APIException {
//Get the User Category cell
ICell cell =
user.getCell(UserConstants.ATT_GENERAL_INFO_USER_CATEGORY);
//Get the available values for the cell
IAgileList license =
cell.getAvailableValues();
//Set the selected value to "Concurrent"
license.setSelection(new Object[] { "Concurrent" });
//Change the cell value
cell.setValue(license);
}
private void setRoles(IUser user) throws APIException {
//Get the Role cell
ICell cell =
user.getCell(UserConstants.ATT_GENERAL_INFO_ROLES);
//Get the available values for the cell
IAgileList roles =
cell.getAvailableValues();
//Set the selected roles to Change Analyst and Administrator
roles.setSelection(new Object[] {"Change
Analyst","Administrator","My User Profile"});
//Change the cell value
cell.setValue(roles);
}
Resetting User Passwords
Administrators with User Administrator privileges can reset the password of other users to a new
value. Users without this privilege are not able to reset user passwords. This feature enables
resetting large numbers of passwords in the batch mode, which is preferable to manually changing
them one at a time using the UI.
SDK Developer Guide - Using Agile APIs
350 Agile Product Lifecycle Management
The changeLoginPassword() method which supports this feature allows passing a null value
instead of the current password value. The following example shows how to use this method to
reset a user’s password using null instead of the current password.
Example: Resetting a password to a new value
public void changeLoginPassword(null, String newPassword)
throws APIException;
Deleting a User
To delete a user, use the IDataObject.delete() method. Like other dataobjects, an object
deleted for the first time is “soft-deleted,” which means it is disabled but not removed from the
database. The Agile Application Server does not allow you to permanently delete a user.
Example: Deleting a user
private void removeUser(IUser user) throws APIException {
user.delete();
user = null;
}
Note In Agile Java Client, deleted users can be listed by choosing Admin > User Settings >
Deleted Users.
Managing User Groups
A user group is an object that contains a list of Agile PLM users. You can use user groups to define
project teams, departments, and global groups and their assigned users. User groups are not site-
related, unlike items and changes, but you can create groups of users based on their location.
Whenever you add a user to a user group, that change is reflected in the user’s Groups setting,
whose attribute ID is UserConstants.ATT_GENERAL_INFO_GROUPS.
Note In Agile Clients such as Agile Web Client, you can send an object, such as a change, to
a user group. The Agile API does not support sending objects to user groups. However,
you can retrieve users from the Users table of a User Group object and then send them
an object.
Getting All User Groups
To retrieve all Agile PLM user groups, run a query for User Group objects. You can iterate through
the user groups to find a particular group. The following example retrieves all user groups and prints
the name, description, maximum number of users, and enabled status for each user group.
Example: Getting all user groups
private void getAllUserGroups() throws APIException {
IQuery q =
(IQuery)m_session.createObject(IQuery.OBJECT_TYPE, "select * from
[User Groups]");
ArrayList groups = new ArrayList();
Iterator itr =
q.execute().getReferentIterator();
Chapter 20: Performing Administrative Tasks
v9.3.1.2 351
while (itr.hasNext()) {
groups.add(itr.next());
}
for (int i = 0; i < groups.size(); i++) {
IUserGroup ug =
(IUserGroup)groups.get(i);
System.out.println(
ug.getValue(UserGroupConstants.ATT_GENERAL_INFO_NAME) + ", " +
ug.getValue(UserGroupConstants.ATT_GENERAL_INFO_DESCRIPTION) + ", "
+
ug.getValue(UserGroupConstants.ATT_GENERAL_INFO_MAX_NUM_OF_NAMED_USE
RS) + ", " +
ug.getValue(UserGroupConstants.ATT_GENERAL_INFO_STATUS)
);
}
}
Creating a User Group
A user group, like a user, is a dataobject and not an administrative node on the Agile Application
Server. To create a user group, you define the user group’s parameters, such as its name, and
pass the parameters to the IAgileSession.createObject() method. The only required
parameter you must specify is the name, whose attribute ID is
UserGroupConstants.ATT_GENERAL_INFO_NAME. You can also specify other user attributes,
which are listed in the UserGroupConstants class. To enable a user group, make sure the
Enabled cell is set to Yes.
After creating a user group, you need to add users to the Users table to make the group meaningful.
To create a new row in the Users table, use the ITable.createRow(java.lang.Object)
method.
Example: Creating a user group
private void userGroupTest() throws APIException {
//Add code here to log in to the Agile Application Server
//After logging in, create a new user group
IUserGroup group =
createGroup("Swallowtail Project");
//Add users to the Western project group
IUser[] selUsers = new IUser[] {
m_session.getObject(IUser.OBJECT_TYPE, "jford"),
m_session.getObject(IUser.OBJECT_TYPE, "hhawkes"),
m_session.getObject(IUser.OBJECT_TYPE, "speckinpah")
};
addUsers(group, selUsers);
}
private IUserGroup createGroup(String groupName) throws APIException {
//Create the user group
IUserGroup group =
(IUserGroup)m_session.createObject(UserGroupConstants.CLASS_USER_
GROUP, groupName);
SDK Developer Guide - Using Agile APIs
352 Agile Product Lifecycle Management
//Enable the user group
ICell cell =
group.getCell(UserGroupConstants.ATT_GENERAL_INFO_STATUS);
IAgileList list = cell.getAvailableValues();
list.setSelection(new Object[] { "Active" });
cell.setValue(list);
return group;
}
private void addUsers(IUserGroup group, IUser[] seUsers) throws
APIException {
ITable usersTable = group.getTable(UserGroupConstants.TABLE_USERS);
for (int i = 0; i < users.length; i++) {
IRow row = usersTable.createRow(users[i]);
}
}
User groups can be global or personal. Global user groups are accessible to all Agile PLM users.
Personal user groups are accessible only to the person who created the group. The following
example shows how to make a user group global.
Example: Making a user group global
private void setGlobal(IUserGroup group) throws APIException {
//Get the Global/Personal cell
ICell cell =
group.getCell(UserGroupConstants.ATT_GENERAL_INFO_GLOBAL_PERSONAL);
//Get the available values for the cell
IAgileList values = cell.getAvailableValues();
//Set the selected value to "Global"
values.setSelection(new Object[] { "Global" });
//Change the cell value
group.setValue(UserGroupConstants.ATT_GENERAL_INFO_GLOBAL_PERSONAL,
values);
}
Adding a User Group to the User's User Group Table
IUserGroup cannot be passed to createRow() to add a user group to the user’s user group
table. You must use a Map as shown in the following example.
Example: Using a Map to add a User Group to a User Group Table
ITable ugTable = user.getTable(UserConstants.TABLE_USERGROUP);
Map map = new HashMap();
map.put(UserConstants.ATT_USER_GROUP_GROUP_NAME, ug.getName());
ugTable.createRow(map);
Chapter 20: Performing Administrative Tasks
v9.3.1.2 353
Listing Users in a User Group
The users contained within a user group are listed on the Users table. Therefore, to get the list of
users in the user group, use the IDataObject.getTable() method and then iterate over the
table rows to access data for each user. The following example shows how to list the users in a
user group.
Example: Listing the users in a user group
private void listUsers(IUserGroup group) throws APIException {
ITable usersTable =
group.getTable(UserGroupConstants.TABLE_USERS);
Iterator it =
usersTable.iterator();
while (it.hasNext()) {
IRow row = (IRow)it.next();
System.out.println(row.getValue(UserGroupConstants.ATT_USERS_USER_NA
ME));
}
}
v9.3.1.2 355
Appendix A
Mapping Agile PLM Client Features to
Agile API
This Appendix includes the following:
Login Features..................................................................................................................................................... 355
General Features................................................................................................................................................. 356
Search Features.................................................................................................................................................. 356
Attachment Features ........................................................................................................................................... 357
Workflow Features............................................................................................................................................... 357
Manufacturing Site Features................................................................................................................................358
Folder Features ................................................................................................................................................... 358
Projects Features................................................................................................................................................. 359
Administrative Features....................................................................................................................................... 359
Login Features
The following table lists general features for logging in to the Agile Application Server.
Feature Equivalent Method(s)
Get an instance of the Agile Application Server session
AgileSessionFactory.getInstance()
Create a session and log in to the Agile Application
Server
AgileSessionFactory.createSession()
Close a session and disconnect from the Agile
Application Server
IAgileSession.close()
SDK Developer Guide - Using Agile APIs
356 Agile Product Lifecycle Management
General Features
The following table lists the General features that apply to all Agile PLM business objects.
Feature Equivalent Method(s)
Create a new object
IAgileSession.createObject()
Load an existing object
IAgileSession.getObject()
Save an object as another object
IDataObject.saveAs()
Delete an object
IDataObject.delete()
IFolder.delete()
IQuery.delete()
Undelete an object
IDataObject.undelete()
Get a cell value for an object
IDataObject.getValue()
Set an cell value for an object
IDataObject.setValue()
Get a table for an object
IDataObject.getTable()
Add a row to a table
ITable.createRow()
Remove a row from a table
ITable.removeRow()
Get subscriptions for an object
ISubscribable.getSubscriptions()
Enable a subscription event
ISubscription.enable()
Modify subscriptions for an object
ISubscribable.modifySubscriptions()
Search Features
The table below lists the supported Search (Query) features.
Feature Equivalent Method(s)
Set the name of a search
IQuery.setName()
Make the search public or private
IQuery.setQueryType()
Set the search type for a query (object search or Where Used
search)
IQuery.setSearchType()
Set and get search criteria
IQuery.setCriteria()
IQuery.getCriteria()
Run a search
IQuery.execute()
Make a search case-sensitive
IQuery.setCaseSensitive()
Delete a search
IQuery.delete()
Save a search as another search
IQuery.saveAs()
Appendix
A
v9.3.1.2 357
Attachment Features
The table below lists features for working with attachments and file folders.
Feature Equivalent Method(s)
Download all files contained in a file folder
IFileFolder.getFile()
Download a single file listed on the Attachments tab
IAttachmentFile.getFile()
Check out a file folder
IFileFolder.checkOut()
Check in a file folder
IFileFolder.checkIn()
Cancel checkout
IFileFolder.cancelCheckOut()
Incorporate or unincorporate an item, thereby locking or
unlocking its attachments
IAttachmentContainer.setIncorporated()
Workflow Features
The table below lists Workflow features for routable Agile PLM objects.
Feature Equivalent Method(s)
Audit a routable object
IRoutable.audit()
Change the status of a routable object
IRoutable.changeStatus()
Send an object to another Agile PLM user(s)
IDataObject.send()
Approve a routable object
IRoutable.approve()
Reject a routable object
IRoutable.reject()
Comment on a routable object
IRoutable.comment()
Add or remove approvers and observers for a routable object
IRoutable.addApprovers()
IRoutable.removeApprovers()
SDK Developer Guide - Using Agile APIs
358 Agile Product Lifecycle Management
Manufacturing Site Features
The table below lists features for working with manufacturing sites.
Feature Equivalent Method(s)
Get the current manufacturing site selected for an
item
IManufacturingSiteSelectable.getManufacturingSi
te()
Get all manufacturing sites for an item
IManufacturingSiteSelectable.getManufacturingSi
tes()
Set an item to use all manufacturing sites
IManufacturingSiteSelectable.setManufacturingSi
te(
ManufacturingSiteConstants.ALL_SITES)
Specify that an item is not site-specific and is
common to all sites.
IManufacturingSiteSelectable.setManufacturingSi
te(
ManufacturingSiteConstants.COMMON_SITE)
Set an item to use a specific manufacturing site
IManufacturingSiteSelectable.setManufacturingSi
te(site)
Folder Features
The following table lists the Folder features for working with folders.
Feature Equivalent Method(s)
Add an item (such as a query) to the folder
IFolder.addChild()
Set the type of folder (public or private)
IFolder.setFolderType()
Set the folder name
IFolder.setName()
Get a folder of the current user
IUser.getFolder()
Remove an item from the folder
IFolder.removeChild()
Clear all objects from the folder
IFolder.clear()
Delete a folder
IFolder.delete()
Appendix
A
v9.3.1.2 359
Projects Features
The following table lists features for working with Projects.
Feature Equivalent Method(s)
Save a Project as another Project or template
IProgram.saveAs()
Reschedule a Project
IProgram.reschedule()
Assign users from a resource pool
IProgram.assignUsersFromPool()
Delegate ownership of a Project to another user
IProgram.delegateOwnership()
Substitute Project resources
IProgram.substituteResource()
Create a baseline
IProgram.createBaseline()
Select a baseline view of the Project
IProgram.selectBaseline()
Lock or unlock a Project
IProgram.setLock()
Reply to a discussion
IMessage.reply()
Administrative Features
The following table provides the list of features for working with Admin nodes and properties in Agile
Java Client.
Feature Equivalent Method(s)
Get an administrative node
IAdmin.getNode()
Get all subnodes (children) of an administrative node
ITreeNode.getChildNodes()
Get all properties of an administrative node
INode.getProperties()
Get the value for an administrative node’s property
IProperty.getValue()
Get the possible values for a list field
IProperty.getAvailableValues()
Get all Agile PLM classes
IAdmin.getAgileClasses(ALL)
Get all top-level Agile PLM classes
IAdmin.getAgileClasses(TOP)
Get all Agile PLM classes that can be instantiated
IAdmin.getAgileClasses(CONCRETE)
Get the list of subclasses for a specific class
IAgileClass.getSubclasses()
Get the Autonumber sources for a subclass
IAgileClass.getAutoNumberSources()
Get an array of attributes for a table
IAgileClass.getTableAttributes()
Get the metadata for a table
IAgileClass.getTableDescriptor()
Get the Agile PLM list library
IAdmin.getListLibrary()
SDK Developer Guide - Using Agile APIs
360 Agile Product Lifecycle Management
Feature Equivalent Method(s)
Create a new Agile PLM list
IListLibrary.createAdminList()
Get an Agile PLM list
IListLibrary.getAdminList()
Get all Agile PLM users Create a query of users
Get all Agile PLM user groups Create a query of user groups
Create a user or user group
IAgileSession.createObject()
Set properties of a user or user group
IProperty.setValue()
Change user passwords
IUser.changeApprovalPassword()
IUser.changeLoginPassword()
v9.3.1.2 361
Appendix B
Migrating Release 9.2.1 and Older Table
Constants to Release 9.2.2 or Later
This Appendix includes the following:
Mapped Pre-Release 9.2.2 Table Constants to 9.2.2 Table Constants .............................................................. 361
Removed Pre-Release 9.2.2 Table Constants.................................................................................................... 364
Information about merging and replacing the Relationship tables first appeared in
Accessing the
New and Merged Relationships Tables on page 67. Tables in this appendix list the Release 9.2.2
table constants and table constants that are either merged and mapped into a single table constant,
or mapped into a new table constant.
Mapped Pre-Release 9.2.2 Table Constants to 9.2.2
Table Constants
This table lists the pre-release 9.2.2 table constants and the new table constants that are either
merged and mapped into Release 9.2.2, or mapped into later releases of the SDK.
Pre 9.2.2 Table Constants 9.2.2 Table Constants
à TABLE_RELATIONSHIPSAFFECTEDBY
à TABLE_RELATIONSHIPSAFFECTS
à TABLE_REFERENCES
TABLE_RELATIONSHIPS
à ATT_RELATIONSHIPS_AFFECTED_BY_CRITERIA
_MET
à ATT_RELATIONSHIPS_AFFECTS_CRITERIA_MET
ATT_RELATIONSHIPS_CRITERIA_ME
T
à ATT_RELATIONSHIPS_AFFECTED_BY_CURRENT_
STATUS
à ATT_RELATIONSHIPS_AFFECTS_CURRENT_STAT
US
ATT_RELATIONSHIPS_CURRENT_STA
TUS
à ATT_RELATIONSHIPS_AFFECTED_BY_DATE01
à ATT_RELATIONSHIPS_AFFECTS_DATE01
ATT_RELATIONSHIPS_DATE01
à ATT_RELATIONSHIPS_AFFECTED_BY_DATE02
à ATT_RELATIONSHIPS_AFFECTS_DATE02
ATT_RELATIONSHIPS_DATE02
à ATT_RELATIONSHIPS_AFFECTED_BY_DATE03
à ATT_RELATIONSHIPS_AFFECTS_DATE03
ATT_RELATIONSHIPS_DATE03
à ATT_RELATIONSHIPS_AFFECTED_BY_DATE04
à ATT_RELATIONSHIPS_AFFECTS_DATE04
ATT_RELATIONSHIPS_DATE04
à ATT_RELATIONSHIPS_AFFECTED_BY_DATE05
à ATT_RELATIONSHIPS_AFFECTS_DATE05
ATT_RELATIONSHIPS_DATE05
à ATT_REFERENCES_DATE01
ATT_RELATIONSHIPS_DATE06
SDK Developer Guide - Using Agile APIs
362 Agile Product Lifecycle Management
à ATT_REFERENCES_DATE02
ATT_RELATIONSHIPS_DATE07
à ATT_REFERENCES_DATE03
ATT_RELATIONSHIPS_DATE08
à ATT_REFERENCES_DATE04
ATT_RELATIONSHIPS_DATE09
à ATT_REFERENCES_DATE05
ATT_RELATIONSHIPS_DATE10
à ATT_RELATIONSHIPS_AFFECTED_BY_DESCRIPT
ION
à ATT_RELATIONSHIPS_AFFECTS_DESCRIPTION
à ATT_REFERENCES_DESCRIPTION
ATT_RELATIONSHIPS_DESCRIPTION
à ATT_RELATIONSHIPS_AFFECTED_BY_LIST01,
ATT_RELATIONSHIPS_AFFECTS_LIST01
ATT_RELATIONSHIPS_LIST01
à ATT_RELATIONSHIPS_AFFECTED_BY_LIST02,
ATT_RELATIONSHIPS_AFFECTS_LIST02
ATT_RELATIONSHIPS_LIST02
à ATT_RELATIONSHIPS_AFFECTED_BY_LIST03
à ATT_RELATIONSHIPS_AFFECTS_LIST03
ATT_RELATIONSHIPS_LIST03
à ATT_RELATIONSHIPS_AFFECTED_BY_LIST04
à ATT_RELATIONSHIPS_AFFECTS_LIST04
ATT_RELATIONSHIPS_LIST04
à ATT_RELATIONSHIPS_AFFECTED_BY_LIST05
à ATT_RELATIONSHIPS_AFFECTS_LIST05
ATT_RELATIONSHIPS_LIST05
à ATT_REFERENCES_LIST01
ATT_RELATIONSHIPS_LIST06
à ATT_REFERENCES_LIST02
ATT_RELATIONSHIPS_LIST07
à ATT_REFERENCES_LIST03
ATT_RELATIONSHIPS_LIST08
à ATT_REFERENCES_LIST04
ATT_RELATIONSHIPS_LIST09
à ATT_REFERENCES_LIST05
ATT_RELATIONSHIPS_LIST10
à ATT_RELATIONSHIPS_AFFECTED_BY_MULTITEX
T01
à ATT_RELATIONSHIPS_AFFECTS_MULTITEXT01
ATT_RELATIONSHIPS_MULTITEXT01
à ATT_RELATIONSHIPS_AFFECTED_BY_MULTITEX
T02
à ATT_RELATIONSHIPS_AFFECTS_MULTITEXT02
ATT_RELATIONSHIPS_MULTITEXT02
à ATT_RELATIONSHIPS_AFFECTED_BY_MULTITEX
T03
à ATT_RELATIONSHIPS_AFFECTS_MULTITEXT03
ATT_RELATIONSHIPS_MULTITEXT03
à ATT_RELATIONSHIPS_AFFECTED_BY_MULTITEX
T04
à ATT_RELATIONSHIPS_AFFECTS_MULTITEXT04
ATT_RELATIONSHIPS_MULTITEXT04
à ATT_RELATIONSHIPS_AFFECTED_BY_MULTITEX
T05
à ATT_RELATIONSHIPS_AFFECTS_MULTITEXT05
ATT_RELATIONSHIPS_MULTITEXT05
à ATT_REFERENCES_MULTITEXT01
ATT_RELATIONSHIPS_MULTITEXT06
à ATT_REFERENCES_MULTITEXT02
ATT_RELATIONSHIPS_MULTITEXT07
à ATT_REFERENCES_MULTITEXT03
ATT_RELATIONSHIPS_MULTITEXT08
à ATT_REFERENCES_MULTITEXT04
ATT_RELATIONSHIPS_MULTITEXT09
Appendix B
v9.3.1.2 363
à ATT_REFERENCES_MULTITEXT05
ATT_RELATIONSHIPS_MULTITEXT10
à ATT_RELATIONSHIPS_AFFECTED_BY_TEXT01
à ATT_RELATIONSHIPS_AFFECTS_TEXT01
ATT_RELATIONSHIPS_TEXT01
à ATT_RELATIONSHIPS_AFFECTED_BY_TEXT02
à ATT_RELATIONSHIPS_AFFECTS_TEXT02
ATT_RELATIONSHIPS_TEXT02
à ATT_RELATIONSHIPS_AFFECTED_BY_TEXT03,
ATT_RELATIONSHIPS_AFFECTS_TEXT03
ATT_RELATIONSHIPS_TEXT03
à ATT_RELATIONSHIPS_AFFECTED_BY_TEXT04,
ATT_RELATIONSHIPS_AFFECTS_TEXT04
ATT_RELATIONSHIPS_TEXT04
à ATT_RELATIONSHIPS_AFFECTED_BY_TEXT05
à ATT_RELATIONSHIPS_AFFECTS_TEXT05
ATT_RELATIONSHIPS_TEXT05
à ATT_REFERENCES_TEXT01
ATT_RELATIONSHIPS_TEXT06
à ATT_REFERENCES_TEXT02
ATT_RELATIONSHIPS_TEXT07
à ATT_REFERENCES_TEXT03
ATT_RELATIONSHIPS_TEXT08
à ATT_REFERENCES_TEXT04
ATT_RELATIONSHIPS_TEXT09
à ATT_REFERENCES_TEXT05
ATT_RELATIONSHIPS_TEXT10
à ATT_RELATIONSHIPS_AFFECTED_BY_NOTES
à ATT_RELATIONSHIPS_AFFECTS_NOTES
ATT_RELATIONSHIPS_NOTES1
à ATT_REFERENCES_NOTES
ATT_RELATIONSHIPS_NOTES2
à ATT_RELATIONSHIPS_AFFECTED_BY_NUMBER
à ATT_RELATIONSHIPS_AFFECTS_NUMBER
à ATT_REFERENCES_NUMBER
ATT_RELATIONSHIPS_NAME
SDK Developer Guide - Using Agile APIs
364 Agile Product Lifecycle Management
Removed Pre-Release 9.2.2 Table Constants
The following pre-release 9.2.2 table constants are no longer available and should not be used in
later releases of the SDK:
à ATT_RELATIONSHIPS_AFFECTED_BY_EVENT
à AT_TRELATIONSHIPS_AFFECTS_TRIGGER_EVENT
à ATT_RELATIONSHIPS_AFFECTED_BY_TRIGGER_EVENT
à ATT_RELATIONSHIPS_AFFECTS_EVENT
à ATT_RELATIONSHIPS_AFFECTS_RESULT
à MaterialDeclarationConstants.TABLE_RELATIONSHIPSAFFECTEDBY
à MaterialDeclarationConstants.TABLE_RELATIONSHIPSAFFECTS
à MaterialDeclarationConstants.TABLE_REFERENCES