WCCustomizers Guide
WCCustomizers Guide
WCCustomizers Guide
Windchill 9.1 Pro/INTRALINK 9.1 Arbortext Content Manager Windchill PDMLink Windchill ProjectLink May 2009
Copyright 2008 Parametric Technology Corporation. All Rights Reserved. User and training guides and related documentation from Parametric Technology Corporation and its subsidiary companies (collectively PTC) are subject to the copyright laws of the United States and other countries and are provided under a license agreement that restricts copying, disclosure, and use of such documentation. PTC hereby grants to the licensed software user the right to make copies in printed form of this documentation if provided on software media, but only for internal/personal use and in accordance with the license agreement under which the applicable software is licensed. Any copy made shall include the PTC copyright notice and any other proprietary notice provided by PTC. Training materials may not be copied without the express written consent of PTC. This documentation may not be disclosed, transferred, modified, or reduced to any form, including electronic media, or transmitted or made publicly available by any means without the prior written consent of PTC and no authorization is granted to make copies for such purposes. Information described herein is furnished for general information only, is subject to change without notice, and should not be construed as a warranty or commitment by PTC. PTC assumes no responsibility or liability for any errors or inaccuracies that may appear in this document. The software described in this document is provided under written license agreement, contains valuable trade secrets and proprietary information, and is protected by the copyright laws of the United States and other countries. It may not be copied or distributed in any form or medium, disclosed to third parties, or used in any manner not provided for in the software licenses agreement except with written prior approval from PTC. UNAUTHORIZED USE OF SOFTWARE OR ITS DOCUMENTATION CAN RESULT IN CIVIL DAMAGES AND CRIMINAL PROSECUTION. PTC regards software piracy as the crime it is, and we view offenders accordingly. We do not tolerate the piracy of PTC software products, and we pursue (both civilly and criminally) those who do so using all legal means available, including public and private surveillance resources. As part of these efforts, PTC uses data monitoring and scouring technologies to obtain and transmit data on users of illegal copies of our software. This data collection is not performed on users of legally licensed software from PTC and its authorized distributors. If you are using an illegal copy of our software and do not consent to the collection and transmission of such data (including to the United States), cease using the illegal version, and contact PTC to obtain a legally licensed copy. For Important Copyright, Trademark, Patent, Licensing and Data Collection Information: For Windchill products, select About Windchill at the bottom of the product page. For InterComm products, on the Help main page, click the link for Copyright 20xx. For other products, click Help > About on the main menu of the product. UNITED STATES GOVERNMENT RESTRICTED RIGHTS LEGEND This document and the software described herein are Commercial Computer Documentation and Software, pursuant to FAR 12.212(a)-(b) (OCT95) or DFARS 227.7202-1(a) and 227.7202-3(a) (JUN95), and are provided to the US Government under a limited commercial license only. For procurements predating the above clauses, use, duplication, or disclosure by the Government is subject to the restrictions set forth in subparagraph (c)(1)(ii) of the Rights in Technical Data and Computer Software Clause at DFARS 252.227 7013 (OCT88) or Commercial Computer Software-Restricted Rights at FAR 52.227 19(c)(1)-(2) (JUN87), as applicable. 10012008 Parametric Technology Corporation, 140 Kendrick Street, Needham, MA 02494 USA
Contents
iii
Property Files........................................................................................................................... 2-10 wt.properties file ................................................................................................................ 2-11 service.properties file ........................................................................................................ 2-12 tools.properties file ............................................................................................................ 2-13 user.properties file............................................................................................................. 2-13 db.properties file................................................................................................................ 2-14 Properties and Property Files .................................................................................................. 2-15 Application Context Service/Resource Properties............................................................. 2-15
iv
Managing Client JAR Files ................................................................................................ 5-14 Best Practices for Adding New Packages and Files.................................................................5-26 Modeling Recommendations ............................................................................................. 5-27 Adding a Custom Service Provider Property File .............................................................. 5-27
Contents
TableUtils package........................................................................................................... 8-9 TreeHandler ...................................................................................................................... 8-10 asyncResponseHandler .................................................................................................... 8-11 rowHandler ........................................................................................................................ 8-11 requestHandler.................................................................................................................. 8-12 Other functions in main.js.................................................................................................. 8-12 Wizard.js functions ............................................................................................................ 8-13
vi
Character Encoding in the URLFactory ............................................................................. 9-26 Offline Package Customization ................................................................................................9-27 Objective ............................................................................................................................ 9-27 Solution .............................................................................................................................. 9-27 Customization Points ......................................................................................................... 9-29 Limitations.......................................................................................................................... 9-29 Offline Package View Supported Icons ............................................................................. 9-29 Sample Code ..................................................................................................................... 9-31 System Banner Alert Message .................................................................................................9-32 Turning on the alert banner feature ................................................................................... 9-32 Displaying the alert message on the top of Windchill UI pages ......................................... 9-32
Contents
vii
Solution ........................................................................................................................... 10-33 Limitations ....................................................................................................................... 10-34 Sample Code................................................................................................................... 10-35 Additional Resources ...................................................................................................... 10-36 Generating HTML Tags for ProductView Visualization Within a JSP Page ........................... 10-37 Tools Overview ...................................................................................................................... 10-40 Available Attributes Report.............................................................................................. 10-40 Debugging ....................................................................................................................... 10-41 Taglib documentation ...................................................................................................... 10-42 Action Report................................................................................................................... 10-43 Action Model Report........................................................................................................ 10-47 Adding Validation Logic for Actions and Properties ............................................................... 10-51 Objective ......................................................................................................................... 10-51 Applicability ..................................................................................................................... 10-51 Structure.......................................................................................................................... 10-51 Participants...................................................................................................................... 10-51 Collaborations ................................................................................................................. 10-52 Consequences ................................................................................................................ 10-53 Implementation................................................................................................................ 10-53 Sample Code................................................................................................................... 10-60
viii
Contents
ix
Sample Code................................................................................................................... 13-90 Adding Custom Modeled Attributes to all Table Views .......................................................... 13-91 Attribute Tables...................................................................................................................... 13-92 Objective ......................................................................................................................... 13-92 Solution ........................................................................................................................... 13-92 Sample Code................................................................................................................... 13-95 Generating the Name Attribute Server................................................................................... 13-97 Objective ......................................................................................................................... 13-97 Solution ........................................................................................................................... 13-97 Customization Points..................................................................................................... 13-100 Limitations ..................................................................................................................... 13-100 Sample Code................................................................................................................. 13-101 Additional Resources .................................................................................................... 13-101 Partial Activation of JSCA .................................................................................................... 13-102 Icon Delegates ..................................................................................................................... 13-103 Objective ....................................................................................................................... 13-103 Solution ......................................................................................................................... 13-103 UI Validation......................................................................................................................... 13-109 Objective ....................................................................................................................... 13-109 Solutions........................................................................................................................ 13-110 Customizing the Find Number Field..................................................................................... 13-152
Building Wizards to Edit a Single Object ................................................................................14-90 Objective .......................................................................................................................... 14-90 Solution ............................................................................................................................ 14-92 Sample Code ................................................................................................................. 14-107 Additional Resources ..................................................................................................... 14-113
Contents
xi
Customization Points....................................................................................................... 16-34 Configuring a Type Picker...................................................................................................... 16-37 How to Use Type Picker.................................................................................................. 16-37 Overview ......................................................................................................................... 16-41 Customization Points....................................................................................................... 16-43 Attributes and Parameters supported by Type Picker..................................................... 16-44 Source code location....................................................................................................... 16-47 Configuring a User Picker ...................................................................................................... 16-50 Objective ......................................................................................................................... 16-50 Solution ........................................................................................................................... 16-51 Customization Points....................................................................................................... 16-53 Configuring a Participant Picker............................................................................................. 16-57 Objective ......................................................................................................................... 16-57 Solution ........................................................................................................................... 16-57 Customization Points....................................................................................................... 16-61 Sample Code................................................................................................................... 16-63
xii
Customization Points ....................................................................................................... 18-22 Other Resources.............................................................................................................. 18-23 Customizing PSE to Handle Modeled Subclasses .................................................................18-24 Objective .......................................................................................................................... 18-24 Solution ............................................................................................................................ 18-24 Customization Points ....................................................................................................... 18-29 Other Resources.............................................................................................................. 18-30 Customizing PSE Structure Queries ......................................................................................18-31 Objective .......................................................................................................................... 18-31 Solution ............................................................................................................................ 18-32 Other Resources.............................................................................................................. 18-34 Customizing Attribute Displays within Section Headings .......................................................18-35 Customizing the Display of Attributes in Groups ............................................................. 18-35 Expanding/Collapsing the Display Groupings.................................................................. 18-40 Customizing the Number of Columns to Display ............................................................. 18-41 Customizing Tabs - Configure Existing Tabs with Subtabs....................................................18-43 Allow Additional Steps During New Object Creation ..............................................................18-45 Type Picker Display Customization ........................................................................................18-47 Disabling Actions by Object Type...........................................................................................18-49 Validator isValidTypeValidator ......................................................................................... 18-50 Creating a Requirements Tab ................................................................................................18-51 Updating the <TabSet> element to include the Requirements tab .................................. 18-51 Define a <Tab> element for the Requirements tab.......................................................... 18-52 Define the <AssociationTable> element for the Requirements tab ................................. 18-53 Define the <StructureAuthorDefinition> element for the association table ...................... 18-53 Define the <StructureDefinitionSimple> element for the part to requirement association 18-54 Define the <Table> element for the Requirement type .................................................... 18-54 Define the menus for the Requirements tab .................................................................... 18-56 Define the labels, tool tips and mnemonics for the Requirements tab............................. 18-59 Define <ActionDefinition> elements referred to in the <MenuItem> elements ................ 18-60 Implement an 'enabled decider' class to control when the tab is enabled ....................... 18-62 Configurable Link Tables........................................................................................................18-67 Configurable Links Example ............................................................................................ 18-67 Installing the Configurable Links Example ....................................................................... 18-67 Uninstalling the Configurable Links Example .................................................................. 18-68 Customizing Configurable Link Tables ............................................................................ 18-69 Defining Access Control Policy Rules for Configurable Links.......................................... 18-73
Contents
xiii
XML Configuration Files .................................................................................................... 19-3 General Windchill MPMLink Customizations ........................................................................... 19-5 Changing the Availability of Windchill MPMLink Explorers ............................................... 19-5 Changing Default Units of Measure .................................................................................. 19-5 Customizing the Process Plan Explorer................................................................................... 19-7 Changing Units of Measure for Cumulated Time and Cost............................................... 19-7 Customizing Work Instructions.......................................................................................... 19-7 Customizing a Windchill MPMLink Explorer.................................................................... 19-16 Changing Operation Numbering...................................................................................... 19-18 Customizing the Manufacturing Product Structure Explorer .................................................. 19-19 Customizing the Transforming of an eBOM into an mBOM ............................................ 19-19
xiv
Objective .......................................................................................................................... 20-24 Solution ............................................................................................................................ 20-26 Sample Code ................................................................................................................... 20-28 Loading an OOTB Saved Query.............................................................................................20-30 Example: SavedQuery.xml .............................................................................................. 20-30 Sample Code: Handler written for the tag SavedQueries ................................................ 20-39 Search Elements and Associated JSPs .................................................................................20-42 Search element and their associated JSP for Simple Search Page ................................ 20-42 Search element and their associated JSP for Advanced Search Page ........................... 20-43
Contents
xv
xvi
Contents
xvii
Sample Code................................................................................................................... 27-72 Report Selection List Customization ...................................................................................... 27-74 Solution ........................................................................................................................... 27-74
xviii
Implementing the NetFactor Interface ............................................................................. 31-29 Implementing the ObjectMappable interface ................................................................... 31-31 Implementing the Persistable interface............................................................................ 31-33 Implementing the Externalizable interface ....................................................................... 31-33 Extending the EnumeratedType class....................................................................................31-36 Stereotyping an interface as remote ................................................................................ 31-37 How Rose UML Maps to Info Objects ....................................................................................31-39 How Rose UML Maps to Database Schema ..........................................................................31-41 How Rose UML Maps to Localizable Resource Info Files......................................................31-47 Metadata Resource Info Header...................................................................................... 31-47 Resource Entry Format.................................................................................................... 31-48 Metadata Resource Entry Examples ............................................................................... 31-48 Building Runtime Resources ........................................................................................... 31-48 Using the Windchill System Generation Tool .........................................................................31-50 Registry Files ................................................................................................................... 31-50 Generating mData Files ................................................................................................... 31-51 Generating Java Code ..................................................................................................... 31-51 Generating Info Files ....................................................................................................... 31-52 Generating SQL Files ...................................................................................................... 31-52 Using Windchill System Generation in a Build Environment ..................................................31-54 Management of the mData File ....................................................................................... 31-54 Build Sequence................................................................................................................ 31-55 Command Line Utilities .................................................................................................... 31-55 Deploying Modeled Customizations .......................................................................................31-60 Objective .......................................................................................................................... 31-60 Solution ............................................................................................................................ 31-60
Contents
xix
Starting the Utility ............................................................................................................ 33-12 GUI Usage of an Enumerated Type....................................................................................... 33-12
xx
Contents
xxi
xxii
Using the Exporter to Export Objects ................................................................................ 41-8 How Import Works ............................................................................................................. 41-9 Importer class .................................................................................................................. 41-12 Use Importer to import object from XML files .................................................................. 41-14 How to Write Exp/Imp Handlers .............................................................................................41-17 Writing Export Handlers for the Export Process .............................................................. 41-17 How to Write Handlers for the Import Process ................................................................ 41-20 Navigating Through an Objects Structure with ObjectSet Application...................................41-26 Object Collection.............................................................................................................. 41-26 Navigating Rules.............................................................................................................. 41-26 List of Existing Generators and Filters ............................................................................. 41-31 Examples ......................................................................................................................... 41-32 Simple Export Handler Code: .......................................................................................... 41-38 Simple Import Handler Code: .......................................................................................... 41-43 Product Design eXchange (PDX) Support for Export.............................................................41-46 Customization Points ....................................................................................................... 41-47 Supported APIs................................................................................................................ 41-47 Sample Program .............................................................................................................. 41-51
Contents
xxiii
xxiv
Single-and multi-object listeners? ....................................................................................... B-9 KeyedEvent's getEventTarget()API .................................................................................. B-10 Multi-Object Delegation Guidelines ......................................................................................... B-10 Converting to wt.services.ac.DefaultServices................................................................... B-10 Multi-Object Exceptions Guidelines......................................................................................... B-11 Basic expectations............................................................................................................ B-11 Pre-flight checks ............................................................................................................... B-11 Multi-object Exceptions and Single-Object APIs............................................................... B-12 Multi-Object CRUD API Guidelines ......................................................................................... B-13 Internal Dependency Issues ............................................................................................. B-13 Batch Update/Delete Guidelines ............................................................................................. B-13 When to Use? ................................................................................................................... B-13 Transaction Context/Listener Guidelines................................................................................. B-14 Transaction Context vs.Method Context........................................................................... B-14 Single-object contexts....................................................................................................... B-14 Deferred validation/work with transaction listeners........................................................... B-14 Neat Tips and Tricks................................................................................................................ B-15 Inflating references ........................................................................................................... B-15 Persisting interdependent data ......................................................................................... B-15
Contents
xxv
URLFactory in the JSP Environment .........................................................................................E-7 Creating an URLFactory...................................................................................................... E-7 Setting the JSP Reference Point......................................................................................... E-8 Generating Links on the Page............................................................................................. E-9 Internationalizing JSP Pages in Windchill ......................................................................... E-11 Using File-Handling Applets in Non-JSP Clients .....................................................................E-15 The Three Applets............................................................................................................. E-15 Advantages and Disadvantages........................................................................................ E-15 The File Selection Applet .................................................................................................. E-16 The Upload Applet............................................................................................................. E-23 The Download Applet ........................................................................................................ E-42
Index
xxvi
Change Record
This section details the major changes in this guide. Table 1 Changes for 9.1
Chapter Description
Added the Adding Custom Code to all Windchill Client Architecture Pages section to this chapter Added the Offline Package Customization section to this chapter Added the System Banner Alert Message section to this chapter Removed the "Customizing Online Help" section from this chapter.
xxvii
Chapter
Description
Chapter 10, Customizing HTML Clients Using the Windchill JSP Framework
Updated the Action Report section. Removed the "Customizing Online Help for a JSP Component" section. Added the Component Access Control section to this chapter. Added the Customizing Access Control For Packages section to this chapter. Updated the Action Report section. Updated the Action Model Report section. Added the Debugging section to this chapter. (MR010) Updated the Windchill Client Architecture Action Framework Overview section. Added the Navigation Stickiness section to this chapter.
xxviii
Chapter
Description
Updated the Constructing and Rendering a Table Using the JSP Framework section Updated the Windchill Client Architecture Tree section Added the Adding Custom Modeled Attributes to all Table Views section Added the Generating the Name Attribute Server section Added the Partial Activation of JSCA section Added the Icon Delegates section Added the UI Validation section Added the Customizing the Find Number Field section Updated the Windchill Client Architecture Wizard section with information on clerks Updated the Windchill Client Architecture Wizard section to remove the Adding the Help Icon section Updated the Wizard Processing section Updated the Building Wizards to Create a Single Object section
Change Record
xxix
Chapter
Description
Added Customizing Attribute Displays within Section Headings to this chapter Added Customizing Tabs Configure Existing Tabs with Subtabs to this chapter Added Allow Additional Steps During New Object Creation to this chapter Added Type Picker Display Customization to this chapter Added Disabling Actions by Object Type to this chapter Added Creating a Requirements Tab to this chapter Added Configurable Link Tables to this chapter
Chapter 19, Customizing Windchill MPMLink Chapter 21, Customizing Business Logic Chapter 26, Customizing Windchill Visualization Services Chapter 27, Report Generation
New chapter. Updated for MR020. Updated the Customizing a Bill of Materials section New chapter. Added Report Selection List Customization to this chapter.
xxx
The Windchill Customizer's Guide describes how to customize the out-of-the-box implementation of Windchill. It is intended for developers who are familiar with Windchill Javadoc. This guide provides customization information for the following Windchill solutions: Windchill PDM Link Windchill ProjectLink Pro/INTRALINK 9.1 Arbortext Content Manager
Examples in this guide referencing third-party products are intended for demonstration purposes only. For additional information about third-party products, contact individual product vendors. Some code examples in this guide have been reformatted for presentation purposes and, therefore, may contain hidden editing characters (such as tabs and end-of-line characters) and extraneous spaces. If you cut and paste code from this manual, check for these characters and remove them before attempting to use the example in your application.
Related Documentation
The following documentation may be helpful: What's New for Windchill Release 9.1 Windchill Installation and Configuration Guide Windchill Upgrade Guide Windchill Data Loading Reference and Best Practices Guide Windchill System Administrator's Guide Windchill Business Administrators Guide Windchill Performance Tuning Guide
xxxi
If books are not installed on your system, see your system administrator.
Technical Support
Contact PTC Technical Support via the PTC Web site, phone, fax, or e-mail if you encounter problems using <product name> or the product documentation. For complete details, refer to Contacting Technical Support in the PTC Customer Service Guide. This guide can be found under the Self Help section of the PTC Web site at: http://www.ptc.com/support/support.htm The PTC Web site also provides a search facility for technical documentation of particular interest. To access this page, use the following URL: http://www.ptc.com/support/support.htm You must have a Service Contract Number (SCN) before you can receive technical support. If you do not have an SCN, contact PTC Maintenance Department using the instructions found in your PTC Customer Service Guide under Contacting Your Maintenance Support Representative.
xxxii
Comments
PTC welcomes your suggestions and comments on its documentation. Send comments to the following address: [email protected] Please include the name of the application and its release number with your comments. For online books, provide the book title.
xxxiii
xxxiv
I
Customization Overview Section
Chapter
Page
Customization Overview........................................................................ 1-1 The Windchill Development Environment ............................................ 2-1 Getting Started With Windchill Customization ..................................... 3-1 Modeling Business Objects.................................................................... 4-1 Managing Customizations...................................................................... 5-1 Windchill Utilities.................................................................................. 6-1 Customization Tutorial .......................................................................... 7-1
1
Customization Overview
The Windchill solutions are designed to fit the needs of customers in different industries and of different sizes. The Windchill solutions are built to enable product development business processes. Input for these solutions comes from the many PTC customers who are leaders in their domains and from PTC industry experts. In order to reduce the cost of ownership, the Windchill solutions provide extensive out-of-the-box capabilities and configuration options to make them easily adaptable to these disparate customers and their different product development processes and needs. Where the configuration options do not provide sufficient flexibility and no appropriate out-of-the-box capabilities are available to satisfy a particular business need, Windchill provides an extensive set of customization features that customers can leverage to satisfy such business needs. Topic Page
1-1
Configuration Options
Properties and Preferences
Windchill provides an extensive set of options that control how the system behaves, how the user interacts with the system, or how the system presents itself to the user. These options are either properties or preferences.
Properties
Properties are created in text files in codebase and control overall system configuration. For example, the wt.home property contains the path to the installation directory. Properties are stored in files with the .properties extension. Changing most properties requires a restart of the Windchill method server. See the Property Files section of the The Windchill Development Environment chapter on page 2-10 for some additional information on property files. A complete set of properties and descriptions for the wt.properties, tools.properties, and db.properties files can be found in the Windchill Administrators Guide and the properties.html file in the codebase directory.
Preferences
Preferences are set through the Windchill user interface and do not require a server restart. They control application behavior1. Preferences can be implemented on different levels of detail. Preferences can be configured to control the whole Windchill installation, or can be used more narrowly to control an organizations or an application containers (e.g. Product, Library), or a specific users setup. See the Preferences section of the Generic UI Customizations chapter on page 9-18 for some additional information on preferences. The table below provides just a few of the available preferences:
Preference Description
Allows creating a change notice without a change request. Enables propagation of effectivity statements down a product structure.
1.
1-2
Preference
Description
Set up a schedule for Digest Notification. That is, instead of sending individual notification of as events of interest to a user happen, the system will collect and send all notifications in one email according to the administrator-setup schedule. Controls whether the thumbnail action available in tables.
Display Thumbnails
Workflow Templates
Windchill provides a very powerful workflow configuration and execution engine. The workflow engine of Windchill can model virtually any business process which can be modeled via an easy-to-use drag-and-drop tool. The workflow engine has an embedded java virtual machine which allows a business analyst to embed java expressions and process logic where appropriate. For more information on workflow templates see the Customizing Workflow Administration chapter on page 24-1.
Customization Overview
1-3
Soft Typing
Soft Typing is the name of the set of Windchill capabilities that allows a customer to, at runtime, add additional types and attributes to the out-of-thebox Windchill Schema. This is done without having adding additional tables to the database, without restarting the database, and without restarting the system. With the Soft Typing capabilities, customers can add data types and meta data attributes that are meaningful to them and which are necessary for their business processes. For all intents and purposes, these customer-defined types are no different than any other out-of-the-box object in the system: Types can assigned access control rules, can be assigned workflows and lifecycles, can be assigned custom UIs, can have Object Initialization Rules assigned to them, are accessible via APIs, etc.
No user interface modifications are necessary as the Windchill user interfaces automatically accommodate (e.g. adapt to) these additional Types and Attributes. The general guideline to be followed is this: If a need can be satisfied by soft typing, then it should. That is, do not customize (i.e. create modeled extensions) to the out-of-the-box schema. The reason for this rule is to minimize the total cost of ownership of Windchill and minimize upgrade costs and burdens. This, in no way, is a limitation on the customizability of Windchill; but, rather, the intent of the rule is to reduce the cost of ownership.
1-4
Customizations
Windchill is an open system that is fully supports customizations at the schema, server, and UI levels. An extensive set of APIs are published, documented, and supported to enable these customizations. But as stated above, in order to reduce the cost of ownership, if changing other mechanisms such as properties or preferences satisfy the business need, then customizations should not be used.
Service Customizations
Windchill supported server-side customizations to enable certain business processes or enforce business constrained. Any kind of customization can be performed. The most common types of customizations falls into one of the following categories: Process form data submitted through the user interface Validate data - (e.g. Do not allow the user to enter a Need Date for a Change Request that is more than 30 days into the future) Implement service listeners - (e.g. Create a listener that waits for any data to be checked in and populate an MRP system with appropriate data) Get/Put data in an external systems - (e.g. when the user navigates to a parts details, get the cost of the part from the ERP system and display it in the same UI)
Customization Overview
1-5
Info*Engine
Info*Engine provides data access and integration capabilities to access Windchill data, remote Windchill systems and non-Windchill data and services (through adapters). Info*Engine components can be used in many different software and hardware configurations to meet your business requirements for accessing, managing, and presenting data from many different information systems. All basic Info*Engine solutions take advantage of five fundamental concepts: JSP pages, tasks, webjects, groups, and the virtual database. Both JSP pages and tasks are text-based documents that define how Info*Engine either displays or retrieves information. Webjects are the means by which Info*Engine JSP pages and tasks gather, manipulate and display data. Groups are the chunks of information generated and manipulated by JSP pages and tasks. The virtual database (VDB) is the special holding area where groups are stored until they are manipulated or passed along by JSP pages and tasks. For more information on Info*Engine see Managing Windchill Info*Engine Tasks on page 5-13.
Custom Reports
Windchill provides predefined, out-of-the-box reports in the areas of change management, project item status, and parts/products. Your company-specific custom reports can be created using Windchill Query Builder or the Windchillintegrated third-party report authoring tool, Cognos. Use Windchill Query Builder if you would like to create very simple tabular reports and your site is not configured for third-party reporting tool, Windchill Business Reporting. Windchill Business Reporting (WBR) is a new reporting framework that embeds Cognos 8 Business Intelligence (BI) within Windchill 9.1 to provide out-of-thebox integration between Windchill and Cognos 8 BI. It also includes pre-built reports on change management, project items status, and parts/products. To create tabular reports, visual and graphical reports, dashboard reports, and drill-down reports, use the optional third-party reporting authoring tool. This optional authoring tool also allows you to modify out-of-the-box reports. Using
1-6
the authoring tool you can create new reports that include charts and graphs (Crosstabs, bar/3D bar, pie, gauge, funnel, scatter and more). The report data sources that are required for creating custom reports in report author tool can be created using Info*Engine report tasks and Query Builder templates. For more information on custom reports see Report Generation on page 27-1.
Customization Overview
1-7
1-8
Extendable: true, it indicates that the class may be extended. For example, WTPart is both Supported and Extendable, as shown in the following illustration.
The fact that a class is part of the Supported API indicates that some part of it is meant to be used, or at least understood by customizers. The Javadoc for some classes is distributed for information purposes (and if that is the case, it should be clear from the Javadoc). A class is meant to be extended only if its Javadoc contains the line indicating Extendable: true. (Classes that can be extended are listed in Appendix B, Extendable Classes in the Windchill Supported API.) Methods and other programming elements may also have a Supported API line in their Javadoc. If a class is not part of the Supported API, then neither are any of its methods. If a class is part of the Supported API, that does not indicate that its methods are, too. For a method to be part of the Supported API, its Javadoc must also state Supported API: true.
Customization Overview
1-9
1-10
2
The Windchill Development Environment
Directory Structure ..............................................................................................2-2 Artifact Management...........................................................................................2-8 Environment Variables........................................................................................2-9 Property Files ....................................................................................................2-10 Properties and Property Files ............................................................................2-15
2-1
Directory Structure
The image below shows the Windchill directory structure after you install all available components. If Windchill was installed as recommended to follow this structure, go to the home directory where Windchill is installed and navigate through this structure as it is described here.
ant
2-2
codebase
Contains the Info*Engine JCA (Java Connector Architecture) which is used for J2EE integrations (EJB or App Server connectivity). It is also used by Info*Engine JCA enabled standalone java SOAP clients.
installer
Contains files used by, or created by, the installation process, including installation logs.
installlib
Contains the wtbeans.jar file, which holds the Java bean components that have been developed for use with Windchill clients.
loadFiles
Contains Windchill modules' model files, which are used for customization development.
opt
Contains files for modeling customizations, and rbInfo files for text
srclib
Contains the I*E task editor startup scripts, help files reside and is the runtime directory for the task editor.
2-3
tasks
Contains the Windchill Help Center which consists of the online help and the pdf manuals.
WinDU
Directory of xml files that declare the existence of tasks that are executable by the Windchill Diagnostic Utility. The codebase directory and src directory are described in more detail in the following subsections.
2-4
Most of these directories contain third party product class files. The html directory contains templates that are used to generate HTML dynamically.
1. To allow presentation in manual format, many subdirectories in the wt directory are not included in this figure.
2-5
The wt and com\ptc directories contains the executable code for the packages supplied by Windchill (only a subset of which are shown in this illustration) and files required for localization, such as resource bundles and HTML files. Within these packages are executable class files compiled from corresponding Java files of the same name in the src\wt directory. This set of Java source or .java files is created by the Windchill code generation tool for every business object modeled in Rose. Files in the form <object> .ClassInfo.ser are also code-generated and contain metadata needed by the runtime environment. They are all described in more detail in the System Generation chapter on page 31-1. Each package also contains resource bundles, that is, files that contain localizable information and are in the form: <packageName >Resource.class <packageName >ModelRB.RB.ser <EnumeratedTypeClassName >RB.RB.ser The wtx directory contains EPM-related files and directories.
2-6
The customization directory contains programming examples of customizations, which are described in more detail in either this guide or the readme file that is in the directory. The wt and com\ptc directories contains the source files for the packages supplied by Windchill (only a subset of which are shown in this illustration). In the wt directory and its package subdirectories, you will see the following kinds of files: Rose model components: model files with the suffix .mdl and package files with the suffix .cat. (The .cat file is described later in this chapter.) Code generation files: files with the suffix mData, which are intermediate files created by the code generation tool and used to create Java classes, Info classes, and SQL files (for more information, see the System Generation chapter on page 31-1). Localizable ResourceInfo (.rbInfo) files, which contain customizable display text for EnumeratedTypes and modeled elements.
2-7
Artifact Management
In Rational Rose, you can optionally separate a model into controlled units as a way of sharing code. Controlled units are source files with a .cat extension that can be checked in and out of your source code control system. Control units are created at the package level. In Rational Rose, right-click on a package in the Browser window, select Units, select Control...; <package>, select the filename for the controlled unit. The menu item is only selectable for packages that are not controlled. This action produces a file with the extension .cat. You can then check in and check out these .cat files to whatever source code management system you use. The directory structure used in the source code management system must match the package structure used in Rose. You can change a control unit that is read-only to write by selecting the WriteEnable<package> item. This is useful if you want to manipulate the model in some way (for example, temporarily changing its appearance before printing it). Be aware that this action does write enable the file at the file system level, so if you dont want it left writable, select the Write Protect <package> item. These are menu items are both available from the same Units menu item mentioned above.
2-8
Environment Variables
When you install the Windchill Information Modeler, the settings required for business modeling and code generation are set automatically. You should have to do nothing more. But, if you have problems, the following sections give information about required settings.
Class path
We recommend that you not make any modifications to your CLASSPATH after installation. In particular, do not add the codebase directory. Doing so can cause Netscape Navigator to incorrectly assume a security violation. (See the Windchill Installation Guide for further information.)
Path
Your PATH variable should contain <Windchill> \bin and JDK\bin. <Windchill> contains batch scripts, such as ToolsSetup.bat, required to use the Information Modeler. (See the Windchill Installation and Configuration Guide for further information.)
SQL path
You must create (or add to) your SQLPATH variable and set it to the location where the SQL scripts that create the necessary tables will be written. When you are in a SQL*Plus session, SQL*Plus searches these directories for SQL scripts. By default, this value is c:\ptc\windchill\db\sql.
2-9
Module specific path maps will also be created automatically, based on information stored in moduleRegistry.properties and moduleDir.properties. For example, wnc/CommonCore is the path map for the CommonCore module of the wnc assembly.
Note: See the Windchill Installation and Configuration Guide for further information.
Property Files
Windchill uses standard Java property files to determine runtime configuration properties. The codebase directory contains: wt.properties Contains properties used for general Java system configuration and Windchill system configuration. service.properties Contains properties used by the Windchill service delegate mechanism. debug.properties Contains properties used by Windchill code to control debug info capturing. (See the wt.util package entry in your installed Windchill Javadoc for more information) user.properties Contains user overrides used by Rational Rose and the Windchill code generation tools. moduleRegistry.properties Contains list of registered modules. moduleDir.properties Contains home directory for each registered module. The db directory contains: db.properties Contains properties used by Windchills database connection layer to access the database. The System Generation jars (SystemGeneration.jar, WindchillUtil.jar & CommonCore.jar) contain: tools.properties
2-10
Contains properties used by Rational Rose and the Windchill code generation tools. debug.properties Contains properties used by Windchill code to control debug info capturing. service.properties Contains properties used by the Windchill service delegate mechanism, for the System Generation tools. typedservices.properties Contains properties used by the Windchill service delegate mechanism, for the System Generation tools. You must use typedservices.properties when the selector object type could be a soft type. wt.properties This is an abbreviated form of the file that is in codebase. (Care must be taken when using a manually created classpath that includes both codebase and System Generation jars, since properties files will be loaded based on the order of the classpath components.) The following sections discuss only a subset that you as a developer are most likely to be interested in. A complete set of properties and descriptions for the wt.properties, tools.properties, and db.properties files can be found in the Windchill Administrators Guide and the properties.html file in the codebase directory. To change properties, you can edit the file directly or use the System Configurator GUI from the Windchill application home page. The System Configurator allows you to modify property files; start, stop, and restart the server manager and all method servers; and launch other Windchill applications.
wt.properties file
To use Windchill, the following properties must be set in the wt.properties file (this is usually done at installation). Note that you must use double back slashes to specify path names in the wt.properties file. This is necessary because the string is read by a Java program. wt.home, which specifies the top level of the class directory structure where Windchill is installed. The default value is c:\\windchill. wt.server.codebase, which is used by client applications (not applets). It specifies a URL from which client applications can download server resources such as property files. Client applets use their own codebase URL as specified in their APPLET tags. Server applications may use this property when writing dynamically generated HTML to be returned to a client
2-11
browser. It is used to build URLs for static resources such as images or HTML files that reside under the servers codebase directory. java.rmi.server.hostname, which specifies a host name used to identify the server host. It is used by the Java RMI runtime for clients to look up the IP address of the server. It can be specified as a symbolic name, such as a fullyqualified Internet domain name, or numerically in dot notation (for example, 127.0.0.1). If not specified, the RMI runtime will use the name returned by InetAddress.getLocalHost() method, which may return a name that is not known to remote clients. We recommend that this property be set to the fullyqualified Internet domain name of the server host.
You may also want to set the following properties: wt.access.enforce This property enforces access control. By default, it is true. However, if you are debugging and want to bypass access control temporarily, you can set it to false. wt.logs.enabled This property enables and disables logging in applications that support it, such as the Windchill Server Manager and Method Server applications. By default, it is false. To write debugging messages to a log file, you must set it to true. wt.method.verboseClient and wt.method.verboseServer These properties cause trace messages to be printed from the client-side and server-side, respectively, of the method server remote interfaces. By default, it is false. Turning on these properties causes trace information to be written to logs for debugging purposes. Similar properties are available for the server manager: wt.manager.verboseClient and wt.manager.verboseServer. In looking through the properties, you will see many service names followed by the word verbose (for example, wt.access.verboseExecution and wt.access.verbosePolicy). In general, these properties allow you to turn on debug tracing.
service.properties file
The service.properties file contains properties used by the Windchill service delegate mechanism. This mechanism is a general facility for adding delegate classes to an existing service to implement new, customized behavior. In this context, service can mean any sort of Java mechanism that provides functionality to other classes. For example, assume a copy service exists that can make copies of certain classes of objects. The service knows how to make copies only for objects of certain classes: the classes for which copy service delegates have been created. Each
2-12
delegate implements an interface, defined as part of the copy service, that contains the methods needed by the service. Once the delegate is created and put in the codebase, the copy service is notified of its existence by adding an entry to the service.properties file. Generally, each service is accessed using a factory. The factory either returns instances of delegates to perform services on particular classes of objects, or it performs the operations on the objects itself by instantiating the necessary delegates internally. If a Windchill service supports customization by adding delegates, the description of how to do the customization is described elsewhere in the documentation.
tools.properties file
The tools.properties file contains properties that are used by the System Generation tools. The following properties within tools.properties are of interest: wt.generation.bin.dir, which specifies where .ClassInfo.ser files (serialized info objects) will be generated, following the package structure. wt.generation.source.dir, which specifies where .mData files are expected to be found and where .java files will be generated, following the package structure.
Note: Because the source.dir entry informs the code generator of the location of mData files and, in Rose, the WT_WORK variable informs the model information export tools of the location of mData files, they must point to the same location. wt.generation.sql.dir, which specifies where SQL scripts will be generated. wt.generation.sql.xxxTablesSize, which sets default sizes for tables. wt.classRegistry.search.path, which specifies the path to search for files representing classes to be registered. wt.classRegistry.search.pattern, which specifies the file pattern to consider as representing classes to be registered.
Note: Because tools.properties is contained within the SystemGeneration.jar, user overrides to these properties are placed in codebase\user.properties.
user.properties file
The user.properties file contains user overrides that are used by the System Generation tools. Note: Configuration overrides for System Generation should be configured in user.properties using the xconfmanager utility. See the Windchill System Administrators Guide for information on the xconfmanager utility.
2-13
db.properties file
The db.properties file contains properties that are used by Windchills persistence layer to access the database. They can be set in the wt.properties file but are usually kept in a separate file identified by the wt.pom.properties entry. Because a password is contained in this file, you should maintain it in a secure location. The values in the separate file override the values in the wt.properties file. In the db.properties file, you must set the following properties: wt.pom.dbUser, which specifies the Oracle user name you or your Oracle administrator defined for you. This user is the owner of Windchill tables and stored procedures. There is no default; it must be set. wt.pom.dbPassword, which specifies the Oracle password you or your Oracle administrator defined for you. There is no default; it must be set. wt.pom.serviceName, which is the service name you or your Oracle administrator created. There is no default; it must be set.
2-14
2-15
The first format is used to locate a Java service or delegate class to perform a function or provide a service. The second format is used to locate a resource file -- for example, a HTML template file or an icon image file
Definitions:
Service Type = the type of service or delegate referenced by this property Resource Type = the type of resource referenced by this property Selector = an identifier used to specify the context in which this service or resource is to be used (for example, an action name) Requestor = the object class for which the service, delegate, or resource is to be used Service Priority Number = a priority rating used to choose between valid delegates (see below) Service Class Name = name of delegate or service class for the given Service Type, Selector, and Requestor Resource Name = name of resource for given Resource Type, Selector, and Requestor Duplicate or singleton = a flag to indicate whether the server should instantiate a shared instance of a delegate class or create a new one for each use. If neither is specified, duplicate will be used. This is an example property for a template processor:
wt.services/svc/default/wt.enterprise.TemplateProcessor/AddAlternates/ wt.part.WTPartMaster/0=wt.part.AlternatesLocalSearchProcessor/duplicate
where
Service Type = "wt.enterprise.TemplateProcessor" Selector = the action name "AddAlternates" Requestor = "wt.part.WTPartMaster"
Note: Any service class that incorporates an HTTPState object should be made duplicate. This would include instances of BasicTemplateProcessor, FormTaskDelegate, NavBarActionDelegate, and NavBarURLActionDelegate. If a factory receives a request for a service or resource class for a given requestor object class but no property entry for that requestor class is found, the factory will attempt to find an entry for the parent class or interface of the requestor class. If no entry for the parent class or interface is found, a search will be made for an entry for the parent of the parent or interface, and so on. It could happen that entries for two or more parent classes or interfaces are found. If the entries have different service priority numbers, the one with the lowest number will be selected. If the entries have the same service priority number, the one selected is arbitrary. To be loaded correctly at runtime, files containing application context service properties must be listed for one of the following properties in wt.properties:
2-16
wt.services.applicationcontext.WTServiceProviderFromProperties. defaultPropertyFiles
wt.services.applicationcontext.WTServiceProviderFromPrope rties.customPropertyFiles
Property files will be loaded in the order listed, and files listed for defaultPropertyFiles will be loaded before those for customPropertyFiles. If the same property is found in more than one file, the value for the one loaded last will be used. Any custom properties should be placed in the latter list. Except for the need to separate application context service properties from ordinary properties and the effect of load order, the grouping of properties into various properties files is unimportant to the system and based primarily on ease of maintenance. If a TemplateProcessor property is put in the htmltemplate.properties file instead of service.properties the system will still find it. Many of the more heavily customized service property files are not created or edited directly but instead are generated from xml files. XML files used to generate property files have the same name as the associated property file but have the additional extension .xconf. For example, the XML file used to generate service.properties is called service.properties.xconf. See the Managing Customizations chapter on page 5-1 for more information on xconf files. If you need to add application context property entries for your custom HTML clients, we recommend you put them in a new properties file or files used only for your customizations. This file should be added to the list of files for WTServiceProviderFromProperties.customPropertyFiles using the xconfmanager utility. This procedure is described in the Managing Customizations chapter on page 5-1.
If you need to add typed service property entries for your custom HTML clients, we recommend you put them in a new properties file or files used only for your customizations. This file should be added to the list of files for
2-17
TypeBasedServiceProviderFromProperties.CustomPropertyFiles using the xconfmanager utility. This procedure is described in the Managing Customizations chapter on page 5-1.
2-18
3
Getting Started With Windchill Customization
The remainder of this manual describes how to create applications using the Windchill product and how to customize existing Windchill applications. You are assumed to be familiar with the third party components used with Windchill: Java, Rational Rose, Oracle, and the IDE (integrated development environment) of your choice. Examples or screen shots use Visual Cafe as an example of a supported IDE, but Windchill supports any Java IDE customers choose to use. This manual does not address how to use these products in general, but how to use them as they relate to Windchill. This chapter gives you a brief overview of the Windchill development process and shows how to create a simple application using Windchill. By following this example, you will perform the major steps in developing an application and verify that the development environment (as described in the The Windchill Development Environment chapter on page 2-1) is set up correctly.
Topic
Page
3-1
SQLPATH The SQLPATH specifies the directory in which sql scripts are generated. It must match the value specified in the tools properties1 file entry named
3-2
2. Verify the contents of the following property files: wt.properties Set the following entry in the windchill\codebase\wt\wt.properties file: java.rmi.server.hostname =<hostname > For example,
java.rmi.server.hostname=Smith.windchill.com
db.properties In the windchill\db\db.properties file, ensure your Oracle user name, password, and service name are entered in this file. wt.pom.dbUser =<username > wt.pom.dbPassword =<password >
3. Start the Windchill servers. Open a new console window. Start the server manager and a method server by entering the following command:
java wt.manager.ServerLauncher
A window will be started for each but they will be minimized. Initialize the administrator tables by entering the following command in a console window:
java wt.load.Demo
This command loads the database with administrative information. Respond "yes" to all prompts. When prompted for a user name/password, enter the same user name and password you use to access your computer. 4. Establish your Rose model directory. In the c:\ptc\windchill\src directory, create the subdirectory helloWorld. This directory will contain files for the helloWorld package.
1.
See the tools.properties file and user.properties file descriptions in the The Windchill Development Environment chapter.
3-3
WT_WORK = c:\ptc\windchill\src WT_EXTENSIONS = c:\ptc\windchill\RoseAddIn WT_STD_PACKAGES = $WT_EXTENSIONS\Standard Packages 2. Establish the initial Rose model by performing the following steps: a. From the File menu, select Open, browse to c:\ptc\windchill\src\wt, and load the model WTDesigner.mdl. b. When asked whether to load subunits, press the Yes button. c. Save the model as c:\ptc\windchill\src\helloWorld\HelloWorld.mdl. d. When asked whether to save subunits, press the No button. 3. Model the person class by performing the following steps: a. In the Logical View/Main class diagram, drop in a Package icon and label it helloWorld. b. Use the dependency tool to draw dependencies from helloWorld to the wt and java packages. c. Go to the Main diagram of the helloWorld package. d. Drop on a class icon and give the class the name Item (the parent for Person). Attributes and operations for Item automatically appear. Change the diagram to suppress attributes and operations of Item. Ensure that the Show Visibility option is on for Item (so you can see in the diagram that it comes from the fc package). e. Drop on another class icon and give it the name Person. f. Make Person a subclass of Item. (Use the generalization icon/tool to draw a line from Person to Item.)
g. Insert the attributes name, age, title, and id. Name, title, and id should be strings (String) and age should be an integer (int). Use lowercase or a mix of upper- and lowercase letters for these attributes; do not use all uppercase letters.2 Right click to start the specification dialog. Make all the attributes public and change the Windchill property of each to constrain=false. Click the Apply button for each change and, when you are done, click the OK button.
2. For every attribute modeled, a corresponding constant is generated using all uppercase letters. For example, if you model an attribute of employeeName, a constant of EMPLOYEE_NAME is generated. Modeling an attribute of EMPLOYEE_NAME would cause the generated constant to conflict with the attribute name. Therefore, unless the attribute being modeled is itself a constant, do not name modeled attributes using all uppercase letters.
3-4
h. Select the menu option Browse > Units. Select the HelloWorld package and press the Control button. Save the unit to c:\ptc\windchill\src\ helloWorld\helloWorld.cat. With the helloWorld package selected, press the Save button. i. Save the Rose model file. When asked whether to save subunits, click the No button.
Tip: From this point on, saving the model is a two-step process: 1. Select the menu option Browse > Units to initiate the Units dialog. In the Units dialog box, select the package you defined earlier and select Save. When asked whether to save subunits, click the Yes button. Close the Units dialog box. 2. Select the menu option File > Save. When asked whether to save subunits, click the No button.
You can verify this step by finding these files in the directories.
3-5
This script creates a Person table and a PersonPk package. You may see a message the first time you run this script because the Person table does not yet exist; you can ignore this message. Note: Establish the project using the IDE of your choice.
3. From the File menu, select Save All and, from the Project menu, select Rebuild All.
3-6
5. Insert the following statement as the first line of the init() method in the CreatePerson.java file:
3-7
WTContext.init(this);
6. Compile the whole applet by selecting Execute from the Project menu. You can now execute the project in Visual Caf using the Applet Viewer or run it outside of Visual Caf in a browser. 7. If you encounter an error that states the CreatePerson.class file cannot be found, close Visual Caf. Copy the contents of c:\ptc\windchill\codebase\ helloWorld to c:\ptc\windchill\src\helloWorld (these are the class files). Start Visual Caf and execute the applet. (Be sure the method server is running.)
Note: wtApplet.jar is used simply to get this example working. For guidelines on managing client JARs, see Managing Client JAR Files in the Getting Started With Windchill Customization chapter on page 5-14. 2. Ensure your web server, servlet engine, and method server are running. Refer to the instructions given earlier in Verify The Development Environment (see page 3-2) if they are not. 3. Open http://<hostname>/<web-app>/wtcore/jsp/CreatePerson.jsp in Mozilla or Internet Explorer.
3-8
4. Enter the name, title, and age (where age must be a number) and press the Save button. 5. The method server should start up automatically, if it is not already started. You should see in the output your message about the Person initialize() method. 6. In your applet, you should see the generated ID (that is, the system time) and the message HelloWorld in the messageField.
3-9
3-10
4
Modeling Business Objects
This chapter explains how to model business objects. Topic Page
Rational Rose and Windchill...............................................................................4-2 Windchill Modeling Heuristics ...........................................................................4-4 Windchill Foundation Abstractions.....................................................................4-8
4-1
On the left side are some of the various analysis diagrams available in Rose. From top to bottom, they are: a use case diagram, a sequence diagram, and a state transition diagram. The right side shows two class diagrams. The class diagram is the only type of diagram used by Windchill for code generation. Although we recommend that you use analysis diagrams, that choice is up to you. Windchill requires only the class diagrams plus some system specifications that you set within Rose to generate code.
4-2
The following figure shows a class diagram for sample business information objects (Customer, Product, and IncidentReport) and the relationships between them. The annotation in bold points out UML (Unified Modeling Language) concepts and notation.
Address is a structured attribute class associated with the Customer class. The composite aggregation notation indicates that Address is considered a part of the Customer class. The Address object depends on the existence of the Customer object. For example, if the Customer class is deleted, the Address class is also deleted. An association class allows you to add attributes, operations, and other features to associations. Because customers register for products, an attributed association is modeled between Customer and Product. IncidentReportCustomer and IncidentReportProduct are also link classes, but they have no attributes. You need not give them a class box. If any of these concepts or notations are unfamiliar, you should learn more about UML and Rose before proceeding. Many of the Windchill concepts are explained using class diagrams.
4-3
As you add subclasses to a parent class, in this case extending class WTObject with Item and then DomainItem, the attributes and methods of each preceding class are inherited by the subclasses. This approach works in many circumstances. But sometimes you need only a small percentage of the functionality that is being inherited. In that case, either you have much more than you actually need in your object, or you copy just the code you want and add it to your own object, creating redundancy and potential maintenance problems.
4-4
Another approach, which we have implemented in Windchill, is to partition functionality, as in the figure below, into objects that are responsible primarily for maintaining business information (also called knowers) versus objects responsible primarily for performing business operations (also called doers).
Using this approach, business models have two major kinds of classes: business information classes and business manager classes. Business information classes represent the business information and associations you want to manage and maintain in a database. These classes extend the foundation classes provided in Windchill. They may implement one or more business manager interfaces. These classes go back and forth between the client and the server with data. Business manager classes represent the business rules that are applied to the business information objects. These classes extend the Windchill StandardManager class. Business managers implement an interface class that provides a client-side API to the business manager methods. The code for business manager classes is located in the server. Business managers are intended to implement small portions of functionality. The knower/doer separation approach allows you to choose which business managers, the doers, to implement for your business information, the knowers. Windchill provides you with a number of managers (described in more detail in the Developing Server Logic chapter on page 35-1) from which you can choose as
4-5
much functionality as you want, or design your own managers to meet your specific business needs. The following is an example of one of the managers Windchill provides, the LockService. (In naming classes, managers are sometimes also called services.)
LockService Example
In this example, the knower is MyItem, which extends Item (a foundation class provided by Windchill). Thus, MyItem inherits all the attributes and behavior of Item. In addition, MyItem implements the Lockable interface. The notation <<Interface>> is a stereotype. It is a cue to the code generator to add an Interface modifier to your generated class. This indicates that you must provide the code for this method in an implementation class. (In Java, an interface is a collection of operations and final fields without implementation methods which form an abstract type. A Java class conforms to an abstract type when it implements an interface. When a Java class implements a Java interface, the class or one of its subclasses must provide an implementation method for each operation in the interface.) Besides the attributes and methods it inherited from Item, MyItem also has the functionality defined in the Lockable interface. The left side of the figure shows how to model the interface for a server-side service on a client. The doer is StandardLockService and it runs on the server. It inherits from the Windchill StandardManager, which provides standard, basic operations for a typical manager, such as starting and shutting down. (When you write your own managers, they also can inherit from StandardManager.) StandardLockService is the actual implementation of the lock service functionality and it implements the LockService remote interface.
4-6
<<RemoteInterface>> is another stereotype. It is a cue to the code generator to create a forwarder class (described in the System Generation chapter on page 31-1). The remote interface must be available on the client. The LockService interface describes the lock services that are available on the client, lock and unlock. These services are invoked remotely from the client to the server. StandardLockService on the server actually contains all the code to support the lock and unlock methods. StandardLockService expects a lockable object. It can accept MyItem because MyItem implemented the Lockable interface. Likewise, it can accept any other business information class that implements the Lockable interface. To get access to the lock service functionality, a class must implement the Lockable interface.
4-7
Foundation Hierarchy
4-8
Classes that are asserted as being ObjectMappable can be written into and read from the database. All remaining abstractions in the foundation hierarchy are a kind of ObjectMappable abstraction. All subtypes of ObjectMappable are Serializable, which gives an object the ability to use RMI for travel between the client and server. Also, every abstract or concrete descendent must implement the externalizable methods writeExternal and readExternal specified in ObjectMappable. These methods provide custom serialization code to decompose and recompose objects to and from a stream. When ObjectMappable is implemented, the code generator generates a readExternal and a writeExternal method. The writeExternal method takes the attributes of an object and writes them into the database. The readExternal method takes a result set from the database and turns it into attributes in an object. For an attribute to have a column in the database, it must implement ObjectMappable. The PersistInfo interface contains information for each object that is stored in the database. PersistInfo does not implement Persistable; it is a structured attribute. It does, however, implement ObjectMappable. This means createStamp, modifyStamp, updateStamp, and updateCount will all be included in readExternal and writeExternal operations. Links, object references, and query keys are generalized as interfaces as shown in the following figure.
Binary Links
The QueryKey interface specifies a qualification for a persistable object in the database. It can be used as a primary key, secondary key, or a foreign key. The WTReference interface specifies an indirect addressing mechanism in which it persists one key that, when used in a query, results in finding an object. If none or more than one object is found, this results in an exception. The object itself is transient and thus not persisted.
4-9
The Link interface specifies the concept of a container of roles and, in particular, the BinaryLink interface, a kind of Link, is an abstraction of an attributed member of an association between two persistable objects. The actual containment of the objects is done by aggregation of references for each role. The Persistable interface gives an object a primary key (that is, the object identifier) as shown in the following figure, and a table in the database.
Persistable Objects
First class objects implement the Persistable interface. As a result, a database table is generated for each class in which their objects will be stored. The structured attributes are stored in the database table of their associated first class object. All persistable objects, plus any structured attributes that must be written into or read from the database, must implement the ObjectMappable interface.
Represents the base class for all Windchill business information classes. Item and ObjectToObjectLink are subclasses of WTObject.
Item
4-10
ObjectToObjectLink
Represents a concrete binary association between two Persistable objects; that is, you can define a link between two items, between an item and a link, and between two links. Each link has a roleA side and a roleB side therefore, if you have a link, you can use it to navigate to all other objects associated with it. The ObjectToObjectLink class can be extended and therefore can have additional attributes and methods. As shown in the following figure, the ObjectToObjectLink aggregates ObjectReference for both role A and B. The ObjectReference in turn aggregates the primary key ObjectIdentifier as an overridden key to reference its object for both roles. The ObjectIdentifier extends QueryKey and adds the id as an additional attribute.
WTObject contains a few general-purpose methods that are inherited by every business object and provide a low level of functionality. For example, the checkAttributes method is called when the object is saved to perform elementary validity checking. If you have not supplied information for required attributes, an exception is thrown and the object is not made persistent.
4-11
4-12
5
Managing Customizations
This chapter describes the best practices that should be used when you are customizing files that are supplied by PTC or changing configuration settings that interact with the way PTC delivers software maintenance releases. The chapter contains information that can help you understand how to structure and maintain the files you modify or add to your Windchill environment. It also describes the tools and Windchill Service Pack options that can be used to set up and update customized files for Windchill maintenance releases. Note: These recommendations apply to managing the <Windchill> installation directory (where <Windchill> is the Windchill Services installation directory). Best practices for products installed into other directories are not described here. If the implementation of Windchill at your site involves modifying files supplied by PTC, it is important to understand that the maintenance installation process could overwrite any file that is delivered by PTC (except for the site.xconf file). This includes files that you may have modified during customization activities. Topic Page
Setting Up a Directory Structure for Managing Customized Files and Text Tailoring ..............................................................................................................5-2 Best Practices for Customizing Files Supplied by PTC ......................................5-9 Best Practices for Adding New Packages and Files..........................................5-26
5-1
Setting Up a Directory Structure for Managing Customized Files and Text Tailoring
To customize a Windchill system it is often necessary to modify files released by PTC. Because these files can subsequently be updated by PTC in a maintenance release, you should use a strategy for managing your files so that your customizations are not lost when the maintenance updates are installed. As a general rule, the Windchill Service Pack installer can overwrite any files that are in established PTC directories under the installation directory where the Windchill product is installed, regardless of their modification status. It is your responsibility to manage your customized files to avoid loss of your changes and, when updates are applied, to be able to easily identify PTC changes that affect the files you have modified. PTC recommends that you manage customized files by creating a directory structure known as the safe area. The actual directory name is <Windchill>/wtSafeArea, where <Windchill> is the directory where Windchill Services is installed. By using the wtSafeArea directory, you can store copies of the customized versions of PTC files where they will not be overwritten by the Windchill Service Pack installer, as well as keep versions of the original PTC files. Additionally, the Windchill Service Pack installer uses this safe area to store updated files that correspond to your customized files. You can then compare the original files to those updated by PTC to identify where changes have been made. Doing the comparison can assist you in incorporating PTC updates into your customized files. PTC provides a script to assist with managing and installing customized files into your system runtime locations within the <Windchill> installation directory. Additionally, if you make changes to resource bundle information files (RBINFO files), then you must use the <Windchill>/wtCustom directory structure to store those changes. The ability to change resource bundles requires that you install the text tailoring option which is selected through the Custom installation type of Windchill Services, Windchill PDMLink, Windchill ProjectLink, or Pro/INTRALINK 9.1.
5-2
versions of the files that PTC has delivered. Following the diagram are the details about how these directories are used.
Managing Customizations
5-3
The following items describe the purpose and processing of the files under each of the subdirectories in more detail: siteMod Under this directory structure, store the site versions of PTC files that you modify and want to run in production When running the Windchill Service Pack installer, selecting the Complete installation type option directs the installer to copy files from the siteMod directories to the selected installation directory. The files that are copied overwrite existing files in the installation directory. The actual file copying is done by the execution of the installSiteChanges target of the <Windchill>/bin/swmaint.xml Ant script. For more information on this target, see PTC Script for Working with Customized Files section on page 5-5. As described in the PTC Script for Working with Customized Files section on page 5-5 there a few files that you should not put under the siteMod directory. You must place and update files in this directory yourself; the Windchill Service Pack installer does not modify the files in the directory. Although the previous diagram only shows a codebase subdirectory of siteMod, modified versions of files from other directories can also be deployed from the siteMod directory. For example, you can add a tasks directory under the siteMod directory and in that directory, store customized Windchill Info*Engine tasks.
ptcCurrent This directory structure holds the most current PTC versions of files you have modified (as identified by the presence of those files under the siteMod directory). Windchill Service Pack installer automatically places files in this directory when the following things are true: The siteMod directory exists. There are files in the siteMod directory that are being updated by the service pack installer.
The files copied to the ptcCurrent directory are the files in the service pack that have the same name as files found in the siteMod directory. Instead of copying these files to your installation directory, the files are put in the ptcCurrent directory. This means that your customized files are not overwritten by the updated PTC files. After running the service pack installer (using any of the installation types), this directory contains updated PTC versions of the set of files that have been modified at your site.
5-4
A file appears in the ptcCurrent directory when PTC delivers an updated version in a maintenance release, but only after you initially create your customized version in the siteMod directory.
ptcOrig Before making first-time modifications to a file, put a copy of the original PTC file in this directory. The original PTC file is the last version of the file that PTC delivered prior to making modifications. This file could be the file supplied in a major release or in one of the maintenance releases. You must place files in this directory yourself; the Windchill Service Pack installer does not modify the files in the directory. ptcOrig is a suggested directory name; there are no PTC tools that actually look for this name.
After setting up this directory structure and installing updated files, you can compare the most recent version of a file from PTC (located in the ptcCurrent directory) with the currently deployed file (located in the siteMod directory) and the original version of the file (located in the ptcOrig directory). From the comparisons, you can determine how the version in the siteMod directory should be updated to incorporate the latest changes from PTC. For additional information, see the Using the Safe Area Directory Structure When Installing the Windchill Service Pack section, later in this section (page 5-8).
Managing Customizations
5-5
Following is a list of the most common target options: createSafeArea -- creates the <Windchill>/wtSafeArea/siteMod, <Windchill>/wtSafeArea/ptcCurrent, and <Windchill>/wtSafeArea/ptcOrig directories. listSiteChanges -- lists the files in the siteMod directory. installSiteChanges -- copies the files under the <Windchill>/wtSafeArea/siteMod directories to their corresponding <Windchill> installation directories. The timestamps on files from the siteMod directory are preserved when the copying is done. There are a few files and directories that could be present under wtSafeArea/siteMod but are not copied. For example, the files under the following wtSafeArea/siteMod directory structures are not copied to installation directories: .xconf-backup installer logs codebase/instreg tasks/codebase temp vaults wtCustom wtSafeArea Note: Most of these directories contain files that you should never modify; therefore, the directories should not be in the wtSafeArea/siteMod directory. If you happen to have files in any of these directories, the target reports that the files were not copied. The following files in the wtSafeArea/siteMod directory structure are also not copied to installation directories: bin/swmaint.xml codebase/.xconf-target-file-hints declarations.xconf site.xconf For an up-to-date list of files and directory structures excluded when the installSiteChanges target option is processed, see the output from the listSiteModExclusions target option (described next). listSiteModExclusions -- lists the files and directory tree structure patterns of those files and directories that are excluded when the installSiteChanges target option is processed. listSiteChangesIgnored -- lists the files under the <Windchill>/wtSafeArea/siteMod directory that are not copied to corresponding <Windchill> installation directories when you run
5-6
installSiteChanges. This target option is also run when you run the swmaint.xml script with the listSiteModExclusions target option. make_jar.config_jars -- rebuilds all client JAR files that are based on codebase/*.jar.config files. This covers the workgroup managers and Optegra Gateway products as well as any new *.jar.config JAR files defined by the site. (Client JAR files handled by jarContents and jarManifest specifications are built separately.) See Managing Client JAR Files on page 5-14.
Executing the swmaint.xml script is always done from an ant command. For example, from a windchill shell, execute the following ant command to copy the siteMod files to their executable location:
ant -f bin/swmaint.xml installSiteChanges
The script is described in PTC Script for Working with Customized Files on page 5-5.
Managing Customizations
5-7
Using the Safe Area Directory Structure When Installing the Windchill Service Pack
Use the following procedure to incorporate updates at a maintenance release: 1. Run the Windchill Service Pack installer using either the Changed Files Only or Updates for Site-Modified Files to Safe Area installation types. Using either of these options puts the updated PTC versions of customized files in the ptcCurrent directory. (A file is copied into the ptcCurrent directory only if the file exists in the siteMod directory.) 2. Using the three versions of the file found in the siteMod, ptcOrig, and ptcCurrent directories, determine what changes PTC has made in this maintenance release to each of your customized files. Note: If there is no corresponding file in the ptcCurrent directory, then there are no updates for the file in the current maintenance release. You can run the following swmaint.xml script from a windchill shell to list the site changes contained in files that are under the wtSafeArea/siteMod directory:
ant -f bin/swmaint.xml listSiteChanges
Additionally, other target options described in PTC Script for Working with Customized Files on page 5-5 may be helpful in completing this step and later steps. 3. Update each file that is in the siteMod directory appropriately. 4. After all files in the siteMod directory have been updated, run the following swmaint.xml script from a windchill shell to copy the files into place for testing.
ant -f bin/swmaint.xml installSiteChanges
Running this target also lists all files that are not copied. Normally, there should be no files listed. Inspect any files listed to determine why they were not copied. If they were in the wrong directory, put them in the correct directory and rerun the script. Note: The Windchill Service Pack installer executes this script and target automatically whenever there is a siteMod directory and you select the Complete installation type.
5-8
Additionally, your site may modify other files in the codebase directory. Use the information in the following sections to help you manage your customizations.
Managing Customizations
5-9
The Windchill Service Pack and temporary patch installers automatically recompile these resources so maintenance updates and your site changes are recombined.
The following sections provide additional details on text tailoring and updating client JAR files. For general information about the enumCustomize tool, see the The Enumerated Type Customization Utility in the Enumerated Types chapter on page 33-11. That chapter, as well as the Internationalization and Localization chapter on page 39-1, includes further discussions about RBINFO files. For recommendations on where and how to create new localized resources (for example, new RBINFO files), see Best Practices for Adding New Packages and Files on page 5-26.
5-10
For your text changes to be used by the running product, they must be compiled into the codebase. Running the enumCustomize tool does this automatically, but only for EnumResourceInfo resources. However, all three kinds of resources can be compiled by using the ant script <Windchill>/bin/tools.xml and the bundle_custom target. To use this script, start a windchill shell and execute the following command:
ant -f bin/tools.xml bundle_custom -Dbundle.input=registry
Both the Windchill Service Pack installer and temporary patch installer automatically execute this command to ensure that any updates delivered by PTC are merged with your site changes in the <Windchill>wtCustom directory. For text changes that are to be used by any applets, you must additionally execute the MakeJar command as follows:
ant -f <Windchill>/codebase/MakeJar.xml custUpdate
(see Managing Client JAR Files on page 5-14 for more information). For example, if you add a life cycle state to StateRB.rbInfo, you must run the above command to see the new state in an applet such as the Lifecycle Administrator.
Managing Customizations
5-11
without an associated XCONF file, a properties file can still be manipulated with the xconfmanager Utility. The following codebase properties should not be manipulated with the xconfmanager Utility: associationRegistry.properties classRegistry.properties descendentRegistry.properties modelRegistry.properties moduleRegistry.properties moduleDir.properties debug.properties This is because these properties are manipulated by Rose Modeling tools or otherwise contain properties not suitable for the xconfmanager Utility. If there are a lot of new properties that you need to add to a file such as wt.properties, rather than using xconfmanager Utility to set each property, consider creating your own declarative XCONF file. In this file, you declare the properties with a targetFile of wt.properties. Then use xconfmanager Utility to install this file into the declarations.xconf file. For an example of creating a service provider property file, see Adding a Custom Service Provider Property File on page 5-27.
5-12
configuring certain clients, such as DCA-based clients. For details on the format and content of the file, see the file itself and the corresponding Javadoc. The file is located in the <Windchill>/codebase directory. To prevent overwriting, use the safe area procedures as described in Setting Up a Directory Structure for Managing Customized Files and Text Tailoring on page 5-2.
Managing Customizations
5-13
registryserver.ini registryclient.ini The Workgroup Manager for CADDS has the following INI files: cadds5workspaceconfig.ini registryclient.ini newdocument.ini
Note: When updating for a maintenance release, running Windchill Service Pack installer with the Complete installation type rebuilds all client JAR files as needed. If you make new customizations or re-install existing customizations after running this installer, you must manually rebuild the client JAR files. Most client JARs are maintained through the use of an Ant script, MakeJar.xml, provided with Windchill. To ensure that the JAR files maintained through the MakeJar.xml script are updated correctly, you should add the following to the <Windchill>/codebase/jarContents/Cust.bom: Paths for the compiled resources (*.ser and/or *.class files) of the files you change Paths of customized property files
To verify that all customized property files are listed in Cust.bom, you can compare targetFile entries in site.xconf with the files listed in Cust.bom. Any files listed in targetFile entries that are not in Cust.bom should be added to Cust.bom. For example, if the site.xconf file has an entry for the following:
targetFile="codebase/wt/change2/change2.properties"
5-14
To rebuild the client JAR files that are managed by jarContents and jarManifest specifications, execute the following command from a windchill shell:
ant -f codebase/MakeJar.xml custUpdate
The concept of a logical JAR was introduced to Windchill in R7.0. Each logical JAR is actually composed of four JARs, in addition to any external dependencies it might have, e.g. to 3rd-party jars. The components of a logical JAR are shown in the figure below.
In this figure, the bolded labels denote role names for each component JAR whereas the italicized name denotes the actual name of the JAR. Thus for a logical JAR named MyApplet, for instance, the components would be MyApplet.jar, MyAppletCust.jar, MyAppletDSU.jar, and MyAppletFCS.jar. Note: The classloading precendence is from left to right in the figure, so that customization JARs override DSU JARs, which in turn override original distribution JARs. Head JARs only include manifests declaring the component and other JARs upon which they depend, as well as a JAR index in cases where the head JAR is the toplevel JAR for an applet. PTC distributions leave customization JARs empty, as these are for customer additions and overrides (e.g. to resource bundles). DSU JARs are left empty until a maintenance release provides additional files to target client(s) and/or newer versions of files already present in the corresponding FCS JAR. The FCS JAR contains all the original files required by a module at FCS (first customer shipment). The head JAR may list additional JARs upon which it is dependent after its own components. Note: The usage of DSU comes from the fact that, pre-R7.0, maintenance releases to Windchill were delivered in Downloadable Software Updates.
Managing Customizations
5-15
In addition to breaking logical JARs into different components for customization, maintenance releases, and original distribution, an effort has been made to break client JARs into appropriate modular components so that resources required by one applet are not automatically downloaded by all applets. This effort has been balanced with a desire to prevent any resource from being downloaded more than once, that is, included in more than one FCS JAR. DSU and Customization JARs will indeed duplicate resources contained by corresponding FCS JARs to override them without requiring an FCS JAR rebuild. Indeed only in small, targeted cases is a resource downloaded in more than one FCS JAR. In general, these efforts have led to the use of a dependency tree (more precisely, a unidirected graph) of logical JARs as described in the following section.
Current Foundation JAR Tree Definition
A representative view of the dependency graph of the client JARs is shown below. Note: The figure and the table following it constitute merely a representative view, not necessarily the complete dependency graph. Each label refers to a logical JAR (composed of head, customization, DSU, and FCS components) unless otherwise noted. Bolded labels are root JARs intended as top-level JARs to directly support applets, whereas the non-bolded labels are intended solely for re-use from other JARs. Each arrow implies a dependency (and essentially inclusion by reference) in the direction of the arrow. It should thus be clear that all JARs currently defined depend on wtApplet and 3rdPartyApplet with the notable exception of wtBootInst. Thus all duplicates are consolidated down the tree except from wtBootInst which is completely independent. The graph shown supports almost all of the Windchill Foundation applets and will certainly grow over time.
5-16
wtApplet
wtBootInst
wtFVault wtExp
wtTypeAdm wtLogin
Managing Customizations
5-17
Description The JARs for the Product Structure Explorer (PSE) applet. There are no customizable or inheritable classes in these JARs.
Note that wt.jar and 3rdparty.jar, the JARs used in Windchill applet deployments prior to R7.0 are not used at all by the new applet deployments. Both of these JARs are now the sole province of any applications which use them to maintain and use as they see fit. The new JARs are dramatically smaller than wt.jar.
The client JARs are built via the Java SDK's jar command and an Ant script (MakeJar.xml) that coordinates the builds of the client JARs and other related activities (e.g. consolidation of duplicate entries, removal of known inappropriate resources, and updating JPI cache versions. To rebuild all of the new client JARs, one can simply type:
ant -f MakeJar.xml
from a command prompt in the <Windchill>/codebase. Caution: As a general rule, customizers should not use this command pattern, as it will rebuild the FCS jars and cause unnecessary downloads by clients that have already downloaded the FCS jars by this point. Instead, 'custUpdate' and 'dsuUpdate' targets, as described in the following sections, should be used If you are using Java 2 v1.4.x, then any resources listed in a .includes file which are not present in your codebase will result in an error. To remove any such resources from your .includes files, add the following to your MakeJar.xml command line:
-DremoveStaleEntries=true
Although it takes only a couple minutes or so to rebuild all client JARs, in most cases you are only testing an applet or two at a time. In this case you will wish to the faster Ant targets for individual applets. For instance, to rebuild all JARs loaded by a workflow applet, one would use (all on one line):
ant -f MakeJar.xml buildFullClientJars -DlogicalJarNames=wtWork -DdoDeepBuild=true
Omitting the '-DdoDeepBuild=true' argument would limit the rebuild to the wtWork JARs, i.e. it would not rebuild the wtApplet JARs and so forth.
5-18
To determine what actions a command would perform, without actually performing them, the following argument can be added to the command line for any of the MakeJar.xml targets:
-DtraceOnly=true
The MakeJar.xml script contains targets allowing a wide variety of JAR building and maintenance operations to be performed for one or more JARs or sets thereof. To obtain more information on these targets, execute the following command:
ant -f MakeJar.xml -projecthelp
For optimal performance, all resources (.class files, .properties files, etc.) needed by a Windchill applet should be contained within one of the client JARs it uses. Each resource not found within one of an applet's client JARs that is needed by the applet will require a separate round-trip network request and the resource will not be compressed as it would be if it was part of a client JAR. This leads to especially poor performance on slow or wide-area networks. Providing the correct content in a client JAR file helps ensure optimal performance of the applet. If you have any customized applets, their JARs may not contain all the custom resources they require. If you suspect that the client JAR file used by an applet does not have the correct contents, you can determine which missing resources should be added. After customizing applets or JARs, you can identify what resources are used by an applet but are not contained in the corresponding client JAR files as they should be. If you are using the Apache Web server, PTC provides the HTTP Request Log utility that can be used to identify resources that are missing from a client JAR file and can then be added to the client JAR file. Use the following steps to determine which resources are missing from a set of client JAR files. 1. Open the HTTP Request Log utility. This marks the location of the current end of Apache log file so that all entries added to the file can be examined to see if they identify resources that have been downloaded to the client. 2. In a browser window, open the applet associated with the client JAR files and test the applet functionalities you wish to ensure/troubleshoot the performance of. Any resource downloaded for use in the client is recorded in the Web server access log. The HTTP Request Log utility searches the log file for the resource requests made of types peculiar to applets (for example, .class and .properties files) since you opened the utility in step 1. These resources were not found in the client JARs and thus were being pulled from the Web server. 3. Use the results from the utility to update the appropriate client JAR files. The following section provides details about using the HTTP Request Log utility.
Managing Customizations
5-19
You can use the HTTP Request Log utility to determine which resources are missing from the client JAR files used by Windchill applets. It searches the Apache log file, either by a specific user or all users, for specified file extensions and displays them in sorted order. Note: To use the utility, you must be using the Apache Web server. 1. Log in as a user named in the wt.sysadm.administrators property in the wt.properties file. For example, if the property value is: $(wt.admin.defaultAdministratorName),demo You can log in as the demo user or the user stored in the wt.admin.defaultAdministratorName property. 2. In a browser window, access the following page:
<local_host_name>/<Web_app_name>/wtcore/jsp/wt/sysadm/HttpRequestLogUtilStart.jsp.
3. In a separate browser window, start to the applets you want to test and complete your testing. 4. Return to the browser window where you started the HTTP Request Log Utility Start Page. Click View single client results to view the results from your testing session. Click View all clients results to view the results from all sessions recorded.
5-20
The results are a sorted list of all of the resources that were accessed during the testing that are not contained in a client JAR file. Use this input to update the appropriate JAR files. For example, if the list is as follows:
5. Copy the resources from the resulting list and paste them into the following file:
<Windchill>/codebase/jarContents/<topJarName>Cust.includes
<topJarName> is the leafname of the top-level JAR used by the applet. For example, the QueryBuilder top-level JAR in the applet tag is wtQB.jar. Therefore, paste the resources into the file named:
<Windchill>/codebase/jarContents/wtQBCust.includes
6. From a Windchill shell, run the following script from the codebase directory:
ant -f MakeJar.xml custUpdate
Tip: The search results are only as accurate and complete as the testing you do. If the HTTP Request Log Utility Start Page was not accessed before the testing, the entire log file is searched. Otherwise, the search begins from the point in the log that immediately follows your most recent access.
Managing Customizations
5-21
The types of resource files that are searched for can be configured. By default, the defined extensions are .class, .ser, and .properties. To change from the default, edit the fileExtensions variable in wtcore/jsp/wt/sysadm/HttpRequestLogUtilStop.jsp file. Note: Depending on the servlet engine configuration you may have to restart the servlet engine for these changes to take effect.
To find all resources needed for an applet, remove the client JARs used by the applet and use the previous steps to log all resources that are used. This type of testing creates a lot of network traffic since every resource is downloaded from the server. You would typically only do this type of testing if you believed the client JARs contained significantly more resources than were required for your use cases. This generally should not be done with PTC supplied *FCS.jar and *DSU.jar files.
Note: If, using the above methods, you discover that there are resources missing from Windchill client JARs that you have not modified, file a problem report with technical support. Include the following in the report:
Adding New Applets Re-using an Existing Root JAR
The list of missing resources. The applet or root JAR against which the testing was being performed. A brief description of the functionalities exercised. The exact build against which the testing was performed. The version of the Java Plug-In used in the testing. The client OS.
If you have decided to directly re-use an existing root JAR for the applet(s) in question, then all you have to do is list this JAR in the plug-in tag.
Using a New Logical Root JAR
In the case where a new JAR is to be added, however, the necessary steps are as follows. 1. Create content and manifest description files for your logical JAR's components. You can use a target within MakeJar.xml to do this for you by executing the following in codebase:
ant -f MakeJar.xml makeNewJarDescr -DlogicalJarName= logicalJarName
For example, for a new logical JAR, foo, one would execute:
ant -f MakeJar.xml makeNewJarDescr -DlogicalJarName=foo
5-22
This creates an empty FCS .includes files for the specified logical JAR in codebase/jarContents, e.g. for a logical JAR, foo, this file would be fooFCS.includes. This also creates head, Customization, DSU, and FCS .manifest files in codebase/jarManifests for the specified logical JAR, e.g. for a logical JAR, foo, these files would be foo.manifest, fooCust.manifest, fooDSU.manifest, and fooFCS.manifest. All of these files except the head manifest (e.g. foo.manifest) are initially empty. The head manifest defaults to have a Class-Path entry listing the Customization, DSU, and FCS JAR components of the logical JAR followed by wtApplet.jar, e.g. for a logical JAR, foo, the entry would be:
Class-Path: fooCust.jar fooDSU.jar fooFCS.jar wtApplet.jar
This entry should be amended if your logical JAR does not depend on wtApplet.jar or has additional dependencies - in either case these should be listed after the FCS JAR entry. 2. Create a .set file in <Windchill>/codebase/jarManifests that includes the logical name of your new JAR. 3. Build your JAR by executing an appropriate target on the MakeJar.xml script (from the codebase directory), e.g.:
ant -f MakeJar.xml buildFullClientJars -DlogicalJarNames=foo
where foo should be replaced by the name of your logical JAR. 4. Test your new JAR by using it in your applets' plug-in tags, recording missing resources via the HTTP Request Logging utility as described in Using the HTTP Request Log Utility on page 5-20. 5. Update your new JARs contents as described in Using the HTTP Request Log Utility on page 5-20. 6. Re-test your applet.
Updating Client JARs At Maintenance Releases
Because of the inclusion of DSU JARs in the logical JARs, clients only have to download resources that were added or changed as part of the maintenance release (plus new root head jars), not the entire set of client JARs. The process of rebuilding the client JARs at a maintenance release has been automated via the following command (note that this command rebuilds Customization JARs when necessitated by new or updated DSU JARs):
ant -f MakeJar.xml dsuUpdate
This command executes the following targets: createCodebaseDsuBOM: Takes entries in codebase/../*_bom.txt BOM files which are in codebase and places them in jarContents/DSU.bom, but written relative to codebase (i.e. it removes "codebase/" from each entry).
Managing Customizations
5-23
updateDSUIncludes: Intersects each FCS .includes file with jarContents/DSU.bom and adds the intersection to the corresponding DSU .includes file. updateCustIncludes: Intersects each FCS .includes and DSU .includes file pair with jarContents/Cust.bom and adds the intersection to the corresponding Customization .includes file expandJarLocales: For resource bundles represented by _en localization in DSU and FCS .includes, places other localizations requested in jarContents/clientJarLocales into Customization .includes removeNonexistantDsuAndCustEntries: Removes any entries from the Customization and DSU .includes files which are not found in codebase. buildDSUClientJars: Rebuilds all DSU and Customization jar components. Also builds all indexed head jars which are parents (directly or indirectly) of these jars.
The only steps omitted by dsuUpdate for the Foundation resources and jars are: The addition of any new DSU jar entries required for reasons other than being in the intersection of the DSU BOM and FCS jar contents (e.g. previously missed entries, new classes, etc). The inclusion of a codebase/../*_bom.txt file containing the files changed by the DSU.
These should both be provided (e.g. as updated DSU .includes files and a foo_bom.txt file) as part of the maintenance release itself.
Updating Client JARs for Customizations
The Customization JAR components exist to allow customization additions and overrides to the out-of-the-box JAR sets as these components take load precedence over the corresponding DSU and FCS components. A customer or customizer can add entries to any Customization .includes files they want and rebuild the corresponding JAR via:
ant -f MakeJar.xml buildCustClientJars DlogicalJarNames=jar1,jar2,
where jar1,jar2, should be replaced by the list of logical JARs whose Customization components should be rebuilt. More often, however, the customer is likely to have a number of files they have overridden and simply wish to have the client JARs updated to account for this. This can be done by listing the overridden/customized files in codebase/jarContents/Cust.bom and then executing the command:
ant -f MakeJar.xml custUpdate
5-24
updateCustIncludes: Intersects each FCS .includes and DSU .includes file pair with jarContents/Cust.bom and adds the intersection to the corresponding Customization .includes file. Note that Cust.bom contains a few of the most volatile entries (e.g. properties files regenerated during code generation) initially out-of-the-box. expandJarLocales: For resource bundles represented by _en localization in DSU and FCS .includes, places other localizations requested in jarContents/clientJarLocales into Customization .includes buildCustClientJars: Re-builds all Customization JAR components. Also, builds all indexed head JARs which are parents (directly or indirectly) of these JARs.
Additionally more extensive client customizations can be supported by proceeding to build new client JAR sets in much the same way as was described for the previous sections.
Handling Localized Resources
The MakeJar.xml script contains reusable targets which wrap custom Ant tasks which handle localized resource entries in client JARs. standardizeJarLocales: removes all except one locale-specific resource entries for each resource bundle encountered in the FCS and DSU .includes of the logical JARs listed by the input property logicalJarNames. Note that the null/default locale entry is also not removed. This target is used by various targets including sanitizeAndBuildJarSets to eliminate most of the overhead of undesired localization in client JARs. expandJarLocales: for each resource bundle in the FCS and DSU .includes of the logical JARs listed by the input property logicalJarName, places the corresponding entries specific to the locales desired by the site (as specified in jarContents/clientJarLocales) in the corresponding Customization .includes files. Conversely, entries from bundles represented in a DSU.includes or FCS.includes but from locales not requested by the site are removed from the corresponding Customization.includes. This target is used by dsuUpdate and custUpdate to ensure that the client JARs support the locales requested by the site.
As a whole the MakeJar.xml script ensures reasonable handling of site-specific locale sets. It does not handle user-specific locale sets (i.e., delivery of different JAR sets to each user depending on their locale settings).
Managing Customizations
5-25
The types of files that you should store under <Windchill>/src/com/mycompany include new Java source files, property files, HTML templates, RBINFO files, XCONF files, and new files created as a result of modeling with Rational Rose. In addition to keeping your new packages and files in a <Windchill>/src/com/mycompany directory structure, you must include corresponding packages and files in your runtime system. For example, the following list explains where your files should be placed: Java files are typically compiled to a comparable directory under <Windchill>/codebase. For example, if you create a new template processing class under <Windchill>/src/com/mycompany/part, you could compile it to <Windchill>/codebase/com/mycompany/part. HTML template files must be installed under <Windchill>/codebase/templates at runtime. For example, if you create some new templates in the directory <Windchill>/src/com/mycompany/part/htmltmpl, you could copy them to <Windchill>/codebase/templates/com/mycompany/part at runtime. Resource bundle files must be compiled into a directory under <Windchill>/codebase at runtime. This can be done using the ResourceBuild command. For example, if you have new RBINFO files in the directory <Windchill>/src/com/mycompany/part, you could compile them to the <Windchill>/codebase/com/mycompany/part directory by executing the following command from a windchill shell:
ResourceBuild com.mycompany.part
5-26
Property files maintained in a custom directory like <Windchill>/src/com/mycompany must be copied to a directory in <Windchill>/codebase at runtime.
Often when you integrate new packages and files into your existing environment, you must change files that were supplied by PTC. Be sure to manage these customized files as directed in earlier sections. Note: When you are updating files for a maintenance release, remember to copy any updated new packages and files that are used in your runtime system from your test system to your production system.
Modeling Recommendations
Sites that use the Rational Rose modeling tool may store their new packages and classes under the <Windchill>/src directory structure; however, the packages that are defined should not be stored under the <Windchill>/src/wt or <Windchill>/src/com/ptc directory. Typically, newly developed packages and classes are stored under the domain name of your company, as described previously. Some customizations can also be stored under the <Windchill>/src/ext directory.
Managing Customizations
5-27
Suppose your new service provider file name is named codebase/ext/sitepart/sitepart.properties. It contains the entries that define your new services. In order to get this property listed as one of the files in the following wt.properties entry:
wt.services.applicationcontext.WTServiceProviderFromProperties.customPropertyFiles
You should create a new declarative XCONF file, for example, codebase/ext/sitepart/sitepart.xconf. It would look like the following:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE Configuration SYSTEM "xconf.dtd"> <Configuration targetFile="codebase/wt.properties"> <!-- Ensure that the file ext/sitepart/sitepart.properties is appended to the list of custom property files. --> <Property default="ext/sitepart/sitepart.properties" name="wt.services. applicationcontext.WTServiceProviderFromProperties.customPropertFiles"/> </Configuration>
The Property statement (formatted on two lines for this guide) is one line in the file that declares that the file ext/sitepart/sitepart.properties (a path relative to the codebase directory) should be added as a value for the property:
wt.services.applicationcontext.WTServiceProviderFromProperties.customPropertyFiles
This property is in the codebase/wt.properties file. Store a copy of new XCONF files in your source directories as described in the Best Practices for Adding New Packages and Files section on page 5-26. To install the codebase/ext/sitepart/sitepart.xconf file and generate the sitepart.properties file, execute the xconfmanager Utility from a windchill shell, as follows:
xconfmanager -i codebase/ext/sitepart/sitepart.xconf -p
After running the above command, the wt.properties file is updated to reference your service provider file, codebase/ext/sitepart/sitepart.properties.
5-28
6
Windchill Utilities
This chapter contains information about the xconfmanager and windchill utilities. Topic Page
About the xconfmanager Utility..........................................................................6-2 About the windchill Command ...........................................................................6-6 About the windchill shell ....................................................................................6-8
6-1
For the purposes of modifying Windchill properties, you will primarily use the -s, -t, and -p parameters as follows: Use the -s (--set) parameter to identify the relevant property and specify the new property value. See the Formatting Property Value Guidelines section (below) for information about formatting the <property_pair) value. Use the -t (--targetfile) parameter to specify the directory location of the property file. If the file name or path contains spaces, you must enclose the
6-2
<property_file> value in double quotes (" "). It is recommended to use a fully qualified file name to ensure an accurate reference to the file is made. Use the -p (--propagate) parameter to propagate the changes made to the XCONF files into the property files being modified in order to keep the XCONF and the property files in sync with one another. Use the -h (--help) parameter to view the help for xconfmanager. The help describes all xconfmanager parameters.
Additionally, you can add and remove property values from properties that are declared as a multi-valued properties using the following parameters: Use the --add parameter to add the value specified at the end of the set of ordered values already defined in the property. Use the --remove parameter to remove the value specified from the set of ordered values already defined in the property.
Tip: If you are unsure as to whether a property is multi-valued, you can display the current set of values using the -d parameter. The output from this parameter lists the multivalue separator when the property is multi-valued. Some examples of using the xconfmanager utility are as follows: xconfmanager is run from the windchill shell. To open a windchill shell, execute the following command at a command prompt:
windchill shell
To display xconfmanager help, execute the following command from the windchill shell:
xconfmanager -h
To display the current settings for a property, execute the following command from the windchill shell:
xconfmanager -d <property_names>
<property_names> is a comma-separated list of property names. This means that you can display the current settings for multiple properties by executing one command. To change a property value, execute the following command from the windchill shell:
xconfmanager -s <property_name>=<property_value> -t <property_file> -p
Tip: Use the fully qualified name of the property file to ensure an accurate reference. If you are sure that there is only one property file that is known to xconfmanager containing the property, you can omit the -t parameter. When setting a value for a new property not in a property file, you must include the -t parameter to name the property file to which the property is added.
Windchill Utilities
6-3
To add a new classpath entry to the Windchill classpath specified in the wt.java.classpath property, execute the following command from the windchill shell:
The value d:\MyLibaries\somelibrary.jar will be added to the end of the ordered set. You do not have to specify the delimiter $(path.sep) as this will be added to the property value automatically by the xconfmanager. Tip: The previous example command did not include the target file in the -t parameter since the property is known to be in only wt.properties.
On a UNIX system, you can use doubles quotes or you can escape the space character with \. For example, use either of the following:
-s "wt.inf.container.SiteOrganization.name=ACME Corporation" -s wt.inf.container.SiteOrganization.name=ACME\ Corporation
In many UNIX shells, the use of a backward slash (\) escapes the following character as a literal. In most cases, using forward slashes (/) in file paths is a simple way to specify a path without having to know the intricacies of your shells command line escaping rules. On UNIX, dollar signs are usually interpreted by shells as variable prefixes. To set a property value that has a dollar symbol in it, use single quotes around the argument so that the shell does not interpret it or use backslash to escape the dollar symbols. For example, use either of the following:
-s 'wt.homepage.jsp=$(wt.server.codebase)/wtcore/jsp/wt/portal/ index.jsp'
or
-s wt.homepage.jsp= \$(wt.server.codebase)/wtcore/jsp/wt/portal/index.jsp
6-4
Other than escaping arguments so that the command-line shell does not misinterpret them, you should not need to escape other values to be compatible with XML or property file syntaxes. The xconfmanager escapes property names and values automatically if necessary.
Windchill Utilities
6-5
You can display the help for the windchill command by executing windchill with the -h argument or with no argument. The following tables list some of the arguments and actions applicable to the windchill command. To see a complete list of the arguments, use the report generated from the help (argument). windchill Arguments:
Arguments (optional) -h, --help -v, --[no]verbose Description Displays help and exits. Explains what is being done when a command is executed. Default is noverbose.
6-6
Description Sets the Windchill home directory. Default is the parent directory containing the windchill script.
Note: On UNIX systems where you have multiple instances of Windchill installed under the same user account, settings made to WT_HOME and SQLPATH environment variables by using this -w option are overridden by any settings to these same variables in the user's .cshrc, .login, and .profile shell initialization files.
--java=JAVA_EXE The Java executable. Default is the wt.java.cmd variable value specified in the $WT_HOME/codebase/wt.properties file. Java classpath. Default is the wt.java.classpath variable value specified in the $WT_HOME/codebase/wt.properties file. Java command line arguments.
-cp, --classpath=PATH
--javaargs=JAVAARGS
Windchill Utilities
6-7
windchill Actions
Action shell Description Sets up a Windchill environment in a new instance of the currently running shell. Starts the Windchill server. Stops the Windchill server. Retrieves the status of the Windchill server. Displays the Windchill installation version. Displays the properties as seen by Windchill for the given resource with substitution and other actions executed. It can be limited to a given set of keys. For example: windchill properties wt.properties lists all wt.properties windchill properties wt.properties?wt.server.codebase lists server codebase windchill properties wt.properties?wt.env.* lists all the environment variables use by windchill shell windchill properties with no arguments generates the help report CLASS [CLASS_ARGS] Run a Windchill class with optional class arguments. For example: windchill wt.load.Developer -UAOps
When you are finished using the windchill shell, you can exit the shell and return to the parent shell. PTC recommends running all server-side Windchill applications, tools, and utilities from the windchill shell. Also, you can use the windchill shell to set up your development environment to use javac or Java directly.
6-8
7
Customization Tutorial
This tutorial is intended for programmers who are not that familiar with Windchill. Topic Page
Tutorial Overview ...............................................................................................7-2 Create Administrator and User............................................................................7-4 Create a Library and Document ........................................................................7-12 Create a New Attribute Definition and Add it to the Document Type..............7-17 As the End User, Create a Document with the new Attribute...........................7-22 Create a Document Soft Type ...........................................................................7-25 Create an Instance of the New Document Soft Type ........................................7-27 Model a New Document Subclass.....................................................................7-28 Create an Instance of the New Document Subclass ..........................................7-38 Verify the Customizations.................................................................................7-39 Summary ...........................................................................................................7-41
7-1
Tutorial Overview
This tutorial illustrates a minimal configuration to create an environment in which you can create administrative objects (users, attribute definitions, types and subclasses) and test them as an end user (by creating a container and document instances). This will give you some idea how to work in Windchill products, and help you ensure that your customization environment is configured correctly. Note: This tutorial is intended for programmers that are not familiar with Windchill.
Goals
In this tutorial you will: set up and navigate a Windchill test system define soft and modeled types create instances of those types
Performing these tasks will: confirm that their development environment is properly configured shows that UIs adapt to new type and attribute definitions
Assumptions
Windchill PDMLink standalone or Integral Windchill PDMLink and Windchill ProjectLink. The system is installed, configured and runs. You know how to start and stop the system. You have the ability to compile Java code into the system codebase. You have access to the system database instance and permission to create new schema. You can login as the Windchill System Administrator.
Outline
1. As the System Administrator, create Organization Administrator and End User. 2. As the end user, create a Library and a document instance. 3. As the Organization Administrator create a soft attribute definition and add it to the standard document type. 4. As the end user, create a document instance which will include the new attribute.
7-2
5. As the Organization Administrator create a second soft attribute. Then create document soft type and add the new attribute definition to it. 6. As the end user, create an instance of the new document soft type. 7. Model a new document subclass and deploy it. 8. As the end user, create an instance of the new document subclass. 9. Verify what you have done, by searching for instances of your documents.
Customization Tutorial
7-3
2. From the first level navigation tabs, select Site. 3. From the second level navigation tabs, select Utilities. 4. Under Business Administration select Principal Administrator. 5. Select New User.
6. Create an Organization Administrator with the following values: User Name (login ID) Full Name E-mail Address
7-4
Password
Organization
Customization Tutorial
7-5
Click Search to search for the organization. Choose the default Organization created for your system (this was specified when the system was installed).
7. Select the Groups tab. 8. Select the black + icon to add groups to the table. 9. In the Search for Parent Groups dialog select Search (leave the search field blank), and then select the three check boxes for Administrators, Attribute Administrators and Type Administrators, then select OK.
Note: For any other organization you would not need to select Administrators. But because this is the default site organization, the
7-6
organization administrator must also be a site administrator in order to manage types and attributes. 10. Select OK.
Customization Tutorial
7-7
12. Create an End User using the same steps that you used to create the Organization Administrator user. Be sure to use the same Organization. Important: Do NOT add the End User to any groups.
7-8
14. Now you must declare the Organization Administrator user as an Organization Administrator. Select the Organization tab from the first level navigation tabs.
15. Select your organization from the Organizations drop down list on the second level navigation. If there is a table of displayed organizations, it may also be there. 16. Select the Administrators tab from second level navigation tabs. 17. Select the Add Users icon.
Customization Tutorial
7-9
18. In the Add Organization Administrators dialog select Find Users, leaving the Search field blank. Select the user you created to be the Organization Administrator, and then select Add >> and OK.
19. With the Organization tab still selected, select the Creators sub tab. In the Current View dropdown select Library Creators.
7-10
20. Select your end user and add them to the Library Creators Group using the Add >> button.
Verify that your end user is now part of the Library Creators group.
At this point in the process, as the System Administrator, you have created an Organization Administrator and an End User. The Organization Administrator is also a Soft Attribute and Soft Type administrator. The End User is also a Library Creator.
Customization Tutorial
7-11
3. As the End User, create a new Library. Select the Library tab and select the New Library icon.
7-12
Customization Tutorial
7-13
6. Select the Folders subtab and then the Add a New Document icon.
7-14
9. Select Finish. You will not be setting attachments during this process.
Customization Tutorial
7-15
10. Here is the new document in its folder. Note that the Number is automatically assigned.
11. Select the View Information icon to see details about the document.
7-16
3. To open the Type and Attribute Manager, select Organization > Utilities > Type and Attribute Manager.
Customization Tutorial
7-17
4. Select Attribute Definition Manager > New Organizer to create a new Attribute Organizer.
5. Specify a name for your new Attribute Organizer, and select OK.
7-18
9. Select OK and your new attribute will be displayed in the attribute hierarchy: 10. Before Saving, change the Display Name of the attribute to Size A. Note that the display name can be localized in resource bundles.
Customization Tutorial
7-19
11. Select the Type Manager tab, and expand the hierarchy under Document to see its subtypes.
12. With Document selected, select the Edit icon. Then select the Template tab. Within the Template tab, select Attribute Root to enable the Add Attributes button.
13. Select Add Attribute and from the dialog find and select the sizeA attribute you created. In the Template tab, select the value cell for sizeA and enter the default value of 1. 14. Select Save and then select the Check In icon.
7-20
15. You have just added the sizeA attribute to the Document type and all of its subtypes.
Customization Tutorial
7-21
7-22
2. Select the View Information icon to see details about the document.
Customization Tutorial
7-23
3. Select More Attributes to see the soft attribute and value that you added.
4. If you go back and look at the attributes for the first document you created, it will now display Size A, but with no value. Even though you specified a default value for sizeA, it only applies to instances created after the attribute existed on the type.
7-24
5. Select the Attribute Definition Manager tab, and create another Integer attribute type as a peer to sizeA called sizeB. Save it.
6. Add attribute sizeB to your new document type with default value 2.
Customization Tutorial
7-25
8. Select the General tab. With the type checked out, select the edit icon and change the Icon to wtcore/image/repair_failure.gif. The name of the icon is not meaningful, but it is a distinctive image that you will be able to pick out in the UI later. 9. Save and check in your type.
7-26
Customization Tutorial
7-27
2. Within Rose you will first be presented with a Create New Model dialog. Cancel that dialog for now. 3. Select File > Edit Path Map and verify that the path map values are referencing your Windchill installation. 4. Close the Path Map window. 5. Select File > Open, and navigate to, and open the model file:
\Windchill\src\wt\WTdesigner.mdl
7-28
7. Wait until the load is complete, at which point the screen will update and look something like this:
8. In the browser pane, expand the Logical View. Right click Logical View and select New > Class Diagram. Name the new diagram "com Packages". Double click on the "com Packages" icon to open the empty diagram.
Customization Tutorial
7-29
9. Select the Package icon then click in the diagram pane. Name the new package "com":
10. Right click the "com" package in the browser and select New > Package. Name the new package "acme". 11. Right click the "acme" package in the browser and select New-> Class Diagram. Name the new diagram "Documents". 12. Double click the Documents diagram icon to open the new empty diagram. 13. Select the Class icon and click in the diagram window. Name the new class "WTDocument" (it must be this name, as it refers to an existing Windchill class that you will inherit from). When prompted to "Delete NewClass from the Model?" select "Yes".
7-30
14. Select the Class icon again and click in the diagram window below WTDocument. Name the new class "AcmeModeledDoc". Select the Generalization icon and draw an arrow from "AcmeModeledDoc" to "WTDocument".
15. Double-click "AcmeModeledDoc" in the Class Diagram to open the Specification Dialog. Select the Attributes tab.
Customization Tutorial
7-31
All of the existing attributes are inherited from WTDocument and its parent classes. Right click on the list of attributes and select "Insert". Name the new attribute "sizeC".
16. Double-click on the new attribute to open the Class Attribute Specification window. 17. Set the following values: Type = Integer Initial Value = 3
7-32
18. Select OK to close the Class Attribute window. 19. Now open the Windchill tab within the Class Specification window. Change the StandardIcon to "wtcore/images/stop.gif".
Customization Tutorial
7-33
The name of the icon is not meaningful, but it is a distinctive image that you will be able to pick out in the UI later.
21. Now you will generate the Java source file, SQL scripts and other artifacts for your new document class.
7-34
22. Select AcmeModeledDoc in the class diagram. Select Tools > Windchill > System Generation. Accept the default selections, select OK.
23. After a minute or so the generation will be complete. You will find the generated java file here:
..Windchill\src\com\acme\AcmeModeledDoc.java
You will find the generated SQL file (to create the new database table) here:
..Windchill\db\sql\com\acme\create_AcmeModeledDoc_Table.sql
You will find the generated ClassInfo.ser file (that contains meta data about the new class) here:
..\Windchill\codebase\com\acme\AcmeModeledDoc.ClassInfo.ser
24. You can inspect the java and sql files to see what was generated (the ClassInfo.ser file is a binary instance of the ClassInfo java class, so you cannot inspect it directly). 25. Now you will compile the java file. 26. Open a Windchill Shell. CD to the directory (<Windchill>/src/com/acme) of the java source file. 27. Compile the java file.
Customization Tutorial
7-35
You'll find the compiled class file in the same directory as the ClassInfo.ser file. 28. Now you will create the table and associated database artifacts for your new document class. To do this, from within sqlplus, you will execute two scripts:
..\Windchill\db\sql\com\Make_pkg_com_Table.sql ..\Windchill\db\sql\com\Make_pkg_com_Index.sql
30. At the " SQL " prompt execute the two scripts using full path names similar to this:
@<Windchill>\db\sql\com\Make_pkg_com_Table.sql @<Windchill>\db\sql\com\Make_pkg_com_Index.sql
31. Now execute a describe command to see the columns in the new table for your class. Note that there is a "SIZEC" column for the attribute you added directly to the class.
describe AcmeModeledDoc
You may also want count the number of rows in the table to confirm that it is empty:
select count(*) from AcmeModeledDoc
7-36
33. As the Organization Administrator, open the Type and Attribute Manager. You will now see your modeled document subclass in the type hierarchy. Note the red flag "stop" icon that you specified for your subclass in the model.
Customization Tutorial
7-37
2. Browse for a file to add as content, and leave the other attributes with default values. 3. Navigate to the More Attributes page for Document 103 and note that the sizeA and sizeC attributes have the correct values. 4. You now have four documents: Document 1 is an instance of the default Windchill document type Document 101 is an instance of the default Windchill document type with the new sizeA attribute that you added Document 102 is an instance of the new soft document type you added Document 103 is an instance of the new modeled document type you added
7-38
3. Now select "Search" button in the bottom right. Four results will be displayed: the four documents you created.
Customization Tutorial
7-39
Note: The instances of the types you created are shown with the custom icons you specified. This confirms that your new custom types are integrated with standard Windchill functionality.
7-40
Summary
In this tutorial you have: Created new users including an Organization Administrator and an End User Made the Organization Administrator a Type and Attribute Administrator Made the End User a Library creator Created a library Created soft attributes definitions and soft type definitions, and instances of those types Created a modeled type and an instance of that type Confirmed that your Windchill development environment is configured to support modeling with Rose Verified what you have done, by searching for instances of your documents.
Customization Tutorial
7-41
7-42
III
User Interface Customization Section
Chapter
Page
User Interface Technology Overview .................................................... 8-1 Generic UI Customizations.................................................................... 9-1 Customizing HTML Clients Using the Windchill JSP Framework..... 10-1 Adding Actions and Hooking Them Up in the UI ............................... 11-1 Gathering the Data for the UI .............................................................. 12-1 Presenting Information in the UI ......................................................... 13-1 Constructing Wizards........................................................................... 14-1 Information Pages ................................................................................ 15-1 Incorporating Pickers in JSP Clients.................................................... 16-1 JSP Customization Scenarios............................................................... 17-1 Customizing the Product Structure Explorer (PSE)............................. 18-1 Customizing Windchill MPMLink ...................................................... 19-1 Customizing Search Functionality ....................................................... 20-1
8
User Interface Technology Overview
This chapter explains and give some basic overview of the Windchill Client Architecture UI Framework. Before reading this chapter, you should be familiar with Java, JavaServer Pages (JSP), JavaServer Pages Standard Tag Library (JSTL) and Expression Language (EL). Topic Page
Windchill Client Architecture Overview ............................................................8-2 Adding Custom Code to all Windchill Client Architecture Pages......................8-8 Javascript Functions Overview ...........................................................................8-9
8-1
The internal code to the jsp will contain the necessary data to describe and configure the sub-components that are used.
begin.jspf
The first and most important is the begin.jspf. This files exists in codebase/netmarkets/jsp/util/. This file is included in most view jsp pages. The purpose of this jspf is to: Include a tag for rendering the header, and 1st and 2nd level navigation.
Take care of housekeeping like: instantiation of beans (context, clipboard, session) including standard .js and .css files including common HTML pieces like <html><body>etc) creating an HTML form for submitting data (called mainform) providing support for closing pop ups and refreshing the main page
8-2
end.jspf
Another jspf that is included on most pages is the end.jspf also located in codebase/netmarkets/jsp/util/. The purpose of this file is: mark the begin and end of the content area for DHTML content switching (for example, switching the 3rd level navigation content without refreshing the page display the footer
catch exceptions and handles them if they occur within the page
beginWizard.jspf
When constructing a wizard, there is a special beginWizard.jspf file, located in netmarkets\jsp\components, that should be used instead of the begin.jspf that will do essentially the same things as the begin.jspf, however, it will not include the rendering of the header for the 1st and 2nd level navigation.
Java Beans
There is a set of Java Beans that is part of the framework that carries data like context and session information. The developer does not need to interact with most of the beans. See NmObject Utilities in the Gathering the Data for the UI chapter on page 12-15 for more information.
8-3
directly. See the Adding Actions and Hooking Them Up in the UI chapter the page 11-1 for more information.
Validation Service
Validation of actions, properties, and wizard steps can be done via logic encapsulated into a validator that gets executed when a component such as a action menu, table, or property panel includes that action or property. When a page including one of these components is requested, the framework will call the validation service to determine which of the actions, properties, or wizard steps should be displayed, disabled, or hidden. The service will invoke the appropriate delegates to gather the requested status for that action, property, or wizard step. As a customization point, you can write a delegate that is mapped to a specific action, property, or wizard step, that contains logic to indicate when that element is valid to show, hide, or disable in the user interface. The validation framework is tied into the Role Based UI framework. Role based support is included for most actions in the product, and customized actions can also take advantage of this capability. Role based capability is supported for soft attributes created via the type manager, not modeled attributes. That validation service will actually call the role based service as a first pass of validation. If the action, property, or wizard step is valid for the user based on role, the service will then invoke the appropriate delegate. The Validation Service is also used to validate the data entered by the user in wizards. For more information on the Role Based UI framework see Customizing Role-Based UI Functions - Attribute Visibility on page 9-8. For more information on the Validation Service see Adding Validation Logic for Actions and Properties on page 10-46.
Reusable Components
There is a broad set of components that are built using the framework that can be reused in customizing your pages. The basic steps to render many components (table, tree, property panel, etc.) are: Describe the component (describe* tags) Acquire the necessary data (get* tags) Render the component (render* tags)
8-4
The configuration of these phases begins with the tag handler in the JSP Page. To use the tags, you need to include the components library. The following code snippet includes the library:
<%@ taglib uri="http://www.ptc.com/windchill/taglib/components" prefix="jca"%>
This section will gloss over what the details of most of the columns and properties in the tags mean for now, and focus on the overall flow of the page.
Component Description
This part of the lifecycle is used to define the columns/properties that the component will display. This happens first since the way the data is retrieved may depend on the properties that are requested. During the component description phase the developer uses a describe tag handler that tells the infrastructure about the component they would like do display. The core describe handler is the describeTable, which might look like the following.
<jca:describeTable var="tableDescriptor" id="my.table.id" configurable="true" type="com.myco.MyType" label="${myLabel}"> <jca:setComponentProperty key="actionModel" value="my action model"/> <jca:describeColumn id="name"/> <jca:describeColumn id="nmActions" /> <jca:describeColumn id="status"> <jca:setComponentProperty key="percent" value="true"/> </jca:describeColumn> </jca:describeTable>
Variations on the describeTable tag are the describePropertyPanel tag, which presents object attributes in label-value rows, and the describeAttributesTable tag, which also presents attributes in label-value rows but in tabular format.
Structure of the tag
The tag contains a set of nested tags which give it some structure. There are two kinds of nested tags: setComponentProperty: this tag configures the properties of its parent tag that arent exposed as attributes of the parent tag itself. This gives the infrastructure and the developer some flexibility about the metadata theyd like to be available down the road, without always requiring a tag library definition (tld) update to do so. describeColumn: This tag describes a particular column that the developer wants to display. Like the parent describeTable tag, this tag accepts child setComponentProperty tags. There is also a describeProperty tag that has the same semantics when used in property panels.
8-5
Underneath the covers, the describeTable tag is simply configuring a java bean that implements the ComponentDescriptor interface. The attributes that are available via the tag handler typically correspond to properties of the ComponentDescriptor. The ComponentDescriptor object is important to keep in mind as it comes into play later on during the data acquisition phase. The ComponentDescriptor object that the describe tag handlers build is communicated to the rest of the world via the required "var" attribute. The handler creates a scoped variable for the ComponentDescriptor object named whatever the var attribute value is. In the example above, the var attribute was mapped to "tableDescriptor", but it can be mapped to any legal JSP variable identifier. Note that this semantic for the var attribute is reused from the JSTL tag handlers. Since the ComponentDescriptor object is a scoped attribute, it can be referenced later in the page using the JSP EL as well as Java code. Subsequent tags can now refer to the descriptor using the ${varName} syntax, for example.
Data Acquisition
The second phase gets the model data based on the description from the first phase. In the data acquisition phase, the developer combines a component description with some additional information on how to actually go and get the data that will back the component. The developer does this with one of client infrastructures get tags. The most typical usage of the tag might look like the following:
<jca:getModel var="tableModel" descriptor="${tableDescriptor}" serviceName="com.myco.MyService" methodName="getMyObjects"> <jca:addServiceArgument value="${myArgument}" type="java.lang.Long"/> </jca:getModel>
The tag gets a component description by using the EL to look up the scoped "tableDescriptor" variable. The tableDescriptor variable would typically be put in the page by a previous describe tag that had a var value of "tableDescriptor". Like the describe tags, the get tags produce a java bean that is added to the page as a scoped variable named with the var attribute value. In the case of the get tags, the resulting bean is an instance of ComponentModel.
What is it doing?
Developers typically do not interact with the ComponentModel object produced by the get tags. Instead, the developer provides information on some lower-level API that the client infrastructure invokes and then transforms into a ComponentModel. The sample code above, for example, will invoke the com.myco.MyService.getMyObjects(myArgument) method, take the results, and turn these into a ComponentModel object.
8-6
The construction of a ComponentModel doesn't happen in the servlet container, but instead in the method server. During the execution of the get tags, the flow of execution leaves the servlet container and jumps over to the method server. On the method server, the client infrastructure runs through several phases to create the ComponentModel. The step of most interest to developers is the invocation of Data Utilities, which are delegates that allow developers to post-process and/or augment the data returned by the low-level data acquisition API.
Rendering
This phase produces HTML and JavaScript based on the model data. Rendering is usually the simplest phase for the developer to set up. The client infrastructure provides a few render tags that take the ComponentModel produced by a get tag and turns it into HTML and JavaScript. Like the get tags, these tags uses the EL to accept scoped variable data from the page:
<jca:renderTable model="${tableModel}"/>
What is it doing?
In this case, the table renderer is taking an input ComponentModel assigned to the scoped variable "tableModel", and rendering it as a table.
8-7
Maintenance Messaging
The file codebase/netmarkets/jsp/util/begin_custom.jspf can also be used to add custom messages to the page for system maintenance or mass communication. The message will appear at the top of the page before the Windchill header is displayed.
Customization Points
codebase/netmarkets/jsp/util/begin_custom.jspf
8-8
TableUtils package
Name Purpose
getTableRows (parentNode)
Return array of Nmcontexts for each row in a table given the outer DIV DOM node. Return array of Nmcontexts for each row in a table given a table id Return array of Nmcontexts for each row in a table given the outer DIV DOM node. Given some DOM Element, walk up the DOM tree to figure out which table this is in. Given some DOM Element, walk up the DOM tree to find the table DOM Node. Gets the hidden input field that contains the added rows of a table id. Returns String that can be tokenized. Gets the hidden input field that contains the removed rows of a table id. Returns String that can be tokenized Walk up the Dom tree finding the first <tr> tag Remove a row from a table/tree returns true/false if the dom NODE is a row in the table with the class JCA_tablerow @param node - checkbox dom node
findTableID (node)
findParentTableNodeId (node)
getAddedRows (tableid)
getRemovedRows (tableid)
8-9
Name
Purpose
Invoked when a checkbox is clicked and it changes the row css so that it appears as highlighted. Get all the form nodes within the given parent node. If parentNode is unspecified, the entire document is searched. Disable all form inputs in the given row Updates row Count in Title bar. turns the outer div node id into a normal table id defined by the jsp tags table__jca.sometable__TABLE -> jca.sometable turns a div table id into the simple table id used as in the jsp tags table__jca.sometable__TABLE -> jca.sometable
getFormNodes (node)
getFormattedTableId (id)
Updates Count of selected rows in footer. Disables the select all checbox given a table id enables the select all checbox given a table id
TreeHandler
Name Purpose
toggle ()
The expand/Collapse function, Finds the current state of the row and changes it to the opposite. This may result in refreshing the page for legacy trees otherwise an ajax call is made to get new rows for the expand action.
8-10
Name
Purpose
Will collapse a row or expand the folder row by changing its icon. Param alist is a list of tree rows, if null it will be calculated from the page. It is faster to not lookup the list of tr nodes over and over. Param action - 'c' or 'e' for the action type
asyncResponseHandler
Name Purpose
Parses actions from an asynchronous response. Generic high level method that will delegate to all the types of responses. Gets rid of unwanted text from the response. Substrings out antying not inbetween the html comment. Can execute javascript blocks conditionally. Start/end are the html comment strings to use to find the response in.
rowHandler
Name Purpose
Add rows to a table. oidList is an array of oids to add as rows. Tablerows is an array of all current rows to improve performance of the api Params is extra params to add to the ajax request.
removeRowsFromParentTable
8-11
Name
Purpose
requestHandler
Name Purpose
Refreshes a table given the params Make the ajax request for the table. Used by the above method to change the url with the options set.
Returns all the children of the parentElement that match the given Tagname and contain the className. Optimized version of getElementsByClassname so that it does not have to look at all the items in the page. Refreshes the contents of a div (via Ajax) when an element fires its change event. Similar to Prototypes updater, performs an Ajax call (appears to ignore divID). Modifies the hidden form fields of tables used in wizards when users dynamically add rows to said table. Can cause the row to be added dynamically if the doAjaxUpdate is true. Refreshes the parent window. Family of methods for getting contents of the Clipboard as a comma delimited list.
getElementHtml(params, divID, doAsynch, url) addRows( list, tableId, refresh, doAjaxUpdate, preventDuplicates )
8-12
Wizard.js functions
Name Purpose
Make the ajax request for the table. Used by the above method to change the url with the options set. Add request params to the options based on the params list passed in. Adds all this form params to the ajax request including the params passed in. Updates the wizard step indicator images for all steps based on the current state. Updates the embedded help based on the current step. Gets the next step id. Sets the next step in the wizard to be refreshed when displayed. Make the wizard go back one step Make the wizard go to the next step Makes a specific step active. wizardAction is an optional parameter. It indicates if the user is attempting to go back or forward in the wizard.
updateStepImage
Find the index of a step id Override what the next step id is Set a step to need a refresh should it display again Set a step to NOT need a refresh should it display again
8-13
Name
Purpose
Set a step to need to be vistited again as it needs more info Set a step to NOT need to be vistited again as it does not needs more info Make a user visit a step before the wizard can be completed Make a user able to complete the wizard WITHOUT visiting the specified step id Remove a step from the list of steps Add a new step to the list of steps based on what has already happened dynamic steps Sets the ok button to be displayed or not based on the current state. Sets the next/back button to be displayed or not based on the current state. Force the finish and apply buttons to be disabled Force the finish and apply buttons to be enabled Gets the current active step id Refreshes the current wizard step Refreshes the speicified wizard step This function takes a url and turns it into an absolute URL. Turns on the progress indicator Turns off the progress indicator Finish the wizard by executing it on the server
removeStep insertStep
resetOkButton resetNextBackButton
8-14
Name
Purpose
handleSubmitResult
Handles the response of the wizard submission, the response is mostly a form result string object that tells the browser what to do. Not quite jSON yet though. To do Ajax validation when an action is clicked. The event object. The key to use in validation code
checkRequired (skipErrorMsg)
Grabs every input that is styled as 'required' and checks to make sure it has a value. If any required fields do not have values, the field in question is highlighted and an alert message is displayed. This function returns a boolean that is true if the required fields are entered and false if any required field is not filled in. @param skipErrorMsg can be used to suppress the alert message
8-15
8-16
9
Generic UI Customizations
This chapter describes user interface customizations that are independent of any particular Windchill client technology. Topic Page
Handling Icons for Business Objects ..................................................................9-2 Defining Localizable Text for the UI ..................................................................9-3 Customizing the Handling of Soft Attributes......................................................9-6 Customizing Role-Based UI Functions - Attribute Visibility .............................9-8 Customizing Role-Based UI Functions - Action Visibility...............................9-17 Preferences ........................................................................................................9-18 Constructing URLs............................................................................................9-24 Offline Package Customization.........................................................................9-27 System Banner Alert Message ..........................................................................9-32
9-1
These paths must be fully qualified from the Windchill codebase. The location for all .gif images at this time is wt/clients/image. The gif image specified must be 16 by 16 pixels. Class inheritance determines what glyphs are overlaid on an object: Subclasses of wt.doc.Document are displayed based on their primary format and will also inherit the overlays of RevisionControlled.
wt.clients.util.IconCache is the class that clients use to access icons. An example of its usage follows:
IconCache icons = new IconCache( someWTContextObj ); Image img = icons.getStandardIcon( someWTObject ); Image img2 = icons.getOpenIcon( someWTObject );
Any subclass of wt.fc.WTObject is accepted as an argument. See this class entry in your installed Windchill Javadoc for more information.
9-2
Generic UI Customizations
9-3
infoReport wt.part.WTPart
b. Inspect the current getDisplayName() values for the WTPart class and its locker attribute:
getDisplayName() getDisplayName() : Part : Locked By
WTPart locker
WTPart.Value Lock.locker.value
2. Add the customization entries to the appropriate ResourceInfo customizations files: a. Add the following entry to <Windchill>/wtCustom/wt/part/partModelRB.rbInfo (create this file if it does not exist):
WTPart.value=Windchill Part
b. Add the following entry to <Windchill>/wtCustom/wt/locks/locksModelRB.rbInfo (create this file if it does not exist):
Lock.locker.value=Lock Held By
3. Build the runtime resource bundles for the customized packages by entering the following commands:
ResourceBuild wt.part.partModelRB ResourceBuild wt.locks.locksModelRB
4. Verify the customizations: a. Obtain an info report for the class and inspect the getDisplayName() values as described in the preceding steps. The values should reflect the customizations. b. If the info report values are unchanged, perform the following steps: i. Verify that the build step actually updated the following serialized resource bundle file:
9-4
<Windchill>/codebase/wt/part/partModelRB.RB.ser
To support other locales, make locale-specific copies of the files and add the localized values, as in step 2 above. For further information on localizing resource entries, see the Internationalization and Localization chapter on page 39-1.
Generic UI Customizations
9-5
Format of AllClients.xml
The format of elements in AllClients.xml is as follows:
<LogicRepository> <ElementGroup> <LogicContext dataType="<object type>"/> <ObjectAttributes id="ObjectAttributes"> <AttributeEditField id="IBA|<attribute logical form name>" showDefaultValue="true|false" inputFieldType="singleLine|multiLine"/> ... </ObjectAttributes> </ElementGroup> ... </LogicRepository>
Multiple ElementGroup tags may be included in AllClients.xml. All ElementGroup tags must be placed between the beginning and ending LogicRepository tags in this file. Each ElementGroup tag includes a LogicContext tag and an ObjectAttributes tag. The LogicContext tag indicates the object type of an ElementGroup. The behavior of all the attributes included in the ElementGroup applies to this object type. The dataType attribute of the LogicContext tag may refer to a soft type or a modeled type. To refer to a soft type use the hierarchical path name for the type, with each element separated by a '|' character. For example, to configure attributes for the soft type "com.MyCompany.www.MyPart" that is derived from WTPart you would specify:
<LogicContext dataType="wt.part.WTPart|com.MyCompany.www.MyPart"/>
9-6
To refer to a soft type "com.MyCompany.www.ABCPart" that is derived from "MyPart" you might specify:
<LogicContext dataType="wt.part.WTPart|com.MyCompany.www.MyPart|com.MyCompany.www.ABCPart"/>
An example reference for a custom modeled subclass of WTPart called ext.part.MyModeledPart is:
<LogicContext dataType="ext.part.MyModeledPart"/>
Note: The LogicContext tag, as defined by LogicRepository.dtd, also includes an optional application attribute. The application attribute is not used for elements in AllClients.xml. The ObjectAttributes tag may include multiple AttributeEditField tags. Include an AttributeEditField tag for each attribute you wish to configure. These tags are described in <Windchill>/codebase/config/dtd/AllClients.dtd. In the id attribute of the AttributeEditField element, modeled attributes are identified by the prefix "MBA" and soft attributes by the prefix "IBA". An AttributeEditField tag may include either a showDefaultValue attribute or an inputFieldType attribute or both. The inputFieldType attribute will be ignored if the attribute is not a string. If no AttributeEditField tag is provided for an attribute its presentation is as follows: 1. Use Default Button - Will be presented if the attribute has a default or initial value, is editable, and has not yet been set in the database. 2. Input Field Type - Will be determined according to the value of the StringLengthThresholdForMultilineInput preference.
Example
An example ElementGroup to configure three soft attributes for the modeled base type wt.part.WTPart is as follows:
<ElementGroup> <LogicContext dataType="wt.part.WTPart"/> <ObjectAttributes id="ObjectAttributes"> <AttributeEditField id="IBA|MyBooleanAttribute" showDefaultValue="false" /> <AttributeEditField id="IBA|MyStringAttribute" showDefaultValue="false" inputFieldType="singleLine"/> <AttributeEditField id="IBA|MyStringAttribute2" inputFieldType="multiLine"/> </ObjectAttributes> </ElementGroup>
Generic UI Customizations
9-7
Background
The role-based UI functionality enables administrators to optimize the number of actions presented to users, so as not to confuse users by seeing actions they dont need or use for their role. Initially this support was just for container managers (in particular, project managers). It has been extended to a concept called profiles which sets action visibility at the site or organization level. A site administrator, organization administrator or container administrator can specify which users have visibility to the actions defined. For site and organization administrators this can be done through profiles. Profiles can be created at Site->Profiles or Org->Profiles. The actions defined will be presented with their default settings, and the administrator can choose to hide those actions. The administrator can then specify which participants (users, groups, orgs) belong to the profile. All members of the profile will have that visibility. If a member is in multiple profiles, the greatest visibility is provided. At the container level, the administrator can specify the visibility based on user roles. Anyone in those roles will have the visibility specified. Container-level role visibility will override any profile in which the member might be a participant. See the Windchill Business Administrators Guide for more details about profile and role-based visibility administration.
Scope/Applicability/Assumptions
The role-based visibility administration capability is turned on, that is, the preference com.ptc.netmarkets.roleAccess.enabled is set to true. The customization can be performed while the capability is turned off, but the results will not appear in the UI until the capability is turned on. The customizer can manage both OOTB UI components and customized UI components with this capability.
Intended Outcome
When configuring visibility by roles and configuring profiles, the administrator is presented with a list of UI components that can be managed. The administrator is unable to manage the visibility for any UI components that are not included in this list. As a customizer, you have the ability to customize the list of UI components available to administrators. You can:
9-8
add UI components to the list, remove UI components from the list, specify default visibility settings for UI components, change the order that UI components appear in the list, and change the labels for the UI components on the list.
At the site or organization level your intention is to manage the list presented when creating profiles:
Generic UI Customizations
9-9
At the container level, you are managing the equivalent list presented when configuring visibility by roles:
Solution
Modify the roleaccessprefs.xml file (and associated files as needed).
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: The behavior of user roles in Windchill The administration of ad hoc access control policies in Windchill The actions framework in the Windchill client architecture
9-10
The navigation framework in the Windchill client architecture The management of XML file customizations The management of RBINFO file customizations
Note: The Additional Resources section below includes references to many or all of these subjects.
Solution Elements
Element *actionModels.xml Type XML Description Files which define the models where actions are used. If an action is not already defined in a model, one will need to be created for the validation code to find the action and properly set visibility. actionmodels.xml is located in <Windchill>/codebase; other *actionmodels.xml files are generally in <Windchill>/codebase/config/actions Files where actions and other UI components are defined. Actions are optionally given a uicomponent value. actions.xml is located in <Windchill>/codebase; other *actions.xml files are generally in <Windchill>/codebase/config/actions. roleaccessprefs.xml XML File for assigning default visibility to UI components. Setting items in this file can make them not appear at all for the site or containers. Whether or not the container manager can override the default value can also be changed here. Located in <Windchill>/codebase. roleAccessResource.rbInfo RBINFO Defines the labels to provide in the Uis for the actions or UI components. Located in <Windchill>/wtCustom/com/ptc/netmarkets/roleAccess/.
*actions.xml
XML
In actions.xml (and all *actions.xml files), an action can be assigned a uicomponent attribute value. The uicomponent attribute provides a name for a UI component that can be referenced from the roleaccessprefs.xml and roleAccessResource.rbInfo files. Multiple actions can use the same uicomponent value; this provides the ability to manage those actions as a single UI component. If an action does not have a uicomponent, then the action name can be used to reference it as a UI component instead. However, in this case it cannot be grouped with other actions into a single UI component. The roleaccessprefs.xml file consists of a <uics> element containing several elements (or sections) that correspond to the primary tabs in the Windchill user interface. For example, the <project> section corresponds to the Project tab. Each
Generic UI Customizations
9-11
section contains zero or more <uic> elements, each representing a UI component whose visibility within that tab can be administered. Each UI component, specified with the name attribute of the <uic> element, can appear in one or more sections. This allows the default visibility settings for that UI component to be assigned independently for different tabs. The roleaccessprefs.xml file applies to the UI component lists for visibility administration based both on profiles (at the site and organization levels) and on roles (at the container levels). However, the <global> section applies only to visibility administration using profiles. If a UI component is not tied to a specific tab (such as is the case with the Search link in the Windchill UI header) or the UI component is a first-level tab itself, it should be listed in the <global> section of roleaccessprefs.xml. Each UI component must have an entry in roleAccessResource.rbInfo that provides a user-friendly label for that UI component. These labels are used for the UI components in the lists that are presented to the administrator when configuring visibility. In this file the resource entry constant identifies the UI component; it must match either the uicomponent from the action definition or the action name if the action has no uicomponent. The resource entry value provides the user-friendly label. Note: Your UI component label should be a verb phrase. If your action/UI component name is not already a verb phrase, place View in front, for example View Team Page.
Note: See the section on the uic element below for attribute descriptions. Note: For actions that are valid for multiple tab types, put the entry under all the sections you want it to affect. 2. In roleAccessResource.rbInfo, add a new resource entry for the action display name:
9-12
Regenerate your bundles. The name of the uic should be the same as the constant for the entry in the resource bundle. 3. In <Windchill>/codebase/actions.xml, modify the create folder action by: adding the attribute uicomponent=PROJECT_CREATE_FOLDERS
<action name= folder_create checkaccess=true uicomponent=PROJECT_CREATE_FOLDERS>
Caution: Follow best practices in backing up your XML files when customizing them. 4. Restart the servlet engine and the method server. Steps 1 through 3 above can be performed in any order. Note that PROJECT_CREATE_FOLDERS is used for the uic name, the resource entry constant (but without the quotes), and the action uicomponent. It is necessary for all three of these items to share the same value in order to tie the customized behavior together. Upon completion of this procedure, an administrator can now configure the visibility to the Create Folder action under the Project, Program, Product, and Library tabs, based on profiles defined at the site or organization level, and based on roles at the container level.
Parameter name
Req? Y
Description The name of the UI component. This must match the value of the uicomponent (or name) attribute on an action element in actions.xml. This must also match the value of a resource entry constant in the resource bundle. The position of this UI component in the wizard. UI components with lower numbers are placed before those with higher numbers.
order
n/a
Integer
Generic UI Customizations
9-13
Parameter enabled
Req? N
Description Whether or not this uicomponent will be shown in the wizard and utilized by the system. The default visibility value for All Members. The default visibility value for Project Managers. Note: The permissions are a union of all permissions across all roles; if you set defaultManager to false; you should also defaultAll to false, otherwise managers will still have access through the ALL_MEMBERS role.
defaultAll defaultManager
true true
N N
defaultGuest
true
true | false
The default visibility value for people in the Guest role. Note: Guests are not technically members of the Project; they are not unioned with the ALL_MEMBERS role.
managerEnabled
true
true | false
Whether or not this uicomponent can affect the manager role. Do not change this value in out-of-the-box UICs. For customized UICs, you may choose your own setting. Whether or not this uicomponent can affect the guest role. Do not change this value in out-of-the-box UICs. For customized UICs, you may choose your own setting.
guestEnabled
true
true | false
9-14
3. Add a new entry to roleAccessResource.rbInfo with a constant that is the same as the uic name. The value is what will be displayed in the profile actions UI.
40.value=View Customized Tab 40.constant=CUSTOMIZED_TAB
Regenerate your bundles. 4. Restart the servlet engine and the MethodServer.
As a result, the Create Folders entry in the Configure Roles and Create Profile pages will affect the visibility for both folder_create and list_create_folder actions.
Generic UI Customizations
9-15
9-16
Generic UI Customizations
9-17
Preferences
The Preferences Framework is based on the principle that a unique preference consists of the following attributes: Parent Node (or root node if at the top of the hierarchy) Preference Node (usually associated as a group of similar preferences) Preference Key
Together these attributes form a unique key structure of parent/node/key. This unique key structure will be referred to as the fully qualified preference key. To separate individual user and group preferences for the same fully qualified preference key, a context is applied to the preference. The context consists of the following elements: Macro a constant defining the type of context (see below) (optionally) Descriptor text defining the name of the context. These elements are placed together with a : to form the Preference Context. The fully qualified preference key when placed together with a context will form a unique row in the database table, allowing users, and other divisions to have individual preferences.
Preference Macros
The wt.prefs.WTPreferences class defines the following types of Preference Context Macros: USER_CONTEXT - the context for individual users DEFAULT_CONTEXT - the context for the system default (shipping) values CONTAINER_CONTEXT - a context used in the container hierarchy CONTAINER_POLICY_CONTEXT - a container context that is enforced as a policy DIVISION_CONTEXT - the context used for any scopes defined in addition to the default, container, and user scopes DIVISION_POLICY_CONTEXT - a division context that is enforced as a policy
9-18
division scope called Windchill Enterprise, and the out-of-the-box wt.prefs.delegates.DelegateOrder property value is: $DEFAULT,$CONTAINER,$DIVISION:WindchillEnterprise,$USER In this value, there is no DIVISION_POLICY_CONTEXT defined since DIVISION_POLICY_CONTEXT and DIVISION_CONTEXT are related and are at the same level in the preference hierarchy. Similarly, the CONTAINER_POLICY_CONTEXT need not be included. Entries are designated differently only when storing and retrieving preferences internally. For more details on correctly naming delegates, see the delegates.properties file. If wt.prefs.delegates.DelegateOrder has been removed from the delegates.properties file, Windchill uses the following: $DEFAULT,$CONTAINER,$USERSetting Preferences Edit the file Windchill/loadFiles/preferences.txt. This file is used to put the system values into the database. Note that you dont put quotes around the strings unless you actually want quotes persisted as part of the preference. Syntax:
PrefEntry~keyName~default value~fullyQualifiedNodePath
Example:
PrefEntry~fileOperationType~ASK~/wt/content
Getting Preferences
You can get a preference by first navigating the preferences tree to the proper node, then setting the context for that particular user, then getting the value for that key. Example:
// returns an instance of the top node in the Windchill preference "tree" Preferences root = WTPreferences.root(); // returns the preference node at that path Preferences myPrefs = root.node( "/wt/content" ); ((WTPreferences)myPrefs).setContextMask (PreferenceHelper.createContextMask() ); // get( ), gets the value for that // preference key String prefValue = myPrefs.get( "fileOperationType", "SAVE" );
Clearing a Preference
There is a big difference between "clear" and "remove". Assuming there are no division-level defaults or policies, if you "clear" a user preference by setting the value to be the empty string "", then the value returned will be ""; but if you "remove" the user-level preference, then the value returned would be system
Generic UI Customizations
9-19
default value. In most cases you will want to remove the user-level preference and not clear it, giving the user the upper hierarchical preference as their default. Example:
Preferences root = WTPreferences.root(); Preferences myPrefs = root.node( "/wt/content" ); ((WTPreferences)myPrefs).setEditContext (PreferenceHelper.createEditMask()); ((WTPreferences)myPrefs).setContextMask (PreferenceHelper.createContextMask()); String prevValue = myPrefs.remove("fileOperationType");
Preference Registry
The preference registry is a way to take a cryptic name like a preference and provide a localized series of data about it. This registry is in the form of rbInfo files. Anyone adding preferences to the system will have the option of adding this localized information to the Preference Registry.
Where /node-name is the name of the node (for example /wt/workflow), /keyname is the name of the key under the node (SortOrder) and % [ ]tag is one of the tags mentioned above (% [ ]DISPLAY_NAME).
Creating a Preference
The creation of a preference is done through an XML load file. When creating a preference the following pieces of information need to be determined: Unique preference name Visibility: if the preference will appear in the preference manger UI and visible at what contexts: SITE, ORGANIZATION, CONTAINER or USER. Preference category: The category the new preference will appear under in the Preference Manager UI. Display name: This is the Name column in the Preference Manager UI string in the form <RBINFO>:< RBINFO key>
9-20
Description: This is the Description column in the Preference Manager UI string in the form : <RBINFO>:<RBINFO key>
Long Description: This description is displayed in the Edit Preference UI, gives a more detailed description including the expected values. string in the form <RBINFO>:<RBINFO key>
In the example below, we will create a new preference named /com/mycompany/MyNewPreference along with an associated preference category to appear in the Preference Manager UI. 1. Create a resource bundle for labels used for your new preference. Labels are needed for display name and description of preference category which the new preference will be visible under in Preference Manager UI. Labels are also needed for the display name, description and long description of your preference. Create the file mycompanyPreferenceResource.rbInfo in package com.mycompany.pref. In this example, this file would be added to the <Windchill>/src/mycompany/pref directory.
ResourceInfo.class=wt.tools.resource.StringResourceInfo ResourceInfo.customizable=true ResourceInfo.deprecated=false # Preference Category labels MyNewPreferenceCategory.displayName.value=My Preference Category MyNewPreferenceCategory.description.value=Preference Category for my custom preferences. # Preference Definition labels MyNewPreference.displayName.value=Display name of preference /com/mycompany/MyNewPreference MyNewPreference.description.value=Description of preference /com/mycompany/MyNewPreference. MyNewPreference.longDescription.value=Long description of preference /com/mycompany/MyNewPreference.
2. Build the resource bundle by executing the following command from a windchill shell:
ResourceBuild com.mycompany.pref.mycompanyPreferenceResource
3. Restart the servlet engine and the MethodServer. 4. Create Preference load file: createMyNewPreference.xml. It will contain a definition for the new preference category and new preference definition.
<?xml version="1.0"?><!DOCTYPE NmLoader SYSTEM "standardX10.dtd">
Generic UI Customizations
9-21
<NmLoader> <csvPreferenceCategory handler="wt.preference.LoadPreference.createPreferenceCategory" > <csvname>CUSTOM_PREFERENCE_CATEGORY</csvname> <csvparentName></csvparentName> <csvdisplayName> com.mycompany.pref.mycompanyPreferenceResource:MyNewPreferenceC ategory.displayName </csvdisplayName> <csvdescription> com.mycompany.pref.mycompanyPreferenceResource:MyNewPreferenceC ategory.description </csvdescription> </csvPreferenceCategory> <csvPreferenceDefinition handler="wt.preference.LoadPreference.createPreferenceDefinitio n"> <csvname>/com/mycompany/MyNewPreference</csvname> <csvvisibility>USER</csvvisibility> <csvcategoryName>CUSTOM_PREFERENCE_CATEGORY</csvcategoryName> <csvdisplayName>com.mycompany.pref.mycompanyPreferenceResource: MyNewPreference.displayName</csvdisplayName> <csvdescription>com.mycompany.pref.mycompanyPreferenceResource: MyNewPreference.description</csvdescription> <csvlongDescription>com.mycompany.pref.mycompanyPreferenceResou rce:MyNewPreference.longDescription</csvlongDescription> <csvdefaultValue>Default Value</csvdefaultValue> <csvhandler>com.ptc.windchill.enterprise.preference.handler.Str ingPreferenceValueHandler:4000</csvhandler> </csvPreferenceDefinition> <csvLinkPreferenceClientDefinition handler="wt.preference.LoadPreference.setClientDefinitionLink"> <csvname>/com/mycompany/MyNewPreference</csvname> <csvclientName>WINDCHILL</csvclientName> </csvLinkPreferenceClientDefinition> </NmLoader>
5. Load the preference category and preference definition using the following command:
windchill wt.load.LoadFromFile -d <full path>/createMyNewPreference.xml
9-22
Deleting a Preference
The deletion of a preference is also done through the use of an XML load file. Using the example from the Creating a Preference section on page 9-20, we will delete the preference /com/mycompany/MyNewPreference. The deletion of the preference will also remove any preference instances which may have been set for this preference in the UI. 1. Create an XML file, deleteMyNewPreference.xml, containing the following
definition to specify the deletion of the preference.
<?xml version="1.0"?><!DOCTYPE NmLoader SYSTEM "standardX10.dtd"> <NmLoader> <csvDeletePreferenceDefinition handler="wt.preference.LoadPreference.deletePreferenceDefinitio n"> <csvname>/com/mycompany/MyNewPreference</csvname> </csvDeletePreferenceDefinition> </NmLoader>
Generic UI Customizations
9-23
Constructing URLs
The URLFactory
The URLFactory is a utility class provided to generate relative HREFs and support the Windchill Single-Point-Of-Contact (SPOC) environment. The URLFactory has been designed to take in a web-resource at a particular state in the Windchill system (from a certain request, host etc.) and generate an appropriate String HREF or URL object corresponding to that resource. The URLFactory was introduced in Release 6.0 to replace the functionality provided by GatewayURL, as GatewayURL has a number of significant limitations in its implementation. The URLFactory is an instance-based toolkit which may be used in either Java code directly, JSP Pages or HTML templates. For Java code directly, there are two constructors defined as can be seen in the Javadoc. The most commonly utilized one will be:
URLFactory aURLFactory = new URLFactory( );
This will utilize the current servers codebase and properties for HREF construction.
If writing a helper class, the GatewayServletHelper provides a good basis for developing further helper classes. Helper classes should not be extended but implemented on a package or servlet specific level and if possible should be declared final for JIT (just-in-time) compilation and optimization.
9-24
may be utilized for the desired resource. Relative links will automatically be returned if the RequestURI is set, and the desired resource can be resolved into a relative link (for example an external link to another site will always be returned as an external link).
Currently there is no functionality in the mapping scheme to map a particular file type to an alternate location/hostname. In future releases of Windchill this may be addressed if there is a need for this capability.
Generic UI Customizations
9-25
For Windchill Development, the mapping scheme should NOT be used to map any components of the core Windchill. This capability has been added to support multiple customer requirements, and should not be utilized as a way to make classes/documents of Windchill re-direct to other classes/documents. The mapping file may be used during development to remap to a new prototype or program, however proper HREFs should be implemented in any relevant files before the program is placed into production. There is a performance decrease using the URLFactory, and it should only be used to support customizations.
9-26
Background
Offline packages exported from Windchill are zip files containing the exported files. Along with the exported content, an offline viewer is provided which allows users to browse the contents in their web browser. By default, offline packages exported from Windchill display the Windchill logo and brand in the header of the offline view. This document describes how to update certain files on your installation server to have the exported packages display your companys brand identity.
Scope/Applicability/Assumptions
Utilizing this solution will change the format of all packages exported from the server. It will affect all users and organizations that make packages from that server.
Intended Outcome
The offline view in exported packages display updated brand identity information for your company.
Solution
Update the CSS in the static resources zip file to style the header of the offline view.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Cascading Style Sheets. This guide assumes a good knowledge of how to specify and write new CSS styles, without going into the specifics of how to write correct CSS. Knowledge and access to the Brand Identity standards for your company.
Generic UI Customizations
9-27
Solution Elements
Element
Type
Description
resources.zip
Zip file
This zip file contains the static elements provided in the resources folder in every package generated from the installation server. This file is located in the %WT_HOME%\codebase\com\ptc\netmarkets\wp\ ixb directory of your server. Contained within the resources.zip file, this CSS style sheet contains the rules which control the look and feel of the offline view. The HTML file which is loaded at the top of every page. The background image of the header Transparent GIF of the Windchill logo.
wpofflinestyles.css
9-28
9. Once you are satisfied with the look of the header, update the resources.zip file with the updated resources folder and files from your working folder. Make sure the file paths are correct inside the zip file all files should have the path resources\. 10. Test to be sure packages are generated correctly by making some experimental packages from the running server and viewing them offline.
Customization Points
CSS rule
Default Value
Description
.pageHeader
Dark teal background with Windchill background image (header.gif) and a dark green bottom border. logoWC.gif Height: 55 pixels.
.wncApplLogo .applLogo
Defines logo graphics file. Defines the height of the logo div, normally shown in the upper left corner of the page. Defines the style of links and text normally in the upper right corner of the page. Links can be added to this div.
Delivered empty
Limitations
Updating the resources.zip file in this manner affects every offline package created by the system. It is not currently possible to apply these changes to one package and not to another. Modification of packages after they are created is not possible on the server.
Generic UI Customizations
9-29
WorkPackage CDRLPackage
Change Objects WTVariance WTChangeRequest2 WTAnalysisActivity WTChangeInvestigation WTChangeProposal PromotionNotice WTChangeActivity2 WTChangeDirective WTChangeIssue WTChangeOrder2 ChangeAction AuthorizationAgreement
9-30
Sample Code
.pageHeader { border-bottom: 1px solid #20313d; background-image: url(header.gif); background-color: #40637A; background-repeat: no-repeat; } .wncApplLogo { background-image: url(logoWC.gif); } .applLogo { background-repeat: no-repeat; height: 55px; background-position:34px;}
Generic UI Customizations
9-31
2. Restart Tomcat.
9-32
Generic UI Customizations
9-33
9-34
10
Customizing HTML Clients Using the Windchill JSP Framework
This chapter explains and give some basic overview of the Windchill Client Architecture UI Framework. Before reading this chapter, you should be familiar with Java, JavaServer Pages (JSP), JavaServer Pages Standard Tag Library (JSTL) and Expression Language (EL). Topic Page
Customizing Generic Aspects of JSP Pages......................................................10-2 Customizing UI Branding .................................................................................10-2 Customizing the UI with Ajax...........................................................................10-4 Checkin/Checkout .............................................................................................10-8 Component Access Control.............................................................................10-11 Attachments.....................................................................................................10-16 Property Panel .................................................................................................10-26 Customizing Access Control For Packages.....................................................10-33 Generating HTML Tags for ProductView Visualization Within a JSP Page .10-37 Tools Overview ...............................................................................................10-40 Adding Validation Logic for Actions and Properties......................................10-51
10-1
Customizing UI Branding
This section describes how to make changes to certain generic items that appear on JSP pages such as logos, site-specific information in headers and footers, and generic error messages. Note: In making changes to .rbInfo files and image files, be sure to follow the coding practices introduced in the Resource Info (.rbInfo) Files section in the Internationalization and Localization on page 39-8. Caution: Do not change any <key>.constant entries in the .rbInfo files, change only <key>.value entries. Setup: It is necessary to have an internationalized Java SDK installed so that the classes can be compiled.
1. Modify <Windchill>/src/com/ptc/netmarkets/netmarkets/netmarketsResource.rbInfo (and/or any of the other language versions) in a text editor. Change entry 0 Old
0.value=Welcome to Windchill ProjectLink,
New
0.value=<Your welcome message>
2. Modify <Windchill>/src/com/ptc/netmarkets/util/utilResource.rbInfo (and/or any of the other language versions) in a text editor. Change entries 4,5,14,15. There are a few other candidates in this file if one was to make a total conversion. Old
4.value=Powered by <A HREF=http:// www.ptc.com/products/windchill/index.htm>Windchill</a> <sup>®</sup> 5.value=About Windchill ProjectLink 14.value=Windchill ProjectLink Error 15.value=Windchill ProjectLink Error
New
4.value=<your powered by>
10-2
5.value=<your about label> 14.value=<your generic error text> 15.value=<your generic error text>
4. Change the icons: Replace <Windchill>/codebase/netmarkets/images/ptclogo.gif with a different image Replace <Windchill>/codebase/netmarkets/images/linklogo.gif with a different image 5. Change the <Windchill>/codebase/presentation.properties Change all of the following to appropriate values. It affects the title on the browser, the cssFiles could be used to plug in more style sheets without replacing the current one:
netmarkets.presentation.website=http\://www.ptc.com netmarkets.presentation.author=PTC netmarkets.presentation.cssFiles=
The colors of JSP clients are derived primarily from the style sheet <Windchill>/codebase/netmarkets/css/nmstyles.css. See the style sheet for more information.
Logos
To override the logo, add a custom css file that overrides the logo styles:
/**** Application Logos for the header area */ .applLogo {background-repeat: no-repeat; height: 55px; background-position:34px;} .wncApplLogo {background-image: url(../../netmarkets/images/logoWC.gif);} .pjlApplLogo {background-image: url(../../netmarkets/images/logoPJL.gif);} .pdmlApplLogo {background-image: url(../../netmarkets/images/logoPDML.gif);} .proIApplLogo {background-image: url(../../netmarkets/images/logoPROI.gif);} .atcmApplLogo {background-image: url(../../netmarkets/images/logoATCM.gif);} /****/
10-3
Background
To make the Windchill product faster and more scalable, it is necessary to use some Ajax based operations to cut down on the refresh times of pages. All actions should be Ajax based where possible. The only actions that should not be Ajax based are those that update the majority of the page like most of the rows of a table. Ajax actions only update the row of the table, or refresh the whole table, that the action was invoked on. The rest of the page and table are unchanged when the action is complete.
Scope/Applicability/Assumptions
Assume you have an action that updates an object and refreshes the parent page when complete and an action that updates all the rows of a table.
Intended Outcome
The result of applying this pattern is that instead of the page refreshing, the row is updated in-line and highlighted in yellow in the first case, and the second case the table fades out and refreshes itself without refreshing the rest of the tables and navigation on the page.
Solution
Specify some Ajax based configuration and code in the action to allow the Ajax refresh to work.
10-4
Solution Elements
Element <your actions>.xml <your>formProcessor.java <your wizard step>.jsp Type XML Java Jsp Description Xml file that contains the action definitions Delegate that performs the db transaction Jsp to partially refresh in a wizard
In the <your>formProcessor.java file, override the setResultNextAction method to return some dynamic refresh Info:
protected FormResult setResultNextAction(FormResult result, NmCommandBean cb) throws WTException{ DynamicRefreshInfo di = new DynamicRefreshInfo(newOid,oid,NmCommandBean.DYNAMIC_UPD) ; result.addDynamicRefreshInfo(di); result.setNextAction(FormResultAction.REFRESH_OPENER); return result; }
Many examples exist, search actions.xml for ajax=row or the processors for the addDynamicrefreshInfo.
10-5
Finally you should have this javascript block in your JSP that need to be refreshed.
<script type=text/javascript> refreshDivTag ('id of div tag', 'id of object to listen to event on', 'url to the page'); </script>
Example:
refreshDivTag ('sourceContextDropDown', 'myContextPicker', '/netmarkets/jsp/folder/sourceFoldersDropDown.jsp');
Examples: codebase\netmarkets\jsp\folder\sourceFoldersDropDown.jsp
Sample Code
Examples of usage in out-of-the-box code.
Packaged samples
Picture of part 1 of the interaction when a popup action dynamically updates the page. The popup action is completed and calls to refresh the opener window.
10-6
Picture of interaction when a popup action dynamically updates the page when a dynamic popup action completes.
10-7
Checkin/Checkout
Objective
You want to be able to checkin and checkout an object.
Background
The ability to check in and checkout gives the ability to track changes to an object by providing an iteration history of each change. Also if a user has an object checked out, no other user may modify the object until it has been checked back in. In order for an object to work with the checkin/checkout common component it must implement the wt.vc.wip.Workable interface.
Scope/Applicability/Assumptions
The object implements either the Workable interface. Familiarity with the actions framework Familiarity with the basic concepts of checkin/checkout
Intended Outcome
By following these procedures you should be able to add or modify the checkin and checkout actions. Checkout action (no wizard involved)
10-8
Checkin wizard (in this case with primary content but the primary attachment component will not appear if your object does not support it).
Solution
Use the Checkin/Checkout common components with your object.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Windchill work in progress checkin/checkout concepts. The actions framework in the Windchill client architecture. Basic development involving HTML forms, JSP, and XML.
10-9
edit actions for your object. Note, only add checkout & download and replace content actions if you are adding these actions for an object that implements the FormatContentHolder interface and you expect it may have primary content.
<action name="checkin" <action name="checkout" <action name="checkout_and_download" <action name="undocheckout" <action name="replace_content" <action name=" checkoutAndEdit " YOUR TYPES ACTIONS XML"/> type="wip"/> type="object"/> type="wip"/> type="object"/> type="wip"/> type="YOUR TYPE FROM
Checkout and edit however requires additional coding. Create an additional action definition in the actions.xml file for your object type. Name the action checkoutAndEdit so that the validation framework will pick it up properly. Then set the url attribute to point to your wizards edit jsp file. Example:
<action name="checkoutAndEdit"> <command class="com.ptc.core.components.forms.EditObjectFormProcessor" method="execute" url="netmarkets/jsp/document/edit.jsp" windowType="popup" /> </action>
Add the appropriate entries for this action in your rbinfo file (see actions framework documentation). In your edit jsp file you will need to add the following tag above the wizard declaration.
<%@ taglib prefix="wip" uri="http://www.ptc.com/windchill/taglib/workinprogress"%> <wip:autoCheckOutItem />
This will allow the wizard to checkout the object if the object is not already checked out. Caution: Using this tag on wizards other then edit or without a processor that is extending EditObjectFormProcessor is not supported and may result in unstable code.
10-10
Background
The Common Access Control Component was developed to provide a consistent interface for Windchill ProjectLink and Windchill PDMLink users to view and manipulate access control permissions on individual Windchill objects. The feature is available in the out of the box Security Clerk through the Manage Security action and also in the Create Document and Create Part wizards. This feature for individual object instances is implemented using ad hoc ACLS. The access component for a folder also has the additional capability of defining permissions and propagating them throughout the folder contents. Preferences are supported to permit sites to tailor the visibility and updatability of individual access control permissions to meet their specific access control requirements.
Scope/Applicability/Assumptions
This feature only applies to objects that implement the wt.access.AdHocControlled interface. The AdHocControlled interface holds information that controls access to a specific instance of an object class. The ad hoc ACL specifies only positive permissions. It cannot be used to deny access to an object. If the ad hoc ACL grants a permission that is denied in the policy ACL, the ad hoc rule supersedes the policy rule, and the access right is granted. The feature may be used in two ways: The Manage Security action can be added to the objects action model. The Access Control Component can be included as a step in the objects Create wizard.
Intended Outcome
Manage Security Action
When the Manage Security action is included in an objects action model, the action will available in the objects action list. Note: The visibility of the action may be constrained by profiles defined in the Role Based UI. See the Windchill Business Administrators Guide for more details about profile- and role-based visibility administration.
10-11
Create Wizard
When the component is included in an objects Create wizard it appears as an optional Access Control step in the create process. The Set Access Control step should be the highlighted step in the wizard at this point. It is not being correctly rendered in the current build.
Solution
Use the Access Control Component to provide an interface to view and manipulate access control on Ad Hoc controlled objects.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Windchill client architecture Basic development involving HTML forms, JSP, and tag libraries. The actions framework in the Windchill client architecture.
Solution Elements
Element
Type
Description
actionmodels.xml
XML
Windchill\codebase\actionmodels.xml The actionmodels file defines the actions available in named action models.
Create<myObject>.jsp
JSP
10-12
The initial state of the permission configuration can be modified by changing the csvdefaultValue for the permission entry. The possible values are HIDE, READ, and UPDATE.
10-13
The Manage Security is an action available in the action list on a document info page. The action is included in the docs details page actions action model defined in Windchill\codebase\actionmodels.xml
<!-- list used on document details page --> <model name="docs details page actions"> <action name="oldedit" type="document"/> <action name="download" type="document"/> <action name="route" type="workflow"/> <action name="setState" type="lifecycle"/> <action name="createSubscription" type="subscription"/> <action name="checkout" type="object"/> <action name="checkin" type="document"/> <action name="undocheckout" type="object"/> <action name="rollupIterations" type="object"/> <action name="update" type="document"/> <action name="rename" type="document"/> <action name="ManageSecurity" type="accessPermission"/> <action name="delete" type="object"/> <action name="bookmarkIt" type="bookmark"/> <action name="create_deli" type="deliverable"/> <action name="cut" type="object"/> <action name="copy" type="object"/> <action name="export" type="object"/> <action name="viewInProductView" type="document"/> <action name="pdmCheckInApply" type="object"/> <action name="SBSendToPdm" type="sandbox"/> <action name="sandboxUndoCheckoutDetails" type="object"/> <action name="removeShare" type="object"/> <action name="EDA_COMPARE" type="EDAcompare"/> <action name="VALIDATION_MANAGER" type="EDAcompare"/> <action name="SETUP_FILE" type="EDAcompare"/> <action name="wtObjCompare" type="ocmp"/> </model>
The Create Document wizard is an example of Access Control as a step in a create wizard. Source file: wcEnterprise\DocumentManagement\src_web\netmarkets\jsp\ document\create.jsp
<%@ taglib prefix="jca" uri="http://www.ptc.com/windchill/taglib/components" %> <%@ taglib prefix="docmgnt" uri="http://www.ptc.com/windchill/taglib/docmgnt" %> <%@ include file="/netmarkets/jsp/components/beginWizard.jspf"%>
10-14
<%@ include file="/netmarkets/jsp/components/includeWizBean.jspf"%> <jca:initializeItem operation="${createBean.create}"/> <docmgnt:validateNameJSTag/> <jca:wizard title="${param.titleString}"> <jca:wizardStep action="setContextWizStep" type="object"/> <jca:wizardStep action="defineItemWizStep" type="object"/> <jca:wizardStep action="setAttributesWizStep" type="object" /> <jca:wizardStep action="attachments_step" type="attachments" /> <jca:wizardStep action="setAccessControlWizStep" type="object"/> </jca:wizard> <jca:action actionName="fileSelectionAndUploadApplet" actionType="attachments" /> <script type="text/javascript"> setUserSubmitFunction(submitFileContent); </script> <%@ include file="/netmarkets/jsp/util/end.jspf"%>
10-15
Attachments
Objective
You want to add or modify the ability to add, modify, and download content from a format content holder or content holder business object
Background
The ability to add attachments to an object is the ability to upload and associate a file, link to a url, or describe an external location of content and associate that content data with this object. For example you may create a document and upload one or more files. You may also add multiple urls that point to additional information as supporting material for a change request. Object types such as documents implement an interface called FormatContentHolder which allows them to associate one piece of content as primary content. There can only be one primary content though. Object types such as a change requests implement ContentHolder which allow them to have multiple secondary content but not primary attachments. Objects that implement FormatContentHolder however can have both primary and secondary attachments because FormatContentHolder is a specialization of the ContentHolder interface.
Scope/Applicability/Assumptions
Assumptions: The wizard that is using the attachment components implements either the FormatContentHolder or the ContentHolder interfaces. The wizard is using the Windchill Client Architecture wizard framework The user is familiar with the actions framework
Intended Outcome
By following these procedures you should be able to add or modify the following components to your UI.
10-16
10-17
Primary content component in an info page properties panel (object must be a FormatContentHolder)
Solution
Use the Attachments Common Components with customized JSP clients associated to that object type.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Basic development involving HTML forms, JSP, and JSP custom tags The wizard is using the Windchill Client Architecture wizard framework The user is familiar with the actions framework
10-18
Solution Elements
Element Type Description
attachments.tld
Defines any common component tags you will need to use the attachments common components. Runtime location: codebase\WEB-INF\tlds\ attachments.tld
Java file
Servlet that redirects download to the appropriate file for the object. Runtime location: codebase\WEB-INF\lib\ wncWeb.jar
AttachmentsValid ationHelper.class
Java file
Supporting methods for validating various attachments related actions. Runtime location: codebase\WEB-INF\lib\ wncWeb.jar
Java file
General form processing delegate that provides shared attachments functionality to the primary and secondary form processors. Runtime location: codebase\WEB-INF\lib\ wncWeb.jar
Java file
Form processing delegate that attaches primary attachments to the object. Runtime location: codebase\WEB-INF\lib\ wncWeb.jar
10-19
Element
Type
Description
Java file
Form processing delegate that attaches secondary attachments to the object. Runtime location: codebase\WEB-INF\lib\ wncWeb.jar
AttachmentsDataU tilityHelper.class
Java file
Supporting methods for displaying attachments data in a data utility. Runtime location: codebase\WEB-INF\lib\ wncWeb.jar
Procedures
Adding primary content to a wizard
To add primary attachment support to a wizard of an object that implements the FormatContentHolder interface you will need to add the applet tag to the main wizard jsp and the primary attachment tag to a wizard step. On the main wizard jsp (which defines the <jca:wizard tag and the wizard steps) add the following tag definition and fileSelectionAndUploadApplet tag. The tag will render a tiny invisible applet which is used for file browsing and file uploading.
<%@taglib prefix="attachments" uri="http://www.ptc.com/windchill/taglib/attachments" %> <attachments:fileSelectionAndUploadApplet/>
On the wizard step you will need to add the same taglib definition above (but not the applet tag) and the following tag. This tag will render the actual primary attachment input components such as the file chooser or the url inputs.
<attachments:primaryAttachment/>
To add secondary attachment support to a wizard of an object that implements the ContentHolder interface you will need to add the applet tag to the main wizard jsp and the attachments wizard step. On the main wizard jsp (which defines the <jca:wizard tag and the wizard steps) add the following tag definition and fileSelectionAndUploadApplet tag. The tag will render a tiny applet which is used for file browsing and file uploading.
10-20
Inside your wizard definition (inside the <jca:wizard tags) add the following wizard step in the order that you would like it to appear.
<jca:wizardStep action="attachments_step" type="attachments" />
To get it on the additional attributes info page add this to your objects attributes.jsp
<jsp:include page="/netmarkets/jsp/attachments/attachments_table.jsp" flush="true"> <jsp:param name="role" value="PRIMARY" /> </jsp:include>
On your objects attributes.jsp add the following to get the secondary attachments to show up under the more attributes sub nav of the info page.
<jsp:include page="/netmarkets/jsp/attachments/attachments_table.jsp" flush="true"> <jsp:param name="role" value="SECONDARY" /> </jsp:include>
In the action model xml file that defines the action model with the menufor attribute for your object type add the following actions. This will provide download or url redirect actions depending on if the object has a primary file or url.
<action name="download_primary_attachment" type="attachments"/> <action name="redirect_primary_attachment" type="attachments"/> <action name="checkout_and_download" <action name="replace_content" type="wip"/> type="wip"/>
10-21
no no no
Allows the Local File option to be displayed. Allows the URL Link option to be displayed. Allows the External Storage option to be displayed. Allows existing primary content to be removed. Displays the optional Comments field. Displays the optional Externally Distributable checkbox. Displays the optional file version, tool version and tool name fields. Displays the optional Authored By and Last Authored fields. Renders the file path specified instead of allowing the user to choose the file. If fixedFileUpload param on this tag and the forceApplet param on the fileSelectionAndUploadA pplet tag are both set this can be used to force the specified file to be uploaded and attached to the object.
allowRemoveP rimaryContent showAttachme ntComments showDistributa ble showOptionalF ileAttributes showAuthoring Information fixedFilePath
no no no
false
True/False
no
false
True/False
no
null
no
10-22
forceApplet
False
True/False
no
Determines if we should force the applet to be rendered regardless of the upload mechanism preference
10-23
Secondary content
For secondary attachments code to function properly you need attachments step defined in your wizard as well as the fileSelectionAndUploadApplet tag, regardless of whether or not you are using applet upload. The fileSelectionAndUploadApplet tag must be on the jsp that defines the wizard but outside of the wizard tags or it will not function properly.
Primary attachments
Wizard JSP
<%@taglib prefix="attachments" uri="http://www.ptc.com/windchill/taglib/attachments" %> ... <jca:wizard buttonList="DefaultWizardButtonsWithSubmitPrompt"> ... <jca:wizardStep action="attributes_step" type="attachments" /> ...
10-24
</jca:wizard> .<attachments:fileSelectionAndUploadApplet/>
10-25
Property Panel
Objective
You want to display the attributes of some object as label value pairs. You want the colons to align and the HTML to be section 508 compliant.
Scope/Applicability/Assumptions
This document assumes you are familiar with the configuring and acquiring the data for a JCA table.
Solution
Use the property panel component to display label/value pairs (or label/input field pairs) for an object. Examples:
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Basic development involving HTML, JSP, JavaScript and Custom taglibs. Overview of JCA tags. JCA Table
10-26
Solution Elements
Element <your_page>.jsp <your>service.properties Type jsp properties Description Your JCA Property Panel implementation jsp file. Data utilities and services are defined here. Run time Location: <Windchill>\ codebase components.tld tld Tags can be defined here. Run time Location: <Windchill>\ codebase\WEB-INF\tlds\
To describe the property panel use the describePropertyPanel and describeProperty tags. For example:
<jca:describePropertyPanel var="<name of the descriptor>"> <jca:describeProperty id="name" /> <jca:describeProperty id="number" /> <jca:describeProperty id="<attribute name | data utility id | logical form>" /> </jca:describePropertyPanel>
The value for <name of the descriptor> can be any name you wish to assign to your panel. The reporting tool that gives details about what properties are available can be accessed here:
http://<HOSTNAME>/<WEBAPP>/netmarkets/jsp/property/propertyReport. jsp
10-27
To acquire data use the either the getModel or getIeModel tag. For example:
<jca:getModel var="<name of the data model>" descriptor="${<name of the descriptor>}" serviceName="wt.fc.StandardPersistenceManager" methodName="refresh"> <jca:addServiceArgument value="${commandBean.primaryOid.oid}" type="wt.fc.ObjectIdentifier" /> </jca:getModel>
The value for <name of the data model> can be any name you wish to assign to your data. The value for <name of the descriptor> should be that used in your describePropertyPanel tag.
Render the Property Panel
To render the property panel use the renderPropertyPanel tag. For example:
<jca:renderPropertyPanel model="${<name of the data model>}"/>
The value for <name of the data model> should be that used in your getModel tag. To see more code examples of using the renderPropertyPanel tag look at:
<WT_HOME>/codebase/netmarkets/jsp/carambola/propertyPanel/examples .jsp
10-28
Parameter scope
Req? No
Description The name of the scope to export the var attribute to.
mode
VIEW
No
Sets the ComponentMode that will be used for validation and for data utilities to determine what kind of GUI component to return.
componentT ype
TABLE
String form of com.ptc.core.ui.resou rces.ComponentType enum: TABLE, WIZARD, WIZARD_TABLE, INFO_ATTRIBUTE S_TABLE, SIMPLE, INFO, PICKER, SEARCH
No
Sets the ComponentType that will be used for validation and for data utilities to determine what kind of GUI component to return.
var
Yes
10-29
Parameter label
Default Value -
Req? No
Description A localized display label for this property. If the label isnt specified, then the infrastructure will attempt to look up a label The name of the scope to export the var attribute to.
scope
page
Can be: "page" , "request", "session" or "application" (case-insensitive). String form of com.ptc.core.ui.res ources.Component Mode enum: VIEW, CREATE, EDIT, SEARCH
No
mode
No
Sets the ComponentMode that will be used for validation and for data utilities to determine what kind of GUI component to return.
Sample Code
There are many ways to use the renderPropertyPanel tag and its child tags to display the ComponentModel that is put into page scope by the getModel tag. To see more code examples of using the renderPropertyPanel tag and its child tags look at:
<WT_HOME>/codebase/netmarkets/jsp/carambola/customization/examples /propertyPanel/examples.jsp
10-30
http://<HOSTNAME>/<WEBAPP>/netmarkets/jsp/carambola/customization/ examples/propertyPanel/examples.jsp
<jca:describePropertyPanel var="attributeDisplayPanelDescriptor" mode="VIEW"> <jca:describeProperty id="number" label="${base_part_number}" /> <jca:describeProperty id="orgid"/> <jca:describeProperty id="version" label="${base_part_version}" /> <jca:describeProperty id="name" label="${base_part_name}" /> </jca:describePropertyPanel> <jca:describePropertyPanel var="attributeInputPanelDescriptor" mode="CREATE" > <jca:describeProperty id="name" inputRequired="true" label="${part_config_name}" /> <jca:describeProperty id="description" label="${part_config_desc}" /> </jca:describePropertyPanel> <wc:batch> <jca:getModel var="attributeDisplayPanel" descriptor="${attributeDisplayPanelDescriptor}" serviceName="wt.fc.StandardPersistenceManager"
10-31
methodName="refresh"> <jca:addServiceArgument value="${commandBean.primaryOid.oid}" type="wt.fc.ObjectIdentifier" /> </jca:getModel> <jca:getModel var="attributeInputPanel" descriptor="${attributeInputPanelDescriptor}" serviceName="com.ptc.core.components.forms.CreateAndEditModelGette r" methodName="getItemAttributes"> <jca:addServiceArgument value="${attributeInputPanelDescriptor}" type="com.ptc.core.components.descriptor.ComponentDescriptor"/> <jca:addServiceArgument value="${commandBean}" type="com.ptc.netmarkets.util.beans.NmCommandBean"/> <jca:addServiceArgument value="${nmcontext.context}" type="com.ptc.netmarkets.util.misc.NmContext"/> </jca:getModel> </wc:batch> <jca:renderPropertyPanel> <jca:addPropertyPanel model="${attributeDisplayPanel}"/> <jca:addSeparator/> <jca:addPropertyPanel model="${attributeInputPanel}" /> <w:radioButton propertyLabel="${populate}" name="PopulationType" value="<%=PartConfigurationCommand.POPULATION_BASIC%>" label="${basic}" checked="true" required="true" /> <w:radioButton name="PopulationType" value="<%=PartConfigurationCommand.POPULATION_FULL%>" label="${full}"/> </jca:renderPropertyPanel>
10-32
Background
Before you can use packages within a context, you must first enable packages for that context. When you enables packages for a given context, the system loads a site-wide package template XML file. The package template file contains package specific roles that are applied to the container team, the default domain structure for packages, and package-related policies. The default domain structure will create a Package domain specific to the current context. All packages created within the context, as well as all of the objects created within the packages (collections, folders, documents, links, and deliveries) will use this package domain by default. Out of the box, the package domain is Private. This means that it won't inherit any policies from the container's default domain.
Scope/Applicability/Assumptions
This guide assumes that you want to customize the default roles, domain structure, or access control policy rules associated with Packages across all contexts. You should be familiar with managing Packages, teams, and administering access control for Windchill business objects.
Intended Outcome
Customize the default roles, domain structure, or access control policy rules associated with Packages across all contexts.
Solution
Use the package template XML file to customize the default roles, domain structure, and access control policy rules associated with Packages across all contexts.
10-33
Prerequisite Knowledge
To achieve this objective, you need to have an understanding of the following: Administering Packages Creating business XML files for templates Windchill team concepts Administering Domains and Policies Access Control
Solution Elements
Element packageTemplate.xml Type XML Description The XML file that contains the roles, domain structure, and policies associated with Packages. This file is loaded when you enable packages for a context. Location: <WT_HOME>/loadXMLFiles/ packageSharedTeamTemplate.xml XML The XML file that contains the shared team roles. This file is loaded in addition to the packageTemplate.xml file when you enable packages for a context that is using a shared team that isnt extended. Location: <WT_HOME>/loadXMLFiles/
Limitations
The packageTemplate.xml file applies to the entire site which means you can not customize it for specific contexts or specific packages.
10-34
If you change the default domain path, you may have to enable packages again. If the domain already exists in a context, you wont be prompted to enable packages again. If the context is using a shared team that isnt extended, the roles from packageSharedTeamTemplate.xml will be used and the roles from packageTemplate.xml will be ignored.
10-35
10-36
Constant defining preferences entry for generating thumbnails on the property page
public static final String DEFAULT_THUMBNAILS_PROP_PAGE_PREF_VALUE
Returns the JavaScript to create the Dialog Window function creationDialogWindow. This should be called once per page. This JavaScript function is used by the HREFs created from getDefaultVisualizationData().
public String[] getDefaultVisualizationData(String representableObjectReference, Boolean forListing, Locale locale)
Returns a set of HTML fragments to allow the default representation to be manipulated by a UI.
public int getIndexOfVisLink(String prefKey, String prefDefault)
Returns the index in the data array returned by getDefaultVisualizationData of the URL to use for launching ProductView.
public int clipboardLinkIndex()
Returns the index of the Add to Clipboard link in the data array returned by getDefaultVisualizationData
public int printLinkIndex()
Returns the index of the Print link in the data array returned by getDefaultVisualizationData
public int viewRepsLinkIndex()
Returns the index of the view representations link in the data array returned by getDefaultVisualizationData
public int[] getThumbnailSize()
10-37
The VisualizationHelper can be instantiated via the newVisualizationHelper() factory method. getCreateDialogWindow() is required to generate the Javascript fragment required by the results returned from getDefaultVisualizationData(String, Boolean, Locale). This code must be embedded somewhere in the HTML returned by the JSP page. getDefaultVisualizationData(String, Boolean, Locale) method returns an array of String values. Each value corresponds to a different component within the ProductView Visualization Service. Elements in the array can be accessed directly through the indexes returned by the following methods: getIndexOfVisLink(String, String), clipboardLinkIndex(), printLinkIndex(), viewRepsLinkIndex(). Each String is the base HTML code for the ProductView visualization component and can be embedded into the HTML returned by the JSP page. It may be an '<A HREF .. /A>' code tag or other simple unformated HTML tags. Note: The getDefaultVisualizationData(String, Boolean, Locale) method returns the basic HTML components necessary for accessing the ProductView visualization components. Most likely the results will need to be used within proper HTML tags. The responsibility of designing the user interface and properly using the values returned by these methods belongs to the implementer. Example usage:
// comp.ptc.wvs.common.ui.VisualizationHelper is assumed to be imported. VisualizationHelper visHelper = newVisualizationHelper(); if (visHelper.isWVSEnabled()) //only execute code if WVS is enabled { // Embed the create dialog JavaScript somewhere in returned HTML. // The below is just an example of calling it. Placement within // HTML is the responsibility of the implementer. out.println(visHelper.getCreateDialogWindow());
//ObjectReference object or and locale object is assumed to be obtained prior to the following line String visData[] = visHelper.getDefaultVisualizationData(or.toString(),new Boolean(false), locale); //Obtain array indices for thumbnail, clipboard link, print link, and representations link int thumbnailIndex = visHelper.getIndexOfVisLink( VisualizationHelper.THUMBNAILS_PROP_PAGE_PREF_KEY, VisualizationHelper.DEFAULT_THUMBNAILS_PROP_PAGE_PREF_VALUE); int clipboardIndex = visHelper.clipboardLinkIndex(); int printIndex = visHelper.printLinkIndex(); int repsOrMarkupsIndex = visHelper.viewRepsLinkIndex(); /**
10-38
* Print the various HTML code fragments generated for each component. * Any HTML formatting code must be wrapped around each of the following lines **/ out.println(visData[thumbnailIndex]); out.println(visData[clipboardIndex]); out.println(visData[printIndex]); out.println(visData[repsOrMarkupsIndex]); }
10-39
Tools Overview
This section contains the following information: Available Attributes Report Debugging Taglib documentation Action Report Action Model Report
http://<machine_name>/<app_name>/netmarkets/jsp/carambola/createta bleview/availableAttributesReport.jsp
10-40
Debugging
There is a debug mode that can be enabled in the UI that can help track down information about a particular action on a page. The jcaDebug tool is a display parameter that can be added to any URL to add debug info to the current page inline with the items in the page. The debug tool can: debug what class is handling data that gets displayed in a table cell shows what kind of component is rendering the cell data shows what class is responsible for hiding/enabling/disabling an action
Enable jcaDebug
To enable the JCA debug feature add the following to the end of any url, that is JCA:
&jcaDebug=true
For example:
<servername>/Windchill/servlet/TypeBasedIncludeServlet?Containe rOid=OR%3Awt.pdmlink.PDMLinkProduct%3A4462&oid=VR%3Awt.part.WTP art%3A5142&u8=1&jcaDebug=true
Displays the name of the action. Displays the action type separated by a period and the action name. The Action Name is also a hyperlink to the action details page. Displays the action model name. The Action Model Name is also a hyperlink to the action model details page.
10-41
Attribute
Description
Displays the data utility. Displays the GUI type. Displays the ID used to look up the customizable delegates. Displays the object passed into the data utility that the table cell is displaying info about.
Taglib documentation
Several tags and taglibs are delivered as part of the framework. These taglibs contain a set of handlers for including components and other common functionality into your pages. Refer to the taglib javadoc at the following location: http://www.ptc.com/view?im_dbkey=61784
10-42
Action Report
We support modularized actions and actionmodels within the system, so to find what file an action is defined in, there is a reporting tool that can be used. On a running Windchill installation, you can use the Actions report. The Action Report is a search page that returns the details of actions matching the search criteria. The Action report allows you to search for actions managed by the StandardNmActionService. You can search by several properties for the action including the label (aka Description), action name, object type. The search supports multiple search parameters, regular expressions and caseinsensitive matching.
Location
http://<your machine name>/<appname>netmarkets/jsp/carambola/tools/actionReport/action.jsp
Search Supports
Multiple search parameters Regular expressions Case-insensitive matching
10-43
If there is no information for the particular action, the line is shown blank.
Search Examples
Description
Action Name
remov.* ==> Matches: "remove", "remove_deliverable", "removeUses", etc. r[a-z]* ==> Matches: "reply", "REVISEITEMS", "reassignLC", etc.
10-44
Hot Keys
.*move ==> Matches: "remove", "CONTAINERMOVE", "WFMOVE", etc. .* ==> Matches: everything
only files under \codebase\ search matches files under "\config\actions\" with specifying it Note: Some matches may be deceiving due to include tags in xml files
Known Bugs
Opposite facing slashes in file paths On Details Page Definition file: Z:\\Windchill\codebase\config/actions/RelContextactions.xml In Details Table
In Internet Explorer When pressing the back button from the Details Page, you are given:
10-45
10-46
Location
The Action Model Report is available at the following location: http://<your machine name>/<appname>/netmarkets/jsp/carambola/tools/actionReport/actionModel.jsp
Search Supports
Multiple search parameters Regular expressions case-insensitive matching
Search Examples
Returns action models depending on search:
10-47
If there is no information for the attribute of a particular action model, the line is shown blank.
Action Model
Model File
Default.* ==> Matches: "DefaultWizardButtons", "DefaultWizardButtons", etc. .*actions ==> Matches: "dti actions", "bookmark actions", "workitem actions", etc. [a-z]*s ==> Matches: "ScmiWizardButtons", "relatedItems", "EditWizardButtons", etc. .* ==> Matches: everything
only files under \codebase\ search matches files under "\config\actions\" without having to specify it
10-48
Note: Some matches may be deceiving due to include tags in xml files.
Order in Table
This shows the order of the actions within an actionmodel xml file.
Known Bugs
In Internet Explorer
When pressing the back button from the Details Page, you are given:
10-49
If the method server is restarted after a search has already been attempted, another search will return "No Objects to Display" no matter what you search for. This is due to the fact that the page relies on a session variable to get the information from the method server. To fix this problem, simply restart your browser.
Wrong Definition File?
Some matches may be deceiving due to include tags in xml files. Check the included files to find what you are looking for.
10-50
Objective
The UI Component Validation Service was created to give Windchill clients a central service to call to perform validation for actions and other components appearing in the Windchill UI. Calls to the service and interpretation of the results should be managed by many of the common components developed in release 9.0. The main responsibility for an application developer would be development of Validator classes that are called by the validation service to validate a specific action or UI component. This design pattern outlines the process and best practices for authoring Validator classes.
Applicability
This design pattern should be used by a developer who is responsible for authoring one or more Validators to determine whether or not an action or UI component is valid on a given page/context/etc. The design pattern should walk through an example of each type of validation operation that a Validator could be called upon to perform.
Structure
All of the classes in the UI Validation Service (except where noted) are defined in the com.ptc.core.ui.validation package. Their source code is located in \ Windchill\src\com\ptc\core\ui\validation. A Validator developer will not need to interact with all of the classes in this diagram, but many of them are applicable. The various classes will be discussed throughout this document, but to begin with, a developer writing a Validator should always define their Validator class to extend DefaultUIComponentValidator. It is also important to note that as requirements evolve, these classes may be updated. To get the latest set of methods and attributes defined in each of the classes see the Windchill Javadoc.
Participants
The readers of this section should have a general understanding of the Java programming language, and also some familiarity with the Windchill solution suite.
10-51
Collaborations
Validator developers need to collaborate with common component developers and other callers of the Validation Service. This collaboration is necessary to ensure that a caller of the service is passing all of the data to the service that a given Validator will need to perform validation. It is strongly recommended that Validator developers include a list of the data required in a given validation method in that methods Javadoc. It is also helpful to include a list of Validation keys (action names) that the method is designed to account for. For example:
public class DefaultWIPValidator extends DefaultUIComponentValidator { /** * This implementation of performLimitedPreValidation will check the checkout * state of all the Workable objects in the ValidationCriteria's targetObjects * WTCollection, and base its validation results on whether an object in the * given state can have the specified action performed on it. (e.g., an object * in the checked-in state can not have an undo checkout action performed on it) * * At a minimum, a caller of this method should provide the targetObjects * WTCollection in the validationCriteria argument. * * The expected validationKey arguments for this method are: * checkin * checkout * undocheckout * * <BR><BR><B>Supported API: </B>false * * @param validationKey The String identifying the action or component being validated. * @param validationCriteria Object holding information required to perform validation tasks. * @param locale The user's Locale. If a <i>null</i> value is passed in, the session locale will be used. * @return UIValidationResultSet **/ public UIValidationResultSet performLimitedPreValidation (String validationKey, UIValidationCriteria validationCriteria, Locale locale) throws WTException { } }
10-52
Consequences
By using this design pattern as a reference, developers should create consistent, performant Validators. A caller of the validation service should be confident that whatever action or UI component they are validating will be validated in a consistent manner.
Implementation Overview
It is probably helpful to begin with a definition of the term validation. For the purposes of this discussion, the term validation refers to activities performed to determine what a user can see or do. For example: Should we display the Create Part action? Should we allow the checkout of this object? Is everything the user entered in this create wizard OK?
For the purposes of our discussion, validation can be broken down into three broad categories: Pre-Validation Attempts to answer the questions: Should something appear to the user in the UI? And, if so, should it be editable/selectable? For example, Should we display and enable the Create Part action for user A in container B? Pre-Validation can be performed for actions or other UI components (status glyphs, attributes, tables, etc.)
Post-Select Validation Attempts to answer the question: Should the operation that was just selected in the UI be allowed to proceed? For example, Can we allow the checkout of parts A, B, and C?
Post-Submit Validation Attempts to answer the question: Is the data the user just entered valid? For example, When the user clicks Next in the Create Part wizard, are we going to let them go to the next step, or do they need to modify some data (e.g., name, number) in the current step?
The UI Component (Action) Validation Service exposes one or more APIs for each of the types of validation listed above.
10-53
From a high level, a common component or some other client invokes a validation API on the Validation Service, passing one or more validation keys (which can be thought of as an action name, like create, for instance) and a UIValidationCriteria bean, which contains data known by the client that is required to perform validation. The Validation Service uses the validation key(s) to perform a lookup and identify the Validator class(es) that should be called to carry out the validation activity. The service then passes the key and UIValidationCriteria on to the identified Validator(s) and awaits a (set of) result(s). When the service has the result(s) from the Validator(s), it (creates a bundle of results and) returns it to the client.
This design pattern will concentrate on the authoring of Validator classes and methods.
Packaging/Modularization
All of the classes related to the UI Component Validation Service are packaged in com.ptc.core.ui.validation. Their source is located in the module \Windchill\src\ com\ptc\core\ui\validation. It is strongly recommended that any time a developer is doing Validator development, they update all of the files in this directory and compile the latest versions of the Java classes.
10-54
Developers writing Validators should put their Validator classes in a package or module that is meaningful for the action(s)/UI component(s) that the Validator validates.
For those methods which you do not override, the default behavior (always enable/permit) will be inherited from the DefaultUIComponentValidator class. You will also need to create a properties entry to associate your Validator class with a particular validation key (action). The validation service uses these entries to find the right Validator for a given validation key (action). The entry will go in service.properties, or your application teams service properties file (ask your group lead where you should put your entry), and should have this format:
wt.services/rsc/default/com.ptc.core.ui.UIComponentValidator/<vali daitonKey>/null/0=com.ptc.my.validators.MyValidator
Where <validationKey> is the validation key for your action/component and the right-side value is the fully-qualified class name of your Validator. There are three types of checks you should never have to perform in your Validator implementations. These checks are performed by the validation service before the Validators are called. They include: Role-based checking (visibility of actions based on input into the RBUI system, which is not to be confused with access control checking, which needs to be done in the Validators.) Install-based checking (should an action or UI component be available given the set of solutions installed on a given system?) Client-based checking (should an action or UI component be available in a given client, like DTI or PSE?)
One of the methods you may choose to override in your Validator implementation is validateSelectedAction. As the method name suggests, this method is called by a client application wanting to know whether or not an action selected by a user
10-55
from the UI can be performed. For example, A user selects revise from a list of actions for a document. Should the revise action proceed? The method signature for validateSelectedAction looks like this:
public UIValidationResult validateSelectedAction (String validationKey, UIValidationCriteria validationCriteria, Locale locale)
As you can see, the method takes three arguments: 1. A string indicating the key that was used by the client to identify the action being validated (think of this as the action name) 2. A UIValidationCriteria object (more on this in a second), and 3. A Locale The first and third arguments should be fairly self-explanatory. The UIValidationCriteria object is the validation criteria bean that was previously mentioned. It holds data that the client set and passed to the validation service (e.g., user, container, context object(s), etc.). The return type is UIValidationResult whose attributes include a status indicating whether or not the action should be permitted. Pseudo-code for a validateSelectedAction implementation would look like this:
import com.ptc.core.ui.validation.*; public class MyValidator extends DefaultUIComponentValidator{ public UIValidationResult validateSelectedAction (String a_key, UIValidationCriteria a_criteria, Locale a_locale) { // get required info from UIValidationCriteria WTContainerRef parentContainer = a_criteria.getParentContainer(); WTReference contextObject = a_criteria.getContextObject(); WTPrincipalReference userRef = a_criteria.getUser(); // create status and message objects to pass back UIValidationStatus status = null; UIValidationFeedbackMsg msg = null; // perform validation logic if (we can allow this action to proceed){ status = UIValidationStatus.PERMITTED; } else{ status = UIValidationStatus.DENIED; msg = new UIValidationMsg(localized text, UIValidationMsgType.INFO) } // return a validation result with the calculated status and message return new UIValidationResult(a_key, contextObject, status, msg);
10-56
} }
Another of the methods that you can override in your Validator implementation is called validateSelectedMultiSelectAction. It is similar to the validateSelectedAction method. The only difference is that this method will be called to validate a multi-select action, and will therefore return multiple results. For example, A user selects checkout from a table header to perform the checkout of several selected parts in the table. Should we allow all of the parts to be checked out? The method signature for validateSelectedMultiSelectAction looks like this:
public UIValidationResultSet validateSelectedAction (String validationKey, UIValidationCriteria validationCriteria, Locale locale)
Note that the arguments are identical to those passed to validateSelectedAction. The only difference is that this method returns an object of type UIValidationResultSet, which, as the name suggests, is just a set of UIValidationResult objects. Pseudo-code for the validateSelectedMultiSelectAction would look like this:
import com.ptc.core.ui.validation.*; public class MyValidator extends DefaultUIComponentValidator{ public UIValidationResultSet validateSelectedMultiSelectAction (String a_key, UIValidationCriteria a_criteria, Locale a_locale){ // get required info from UIValidationCriteria WTContainerRef parentContainer = a_criteria.getParentContainer(); WTCollection targetObjects = a_criteria.getTargetObjects(); WTPrincipalReference userRef = a_criteria.getUser(); // create result set to return UIValidationResultSet resultSet = new UIValidationResultSet(); // iterate through target objects Iterator targetRefIterator = targetObjects.referenceIterator(); while (targetRefIterator.hasNext()){ WTReference targetRef = (WTReference)targetRefIterator.next(); if (we can allow this action to proceed for this object){ resultSet.addResult(new UIValidationResult(a_key, targetRef, UIValidationStatus.PERMITTED, null)); } else{ resultSet.addResult(new UIValidationResult(a_key, targetRef,
10-57
A third method you can override in your Validator implementation is validateFormSubmission. This method would be invoked on the service by a client wanting to validate whether or not the user-entered data in a form is valid. For example, A user clicks next after entering data on the details step of a create part wizard. Should we allow them to go to the next step, based on what theyve entered? The method arguments and return type for validateFormSubmission are identical to those for validateSelectedAction:
public UIValidationResult validateFormSubmission (String validationKey, UIValidationCriteria validationCriteria, Locale locale)
Similarly, a pseudo-implementation of this method would be similar to what we provided for validateSelectedAction.
Implementing Pre-Validation Methods
The last two methods you can override in your Validator implementation are performFullPreValidation and performLimitedPreValidation. The methods provide similar functionality, as they are both called by clients wanting to know whether an action (or other UI component) should be enabled, disabled, or hidden in the UI. The intended usage of performLimitedPreValidation is that a client would call it when they want to do a quick check of whether or not an action should appear in the UI. A client calling this method should know that they are not guaranteed that actions will be accurately hidden in all cases we are sacrificing accuracy in favor of performance. On the other hand, a client would call performFullPreValidation in cases where they want accurate results, at the potential cost of decreased performance. Some examples of Pre-Validation include: Example 1: We are rendering a table in which each row could have action icons for check-out, check-in, revise, or delete. Given the objects in the table, which actions should be enabled in which row?
10-58
Note: In this case, we would probably want to perform limited pre-validation for performance reasons. Example 2: We are rendering a dropdown list of actions on a doc details page. Given a list of several actions, which ones should be available for this particular doc? Note: In this case, we would probably want to perform full pre-validation, since performance is not as much of an issue (only one object, as opposed to several in the first example), and accuracy is more important. The argument list and return types for each Pre-Validation method are identical:
public UIValidationResultSet performFullPreValidation (String validationKey, UIValidationCriteria validationCriteria, Locale locale)
public UIValidationResultSet performLimitedPreValidation (String validationKey, UIValidationCriteria validationCriteria, Locale locale)
10-59
Pseudo-code for a performLimitedPreValidation would look identical to the example above for performFullPreValidation. The only difference in the actual implementation is that the level of scrutiny used to determine validity may be higher (and less performant) in the full pre-validation example. However, its important to note that in practice its possible that the limited pre-validation and the full pre-validation checks to be identical (in this case, we would likely be saying that there are no significant performance impacts of performing full prevalidation all the time).
import org.apache.log4j.Logger; import import import import import wt.access.AccessPermission; wt.access.AccessControlHelper; wt.epm.workspaces.EPMWorkspaceHelper; wt.fc.Persistable; wt.fc.ReferenceFactory;
10-60
import import import import import import import import import import import import import import import import import import import
wt.fc.WTReference; wt.fc.collections.WTArrayList; wt.fc.collections.WTCollection; wt.folder.CabinetBased; wt.folder.CabinetMember; wt.folder.Foldered; wt.folder.FolderHelper; wt.inf.container.WTContained; wt.inf.container.WTContainerHelper; wt.log4j.LogR; wt.org.WTUser; wt.sandbox.SandboxHelper; wt.session.SessionHelper; wt.util.WTException; wt.vc.Iterated; wt.vc.VersionControlHelper; wt.vc.wip.Workable; wt.vc.wip.WorkInProgressHelper; wt.vc.wip.WorkInProgressState;
public class DefaultWIPValidator extends DefaultUIComponentValidator { private Logger logger = LogR.getLogger("wt.method.server.httpgw"); private ReferenceFactoryrefFactory = null; private static final String FULL = "full"; private static final String LIMITED = "limited"; private static final String SELECTED = "selected"; /** * This implementation of performLimitedPreValidation will check the checkout * state of all the Workable objects in the ValidationCriteria's targetObjects * WTCollection, and base its validation results on whether an object in the * given state can have the specified action performed on it. (e.g., an object * in the checked-in state can not have an undo checkout action performed on it) * * At a minimum, a caller of this method should provide the targetObjects * WTCollection in the validationCriteria argument. * * The expected validationKey arguments for this method are: * checkin * checkout * undocheckout * * <BR><BR><B>Supported API: </B>false * * @param validationKey The String identifying the action or component being validated. * @param validationCriteria Object holding information required to perform validation tasks. * @param locale The user's Locale. If a <i>null</i> value is passed in, the session locale will be used. * @return UIValidationResultSet **/ public UIValidationResultSet performLimitedPreValidation (String validationKey, UIValidationCriteria validationCriteria, Locale locale) throws WTException
10-61
{ logger.debug("ENTERING DefaultWIPValidator.performLimitedPreValidation"); logger.trace(" validtionKey -> " + validationKey); logger.trace(" validationCriteria -> " + validationCriteria.toString()); UIValidationResultSet resultSet = performWIPValidation(validationKey, validationCriteria, locale, LIMITED); logger.trace("RETURNING " + resultSet.toString()); logger.debug("EXITING DefaultWIPValidator.performLimitedPreValidation"); return resultSet; }
public UIValidationResultSet performFullPreValidation (String validationKey, UIValidationCriteria validationCriteria, Locale locale) throws WTException { logger.debug("ENTERING DefaultWIPValidator.performFullPreValidation"); logger.trace(" validtionKey -> " + validationKey); logger.trace(" validationCriteria -> " + validationCriteria.toString()); UIValidationResultSet resultSet = performWIPValidation(validationKey, validationCriteria, locale, FULL); logger.trace("RETURNING " + resultSet.toString()); logger.debug("EXITING DefaultWIPValidator.performFullPreValidation"); return resultSet; }
public UIValidationResult validateSelectedAction (String validationKey, UIValidationCriteria validationCriteria, Locale locale) throws WTException { logger.debug("ENTERING DefaultWIPValidator.validateSelectedAction"); logger.trace(" validtionKey -> " + validationKey); logger.trace(" validationCriteria -> " + validationCriteria.toString()); UIValidationResult result = null; WTReference wtRef = validationCriteria.getContextObject(); Persistable persistable = wtRef.getObject(); if (!(persistable instanceof Workable)){ return new UIValidationResult(validationKey, wtRef, UIValidationStatus.DENIED, null); } Workable workable = (Workable)persistable; if (validationKey.equalsIgnoreCase("checkin") || validationKey.equalsIgnoreCase("undocheckout")){ result = performCheckinValidation(validationKey, workable, SELECTED, (WTUser)(validationCriteria.getUser().getPrincipal())); } else if (validationKey.equalsIgnoreCase("checkout")){ result = performCheckoutValidation(validationKey, workable, SELECTED);
10-62
public UIValidationResultSet validateSelectedMultiSelectAction (String validationKey, UIValidationCriteria validationCriteria, Locale locale) throws WTException { logger.debug("ENTERING DefaultWIPValidator.validateSelectedMultiSelectAction"); logger.trace(" validtionKey -> " + validationKey); logger.trace(" validationCriteria -> " + validationCriteria.toString()); UIValidationResultSet resultSet = performWIPValidation(validationKey, validationCriteria, locale, SELECTED); logger.trace("RETURNING " + resultSet.toString()); logger.debug("EXITING DefaultWIPValidator.validateSelectedMultiSelectAction"); return resultSet; } // // // // // ***NOTE: There is no post-submit validation for the WIP actions (checkin, checkout, undocheckout), since there is no wizard launched when one of the actions is performed. Therefore, there is no need to define a validateFormSubmission method in this class. // // public UIValidationResult validateFormSubmission (String validationKey, // UIValidaitonCriteria validationCriteria, Locale locale)
private UIValidationResultSet performWIPValidation(String validationKey, UIValidationCriteria validationCriteria, Locale locale, String validationType) throws WTException { UIValidationResultSet resultSet = new UIValidationResultSet(); WTCollection targetObjects = new WTArrayList(validationCriteria.getTargetObjects()); Iterator workableIter = getWorkableIterator(targetObjects); Workable workable = null; while (workableIter.hasNext()){ workable = (Workable)workableIter.next(); if (validationKey.equalsIgnoreCase("checkin") || validationKey.equalsIgnoreCase("undocheckout")){ resultSet.addResult(performCheckinValidation(validationKey, workable, validationType, (WTUser)(validationCriteria.getUser().getPrincipal()))); } else if (validationKey.equalsIgnoreCase("checkout")){
10-63
private UIValidationResult performCheckinValidation(String validationKey, Workable workable, String validationType, WTUser user) throws WTException { WTReference wtRef = getWTReference(workable); if (validationType.equals(LIMITED)){ WorkInProgressState state = workable.getCheckoutInfo().getState(); if (state.equals(WorkInProgressState.CHECKED_OUT) || state.equals(WorkInProgressState.CHECKED_OUT_TO_SANDBOX)){ return new UIValidationResult(validationKey, wtRef, UIValidationStatus.ENABLED, null); } else{ return new UIValidationResult(validationKey, wtRef, UIValidationStatus.DISABLED, null); } } else if (validationType.equals(FULL) || validationType.equals(SELECTED)){ UIValidationStatus goodStatus = null; UIValidationStatus badStatus = null; if (validationType.equals(FULL)){ goodStatus = UIValidationStatus.ENABLED; badStatus = UIValidationStatus.DISABLED; } else{ goodStatus = UIValidationStatus.PERMITTED; badStatus = UIValidationStatus.DENIED; } if (workable instanceof CabinetBased){ CabinetBased orig; if (WorkInProgressHelper.isWorkingCopy(workable)) { orig = (CabinetBased)WorkInProgressHelper.service.originalCopyOf(workable); } else { orig = (CabinetBased)workable; } if (isNewInWorkspace(orig)){ return new UIValidationResult(validationKey, wtRef, badStatus, null); } }
10-64
if (WorkInProgressHelper.isCheckedOut(workable, user) || (WorkInProgressHelper.isCheckedOut(workable) && WTContainerHelper.service.isAdministrator(((WTContained)workable).getContainerRefer ence(), user))){ return new UIValidationResult(validationKey, wtRef, goodStatus, null); } else{ return new UIValidationResult(validationKey, wtRef, badStatus, null); } } return new UIValidationResult(validationKey, wtRef, UIValidationStatus.ENABLED, null); }
private UIValidationResult performCheckoutValidation(String validationKey, Workable workable, String validationType) throws WTException { WTReference wtRef = getWTReference(workable); if (validationType.equals(LIMITED)){ WorkInProgressState state = workable.getCheckoutInfo().getState(); if (state.equals(WorkInProgressState.CHECKED_OUT) || state.equals(WorkInProgressState.CHECKED_OUT_TO_SANDBOX)){ return new UIValidationResult(validationKey, wtRef, UIValidationStatus.DISABLED, null); } else{ return new UIValidationResult(validationKey, wtRef, UIValidationStatus.ENABLED, null); } } else if (validationType.equals(FULL) || validationType.equals(SELECTED)){ UIValidationStatus goodStatus = null; UIValidationStatus badStatus = null; if (validationType.equals(FULL)){ goodStatus = UIValidationStatus.ENABLED; badStatus = UIValidationStatus.DISABLED; } else{ goodStatus = UIValidationStatus.PERMITTED; badStatus = UIValidationStatus.DENIED; } if (isNewInWorkspace(workable)){ return new UIValidationResult(validationKey, wtRef, badStatus, null); }
10-65
if ((AccessControlHelper.manager.hasAccess(workable, AccessPermission.MODIFY)) && (!WorkInProgressHelper.isCheckedOut(workable) && (VersionControlHelper.isLatestIteration((Iterated)workable)) && (!SandboxHelper.isCheckedOutToSandbox(workable)))){ return new UIValidationResult(validationKey, wtRef, goodStatus, null); } else{ return new UIValidationResult(validationKey, wtRef, badStatus, null); } } return new UIValidationResult(validationKey, wtRef, UIValidationStatus.ENABLED, null); }
private Iterator getWorkableIterator(WTCollection targetObjects) { try{ return targetObjects.persistableIterator(Class.forName("wt.vc.wip.Workable"), true); } catch(Exception e){ return (new ArrayList(0)).iterator(); } }
private WTReference getWTReference(Workable workable) { if (refFactory == null){ refFactory = new ReferenceFactory(); } try{ return refFactory.getReference(workable); } catch(WTException wte){ return null; } }
private static boolean isNewInWorkspace(Object object) throws WTException { if(object instanceof Foldered || object instanceof CabinetMember) { WTArrayList objArray = new WTArrayList(); objArray.add(object); if(FolderHelper.service.getObjsInPersonalCabinets(objArray).size() > 0) { if(EPMWorkspaceHelper.manager.getNewObjects(objArray).size() > 0) { return true; } }
10-66
} return false; }
private UIValidationResultSet processNonWorkables(WTCollection targetObjects, String validationKey, String validationType) { UIValidationResultSet resultSet = new UIValidationResultSet(); UIValidationStatus status = null; if (validationType.equals(SELECTED)) status = UIValidationStatus.DENIED; else status = UIValidationStatus.HIDDEN; try{ targetObjects.removeAll(Class.forName("wt.vc.wip.Workable"), true); } catch(ClassNotFoundException cnfe){ // do nothing } Iterator nonWorkableIter = targetObjects.referenceIterator(); WTReference wtRef = null; while(nonWorkableIter.hasNext()){ wtRef = (WTReference)nonWorkableIter.next(); resultSet.addResult(new UIValidationResult(validationKey, wtRef, status, null)); } return resultSet; } }
Known Uses
This design pattern should be used by any developer responsible for writing a Validator for an action or UI component.
10-67
10-68
11
Adding Actions and Hooking Them Up in the UI
This chapter describes how to customize actions and add them to the user interface. Topic Page
Windchill Client Architecture Action Framework Overview .......................... 11-2 Tab Models..................................................................................................... 11-16 Action Visibility ............................................................................................. 11-27 Navigation Stickiness ..................................................................................... 11-36
11-1
Background
The action framework for the Windchill client architecture supports the ability to configure new actions and action models in the system.
Scope/Applicability/Assumptions
This section describes the action framework for the Windchill Client Architecture. It does not include information on how to control the display of the action.
Intended Outcome
When you are finished reading this, you should understand how the action framework works, and how to register actions and action models into the action framework. You should also be familiar with the tools and debug settings that can help in your development.
Solutions
Define a new action and add it to an action model. Define a new action model to the system. Remove an action from an action model.
Prerequisite knowledge
XML file structures
Solution Elements
Element
Type
Description
.java
The StandardNmActionService manages the actions and actionmodels in the system. Run time Location: <Windchill>\codebase\com\ptc\netmarkets\util\misc
11-2
Element
Type
Description
actions.xml
.xml
Default system xml file for defining actions in the system. Run time Location: <Windchill>\codebase\config\actions
actionmodels.xml
*.xml
Default system xml file for defining action models ins the system. Run time Location: <Windchill>\codebase\config\actions
actions.dtd
.xml
Default system dtd file for defining structure of an actions*.xml Run time Location: <Windchill>\codebase\config\actions
actionmodels.dtd
*.xml
Default system dtd file for defining structure of an actionsmodels*.xml Run time Location: <Windchill>\codebase\config\actions
The action framework provides a way to define actions and action models within the system. A service, called the StandardNmActionService manages the set of actions and action models in the system. Actions and action models are defined via xml files referred to as actions*.xml and actionmodels*.xml. There is one default actions.xml and actionmodels.xml file that is delivered with the system. However, each functional area may also have its own xml file as well which is also managed by the action service. For customization purposes, a customactions.xml and custom-actionmodels.xml is delivered with the product and are found in codebase/config/actions relative to the Windchill installation directory. All other out of the box actions.xml and actionmodels.xml files are also located in <windchill-install-dir>/codebase/config/actions. The default actions.xml and actionmodels.xml files contain commonly used actions, such as copy, cut, and commonly used action models such as wizard buttons. Additional actions*.xml and actionmodels*.xml files contain actions. and action models related to their functional areas. (e.g. ChangeManagement-actions.xml contains actions related to change management, PartManagement-actions.xml contains actions related to part management). In general, as a developer you would not have to directly make calls to the StandardNmActionService. These calls are done via the components that support display of actions and action models, for example tables, trees, information pages.
11-3
For details about how to configure the action model to use for a component, see related sections: See the Constructing Wizards chapter beginning on page 14-1 for more detailed information on wizards See the information on tables and trees in the Presenting Information in the UI chapter beginning on page 13-1 See the information in the Information Pages chapter beginning on page 15-1
The objecttype name is a way to create a name space as well as packaging for actions related to a specific object or functional area. In the above example, the name document creates a unique name space for actions that apply to wt.doc.WTDocuments. Naming conventions for the name of an objecttype can be any combination of alpha-numeric characters. Most objecttypes are an alias for the persistable object to which the actions relate. Actions that apply to any object type, such as copy, can be put within the objecttype of object. We recommend that all your objecttypes have a prefix specific to your company to prevent collisions with object types delivered with the product.
Possible Object Type Attributes
The table below describes the valid parameters for a objecttype. Details about these parameters can also be found in the codebase/config/actions/actions.dtd.
Default Value n/a Possible Values any combination of alpha-numeric characters
Parameter name
Req? Yes
11-4
Possible Values A valid java class Any valid resource bundle class name
Req? Yes No
Description Object class for the enclosed actions Class name for the default resource bundle to use for the properties of the actions that are to be localized
The action name is a unique identifier for an action within the context of the object type. The object type in conjunction with the action name make the action unique within the system. By default, the action name corresponds to the name of a jsp within the package named for the objecttype. The packaging is relative to codebase/netmarkets/jsp. For example, the action name in the xml above, called create, within the objecttype of document has a jsp in codebase/netmarkets/jsp/document called create.jsp. Naming conventions for the name of an action can be any combination of alphanumeric characters. We recommend that all your actions have a prefix specific to your company to prevent collisions with names of actions delivered with the product.
Possible Action Attributes
The table below describes the valid parameters for a action. Details about these parameters can also be found in the codebase/config/actions/actions.dtd.
Possible values all Page Component Row thirdLevelNav popupMenu
Req? Yes No
Description This is the name by which the action will be referenced Specifies the scope of the AJAX refresh
n/a false false n/a true true WINDCHILL PDM PDM PJL PDM
No No No No
The jsp that is requested via ajax Indicates if this action is only valid within the Wildfire embedded browser Enabled when the project is suspended/cancelled/completed Applicable actions based on the installed components. This is for legacy purposes only.
11-5
Req? No No
Description Used to indicate that multi-selection of row data can be used for this action. Determines if the UI should allow the action to proceed if nothing has been selected. Results in "Nothing Selected" popup JS function name to invoke on client side validation for a wizard step after the step is completed. JS function name to invoke client side validation for a wizard step when the step is loaded Server validator name to invoke client side validation for a wizard step after it is finished. Server validator name to invoke client side validation for a wizard step when the step is loaded. Overrides the id of the wizard step (default is objecttype.action) Specifies that the wizard step is to be downloaded when the wizard is launched A wizard step to be hidden first, or that an action is rendered as non-clickable Used for an wizard action that represents a step in the wizard. Specifies the wizard step is required. Class name for the resource bundle to use for the properties of the actions that are to be localized
afterJS
n/a
No
beforeJS
n/a
No
afterVK
n/a
No
beforeVK
n/a
No
objecttype.actio n true false false false / true false / true false / true
No No No No
resourceBundle
No
11-6
Parameter renderType
Default Value
Req? No
Description Default: http://<host>/<webapp> General: http://<host>/<webapp><command.meth od> General with context: http://<host>/<webapp><command.meth od>?oid=... PDM: url generated by URLactionDelegate; used for template processing or DCA
uicomponent preloadJS
No No
References entry n roleaccessprefs.xml (uic.name) to specify role-based access. The javascript function executed executed before a wizard step is loaded or displayed. The javascript function is executed after a wizard step is loaded into memory, but before it is displayed to the user.
postloadJS
No
If necessary, place a <command> tag in the body of the <action> tag to define the processing aspects of the action.
<command class="com.ptc.windchill.enterprise.doc.forms.CreateDocFormProcess or" method="execute" windowType="popup" onClick="validateCreateLocation(event)"/>
The class attribute defines what class to use for processing. The method attribute defines what method to execute in the class. The windowType attribute determines what window action to take. In the example above the command is for the New Document action which is a Wizard so the windowType is popup. The framework will add javascript that launches this action in a new window. The specified class and method are executed upon submit of the wizard.
11-7
Possible Command Attributes Parameter class method url onClick Default Value n/a n/a n/a n/a Possible Values Req? No No No No Description The class to handle post The method in the class to execute and handle post Used to override the generated url Specified an additional onclick function to call. Useful for confirming with the user whether to execute a special action New: like a popup, except includes a browser bar no_content: no window action normal: default, submit the form wizard_step: display the action as a wizard step page: display a new page popup: create a non-modal popup dialog, typically a wizard. Sets come form of data Possible NonSupportedType Attributes Parameter value Default Value n/a Possible Values Any object types. It can be comma separated. Req? Yes Description This action will be disabled for the object type/s mentioned in the "Possible values". Actions will be disabled in Third Level Navigation, Row Level action. No filtering will be done for MenuBar and Table Tool Bar actions.
windowType
page
No
11-8
Possible SupportedType Attributes Parameter value Default Value n/a Possible Values Any object types. It can be comma separated. Req? Yes Description This action will be enabled only for the objecttype/s mentioned in the "Possible values". Actions will be enabled in Third Level Navigation, Row Level action. No filtering will be done for MenuBar and Table Tool Bar actions.
By specifying SupportedTypeAttribute or NonSupportedTypeAttribute, ActionFramework will either enable or disable the Actions depending upon the object types mentioned. This filtering will be applied only for Third Level Navigation and Row Level Actions. Also this will be carried out before calling any other Filtering ( Validation service ) class defined by application developers. In short it is a UniversalFilter. If an action is disabled by this Universal Filter, Custom Validators written will not get executed. If an action is enabled by this Universal Filter, Custom Validators will get invoked. Example:
<objecttype name="object" class="java.lang.Object" > <action name="reports" enabledwhensuspended="true"> <command url="netmarkets/jsp/carambola/customization/reports/base.jsp"/> <nonSupportedTypes value="wt.doc.WTDocument,wt.part.WTPart"/> </action> </objecttype> Alternatively you can do it as:<objecttype name="object" class="java.lang.Object" > <action name="reports" enabledwhensuspended="true"> <command url="netmarkets/jsp/carambola/customization/reports/base.jsp"/> <nonSupportedTypes> <type value="wt.doc.WTDocument" /> <type value=" wt.part.WTPart " /> </nonSupportedTypes> </action> </objecttype>
11-9
Possible Values all all title description tooltip icon morurlinfo hotkey
Description Corresponds to the name of the objecttype specified in the actions.xml file. Corresponds to the name of the action specified in the actions.xml file. title: localizable text for the title bar if the action is for a wizard description: the localizable text for the label of the action tooltip: the localizable text shown on mouse over of the action icon: image file, relative to codebase/netmarkets/images moreurlinfo: parameters used to size the window for this action hotkey: the alphanumeric key to trigger this action.
value
all
For example:
<objecttype name="document" class="wt.doc.WTDocument" resourceBundle="com.ptc.windchill.enterprise.doc.documentResource"> <action name="create" uicomponent="CREATE_DOC" dtiUpload="true"> <command class="com.ptc.windchill.enterprise.doc.forms.CreateDocFormProcessor" method="execute" windowType="popup" onClick="validateCreateLocation(event)"/> <includeFilter name="projectM4D" /> </action> </objecttype>
11-10
You can also specify a resourceBundle property on the on the <objecttype> element. If an <action> element does not specify a resourceBundle property, the resourceBundle property specified on the <objecttype> element for that action will be used.
type="object"/> type="object"/> type="object"/> type="saveas"/> type="folder"/> type="object"/> type="pdmObject"/> type="folder"/> type="folder"/> type="separator"/> type="folder"/> type="folder"/> type="document"/> type="document"/> type="document"/> type="document"/> type="part"/> type="part"/>
11-11
The objecttype name is a way to create a name space as well as packaging for actions related to a specific object or functional area. In the above example, the name document creates a unique name space for actions that apply to wt.doc.WTDocuments.
Possible Model Attributes
defaultActionNa me
First action in the model is used by default First action in the model is used by default
Action name for one of the actions in the model. Object type of one of the actions in the model.
defaultActionTy pe resourceBundle
Class name for the resource bundle to use for the properties of the action models that are to be localized
11-12
Parameter type
Req? Yes
Naming conventions for the name of an action model can be any combination of alpha-numeric characters. Most action models are names include the component that they are used in. Your action models should have a prefix specific to your company to prevent collisions with other action models delivered with the product.
Possible SubModel Attributes
The entries follow the same format as that of the actions, as noted in Procedure Localizing an action on page 11-9.
object.relatedItems.description.value=<U class='mnemonic'>R</U>elated Objects
11-13
object.relatedItems.description.comment=Used for the text on the Related Objects third level navigation menu. The <U class=mnemonic> </U> tag should be put around the character that is the access key. object.relatedItems.hotkey.value=r object.relatedItems.hotkey.comment=Mnemonic for the Related Objects third level navigation menu. This should be a character that matches the character surrounded by the <U class=mnemonic> </U> tag in the value line above.
We support modularized actions and actionmodels within the system, so to find what file an action is defined in, or what action models the action is used in, there is a reporting tool that can be used. On a running Windchill installation, you can use the Actions and ActionModels reports. See the Tools Overview section in the Customizing HTML Clients Using the Windchill JSP Framework chapter on page 10-40 for information on the Action Report and the Action Models Report.
Customization Points
As mentioned earlier in Solution Elements section on page 11-2, there are two files, custom-actions.xml and custom-actionmodels.xml, that are delivered with the product. If you want to add/modify an action/actionmodel you can put the changes in these files. It is important to note that if you have an <objecttype> element in the customactions.xml file, and that type exists within another actions.xml file, the actions from your file will be added to the full set of actions supported for that type. This custom-actions.xml is read in last of all the actions.xml files, so if action names are duplicated, the one in this file will be used. It is also important to note that if you have a <model> element in the customactionmodels.xml file, and a model by that name already exists, your model will completely wipe out the ones read in before yours. Be very careful in the naming of your models so that you don't wipe out others from files read in before yours unless that is the intent.
11-14
Where org.default.www.SampleChangeRequest is the Name of the soft type entered in the Type Manager.
11-15
Tab Models
Objective
You want to change something in the header section of the page. Examples: Add and remove tabs or sub tabs, Change logo, change other styles.
Background
The tabs and sub tabs rendered in the header area are actions in action lists just like any other actions in the system. The action lists are being displayed by a special tag that knows how to render them as tabs and sub tabs instead of rendering them in any of the other formats found throughout the system. Adding tabs and sub tabs is very much like adding any other action into the system, but there are some additional special consideration. The look and feel of the header and footer areas is controlled by CSS classes in nmstyles.css. A detailed list of the styles used and a description of their purpose is provided in this document in the Procedure - Changing the header or footer look and feel section on page 11-21.
Scope/Applicability/Assumptions
Assume you need to change the look and feel of Windchill to conform to your company's branding. Assume you need to add a new tab or sub tab to the main navigation of the product. Assume you need to remove an existing tab or sub tab from the main navigation of the product.
Solution
Create new actions, an action model, and JSPs for the tab and sub tabs to be added.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Basic development involving CSS, JSP and XML. The actions framework in the Windchill client architecture. For more information see, Windchill Client Architecture Action Framework Overview on page 11-2.
The management of RBINFO file customizations. For more information see, Procedure - Localizing an action on page 11-9.
11-16
Solution Elements Element codebase\config\actions\ navigation-actions.xml codebase\config\actions\ nigation-actionModels.xml Type XML Description This file contains the action definitions for the actions that represent the tabs and sub tabs in the Windchill system This file contains the action model definitions used in the navigation. Including the main tab list, the sub tab list, the recent lists, and the header actions lists. Preferences files This file contains the style classes used to create the look and feel of the Windchill header and footer. This is the JSP file you will create as the default content for the tab you are adding. You can create as many additional JSPs to associate with sub tabs as you need.
XML
rbinfo CSS
JSP
Create an action for your new tab in navigation-actions.xml. If your action requires stickiness you should use the navigation servlet for your action.
<objecttype name="navigation" class=""> <action name="mytab" renderType="GENERAL"> <command class="netmarkets" method="servlet/Navigation?tab=mytab" windowType="page"/> </action> </objecttype>
11-17
To get your main tab to show up you will need to add it to the action model for the main tabs. My new tab is shown in bold below:
<!-- Main navigation --> <model name="main navigation"> <action name="home" type="navigation"/> <action name="product" type="navigation"/> <action name="project" type="navigation"/> <action name="change" type="navigation"/> <action name="library" type="navigation"/> <action name="mytab" type="navigation"/> <action name="org" type="navigation"/> <action name="site" type="navigation"/> </model>
Create localization strings for your action in action.properties or your own rbInfo file. For more information see, Procedure - Localizing an action on page 11-9.
Create a new sub tab model for your tab in navigation-actionModels.xml
Your new tab will need a sub tab model. In order for the navigation to find the subtab model it must be named after the main tab that it belongs to. For sub tab models the parameters defaultActionType and defaultActionName are required. These parameters tell the system which action is the default when the user has never visited this tab before. In our example we will need to create a new action model called "mytab navigation" like this:
<model name="mytab navigation" defaultActionType="mytab" defaultActionName="list"> </model>
You can now add subtabs to your new action model. You must create at least one sub tab whose name and type match the defaults specified in the action model tag.
Create a new stickiness Preference and load it into the Database
Your preferences should be named <tabName>stickyAction and <tabName>StickyType. So for this example they are mytabStickyAction and mytabStickyType. Here is a complete xml examples for the two preferences for mytab.
<?xml version="1.0"?><!DOCTYPE NmLoader SYSTEM "standardX10.dtd"> <NmLoader> <csvPreferenceDefinition handler="wt.preference.LoadPreference.createPreferenceDefinition"> <csvname>mytabStickyAction</csvname> <csvvisibility>HIDDEN</csvvisibility> <csvcategoryName>DISPLAY_CATEGORY</csvcategoryName> <csvdisplayName>wt.preference.preferenceResource:UNASSIGNED_WIT
11-18
H_NAME</csvdisplayName> <csvdescription>wt.preference.preferenceResource:UNASSIGNED_WIT H_NAME</csvdescription> <csvlongDescription>wt.preference.preferenceResource:UNASSIGNED _WITH_NAME</csvlongDescription> <csvdefaultValue/> <csvhandler>com.ptc.windchill.enterprise.preference.handler.Str ingPreferenceValueHandler:</csvhandler> </csvPreferenceDefinition> <csvLinkPreferenceClientDefinition handler="wt.preference.LoadPreference.setClientDefinitionLink"> <csvname>mytabStickyAction</csvname> <csvclientName>WINDCHILL</csvclientName> </csvLinkPreferenceClientDefinition> <csvPreferenceDefinition handler="wt.preference.LoadPreference.createPreferenceDefinition"> <csvname>mytabStickyOid</csvname> <csvvisibility>HIDDEN</csvvisibility> <csvcategoryName>DISPLAY_CATEGORY</csvcategoryName> <csvdisplayName>wt.preference.preferenceResource:UNASSIGNED_WIT H_NAME</csvdisplayName> <csvdescription>wt.preference.preferenceResource:UNASSIGNED_WIT H_NAME</csvdescription> <csvlongDescription>wt.preference.preferenceResource:UNASSIGNED _WITH_NAME</csvlongDescription> <csvdefaultValue/> <csvhandler>com.ptc.windchill.enterprise.preference.handler.Str ingPreferenceValueHandler:</csvhandler> </csvPreferenceDefinition> <csvLinkPreferenceClientDefinition handler="wt.preference.LoadPreference.setClientDefinitionLink"> <csvname>homeStickyOid</csvname> <csvclientName>WINDCHILL</csvclientName> </csvLinkPreferenceClientDefinition> </NmLoader>
This step consists of multiple sub steps and can be repeated as many times as needed. The process of adding a main tab consists of the following steps:
Create the JSP
Create the JSP Create an action in navigation-actions.xml Create an entry in action.properties or an rbinfo file Add your action to the action list in navigation-actionModels.xml
In order to ensure that the correct main tab is selected properly, you must create your JSP in a package named after that tab. In our example I will create my list.jsp in the following path: codebase\netmarkets\jsp\mytab\list.jsp
11-19
This will ensure that mytab is selected when the user is viewing this JSP. Example JSP content:
<!-- Import the navigationRB file that contains the constant for the page title. --> <%@page import="com.ptc.core.ui.navigationRB" %> <!-- Set a request attribute to tell the navigation infrastructure the title constant --> <!-- OPTIONAL, the default is "Windchill" --> <!-- This must be done before including begin.jspf --> <%request.setAttribute("browserWinTitleConst", navigationRB.WIN_TITLE_WORKSPACE_VIEW); %> <!-- Set a request attribute to tell the navigation infrastructure the help context --> <!-- OPTIONAL, the default is that no help is displayed --> <!-- This must be done before including begin.jspf --> <%request.setAttribute("helpFileSelectorKey", "myTabListHelp"; %> <!-- begin.jspf is required to draw the header --> <%@ include file="/netmarkets/jsp/util/begin.jspf"%> <!-- Your content should occur between begin.jspf and end.jspf --> <H1>Hello World!</H1> <!-- end.jspf is required to draw the footer --> <%@ include file="/netmarkets/jsp/util/end.jspf"%>
Create an action for your new sub tab in navigation-actions.xml. You can create any type of action for a sub tab. In this example we will create an action that maps to the JSP created in the previous step.
<objecttype name="mytab" class="com.ptc.myTabClass"> <action name="list" > <command windowType="page"/> </action> </objecttype>
Create localization strings for your action in action.properties or your own rbInfo file. For more details see Customizing Localizable Labels and Enumerations on page 18-29.
Add your action to the action list in navigation-actionModels.xml
Add an entry to the action model that will add your action to
<model name="mytab navigation" defaultActionType="mytab" defaultActionName="list"> <action name="list" type="mytab"/>
11-20
</model>
Customization Points
Procedure - Changing the application logo Procedure - Changing the header or footer look and feel Procedure - Removing a Main Tab Procedure - Removing a Sub Tab Procedure - Context Bar
The application logo is controlled by CSS. Depending on what your install set is, a different CSS style is used. The following table lists the CSS style classes that are used and when they are used. When in doubt you can always change all the CSS classes to indicate the logo image you desire.
Style Class Install Set
Windchill ProjectLink standalone is installed. Windchill PDMLink standalone is installed. ProI is installed. Arbortext Content Manager is installed. Windchill ProjectLink and Windchill PDMLink are installed together.
The look and feel of the header and footer is controlled by CSS style classes defined in nmstyles.css. To change the look of the header update the appropriate style class. Below is a list of all the style classes and a description of what they do. For details on the logo image, please see the previous section Procedure Changing the application logo.
Style Class Description
pageHeader
This style defines the image that displays behind the logo and above the tabs and subtabs.
11-21
Style Class
Description
pageHeaderActions
This style controls the look and feel of the actions that are rendered above the tabs in the page header. This style controls the look and feel of the copy page button that is rendered above the tabs in the page header. This style controls the look and feel of the first level tabs. This style controls the look and feel of the second level navigation or sub tabs. This style defines the look and feel of the page footer, including the PTC logo displayed in the footer.
headerBtns
nav1 nav2
footer
To remove a main tab simply remove the action for that tab from the main navigation list in navigation-actionModels.xml.
<!-- Main navigation --> <model name="main navigation"> <action name="home" type="navigation"/> <action name="product" type="navigation"/> <action name="project" type="navigation"/> <action name="change" type="navigation"/> <action name="library" type="navigation"/> <action name="mytab" type="navigation"/> <action name="org" type="navigation"/> <action name="site" type="navigation"/> </model>
After removing the change tab from the main navigation action model above. The list will look like this:
<!-- Main navigation --> <model name="main navigation"> <action name="home" type="navigation"/> <action name="product" type="navigation"/> <action name="project" type="navigation"/> <action name="library" type="navigation"/> <action name="mytab" type="navigation"/> <action name="org" type="navigation"/> <action name="site" type="navigation"/> </model>
11-22
To remove a sub tab simply remove the action for that sub tab from the sub tab navigation list in navigation-actionModels.xml.
<model name="product navigation"> <action name="list" <action name="separator" <action name="view" <action name="listFiles" <action name="listTeam" <action name="listProduct" <action name="changeMonitor" <action name="view_forum" <action name="MyWorkspace" <action name="listTemplates" <action name="listUtilities" </model> type="product"/> type="separator"/> type="object"/> type="product"/> type="product"/> type="work"/> type="product"/> type="project"/> type="product"/> type="product"/> type="product"/>
After removing the Change Monitor sub tab from the product sub tab list above. The list will look like this:
<model name="product navigation"> <action name="list" <action name="separator" <action name="view" <action name="listFiles" <action name="listTeam" <action name="listProduct" <action name="view_forum" <action name="MyWorkspace" <action name="listTemplates" <action name="listUtilities" </model> type="product"/> type="separator"/> type="object"/> type="product"/> type="product"/> type="work"/> type="project"/> type="product"/> type="product"/> type="product"/>
The context bar has the capability to be customized. Three parts exist in the context bar. You have the container type followed by the container name. Then you may have a bread crumb depending on your location. In the example shown below, the bread crumb shows we are in a workspace and gives the name. Depending on your location you may see actions to the left of the container. These three parts of the context bar have the ability to be customized. Extend the ContextBarDelegate or a subclass of ContextBarDelegate Register MyContextBarDelegate
The ContextBarDelegate is packaged under com.ptc.windchill.enterprise.navigation.ContextBarDelegate. The first thing you need to do is create a subclass of ContextBarDelegate or extend a subclass like WTLibraryContextBarDelegate. Below is an example. Since we are extending WTLibraryContextBarDelegate we have the choice of using super method instead
11-23
of having to override the three main methods. Otherwise, if ContextBarDelegate is extended you will need to implement each of the three abstract methods. Sample Code:
public class MyContextBarDelegate extends WTLibraryContextBarDelegate { @Override protected NmHTMLActionModel getActionModel() throws WTException { //Insert customized code } @Override protected GUIComponentArray getLeftSideComponents() throws WTException { //Insert customized code } @Override protected GUIComponentArray getRightSideComponents() throws WTException { //Insert customized code } }
Description of the three methods getActionModel() - This returns the action model to be shown in the context bar getLeftSideComponents() - In most cases this currently returns the container type, name and the breadcrumb. getRightSideComponents() - Components can be shown on the far right side of the context bar. An example of this is when you are in the Project container you will see a yellow/green/red indicator of the project status.
Register MyContextBarDelegate
As an example you can view the components.service.properties.xconf located under: Windchill\codebase\com\ptc\core\components. Though the properties should be added to a specific customized service.properties.xconf file. In the above example you would write something like the following:
<Service context="default" name="com.ptc.windchill.enterprise.navigation.ContextBarDelegate"> <Option requestor=" wt.inf.library.WTLibrary" serviceClass="com.ptc.windchill.enterprise.org.navigation.MyContex tBar" selector="cbNav" /> </Service>
11-24
Procedure - Display a custom object type's details page under your new tab
This section describes how to make a custom object's details page display on a custom tab. This assumes the custom object has already been created and is called com.mycompany.MyObject and the custom tab has already been added following the instructions above and is called mytab.
Create a custom Navigation Delegate
The tab highlighting has the capability to be customized even further than the examples given already above. Tab highlighting is controlled by classes that extend the interface com.ptc.windchill.enterprise,navigation.NavigationDelegate. In general it is not recommended to implement the interface directly. You should subclass one of the existing out of the box implementations. Many of the NavigationDelegates available out of the box can be found in the com.ptc.windchill.enterprise.navigation package. For this example you will need to create a custom subclass of com.ptc.windchill.enterprise.WTContainedNavigationDelegate. This subclass will be very simple as it only needs to override one method: getSelectedTabFromContextObject()
Package com.mycompany; import wt.util.WTException; import com.ptc.windchill.enterprise.navigation.WTContainedNavigationDeleg ate; public class MyObjectNavigationDelegate extends WTContainedNavigationDelegate { /** * Creates a new instance of MyObjectNavigationDelegate */ public void MyObjectNavigationDelegate () {} /** * All MyObjects are displayed on mytab, so when this class is * invoked, The tab from context object should always be mytab. */ protected final String getSelectedTabFromContextObject() throws WTException { return "mytab"; } }
There are other methods that you may wish to override but getSelectedTabFromContextObject() is the only one required for this use case.
Register MyObjectNavigationDelegate
For some examples you can view the components.service.properties.xconf located under: Windchill\codebase\com\ptc\core\components. Though the properties
11-25
should be added to a specific customized service.properties.xconf file or site.xconf. In the above example you would write something like the following:
<Service context="default" name="com.ptc.windchill.en terprise.navigation.NavigationDelegate"> <Option requestor="com.mycompany.MyObject " serviceClass="com.mycompany.MyObjectNavigationDelegate" selector="mainNav" /> </Service>
After registering you will need to run xconfmanager -p from a windchill shell and restart the method server. In some cases it may be necessary to increase the order of the delegate. Essentially this increases the priority of the delegate and bumps it above other delegates. Currently this is done in the out of the box product for the VerstionableChangeItemNavigationDelegate like so:
<Service context="default" name="com.ptc.windchill.enterprise.navigation.NavigationDelegate"> <Option order="1" requestor="wt.change2.VersionableChangeItem" serviceClass="com.ptc.windchill.enterprise.change2.navigatio n.VersionableChangeItemNavigationDelegate" selector="mainNav" /> </Service>
When order is used be sure to use an order higher than the delegate you are trying override.
Limitations
In order to get your tab and sub tab to display and highlight correctly you must follow the following conventions You must place your sub tab JSPs in a directory that exactly matches the name you gave to your main tab in Procedure - Adding a Main Tab on page 11-17. In that example the main tab name is "mytab". You must create a JSP whose name exactly matches the defaultActionName and whose directory exactly matches the defaultActionType you specified on the action model in the Create a new sub tab model for your tab in navigationactionModels.xml section on page 11-18. In this example the JSP would be "mytab\list.jsp". You must name your JSP exactly the same as your action. In this example both are named "list".
11-26
Action Visibility
Objective
You want to customize the set of UI components (actions or other UI elements) that the administrators of the site, organization or containers can manage using the role-based visibility feature.
Background
The role-based UI functionality enables administrators to optimize the number of actions presented to users, so as not to confuse users by seeing actions they don't need or use for their role. Initially this support was just for container managers (in particular, project managers). It has been extended to a concept called profiles which sets action visibility at the site or organization level. A site administrator, organization administrator or container administrator can specify which users have visibility to the actions defined. For site and organization administrators this can be done through profiles. Profiles can be created at Site->Profiles or Org->Profiles. The actions defined will be presented with their default settings, and the administrator can choose to hide those actions. The administrator can then specify which participants (users, groups, orgs) belong to the profile. All members of the profile will have that visibility. If a member is in multiple profiles, the greatest visibility is provided. At the container level, the administrator can specify the visibility based on user roles. Anyone in those roles will have the visibility specified. Container-level role visibility will override any profile in which the member might be a participant. See the Windchill Business Administrator's Guide for more details about profileand role-based visibility administration.
Scope/Applicability/Assumptions
The role-based visibility administration capability is turned on, that is, the preference com.ptc.netmarkets.roleAccess.enabled is set to true. The customization can be performed while the capability is turned off, but the results will not appear in the UI until the capability is turned on. The customizer can manage both out-of-the-box UI components and customized UI components with this capability.
Intended Outcome
When configuring visibility by roles and configuring profiles, the administrator is presented with a list of UI components that can be managed. The administrator is unable to manage the visibility for any UI components that are not included in this list. As a customizer, you have the ability to customize the list of UI components available to administrators. You can:
11-27
add UI components to the list, remove UI components from the list, specify default visibility settings for UI components, change the order that UI components appear in the list, and change the labels for the UI components on the list.
At the site or organization level your intention is to manage the list presented when creating profiles:
At the container level, you are managing the equivalent list presented when configuring visibility by roles:
11-28
Solution
Modify the roleaccessprefs.xml file (and associated files as needed).
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: The behavior of user roles in Windchill The administration of ad hoc access control policies in Windchill The actions framework in the Windchill client architecture The navigation framework in the Windchill client architecture The management of XML file customizations The management of RBINFO file customizations
11-29
Solution Elements
Element Type Description
*actions.xml
XML
Files where actions and other UI components are defined. Actions are optionally given a uicomponent value.Actions.xml is located in <Windchill>/codebase; other *actions.xml files are generally in <Windchill>/codebase/config/actions. File for assigning default visibility to UI components. Setting items in this file can make them not appear at all for the site or containers. Whether or not the container manager can override the default value can also be changed here.Located in <Windchill>/codebase. Defines the labels to provide in the Uis for the actions or UI components.Located in <Windchill>/wtCustom/com/ptc/netmarkets/roleAcc ess/.
Roleaccessprefs.xml
XML
RoleAccessResource.rbInfo
RBINFO
In actions.xml (and all *actions.xml files), an action can be assigned a uicomponent attribute value. The uicomponent attribute provides a name for a UI component that can be referenced from the roleaccessprefs.xml and roleAccessResource.rbInfo files. Multiple actions can use the same uicomponent value; this provides the ability to manage those actions as a single UI component. If an action does not have a uicomponent, then the action name can be used to reference it as a UI component instead. However, in this case it cannot be grouped with other actions into a single UI component. The roleaccessprefs.xml file consists of a <uics> element containing several elements (or sections) that correspond to the primary tabs in the Windchill user interface. For example, the <project> section corresponds to the Project tab. Each section contains zero or more <uic> elements, each representing a UI component whose visibility within that tab can be administered. Each UI component, specified with the name attribute of the <uic> element, can appear in one or more sections. This allows the default visibility settings for that UI component to be assigned independently for different tabs. The roleaccessprefs.xml file applies to the UI component lists for visibility administration based both on profiles (at the site and organization levels) and on roles (at the container levels). However, the <global> section applies only to visibility administration using profiles. If a UI component is not tied to a specific tab (such as is the case with the Search link in the Windchill UI header) or the UI component is a first-level tab itself, it should be listed in the <global> section of roleaccessprefs.xml. Each UI component must have an entry in roleAccessResource.rbInfo that provides a user-friendly label for that UI component. These labels are used for the
11-30
UI components in the lists that are presented to the administrator when configuring visibility. In this file the resource entry constant identifies the UI component; it must match either the uicomponent from the action definition or the action name if the action has no uicomponent. The resource entry value provides the user-friendly label. Note: Your UI component label should be a verb phrase. If your action/UI component name is not already a verb phrase, place 'View' in front, for example "View Team Page."
See the section on the The uic Element on page 11-32 for attribute descriptions. Note: For actions that are valid for multiple tab types, put the entry under all the sections you want it to affect. 2. In roleAccessResource.rbInfo, add a new resource entry for the action display name:
31.value=Create Folders 31.constant=PROJECT_CREATE_FOLDERS
Regenerate your bundles. The name of the uic should be the same as the constant for the entry in the resource bundle. 3. In <Windchill>/codebase/actions.xml, modify the create folder action by: adding the attribute uicomponent="PROJECT_CREATE_FOLDERS"
<action name=" folder_create" checkaccess="true" uicomponent="PROJECT_CREATE_FOLDERS">
Caution: Follow best practices in backing up your XML files when customizing them. 4. Restart the servlet engine and the method server.
11-31
Steps 1 through 3 above can be performed in any order. Note that "PROJECT_CREATE_FOLDERS" is used for the uic name, the resource entry constant (but without the quotes), and the action uicomponent. It is necessary for all three of these items to share the same value in order to tie the customized behavior together. Upon completion of this procedure, an administrator can now configure the visibility to the Create Folder action under the Project, Program, Product, and Library tabs, based on profiles defined at the site or organization level, and based on roles at the container level.
Order
N N N
DefaultGuest
11-32
Parameter ManagerEnabl ed
Req? N
Description Whether or not this uicomponent can affect the manager role. Do not change this value in out-ofthe-box UICs. For customized UICs, you may choose your own setting. Whether or not this uicomponent can affect the guest role. Do not change this value in out-of-thebox UICs. For customized UICs, you may choose your own setting. The class on which runMethod exists The method to run when the UIAccess is changed. This represents the name of a method that will be run when a UIAccess element associated with this UIComponent is updated. The signature of this method must be: void foo(WTPrincipal principal, WTContainer container, boolean isRender) The principal passed in will be the group or user on which to operate. The boolean isRender is the updated value for the UIAccess.
GuestEnabled
true
true | false
RunClass runMethod
N N
11-33
3. Add a new entry to roleAccessResource.rbInfo with a constant that is the same as the uic name. The value is what will be displayed in the profile actions UI.
40.value=View Customized Tab 40.constant=CUSTOMIZED_TAB
Regenerate your bundles. 4. Restart the servlet engine and the MethodServer.
As a result, the "Create Folders" entry in the Configure Roles and Create Profile pages will affect the visibility for both folder_create and list_create_folder actions.
11-34
The only restriction on runClass is that it needs to be accessible from the MethodServer. Given runMethod="myRunMethod", then myRunMethod must have the following signature:
public static void myRunMethod(WTPrincipal principal, WTContainer container, boolean isRender) throws WTException
The principal passed in will be the group or user on which to operate. The boolean isRender is what the field in the UIAccess table was just set to for the passed in principal.
11-35
Navigation Stickiness
Objective
Your users are not able to access tabs because the stickiness context is wrong. Examples: Clicking on Library tab leads to the Product tab.
Background
Each tab maintains a sticky info in order to take the user back to the same page they were on last time they visited the tab. It is possible for the stickiness info to be corrupted somehow (e.g. Library tab having a sticky context object that is in a Product results in the issue described in the problem statement clicking on the Library tab leads to the Product tab). This issue should not occur during the normal course of navigating the UI, but it is very easy to simulate the issue by manually manipulating the url. One way to force this issue to occur is to visit the details page of an object in a Product and add tab=library as a url parameter. This would cause the object in the Product to be stored as the sticky object for the Library tab. Now clicking on the Library tab will lead to the Product tab.
Solution
Clear the sticky info for the tab with the issue.
Prerequisite knowledge
To see or clear the sticky info for a particular user, you need to be logged in as the user. Note: Depending on which solutions are installed and the users role, you would see a different set of tabs than what is shown in the screen shots.
11-36
In the above example you can see that the sticky info for the Product tab is a Product oid and the Discussions action (the Discussions sub tab). Also note, you can see there is no sticky info in the current session for the Project tab. This means either you havent visited the project tab in this session, or you have just cleared the sticky info for the project tab. Once youve visited a tab within the session, youd see at least a sticky action. The sticky context oid is optional and some sub tabs dont have one. (e.g. the Products List)
For example, if clicking on the Library tab leads to the Product tab, the Library tab sticky info should be cleared. So click on the clear library tab hyperlink. (or click on clear sticky info for all tabs if you dont mind clearing out all the stickiness info for that user) Notice both sticky context oid and sticky action should be blank after youve cleared the sticky info.
11-37
Additional Resources:
Windchill Client Architecture Action Framework Overview on page 11-2
11-38
12
Gathering the Data for the UI
This chapter describes how to gather data to be used in the user interface. Topic Page
Data Acquisition Configuration Properties .............................................. Page 12-2 Acquiring Data via Info*Engine .............................................................. Page 12-9 NmObject Utilities ................................................................................. Page 12-15
12-1
Background
This document describes how you can configure Windchill Client Architecture components to retrieve and process data, without writing framework-specific Java code. Windchill Client Architecture allows you to configure a means to get your backing component data, and then a way to configure how this data is postprocessed to extract the properties that will actually be shown in the UI. What this means is that you have a lot of flexibility regarding the kind of data you retrieve, as long as it can be post-processed by the infrastructure.
Scope/Applicability/Assumptions
Specific considerations for each type of Windchill Client Architecture component are covered in their respective sections within the Windchill Customizers Guide.
Intended Outcome
An understanding of what options are available to you to configure data acquisition for a Windchill Client Architecture component.
Solution
Use the getModel, describeColumn and describeProperty tags to configure a data source for your Windchill Client Architecture component.
Prerequisite knowledge
To apply this knowledge you need to have an understanding of the following: JSP expression language (EL) JSP tags Windchill Client Architecture overview
12-2
Solution Elements
Element getModel tag getIeModel tag describeColumn tag describeProperty tag Type JSP tag JSP tag JSP tag JSP tag Description Configures a MethodServer data source Configures an Info*Engine data source Configures a column to display in a table Configures a property to display in a property panel. Supports the same API as describeColumn. A tag attribute that allows you to change the "backing object" A reporting tool to find what existing Windchill Client Architecture extension points are in the system Batches together multiple getModel calls
batch tag
JSP tag
Your choice will often be dictated by some pre-existing API that you are trying to integrate into the page. If that is not the case, then consider the following. getModel will: Enable coding to Persistable and other plug and play interfaces Facilitate unit testing and more POJO-style development
getIeModel will: Facilitate federation and customization Limit the attributes available to you to whatever is specifically requested, rather than the entire java object. This can either be a good or bad thing, depending on the use case Require the definition of logical attributes to return associations
If you choose to use the getModel tag, then refer to the Constructing and Rendering a Table Using the JSP Framework section on page 13-23 for details on how it is configured.
12-3
If you choose to use the getIeModel tag, then refer to the Acquiring Data via Info*Engine section on page 12-9 for more information.
Procedure - Extracting properties from data elements when using the getModel tag
If you configured your component using the getModel tag, you still need to tell the Windchill Client Architecture framework how to extract each property that will be displayed in the component from the resulting data elements. In many cases Windchill Client Architecture can automatically figure out how to extract these properties: Bean properties: If you are using an API that returns a Java bean, and you intend to display a property in the UI that corresponds to a property of the bean, the infrastructure can handle this automatically. Soft attributes: Windchill Client Architecture knows how to automatically find soft attributes for your business objects, even if the objects you returned do not know about the soft attributes. Existing Windchill Client Architecture extensions: Windchill Client Architecture already has a rich set of logical "properties" which can augment the business object or Info*Engine Element that you return.
Your backing APIs and tasks do not need to return Persistable objects. However, in order for non-Persistable objects to be selectable in the interface some additional configuration and/or extension may be necessary.
Bean properties
Windchill Client Architecture handles Java beans in the same way that the JSP EL does, meaning you can refer to a property name and the infrastructure will look for a corresponding getter on your object. For example, if you have described a table with a column like the following:
<jca:describeColumn id="foo" .../>
Then the infrastructure will look for a "getFoo" method on each result object that it processes when it executes your getModel API. If the method isn't found, then the infrastructure does not fail, but instead will simply return a null value, for the UI component to process in whatever way it chooses. By default the UI components just render a blank in this case. You are not limited to simple properties of the bean. In fact, anything you can do with the JSP EL can also be accomplished with Windchill Client Architecture. For example, you can use the dot notation to refer to nested properties. In addition, Windchill Client Architecture treats Map objects as beans, so if your API returns a Map or has a nested Map property, you can refer to it just as if it had getter methods. For complete information on what you can specify in bean notation, refer to the documentation for beanutils, the core package that Windchill Client Architecture uses to process bean properties.
12-4
More examples: bar[0]: get the first value of the bar property. This works if bar maps to a List or an Array. foo.bar: get the nested "bar" property of a "foo" property. If getFoo() returns a Map, then this would correspond to getFoo().get("bar")
The bean-style property access only works for getModel calls. Info*Engine calls that need to retrieve associated properties should instead define logical attributes for those properties.
targetObject
targetObject provides a complementary approach to bean-style notation to access nested properties of objects. It is described in more detail below.
Soft attributes
Windchill Client Architecture can automatically look up the soft attributes for your Typed business objects if you ask it to. If you have a soft attribute on your part named "baz", and have added a column descriptor as follows:
<jca:describeColumn id="baz" .../>
Windchill Client Architecture will fail to find a bean property for "baz" on your business object, but will not just give up. It will next try to see if "baz" could be a soft attribute of the object. There are two ways that Windchill Client Architecture can determine this: If "baz" corresponds to a logical attribute of the object type. If the component id is a soft attribute external form, such as IBA|baz
If Windchill Client Architecture is able to find a soft attribute definition for the object, then it will go and fetch the object's value. Retrieval of soft attributes can be expensive, so if Windchill Client Architecture determines a soft attribute retrieval is in order, it will get the soft attributes for all objects in the data set at once.
The soft typing infrastructure provides some convenience attributes that you can include in table definition to get a collection of related soft attributes. For example, the ALL_SOFT_ATTRIBUTES attribute will, as the name implies, retrieve any soft attribute that is visible on the object. To use this in a table definition, do the following:
<describeColumn id="ALL_SOFT_ATTRIBUTES" .../>
12-5
The out-of-the-box Windchill Client Architecture rendering infrastructure recognizes batch attributes and knows to expand out the resulting attribute set into individual columns per attribute.
Existing Windchill Client Architecture extensions
Beyond simple bean-style property retrieval and soft typing, Windchill Client Architecture also provides extensions that handle the many properties that need additional processing beyond what the core business object model provides. Some of these properties may still correspond to an underlying property of the business object, and some may in fact be doing their own separate data acquisition to add in data that the core business object doesn't know about. Refer to the "Finding existing Windchill Client Architecture extensions" procedure below for more information on discovering what extension points exist in the system.
Procedure - Using the targetObject configuration to change the "backing object" for a component
targetObject allows the developer to manipulate the result set from a backing API call, so that the infrastructure treats a property of each result object as the "row" object rather than the result object itself. For example the following configuration tells the infrastructure to use the "foo" property of the result object as the backing object for the "bar" row:
<jca:describeColumn id="bar" targetObject="foo" .../>
You may be wondering how this configuration of targetObject differs from a configuration that uses bean-style property configuration. For example the following configuration calls getFoo().getBar() on the row object returned by your API:
<jca:describeColumn id="foo.bar" .../>
Rule of thumb: Use targetObject with Windchill Client Architecture extension classes
The difference between the foo.bar and targetObject="foo" approaches is that when you configure target object, the infrastructure treats the target object as if it were the object returned by your backing API. When you use the bean-style property configuration, the backing object for the API remains the row object that the Windchill Client Architecture infrastructure interacts with. This difference becomes significant when using Windchill Client Architecture extension classes in particular -- these classes may base functionality on what they think the current row object is, not just on what the specific property is that was requested in the component configuration. For this reason, it is generally a good practice to use the targetObject property when reusing a Windchill Client Architecture extension class (typically a DataUtility implementation).
12-6
This difference is also significant when implementing a selectable component. With targetObject, the selected object will be the nested object, whereas if using bean properties, the selected object will still be the data element returned by the getModel API.
Where can I use targetObject?
You can use target object at both the component level, in which case it applies to all columns or properties, or on specific columns or properties within the component.
What object types can targetObject return?
The targetObject can be any of the following types: Persistable WTReference ObjectIdentifier NmObject NmOid NmSimpleOid
You can use target object to point to an object that is not a Persistable by wrapping the object in an NmSimpleOid. Refer to the NmObject Utilities section on page 12-15 for more information.
For information on how to implement your own Windchill Client Architecture extensions, refer to the Data Acquisition Configuration Properties section on page 12-2 for more information.
12-7
Customization Points
Refer to the Constructing and Rendering a Table Using the JSP Framework section on page 13-23 and the Windchill Client Architecture Tree section on page 13-64 for details on the various tag customization points discussed in this document
Sample Code
Refer to the Constructing and Rendering a Table Using the JSP Framework section on page 13-23 and the Windchill Client Architecture Tree section on page 13-64 for more code samples.
12-8
Background
Windchill Client Architecture provides a getIeModel tag that works similarly to the getModel tag, but that retrieves its data from Info*Engine. The tag interacts with other Windchill Client Architecture tags just as getModel does. The difference is that instead of specifying a service method, one specifies an action that maps to an Info*Engine task.
Intended Outcome
A Windchill Client Architecture table that has its data backed by an Info*Engine task
Solution
Use the Windchill Client Architecture getIeModel tag to configure a Windchill Client Architecture table component
Prerequisite knowledge
Readers should be familiar with Info*Engine as well as with the basic Windchill Client Architecture data acquisition concepts.
Solution Elements
Description Configures the task to use to get the data The Info*Engine tag library A tag from the ie tag library that supplies parameters to the getIeModel tag
12-9
task, where the resulting model is put in the scoped tableModel variable, and the relevant table descriptor is supplied by the tableDescriptor scoped variable:
<jca:getIeModel var="tableModel" descriptor="${tableDescriptor}" action="dca-search"/>
getIeModel is implemented by an Info*Engine-based tag handler. This means it works like the tags included in the Info*Engine JSP library, and can interact with them. Since it is an Info*Engine tag, getIeModel uses the page VDB and is embeddable. In addition, you supply parameters to the tag using Info*Engines param tag. To use the param tag, you need to include the Info*Engine tag library in your page, as follows:
<%@ taglib uri="http://www.ptc.com/infoengine/taglib/core" prefix="ie"%>
Internally, the getIeModel tag uses Info*Engines Dispatch-Tasks webject to look up the task implementation for the action task name that is configured in the JSP. getIeModel exposes several parameters which are passed on to Dispatch-Tasks that it uses to choose the right implementation task. Refer to the Dispatch-Tasks documentation in the Info*Engine Users Guide.
<jca:getIeModel var="tableModel" descriptor="${tableDescriptor}" action="dca-search"> <!--These parameters are used by Dispatch-Tasks--> <ie:param name="GROUP_IN" data="groupInName"/> <ie:param name="TYPE" data="typeName"/> <ie:param name="CLIMBER" data="climberName"/> </jca:getIeModel>
By default, any request parameters in your JSP page will be supplied as part of the form data to your task. So, if the pages URL ends with something like /somePage.jsp?foo=bar, then in your task implementation, @FORM[]foo[] will map to bar. If you want to explicitly configure the form data for your task, then you can do this by creating the form group in your jsp page (using Info*Engines JSP tag library), and then specifying the name of the group as an attribute of the getIeModel tag, as follows:
<jca:getIeModel var="tableModel" descriptor="${tableDescriptor}" form="formGroupName" action="dca-search">
12-10
The getIeModel tag fully supports configurable table views. Sort and filter criteria from the current table view are passed along to your task as described in the following section.
Using information supplied to your task by Windchill Client Architecture
Windchill Client Architecture supplies information to your task about the attributes displayed by the requesting component and current table view (if the component uses configurable tables). Your task can then use this information to query for the right resulting data. The additional parameters supplied to your task map to a subset of those accepted by the Query-Objects webject: ATTRIBUTE: This contains the list of attributes the component wants to display SORTBY: What attributes to sort by SORTED: The sort direction for each attribute WHERE: Filter criteria TYPE: The type or types to search for. VERSION: Whether LATEST or ALL versions should be returned. ITERATION: Whether LATEST or ALL iterations should be returned ATTRIBUTE_TYPE_CONTEXT: When multiple types are supplied, the type that should be used as a context to look up attribute definitions PAGE_LIMIT: The number of results per page PAGE_OFFSET: The first result row to return from the paging session, if any PAGING_SESSION_ID: The current paging session id, if any
Note: Most of these parameter names can be reconfigured to some other name using ie:params. See the Customization Points section below for details.
12-11
Any
No
The name of the attribute to put the page limit info in The name of the attribute to put the page offset info in
PAGE_OFFSE T
Any
No
Limitations
Currently there is no Info*Engine support for trees.
12-12
Sample Code
The following JSP page demonstrates how a simple search page could be constructed, given a backing task name demo-Search. The page submits back to itself, supplying the TYPE and WHERE parameters to the backing task.
<%@ include file="/netmarkets/jsp/util/begin.jspf"%> <%@ taglib uri=http://www.ptc.com/windchill/taglib/components prefix="jca"%> <%@ taglib uri=http://www.ptc.com/infoengine/taglib/core prefix="ie"%> <h2>Test Search</h2> <table> <tr> <th scope="row" align="right">Type:</th> <td> <input type="text" name="TYPE" value="${param.TYPE}"/> </td> </tr> <tr> <th scope="row" align="right">Additional criteria:</th> <td> <input type="text" name="WHERE" value="${param.WHERE}"/> </td> </tr> <tr> <td colspan="2" align="right"><input type="submit" value="Search"/></td> </tr> </table> <p> <jca:describeTable var="tableDescriptor" id="searchTable" label="Search Results"> <jca:describeColumn id="name"/> <jca:describeColumn id="number"/> <jca:describeColumn id="version"/> </jca:describeTable> <jca:getIeModel var="tableModel" descriptor="${tableDescriptor}" action="demo-Search"/> <jca:renderTable model="${tableModel}"/> <%@ include file="/netmarkets/jsp/util/end.jspf"%>
12-13
12-14
NmObject Utilities
Objective
You need to give each row in a Windchill Client Architecture table or tree a unique identifier, and a persisted object identifier is either inappropriate or unavailable.
Background
Left to their own devices, Windchill Client Architecture components assume that each row object that they are processing is a Windchill Persistable object. Components use the object identifier from the Persistable as a way to uniquely identify the object for selection and hyperlinks. If you run into a situation where the data returned by your query is not a Persistable object, or the data does not map to a Persistable in an obvious way, then you can implement an NmObjectUtility to provide the infrastructure a way to uniquely identify your objects. targetObject is preferable to NmObjectUtility If the row objects expose an API that returns a supported object type, then you do not need to write an NmObjectUtility. In this case, you can use the targetObject configuration at the table and/or column level to tell the infrastructure what property to use as the backing object for the row. The supported object types along with additional information are documented in the Data Acquisition Configuration Properties section on page 12-2. If it is possible to modify the row objects to expose an API for targetObject, this approach is considered a better practice than writing an NmObjectUtility, as it means you have fewer dependencies on framework-specific code.
Intended Outcome
An implementation of the NmObjectUtility interface
Solution
Implementing an NmObjectUtility
Prerequisite knowledge
You need to have an understanding of the following: Windchill application context (service.properties) Windchill Client Architecture Overview Configuring Data Acquisition NmObjects Overview
12-15
Solution Elements
Element NmObjectUtility DefaultNmObjectUtilit y An xconf file Type Interface Class Configuration file Description The NmObjectUtility interface that you will implement The default implementation of NmObjectUtility that you may extend The file in which you will register your new NmObjectUtility
To construct an NmObject for a persisted object, you must obtain a Persistable, WTReference, or ObjectIdentifier for that object. Once you have the identifier, you use it to construct an NmOid and subsequently an NmObject.
//Construct an NmObject from a Persistable public NmObject getNmObject(Object datum, ModelContext mc) { //getPersistableFromDatum is your method to find //the Persistable object Persistable p = getPersistableFromDatum(datum); NmOid oid = new NmOid(p); NmObject result = new NmObject(); result.setOid(oid); return result; }
To construct an NmObject for a non-persisted object, you must create a unique String key for the object. Once you have the key, you use it to construct an NmSimpleOid and subsequently an NmObject.
//Construct an NmObject from a Persistable public NmObject getNmObject(Object datum, ModelContext mc) { //getStringKeyFromDatum is your method to find //the unique String key String key = getStringKeyFromDatum (datum); NmSimpleOid oid = new NmSimpleOid(); oid.setInternalName(key); NmObject result = new NmObject();
12-16
Once you have written your NmObjectUtility, you need to let the Windchill Client Architecture infrastructure know about it. To do this, you add an application context mapping for the NmObjectUtility, where the table id that you want the NmObjectUtility to be used for is the application context selector. For example, if the table id is customTable, then the xconf entry would look as follows:
<Service name="com.ptc.core.components.descriptor.NmObjectUtility"> <Option serviceClass="com.myco.MyCoNmObjectUtility" selector="customTable" requestor="java.lang.Object" cardinality="singleton"/> </Service>
After adding the xconf entry, be sure to run the xconfmanager to propagate the change to your installation.
NmCommandBean
Object that provides Windchill Client Architecture state information to other Windchill Client Architecture layers. It is the what, where, and how of the UI. It wraps the request object and adds value by parsing the parameters into related items. Once initialized by the request, the NmCommandbean can answer Windchill Client Architecture related questions. It will execute actions if they exist on the request but it won't execute actions accidentally if the page is manually refreshed and the form is resubmitted. It essentially carries the request and state information from the Tomcat VM to the Method Server VM. Interesting attributes: Context: the where. compcontext, parentContext, element context, etc are used to determine what page is displayed and where actions are launched. oids : the objects that actions or pages apply to. requestData : all the state info about the page
Contains a number of helper APIs: getActionOid() : gets the object that is the target of the action. getPageOid() : gets object that the page is being displayed in this page. getViewingContainer() : gets the container that the page is displayed in.
12-17
NmAction
NmAction represents a line from actions.xml which describes a page in Windchill. It is rendered as all the icons and links that one can click to make changes to the Windchill system. Each jsp page should be described by an NmAction in an xml file. The localized attributes of the NmAction can be found in the action.properties or other rbInfo files.
NmOid
A Netmarkets version of a WTReference that hides some details of the different reference types and provides helper apis to aid in caching. Furthermore, it is the object that understands how to parse any string format from the request that represents an object in the db.
NmSimpleOid
NmSimpleOid represents a non-persisted business object. Often it is used to represent some item that has not been created yet or some object that wraps a persistable with more information. String parsing of the NmSimpleOid is completely handled by the code for the relevant table and actions and should be in an NmObjectUtility.
NmContext
NmContext represents a UI address of a page. Component is a jsp page Jsp page can include multiple components Component address includes addresses of ancestor components Context (address) of a component B is "Address 1 - Address B"
Example NmContext string a document residing in a folder on a project's folders page. Note that the $, ^, and !* are reserved separator characters.
"folder$list$OR:wt.projmgmt.admin.Project2:2343$OR:wt.folder.Su bFolder:7195^VR:wt.doc.WTDocument:18913!*
12-18
13
Presenting Information in the UI
This chapter describes how to customize information that is displayed in the user interface. Topic Page
Attribute Handling.............................................................................................13-2 Soft Attributes and SCAs ................................................................................13-21 Constructing and Rendering a Table Using the JSP Framework ....................13-23 Windchill Client Architecture Tree.................................................................13-64 Adding Custom Modeled Attributes to all Table Views.................................13-91 Attribute Tables...............................................................................................13-92 Generating the Name Attribute Server............................................................13-97 Partial Activation of JSCA ............................................................................13-102 Icon Delegates ...............................................................................................13-103 UI Validation.................................................................................................13-109 Customizing the Find Number Field .............................................................13-152
13-1
Attribute Handling
Objective
You want to render a UI component for an attribute of a Windchill object to either capture the users input during Create/Edit or to display the existing value of that attribute.
Background
In a Windchill client application, attributes of Windchill objects are rendered in 2 modes the input mode for Create and Edit and the view mode (on the Information pages, Tables, etc). The data-type of these attributes is restricted to the Windchill supported data-types exposed in the Information Modeler and the Attribute Manager. Standard data acquisition, translation, rendering and form processing mechanisms are required to maintain consistent attribute handling behavior across all client applications. The consistency is achieved by using the JCA framework. This framework provides re-usable components for building the UI components to represent attributes, from the server-side objects that represent them. The framework also provides extension points for customization via the ability to override the standard data-translation and rendering behavior. This document describes the best practices for creating and rendering a HTML GUI component to represent a Windchill attribute. A data utility is used to create a GUI component for an attribute. The data used to create this GUI component is a combination of the attribute and constraint definitions, and the configurations listed in the Customization Points section on page 13-12. The renderer for the GUI component generates the HTML for rendering the component. The Property Panel section on page 10-26 and the Constructing and Rendering a Table Using the JSP Framework on page 13-23 describe how to configure an attribute for being rendered in the client. The GUI components and their renderers can also be used to represent attributes that are not Windchill attributes like drawing a simple check-box on a page to capture some input from the user. GUI components can be simple components such as a text-box or composite GUI components built using the simple components, like a component that uses a textbox and 2 combo-boxes, as shown below: Simple GUI component:
13-2
The components generated by this framework also have some built-in client-side validations, based on the constraint definitions and the configurations.
Scope/Applicability/Assumptions
Applicability
This practice should be followed when developing clients that need to display the following attributes: Attributes whose type is a valid Windchill soft attribute type. Boolean Integer Floating point number Floating point number with Units String Date & Time wt.fc.EnumeratedType URL WTOrgRef: At this time, the framework has support to display the value of these types of attributes, but does not support the input/editing of those values. The Windchill Product Structure Explorer provides the necessary support to input values for these attributes. Classification Node
Attributes whose type is any of the following native Java types: primitive boolean, java.lang.Boolean primitive byte, short, integer, long, java.lang.Byte, java.lang.Short, java.lang.Integer, java.lang.Long primitive float, double, java.lang.Float, java.lang.Double java.lang.String java.sql.Timestamp
13-3
Name Number Location Revision label Principal Status (work in progress state) Lifecycle state Lifecycle template Team template
Intended Outcome
Consistent attribute handling behavior (rendering, validation wherever applicable and attribute processing) on any Windchill client that uses a given Windchill attribute in a given mode.
Solution
Use the Windchill client framework for rendering attributes in a Windchill client application.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: The Windchill soft attributes, Attribute Manager, Type Manager, constraints that can be defined on attributes in the Type Manager. The InfoModeler and constraints that can be defined on attributes in the InfoModeler. Basic knowledge of the Windchill Client Architecture The Windchill JSP describeColumn , describeProperty tags AllClients.xml and Windchill preferences for customizations The management of RBINFO file customizations
13-4
Solution Elements
Type
Description Used to define the modeled attributes of a Windchill class and to define the constraints on each of those attributes. Used to define the instance based attributes and the attribute constraints using this tool. Used to define rules and constraints on objects. Used to customize some of the attribute rendering behavior that needs to be applied to all attributes across all clients.
Windchill Attribute Manager and Type Manager Object Initialization Rules Administrator Windchill Preference Manager AllClients.xml Xml file
Used to customize some of the attribute rendering behavior that needs to be applied to a specific attribute across all clients. Used to customize some of the attribute rendering behavior that needs to be applied to a specific attribute in a specific client.
Jsp files
JSP
rbInfo rbInfo java Contains localized strings, can be defined separately for each module. Implements the methods to create concrete GUI component objects for a given attribute. Configuration point for mapping components to data utilities to override default GUI component creation behavior The model for a GUI component class Implements the rendering of a GUI component Configuration point for mapping GUI components to renderers to override default rendering behavior
properties
13-5
Type java
Description The classes that process the form data of the OOTB GUI components.
If the type of your attribute is not one of the Windchill Client Architecture framework supported types listed in the Scope/Applicability/Assumptions section on page 13-3, or you need to augment/alter the data returned by a core API, implement a data utility as explained below in the Implementing a Data Utility section on page 13-8 to create a GUI component for that attribute. Example: The 9.0 Windchill Client Architecture does not support the handling of attributes of type java.sql.Date out-of-the-box. If you want to render an attribute of this type in a JCA client, you may need to implement a DataUtility that knows how to create a GUIComponent for this type.
Object getDataValue(String component_id, Object datum, ModelContext mc) throws WTException { Object rawValue = getAttributeValue(component, datum, mc); DateDisplayComponent gui = new DateDisplayComponent(label); if (rawVal != null && rawVal instanceof Date) { gui.setValue(new Timestamp(rawVal.getTime())); } return gui; }
If custom UI behavior is required for the attribute, you are familiar with the JCA GuiComponent that represents that attribute and the data held in this object is sufficient to provide the rendering behavior you require, implement a custom Renderer for rendering the GUI component outlined in the Implementing a GUI component renderer section on page 13-10. Example:
13-6
The OOTB Renderer implementation for rendering a GUI component for date & time renders the component like this:
In this case you would write a custom renderer for the DateInputComponent. If the desired behavior cannot be achieved by just implementing a Renderer, the next alternative is to implement a GUI component for the attribute as outlined in Implementing a GUI component section on page 13-11. You may need to create a special form processing delegate if you are trying to use custom GUI components. See the Wizard Processing section on page 14-19 and Building Wizards to Create a Single Object on page 14-38 for information on how to do this.
Attribute Type is Windchill supported type, but you need to modify the way it is rendered
Same as Attribute type is not a Windchill JCA framework supported type on page 13-6 except that you may need to implement a data utility only if you are creating a custom GUI component.
Data needs to come from a different source
You may be able to do this just by configuration using the target object as described in Data Acquisition Configuration Properties on page 12-2. If that does not meet your requirements, you can implement a data utility that knows how to interpret the data and create a GUI component from it.
Need to post-process the raw data returned by the core APIs before displaying it
Same as Attribute type is not a Windchill JCA framework supported type on page 13-6. You can post-process the raw data in the data utility before using it to create the GUI component. You may need to create a special form processing delegate if you are planning to use custom GUI components. For example, you may want to generate a hidden
13-7
field to store some data that may be required in conjunction with the data from the GUI component in order to derive the actual value for an attribute. The generic OOTB form processors will not have any knowledge of this specific hidden field that was part of your custom GUI component and how it needs to be processed. In this case, you may need to write your own form processing delegate that knows how to process this field.
3. Perform any necessary customizations as described in the Customization Points section on page 13-12. Refer to the Data Acquisition Configuration Properties on page 12-2 for details on how to get a report of all the available ids that you can add to your configurations, as well as what the data utility implementation class is for that id.
After defining your attribute and its constraints, you should be ready to implemenat a data utility to handle that attribute. Since data utilities are looked up using application context, your implementation class must be public, and have a public no-arg constructor.
13-8
The getDataValue method gets the value that should be placed within a particular table cell. Typically, the object that is returned by this method should be an instance of GUIComponent. Example: Suppose you want to append the value of a specific string attribute with some extra text. This can be done as follows:
Object getDataValue(String component_id, Object datum, ModelContext mc) throws WTException { .. .. String rawVal = myObjetc.get(component_id); String displayVal = rawVal + My extra text; TextDisplayComponent gui = new TextDisplayComponent(); gui.setValue(displayVal); return gui; }
When multiple objects needs to be fetched, as in the case of a table where multiple row objects needs to be fetched, the setModelData() method allows the data utility to prefetch data for all the row objects that will be rendered. The method is called before getDataValue() is called for any row, and is supplied in a list of all the objects that will be processed. You can take advantage of this call to do some multi-object queries. The FolderedDataUtility is one example that does this (it queries for all folder locations at once). If this method is implemented, then you must configure the data utility to be stateful.
Configure the data utility
13-9
cardinality="duplicate"/> </Service>
A note on cardinality: Your safest bet is to use a "duplicate" cardinality. This will create a new instance of the data utility each time one is requested. Example: The FolderedDataUtility is configured with cardinality "duplicate". This is because the FolderedDataUtility is stateful, it does some multi-object querying in setModelData, and then holds on to this data for subsequent calls to getDataValue. Since the utility is stateful, you must create a new instance of the utility for each table rendering request. By registering the data utility as "duplicate", application context will instantiate a new data utility for you each time one is requested. Data utility configuration entries can be added to any xconf file that ends up being read in by application context (any "service.properties"-type file).
Example: The OOTB Renderer implementation for rendering a GUI component for date & time renders the component like this:
13-10
In this case you would write a custom renderer for the DateInputComponent. 1. Implement the custom renderer
public abstract class MyDateRenderer implements Renderer { public void draw(T o, Writer out, RenderingContext renderContext) throws RenderingException { // render the textbox and icon for the calendar widget // render a new line // render the combo box for the hours, the combo box for the minutes and the time zone } }
2. Register your custom renderer. In your data utility, when creating the GuiComponent in the getDataValue method, register this custom renderer as your DateInputComponents renderer
DateInputComponent gui = new DateInputComponent(); gui.setRenderer(new MyDateRenderer());
It is recommended that when you implement a new Renderer, you extend the AbstractGuiComponent base class.
13-11
private int maxCharLimit = 20; protected Renderer renderer; public void draw(Writer out, RenderingContext renderContext) throws RenderingException { if (renderer != null) { renderer.draw((Object)this,out,renderContext); } } }
The TLD is
$WT_HOME/WEB_INF/tlds/wrappers.tld
Customization Points
Windchill preferences
Parameter Default Value Display Mode (Site level) Default Value Pre-populate Possible Values Do not display Pre-populate Button Description Mode of displaying the default value in the Create and Update modes This applies to all attributes. Selection List Style (Site level) Buttons Buttons Dropdown List UI style for Discretesets/Enumerated set elements
13-12
Description UI style for Boolean attributes A preference used to determine whether the input field for String attributes and URL IBA type attributes should be single-line or multi-line. Local time zone of the user will be used as the time zone for the display / input of date values. Determines the measurement system to be used for all numeric values that have a Unit of Measure. This will filter out special HTML characters from strings while displaying the string values. Used to control the number of characters displayed when the attributes value is displayed on a table. This is also known as the truncation length of an attribute value.
60
Measurement system(User)
SI
No
Yes No
30
13-13
Default Value 30
Description Used to control the number of characters displayed when the attributes value is displayed on an info page. This is limited to the top attributes panel and the folder location (for folder info pages). Any table displayed on an info page will be based Display length for attribute value in tables. This is also known as the truncation length of an attribute value.
13-14
AllClients.xml
Codebase location: WT_HOME/codebase/config/logicrepository/xml/AllClients.xml Examples for the configuration are available in the documentation provided in this xml file.
Possible Values - none prePopulate - button selectionListStyle - buttons - dropdown stringLengthThres hholdForMultilineI nput inputFieldType multiLine Any number >= 0 No No UI style for Discrete-sets/Enumerated set elements A preference used to determine whether the input field for String attributes and URL IBA type attributes should be single-line or multi-line.
Default Value
Req? No
Description Mode of displaying the default value in the Create and Update modes This applies to all attributes.
- singleLine - multiLine
No
dateInputFieldTyp e
No
Need to know this for CREATE & EDIT modes so that the UI can be created accordingly. (It is not possible to obtain this info from the format because the formats will be localized and it is not easy to parse the localized formats to get this info) This determines the display format for the Timestamp values.
dateDisplayFormat
Entries should have these 2 parts: rbInfo=nam e of the rbInfo file key=name of the entry
ignoreUrls
- true - false
No
This will filter out special HTML characters from strings while displaying the string values.
13-15
Default Value
Req? No
Description Used to control the number of characters displayed when the attributes value is displayed on a table. Used to control the number of characters displayed when the attributes value is displayed on an info page. This is limited to the top attributes panel and the folder location (for folder info pages). Any table displayed on an info page will be based Display length for attribute value in tables. Determines if a numeric value should be formatted with the locale-specific percent format Determines if a numeric value should be formatted with the locale-specific currency format
No
percent
true false
No
currency
true false
No
13-16
JSP files
Parameter defaultValueDispl ayMode Default Values Possible Values - none - prePopulate - button Req? No Description Mode of displaying the default value in the Create and Update modes This applies to all attributes. Example: <jca:describeProperty id="defaultUnit" defaultValueDisplayMode=button /> selectionListStyle - buttons - dropdown No UI style for Discrete-sets/Enumerated set elements Example: <jca:describeProperty id="defaultUnit" selectionListStyle=buttons /> stringLengthThres hholdForMultilineI nput Any number >= 0 No A preference used to determine whether the input field for String attributes and URL IBA type attributes should be single-line or multi-line. <jca:describeProperty id="description" stringLengthThreshholdForMultilineIn put =500/> inputFieldType multiLine - singleLine - multiLine No Overrides the behavior determined by
stringLengthThreshholdForMultilineInput
dateInputFieldTyp e
No
Need to know this for CREATE & EDIT modes so that the UI can be created accordingly. (It is not possible to obtain this info from the format because the formats will be localized and it is not easy to parse the localized formats to get this info) Example: <jca:describeProperty id="startDate" dateInputFieldType= dateAndTime/>
13-17
Parameter dateDisplayFormat
Default Values
Possible Values A format string specified as an entry in an rbInfo file. This format string shall use the format pattern letters specified by Javas SimpleDateF ormat class. Standard Windchill formats are defined in \ wcCliSource\ UICommonR esources\src\ com\ptc\ core\ui\ componentR B.rbInfo And these can be used by specifying the entries in \Windchill\ DevModules\ CommonCo mponents\ src_web\ netmarkets\ jsp\ components\ standardAttri buteConfigs.j spf
Req?
Description This determines the display format for the Timestamp values. Example: <jca:describeProperty id="startDate" dateDisplayFormat="${standardDateTi me}"/>
13-18
Default Values
Req? Yes
Description Used to control the number of characters displayed when the attributes value is displayed on a table. This is also known as the truncation length of an attribute value. Example: <jca:describeProperty id="description"
displayLengthInTables =15/>
displayLengthInInf oPage
Yes
Used to control the number of characters displayed when the attributes value is displayed on an info page. This is limited to the top attributes panel and the folder location (for folder info pages). Any table displayed on an info page will be based Display length for attribute value in tables. This is also known as the truncation length of an attribute value. Example: <jca:describeProperty id="description" displayLengthInInfoPage=15/>
percent
true false
Determines if a numeric value should be formatted with the locale-specific percent format Example: <jca:describeProperty id="percentComplete" percent=true/>
currency
true false
Determines if a numeric value should be formatted with the locale-specific currency format Example: <jca:describeProperty id="cost" currency=true/>
inputRequired
true false
Used to mark fields as Required fields even though they may not have a Required constraint. Example: <jca:describeProperty id="startDate" inputRequired=true/>
13-19
Parameter isInfoPageLink
Default Values
Req?
Description Applicable to Name and Number and Principal attributes only. Used to specify if the attribute is to be displayed as a hyperlink to the Info Page. This would override the default behavior. Example: <jca:describeProperty id="name" isInfoPageLink=false/>
componentRB.rbInfo file
Parameter CALENDAR_PAR SE_DATE in \ wcCliSource\ UICommonResour ces\src\com\ptc\ core\ui\ componentRB.rbIn fo HOUR_FORMAT in \wcCliSource\ UICommonResour ces\src\com\ptc\ core\ui\ componentRB.rbIn fo Default Value Possible Value A legal localized date format defined using valid dateformat characters. 12 24 Req? Description Date input format (dd/mm/yyyy vs. mm/dd/yyyy etc) This is required so that the entered value can be parsed according to the format.
12 Hour/ 24 Hour format This determines the entries in the hours dropdown (0 - 12 AM/PM vs. 024)
Additional Resources
See the following sections for more information. Building Wizards to Create a Single Object (on page 14-38) Building Wizards to Edit a Single Object (on page 14-90) Data Acquisition Configuration Properties (on page 12-2) Presenting Information in the UI chapter - various sections on tables (starting on page 13-1) Property Panel (on page 10-26)
13-20
ALL_SOFT_CLASSIFICATION_ATTR IBUTES
ALL_SOFT_NON_SCHEMA_ATTRIB UTES
ALL_SOFT_SCHEMA_ATTRIBUTES
ALL_SOFT_SCHEMA_ATTRIBUTES_ FOR_INPUT_TYPE
ALL_SOFT_NON_CLASSIFICATION_ ATTRIBUTES
Example:
TypeIdentifier type_x = ...; AttributeTypeIdentifier ati = (AttributeTypeIdentifier) IDENTIFIER_FACTORY.get("ALL_SOFT_SCHEMA_ATTRIBUTES_FOR_INPUT_TYPE" ,type_x);
If 'ati' is requested to be returned when a TypeInstance is retrieved, it will return a list of only the attributes associated with type_x, regardless of the actual type of the retrieved object.
13-21
This attribute is typically used for tables of objects which may or may not be of the same type, but all have a common supertype which defines the appropriate columns to display.
Attribute ALL_SOFT_NON_CLASSIFICATION_ SCHEMA_ATTRIBUTES Description Returns a list of all soft attributes associated with the type of the retrieved object which are NOT associated with the classification(s) of the retrieved object as well as values for all of those attributes. Returns a list of all custom hard attributes associated with the type indicated by the context of the constructed AttributeTypeIdentifier as well as values for all of those attributes. 'Custom' hard attributes are defined to be all modeled attributes which are not inherited from classes in the 'wt' or 'com.ptc' packages.
ALL_CUSTOM_HARD_ATTRIBUTES _FOR_INPUT_TYPE"
13-22
Background
The table common component presents information in a tabular format to help users scan, locate, compare, and take actions on related data. Users may control how to view data in the table using sorting and views. The following tables details the specific elements within a table.
Element Description
Title Bar
The title bar area tells users what information is displayed in the table. The table title bar is located at the top of the table and may contain: a table title, an object count, the Current View pulldown list, and several action icons - Help etc. Tables with many actions will display a menu bar. Each menu title provides a pulldown list of actions. The shortcut tool bar displays a subset of actions from the menu bar. These are actions that are frequently used. The shortcut tool bar may be used without the menu bar when a table contains few actions. Sorting allows the user to control the presentation of table data. The checkbox column allows users to select and deselect objects within the table that they wish to perform an action upon. A user can also select the rows across the multiple pages and perform the desired actions on the same. The status glyph column(s) convey status and messaging information about individual objects in the table. The object icon column displays the appropriate icon for that object.
13-23
Element
Description
Action Column(s)
The action columns in the content area of a table contain the row-level actions for specific objects in a table. The data rows of a table contain attributes for a given object in the table. This section covers table scroll bars. The table footer is located at the bottom of the table. It provides visual closure to the table and contains the paging and View All functionality, if used.
Data Rows
Footer
Scope/Applicability/Assumptions
Table common component should be used when there is a requirement to display Windchill business objects in tabular form and not just for displaying the HTML Table.
Intended Outcome
Depending upon the configuration, Table can be displayed in different formats. Following is a general layout of a Table:
13-24
Solution
Use Table Component to display the information in tabular format.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Basic development involving HTML, JSP, JavaScript and Custom taglibs. Overview of Windchill Client Architecture tags. The actions framework in the Windchill client architecture. Configuring views. Data acquisition, Data Utilities, GUI component
13-25
Solution Elements
Element Type Description
<your_page>.jsp <your>service.properties
JSP properties
Your Windchill Client Architecture Table implementation JSP file. Data utilities and services are defined here. Run time Location: <Windchill>\ codebase
<your>action.properties
properties
<your>actions.xml
xml
Actions can be defined here. Run time Location: <Windchill>\ codebase\ config\actions
<your>actionModels.xml
xml
Action models can be defined here. Run time Location: <Windchill>\ codebase\config\actions
components.tld
tld
<your>action.rbInfo
rbInfo
You should include the necessary artifacts in your configuring JSP file e.g. /netmarkets/jsp/begin.jspf or /netmarkets/jsp/beginPopup.jspf file and /netmarkets/jsp/end.jspf file. You also need to declare jcataglib directive. (uri=http://www.ptc.com/windchill/taglib/components)
Configure Table
<%@ include file="/netmarkets/jsp/util/begin.jspf"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="http://www.ptc.com/windchill/taglib/components" prefix="jca"%> <%@ taglib uri="http://www.ptc.com/windchill/taglib/core" prefix="wc"%>
13-26
<%-->Build a table descriptor and assign it to page variable td<-%> <jca:describeTable var="tableDescriptor" id="netmarkets.project.list" configurable="true" type="wt.projmgmt.admin.Project2" label="Project List"> <jca:setComponentProperty key="actionModel" value="project list"/> <jca:describeColumn id="name" label="Name" sortable="true"/> <jca:describeColumn id="nmActions" /> <jca:describeColumn id="owner" need="containerInfo.ownerRef"/> <jca:describeColumn id="container" label="Host" need="containerReference"/> <jca:describeColumn id="category"/> <jca:describeColumn id="phase"/> <jca:describeColumn id="state" need="containerTeamManagedInfo.state"/> <jca:describeColumn id="projectHealthStatus" need="healthStatus"/> <jca:describeColumn id="completionStatus"> <jca:setComponentProperty key="percent" value="true"/> </jca:describeColumn> <jca:describeColumn id="modifyStamp" need="thePersistInfo.modifyStamp" sortable="true" defaultSort="true" /> </jca:describeTable> <%-->Get a component model for our table<--%> <wc:getCurrentUser var="user"/> <jca:getModel var="tableModel" descriptor="${tableDescriptor}" serviceName="com.ptc.netmarkets.project.NmProjectService" methodName="getProjects"> <comp:addServiceArgument value="${user}"/> </jca:getModel> <%-->Get the NmHTMLTable from the command<--%> <jca:renderTable model="${tableModel}"/> <%@ include file="/netmarkets/jsp/util/end.jspf"%>
The first thing the JSP page does is defines a table using the describeTable tag. This tag creates a table descriptor object and assigns it to the page variable specified by the var attribute. This allows the descriptor to be referenced in the JSP using the JSP expression language (EL). The table defines a type, in this case Project2. The type is optional, and is only used to do some defaulting of values. In this example, it is only being used to default the labels for model-based column ids. The actionModel property indicates the name of the action model (from actionmodels.xml) that should be rendered in the table's toolbar. The columns in the table each have their own describeColumn tag. Each column's cell values will be produced by a data utility.
13-27
Once the table descriptor is set up, it is passed in to the getModel tag. The getModel tag takes your table descriptor plus a way to get table data and returns a model object that can be used to render the table. Like the describeTable tag, the result of the getModel tag is placed in the pagescoped variable defined by the var attribute. The rendering portion of the table is simply done by passing your model object (defined by the getModel tag) into the renderTable tag. The Default Sorted column is defined with the defaultSort="true" attribute on the column tag.
Parameter id
Default Value -
Req? Yes
Description The identifier for this table descriptor. If this table supports configurable views, then this id may be used to look up the view configurations, unless it is overridden by the configurableTableId attribute. Name of the exported scoped variable for the table descriptor. The type of the variable is com.ptc.core.components.descriptor.Co mponentDescriptor. The name of the scope to export the var attribute to.
var
Yes
scope
No
type
No
Name of the main type of object displayed in this table. This can be either a modeled or soft type. When specified, the infrastructure will use the type to look up labels and other default values when it can't find them otherwise.
13-28
Parameter label
Default Value -
Possible Values Any java.lang.String value java.lang.String value of a com.ptc.core.ui.r esources.Compo nentMode java.lang.String value of a com.ptc.core.ui.r esources.Compo nentMode boolean -
Req? No
mode
No
The name of one of the modes defined in the com.ptc.core.ui.resoureces.Component Mode enum. VIEW is the default mode if not specified. The name of one of the component types defined in the com.ptc.core.ui.resoureces.Component Type enum. TABLE is the default if not specified. Whether or not this table supports configurable views. The id to use to look up configurable views. If unspecified, then defaults to the table id. Only used if configurable is set to 'true' When this property is true, and the table is configurable, then this property will change the table rendering so that the table view edit wizard is launched directly from the table, as opposed to launching the table view manager. This is useful when the table does not support views, but still needs to allow the user to select columns and sort order.
componentTyp e
No
configurable viewId
false -
No No
singleViewOnl y
true/false
toolbarName
No
The name of the action model to use for toolbar actions. The name of the action model to use for menubar actions. The help context for this table. No help icon will be displayed if no help context is specified.
menubarName
No
helpContext
No
13-29
Parameter targetObject
Default Value -
Possible Values -
Req? No
Description Allows the developer to provide more objects for a single table row. Typically the infrastructure treats each index of the array returned by the getModel tag's API as a "row" object. This row object is passed to each column's DataUtility. If a different object is needed for some DataUtilities then that object can be specified as the targetObject in the describeTable or describeColumn tag. The original row object must have a getter method for the name specified as the target object. (i.e. targetObject="my_related_part" would mean the object needs a getMy_related_part() method). The target object will be used in the following places: The row object supplied to data utilities. The object that soft attributes will be extracted from The context object for the row checkbox
summary
No
A localized summary of the information in this table, which is used for accessibility compliance. Flag to indicate enable or disable collapse/expand action. It will work only when useJSCA=false This property when set to true, then current table will be considered for column freezing. By default the value is true.
disableAction
No
isFreezable
Boolean
No
13-30
Additional attributes set via the setComponentProperty sub tag Parameter actionModel scrollType Possible Values java.lang.String java.lang.String Description value that corresponds to an entry in an *actionmodel.xml file Value that represents constants from the JSTableConstants class under keys .JSTABLE_IMPL* "default" - chooses the browser default "D" = Dom based scrolling, the default for tables in popup wizard pages.
selectable
true/false
Determines if the checkbox column will be displayed. If set to false there will not be any check box column for table as well as tree.
Parameter var
Default Value -
Req? Yes
Description Name of the exported scoped variable for the descriptor. The name of the scope to export the var attribute to.
scope
No
serviceName
No
The name of the service class to use to get model data. This property is mutually exclusive with the queryCommand or statementSpec attributes. If this attribute is specified, then methodName must be specified as well. Arguments to the method can be specified with the addServiceArgument tag. The service class must either be a registered Windchill service or implement wt.method.RemoteAccess.
13-31
Parameter methodName
Default Value -
Req? No
Description The name of the method to use to get model data. This property is mutually exclusive with the queryCommand or statementSpec attributes. If this attribute is specified, then serviceName must be specified as well. Arguments to this method can be specified with the addServiceArgument tag. The StatementSpec to use to get model data. Note that QuerySpec implements StatementSpec. This property is mutually exclusive with the queryCommand, serviceName, and methodName attributes. The AbstractQueryCommand to use to get model data. This property is mutually exclusive with the statementSpec, serviceName, and methodName attributes. The descriptor to base the component model on
statementSpec
No
queryComman d
Is of type com.ptc.core.que ry.command.co mmon.Abstract QueryCommand Is of Type com.ptc.core.co mponents.descri ptor.Component Descriptor java.lang.String of a fully qualified class name Any integer value
No
descriptor
True
treeHandler
No
The selector for the TreeHandler to use to build the data model. The tree handler should be registered in application context. The number of rows to display per page in the table. This attribute has been moved from renderTable tag to getModel tag and henceforth will be deprecated for renderTable tag.
pageLimit
No
13-32
Parameter fullListLimit
Req? No
Description Specify a different maximum value of rows to be displayed in a table when the full list action is clicked. To keep the browser from crashing with too much html. The objective of shifting fullListLimit parameter to getModel tag was to provide a two-pass approach for Table model generation for performance enhancement. If fullListLimit is specified at getModel tag, then paging happens at MethodServer side and only the populated table model is sent to tomcat for rendering which improves performance considerably.
scope
Can be (caseinsensitive): page , request, session or application Of type com.ptc.core.compo nents.descriptor.Com ponentModel
No
model
No
The component model to create (and optionally draw) an NmHTMLTable from. If unspecified, then an NmHTMLTable must be specified using the table attribute.
13-33
Parameter table
Default Value -
Req? No
Description The NmHTMLTable to render. If this is not specified, then a ComponentModel must be specified from which a table will be created. Optionally show the count of objects in the table title area. The count is displayed as X of Y total objects, if Table has filter view displayed, else X total objects. X is number of objects displayed in current page & view of the table. Y is total number of objects in current view of the table across all pages. Determines whether the table is paged. Determines whether or not to show The customize view link in the view drop down. The number of rows to display per page in the table. If this was specified by the getIeModel tag, it does not need to be re-specified here.Its deprecated and will be specified henceforth in getModel tag. Specify a different maximum value of rows to be displayed in a table when the full list action is clicked. To keep the browser from crashing with too much html. Its deprecated and will be specified henceforth in getModel tag.
showCount
No
true -
boolean boolean
No No
integer
No
fullListLimit
10000
integer
viewAllLink helpContext
URL to the view all page. Any java.lang.String value boolean boolean
No No
Option to show a view all link at the bottom of the table. The help context for this table. No help icon will be displayed if no help context is specified. Single Select mode. Use Radio buttons or checkboxes for the row selection. Specifies that the table should use scrollbars to keep the header and actions in view when looking down at the items in the bottom of the table.
singleSelect scroll
false
No No
13-34
Default Value -
Req? No
Description Whether objectHandles are needed for each row. By default, the value of this attribute is false. Set to true to render a table for creating/editing multiple objects in a create/edit wizard. JavaScript method to execute after the table has been rendered or re-rendered as a result of sorting etc. Specifies whether the table should use JSCA. If this attribute is set the rules are ignored and the passed in value is used to determine whether or not to use JSCA. Set to true to force the table to use JSCA. Set to false to force the table to use JCA The "preferenceContext" variable is used to control the scope of the preference. For e.g. user may or may not want the preference to be applied even when the context object is changed.
afterJS
No
useJSCA
false
preferenceCo ntext
false
To start with, make sure the page includes the begin and end JSPF files. Also, include the common components tag library file. The code for the same is as follows:
<%@ include file="/netmarkets/jsp/util/begin.jspf"%> <%@ taglib uri="http://www.ptc.com/windchill/taglib/components" prefix="jca"%> <%@ include file="/netmarkets/jsp/util/end.jspf"%
Every JSP page can be structured into three main parts: Creating the table descriptor object Defining the component model Rendering
13-35
Details on configuring tables The following table configuration topics are included in the following subsections: Configuring Tables - Defining Table Attributes on page 13-36 Configuring Tables Set Table Model for Data acquisition on page 13-37 Configuring Tables Render Table on page 13-38 Configuring Tables Set sortable columns on page 13-39 Configuring Tables Adding Toolbar on page 13-40 Configuring Tables Adding row-level actions on page 13-41 Configuring Tables Adding Menu Bar on page 13-42 Configuring Tables Enabling row selection on page 13-43 Configuring Tables Enabling single/multiple row selection on page 13-44 Configuring Tables Adding the help icon on page 13-44 Configuring Tables Adding pagination and page limit on page 13-45 Configuring Tables Specify DataUtility for columns on page 13-46 Configuring Tables Adding an info page hyperlink to table data on page 13-47 Configuring Tables Enabling views on page 13-48 Configuring Tables - Defining Table Attributes on page 13-36 Configuring Tables - Show custom view Link on page 13-54 Configuring Tables Enable Scrolling on page 13-59 Configuring Tables Accessibility compliance on page 13-59 Configuring Tables Enable Table Count on page 13-60 Configuring Tables Hiding column of the table on page 13-60 Configuring Tables Display view all link on page 13-60 Configuring Tables Customize Preferences on page 13-60
The table attributes can be defined using the describeTable tag. This tag creates the table descriptor object and assigns it to the page variable specified by the var attribute. The id attribute stores the identifier for this table descriptor.
13-36
The label attribute is the localized label for this component and is displayed as the table header in the UI. The columns in the table are produced by adding the describeColumn subtag. This tag describes a particular column that the developer wants to display. Like the parent describeTable tag, this tag accepts child setComponentProperty tags. There is also a describeProperty tag, which has the same semantics when used in table components. The id attribute for this tag is used to look up default properties for the column. The code for the same is as follows:
<%-->Build a descriptor and assign it to page variable tableDescriptor<--%> <describeTable var="tableDescriptor" type="wt.part.WTPart" id="netmarkets.test.table" label="${tableName}" > <describeColumn id="name"/> <describeColumn id="number"/> </describeTable>
Here <describeTable> is the tag which is responsible for rendering the columns in the table . The label of the column can be fetched from the resource file. For this we need to make the entry in the rbInfo file and give the key as a label in the <describeColumn> tag. To add/remove columns in the Table, insert/remove describeColumn tag from the describeTable tag. The column order is the order in which the columns are defined using the describeColumn tag in describeTable tag in a JSP file. Each column has a guiComponent corresponding to the value to be shown in the column. Each guiComponent has a reference to renderer object that is responsible for generating the html. To change the default renderer we need to change the guiComponent or the renderer reference for that guiComponent. GuiComponent are created using the dataUtility. To hide a column, use hidden attribute in the <describeColumn> tag. When true, the column will not be shown in the displayed page but can be used in sorting and filtering. This allows custom sorting and filtering options. The default value is false.
Configuring Tables Set Table Model for Data acquisition
We can pass the table descriptor to the getModel tag. In the data acquisition phase, the developer combines a component descriptor with some additional information on how to actually go and get the data that will back the component. This takes the table descriptor and a way to get the table data and returns a model object that will be used to render the table. The table descriptor variable must be specified in the descriptor attribute. The serviceName attribute is used to specify the Java API service class that retrieves the table data.
13-37
When serviceName is included, the methodName attribute must also be used. The name of the method within the service class is indicated using this attribute. The code for the same is as follows:
<%-->Get a table model using our descriptor and query command, assign model to page variable tableModel<--%> <getModel var="tableModel" descriptor="${tableDescriptor}" queryCommand="${queryCommand}"/>
The rendering part is done by passing the model object into the renderTable tag. The variable for the model object specified in the getModel tag should be passed to the renderTable. If the model attribute is not specified, then NmHTMLTable must be specified using the table attribute. The code for the same is as follows:
<%-->Render the table model<--%> <renderTable model="${tableModel}"/>
<%-->Get a query command and assign it to page variable queryCommand<--%> <cmb:getTypeInstanceCommand var="queryCommand" descriptor="${tableDescriptor}"/>
<%-->Get a table model using our descriptor and query command, assign model to page variable tableModel<--%> <getModel var="tableModel" descriptor="${tableDescriptor}" queryCommand="${queryCommand}"/>
13-38
A table column can be made sortable by setting the sortable attribute to true. If we want to sort the table by default with a specific column, then we can mark the column as defaultSort. The code for the same is as follows:
<describeColumn id="name" sortable="true" defaultSort="true" />
This code snippet will sort the column name at the page load time (defaultSort="true"). As well as user can sort the column as and when required (sortable=true). This will generate the Table as follows:
Note: If a column in a table is marked as non-sortable in a JSP through describeColumn, then the respective change should be done in the view configuration as well (through ConfigurableTable class). The table column definition in the JSP should be in synch with ConfigurableTable class. If the column definition in JSP is not in sync with the view definition then it can result into anomalies at the user interface.
Sorting Behavior
Sorting behavior differs in following scenario: 1. For Paging tables a. If the table had no selected rows: If the user is on page X then, table refresh resulted because of sort action will show the table vertically positioned at the first row of the first page. b. If the table had selected rows:
13-39
When the table is refreshed because of sort action, the table will page to the page that contains the last of the pre-sort selected rows. The selected rows will be retained. 2. If the table is a scrolling table, i.e. do not have pagination enabled or a full list table a. If the table had no selected rows: On sort action, the table will be positioned at the first row in the table. b. If the table had selected rows: On sort action, the table will scroll to show the last row that was selected. The selections are retained. 3. If column freeze is applied on the table the horizontal scroll position is always maintained after a sort action. 4. The "Multiclick to sort" feature allows the user to sort multiple columns at a time there by pressing the shift key and then sorting. The limitation is maximum three columns are allowed to sort at a time.
Configuring Tables Adding Toolbar
Adding a toolbar to the table is achieved by using the setComponentProperty tag. setComponentProperty tag configures properties of its parent tag that aren't exposed as attributes of the parent tag itself. This gives the infrastructure and the developer flexibility about the metadata they'd like to be available, without always requiring a tld update to do so. This is a helper tag that sets properties on the component descriptor managed by a parent describe tag. The key attribute and the value attribute are the key and value for the properties map of the target ComponentDescriptor, respectively. In order to add a toolbar, the key attribute must be set to actionModel and the value attribute must be set to the name of the action model that contains the toolbar actions. The code for the same is as follows:
<describeTable var="tableDescriptor" type="wt.part.WTPart" id="tableId" menubarName = "tabular input toolbar" label="${tableName}" configurable="true"> <setComponentProperty key="actionModel" value="customToolbar"/> <setComponentProperty key="selectable" value="true"/> <describeColumn id="name" sortable="true" defaultSort="true" /> <describeColumn id="number" sortable="false"/> </describeTable>
This example uses a toolbar named customToolbar that contains pre-existing folder actions.
13-40
If the table uses a new action model for the toolbar, it must be registered in the actionModels.xml file.
<model name="CustomToolbar"> <action <action <action <action <action <action </model> name="list_cut" name="list_copy" name="fbpaste" name="list_delete" name=" separator " name="create" type="object"/> type="object"/> type="object"/> type="object"/> type="separator"/> type="document"/>
The *actions.xml and *actionModels.xml files can be modularized with logical packaging. These files are located in <Windchill>/codebase/config/actions. There is also a custom-actions.xml and custom-actionModels.xml file available to register new actions and action models. The customToolbar action model is registered in the custom-actionModels.xml file. The "cross page functionality" allows the user to select multiple rows across multiple pages and apply the tool bar actions to the rows across multiple pages. Here is the simple table example with the custom toolbar added:
Use <describeColumn id="nmActions" sortable="false"/> in the table. NmActions Data Utility gets the "Actions" hyperlink by default, but can be configured with properties to get any NmHTMLActionModel or NmAction. The drop down is generated using the Menu component. By default this data utility will return the Actions hyperlink. And by default the Actions hyperlink will display the action model flagged with menufor="<someObjectType>" in an actionmodels.xml file, where <someObjectType> is the type of the row object (e.g. wt.part.WTPart) This is determined dynamically, you should not have to configure which action model to use, even if your table has multiple object types. To have this data utility return an Actions hyperlink to an action model other than the default use the "actionModel" property. In a jsp it would be like:
<jca:describeColumn id="nmActions">
13-41
From a data utility class it would be like: descriptor.setProperty(DescriptorConstants.ActionProperties.ACTION_MODEL, "<action_model_name>"); Where <action_model_name> is the name of some action model in an actionmodels.xml. Note: To avoid inconstancies in ordering/grouping of the actions and issues with finding all the action models to adjust when adding new actions, it is preferred to have one action model per object type that represents the Actions list across the system (meaning in represents the actions list used in tables/trees and also on the info page). Action validation should be used to filter the list.
Configuring Tables Adding Menu Bar
To add a menu bar, the menubarName attribute from the describeTable tag must be included The name of the action model to use for the menu bar actions is specified in this attribute
<describeTable var="tableDescriptor" type="wt.part.WTPart" id="tableId" menubarName = "customMenubar" label="${tableName}" configurable="true"> <setComponentProperty key="actionModel" value="customToolbar"/> <setComponentProperty key="selectable" value="true"/> <describeColumn id="name" sortable="true" defaultSort="true" /> <describeColumn id="number" sortable="false"/> </describeTable>
This example uses an action model named customMenubar. The action model must also be registered in the *action-models.xml file. Action models can be nested using the submodel tag. Code for the same is as follows:
<model name="customMenubar"> <submodel name="fileMenu"> <submodel name="editMenu"> </model> <model name="fileMenu"> <action name="list_cut" <action name="list_copy" <action name="fbpast" <action name="list_delete" </model> <model name="editMenu">
13-42
type="document"/>
In order to label each menu, the description must be set for the File and Edit submodels The action properties must be included in either the action.properties file or in a resource bundle The properties depicted below are the entries that get added to the action.properties file:
object.fileMenu.description=File object.editMenu.description=Edit
The entries for the File and Edit actionModels would look like:
object.fileMenu.description.value=File object.editMenu.description.value=Edit
Since "cross page functionality" is now provided which allows the user to select multiple rows across multiple pages, the menu bar actions will now be applicable to the rows across multiple pages.
Configuring Tables Enabling row selection
Making the rows selectable can be done by adding another setComponentProperty tag. The key attribute must be set to selectable and the value attribute must be set to true. This will provide the checkbox for each of the rows in the table, by which the user can select any of the records for the update or deletion. Code for the same is as follows:
<describeTable id="tableId" var="tableDescriptor" label="${componentName}" >
13-43
We can also give the single select facility to the table. This restricts the user to select only one record at a time from the table. This can be done by setting the singleSelect property of the tag <renderTable> to true. A true value will present the table in a single select (radio buttons) mode whereas a false value presents it in a multi select (checkboxes) mode. The code for the same is as follows:
<renderTable model="${tableModel}" showPagingLinks singleSelect="true"/>
The help page can easily be integrated in the table. The help page can be localized. The tag for the same is <renderTable> and attribute for the same is helpContext. This tag will pick up the entry from service.properties.xconf. The entry in service.properties.xconf will be as follows
<Option requestor="java.lang.Object" resource="online.accessible.ATTablesUse" selector="TEST_HELP"/>
online/accessible/TTablesUse.html is the path for the help page. The code to be written for the help page will be as follows
<renderTable model="${tableModel}" helpContext="TEST_HELP"/>
13-44
On click of the ? sign the pop up will open up which will show up the help for the table.
Configuring Tables Adding pagination and page limit
Depending on the number of records in the table, the pagination facility can be given. The tag used for the pagination is <renderTable>. If the attribute showPagingLinks is set to true, the pagination will be enabled. We can also specify the number of records that are to be shown on each page. This can be set by setting the maximum number of records to be displayed to the attribute pageLimit. If the value for pageLimit is not defined, it would be fetched from the preference value. The code for the same is as follows:
<jca:getModel var="tableModel" pageLimit="10"/>
13-45
You can can add the paging links in header. This option can be set through preference manager. By default this option is disabled and if set it will display the paging links in header as well as footer.
Data utilities allow developers to post-process and/or augment the data returned by the low-level data acquisition API. The additional information can be returned by an additional query, a call to a service, or whatever else you can get at via Java code. To specify the data utility for a column can be done by using dataUtilityId attributes of the describeColumn tag.
13-46
To register the dataUtility, you need to put in *service.properties. An example entry is:
<Service name="com.ptc.core.components.descriptor.DataUtility"> <Option serviceClass="com.ptc.windchill.enterprise.picker.type.dataUtiliti es.IconTypeDataUtility" requestor="java.lang.Object" selector="typePicker.iconType" cardinality="duplicate"/> </Service>
We can specify the name columns link to the info page of the row object. When the user clicks on that link, the new page (Infopage) will open up. This can be done by setting the isInfoPageLink attribute of the <describeColumn> tag to true. The code for the same is as follows.
<describeColumn id="name" isInfoPageLink="true"/>
The isInfoPageLink attribute overrides the default behavior of the column to add or remove a hyperlink to the info page of the context object. The attribute is only applicable for the name and number columns. By default the number is a hyperlink to the info page and name is not. Adding the link will produce the following results:
Displaying table data as hyperlink can also be achieved using a data utility. The data utility can be configured in service.properties file.
13-47
To filter data for a table one has to use customized views. If the table has the customized view option available then using that, we can filter the data. The view wizard has a "set filters" step, which can be helpful in setting the filtering rules. There are two main steps to defining a configurable table: Define the columns, filter criteria, etc that you want to show up in the configurable view wizard Register your table, and set up your JSP page to enable configurable tables
In order for a table to be configurable, you must explicitly specify this in the JSP. To do this, add a configurable="true" attribute to the describeTableTag, as follows:
<describeTable id="someTable" configurable="true" ... />
Setting configurable="true" adds the Current View drop-down to the top-right corner of the table. If you want your table to use a configurable table id that is different from the table id, you can use the new "viewId" attribute:
<describeTable id="someTable" viewId="my_view_Id" ... />
Table views intended for JCA are required to extend the com.ptc.core.htmlcomp.components.JCAConfigurableTable class. Once the table is implemented, it needs to be registered in an application context in order for the infrastructure to find it. For that, add a service to the service.properties.xconf file and the serviceClass attribute must match the location of the JCAConfigurableTable class. The selector must match your table's id. When implementing getOOTBTableViews and defining OOTB views, it is important to use the correct column ids. Column ids for common attributes are defined in com.ptc.core.components.descriptor.DescriptorConstants.ColumnIdentifiers. If the column is not found here, then it is best to use the available attribute report for the types contained in the table.
13-48
The table currently displays the "Sample View" created in the configurable table implementation. If more than one table view was implemented, then the current view displayed would be either the first view on the list (alphabetically) or the table view set in the getOOTBActiveViewName method. Selecting "Customize" from the current view list launches a pop-up displaying the configurable table views. From there, additional table views can be added and removed using the toolbar actions. For each view in that list, there is an action to set that view as "active". By using this action, any view can be set as the default.
Configuring Tables - Creating a Configurable Table Instance
The way to define a new configurable table is by implementing the com.ptc.core.htmlcomp.tableview.ConfigurableTable interface. This interface has methods that allow the configurable table wizard to find out what wizard steps, columns and types should be available. In general, this interface should not be implemented directly. Table views intended for the Windchill Client Architecture are required to extend the com.ptc.core.htmlcomp.components.JCAConfigurableTable base class. This is required so that the appropriate mapping between Windchill Client Architecture and CADX attribute ids can occur. For more information, see com.ptc.core.htmlcomp.components.JCAConfigurableTableAdapter.
Controlling Which Steps Are Displayed
Each step can be hidden or displayed in the create and edit view wizard by overriding the appropriate method. Return true to display the step and false to hide it. By default all steps are displayed. showSetNameStep() - This step allows the user to set\edit the name for the view. This step is usually hidden when only allowing a single user-editable view. showChooseItemTypesStep() - This step allows the user to set\edit the set of types that will be displayed in the view. This step is usually hidden if the table only contains a single type. showFilteringStep() - This step allows the used to define filtering criteria used to filter the data displayed in the table. This step is usually hidden if attribute filtering is not supported or is supported by other means. (i.e. Search)
13-49
showSetColumnsStep() - This step allows the user to select the set of columns that will be displayed in the table. There is currently no reason to ever hide this step. showSortingStep() - Select sorting step. There is currently no reason to ever hide this step.
Example
// Hide the name step public boolean showSetNameStep(){ return false; }
There are two methods that define the list of types that can appear as rows in the table. getClassTypes() - Defines the list of available types. This method should construct and return an array of java.lang.Class objects. This list of types, along with any child types, will show up in the "Choose Item Types" step. getAttributeOnlyClassTypes() - The types defined here will not appear in the "Choose Item Types" step, but will be used to generate attributes for the "Select a Column" step.
This information is used to determine the set of available columns that can be selected for the table. For example, if the class list includes WTPart.class, then the infrastructure knows that there are a few columns that should always be available for parts (like name, number, etc). If null is returned from this method, all of the columns will be determined by getSpecialTableColumnsAttrDefinition(Locale).
Example
public Class[] getClassTypes() { return new Class[] { WTPart.class }; }
The available attributes factory is responsible for determining the initial list of attributes for each configurable table. Attributes are defined per type in the available attribute xml files. The list of types defined in the configurable table is passed to the available attribute factory and the list of attributes for those types is returned. This base list can be added to or filtered differently for each step.
Removing Attributes
An attribute can be removed from any step by overriding the appropriate method and returning false for the attribute's id.
13-50
canAttributeBeUsedInFilter(String) - Removes the attribute from the attribute filtering step. isAttributeValidForColumnStep(String) - Removes the attribute from the list of available columns. isAttributeValidForSortingStep(String) - Removes the attribute from the list of sortable columns.
Example
// Sorting on the info page action doesn't make sense, so it is being removed public boolean isAttributeValidForSortingStep(String key) { return !key.equals(ColumnIdentifiers.INFO_ACTION); }
Special Columns
The getSpecialTableColumnsAttrDefinition(Locale) method tells the configurable view wizard about columns that it cannot find out about automatically (this is what makes these columns "special"). Automatic columns are discovered by looking up the global columns that map to each data type returned by getClassTypes. The getSpecialTableColumnsAttrDefinition method returns a list of com.ptc.core.htmlcomp.createtableview.Attribute.AbstractAttribute objects. Each one of these attributes represents a column that a user can choose to include in the table view. The primary value of these attribute definitions is that they allow the table view wizard to know how to present filter criteria for the column. For example, if a column is represented by a BooleanAttribute, then the wizard knows that to filter on this column, the user should select either true or false. There are 5 concrete types of AbstractAttributes: BooleanAttribute - A column that contains a boolean value CustomAttribute - Not used by the Windchill Client Architecture DateAttribute - A column that contains a Date value TextAttribute - A column that contains a String value ListAttribute - A column that contains a list of predefined values
The IDs for the attributes returned here should correspond to the ids used to define data utilities for the columns, if needed Most columns will not need to be listed here. It is very unlikely that a table will have more than a few special columns. Only add a column here if it is specific to the table. A common exception to this rule is the Actions column. Since it is not defined globally, you will need to add it here if you want that column.
13-51
Example
public List getSpecialTableColumnsAttrDefinition(Locale locale) { List result = new ArrayList(); // add the actions column as a special column result.add(new Attribute.TextAttribute(ACTIONS, projectRb.getString(projectResource.ACTIONS), locale)); ... return result; }
The getOOTBTableViews(String, Locale) method returns a list of com.ptc.core.htmlcomp.tableview.TableViewDescriptor objects, where each descriptor represents a view that should appear in the view selection list by default. These views are loaded into the database the first time the table is visited by the user. Because these OOTB view definitions are loaded into the database, the loaded definitions will need to be cleared after making changes for them to take effect. Each TableViewDescriptor contains a Vector of com.ptc.core.htmlcomp.tableview.TableColumnDefinition objects. Each TableColumnDefinition represents a column that should appear in the view. The TableViewDescriptor has a few flags that are of interest: system - Flags the view as a system loaded view. This prevents the user from being able to delete or edit it. The user can, however, still choose not to show it in the view manager. This should be false if the table only supports a single user-editable view. global - No longer used. This property is ignored. match - Whether or not to match all or any criteria. If set to true, the criterion are ANDed together. If false, they are ORed.
Configurable table implementations that extend com.ptc.core.htmlcomp.tableview.AbstractConfigurableTable (JCAConfigurableTable extends this) can take advantage of some reusable helper methods. There are helpers to get: Latest version/revision criterion. (See getAdvVersionLatestCriterion() and getAdvRevisionLatestCriterion()) Latest version/revision column. (See getAdvVersionAttrDef(Locale), getAdvRevisionAttrDef(Locale) and getAdvVersIterAttrDef(Locale, String, String)) Localized OOTB table view names and descriptions. (See getResourceEntryKey( String classname, String propertyName))
13-52
View Filtering
Views can have filters, or TableViewCriterion, attached to them that filter the table rows based on a set of criteria. In order to properly filter on object type, the criterion must be formed properly. This is required in order to show the proper object types selected in the Select Object Types Step of the create and edit view wizard. To form the criterion properly, the method com.ptc.core.htmlcomp.createtableview.AttributeHelper.getObjTypeKey(Class) should be used. To get localized enumerated type filters, use getStringValue() on the enumerated type value.
Example
public List getOOTBTableViews(String tableId, Locale locale) throws WTException { // The list of all ootb views List<TableViewDescriptor> ootbViews = new ArrayList<TableViewDescriptor>(); // The columns that make up one ootb view Vector<TableColumnDefinition> columns = new Vector<TableColumnDefinition>(); columns.add(TableColumnDefinition.newTableColumnDefinition(ColumnI dentifiers.FOO, /*lockable*/false)); columns.add(TableColumnDefinition.newTableColumnDefinition(ColumnI dentifiers.BAR, /*lockable*/false)); // The criteria for this ootb view Vector<TableViewCriterion> criteria = new Vector<TableViewCriterion>(); criteria.add(TableViewCriterion.newTableViewCriterion(ColumnIdenti fiers.STATE, OperatorConstants.EQUALTO, ProjectState.RUNNING.getStringValue(), null)); criteria.add(TableViewCriterion.newTableViewCriterion(ColumnIdenti fiers.ICON, OperatorConstants.EQUALTO, AttributeHelper.getObjTypeKey(Milestone.class), null); // Get the localized name an description of the view String name = getViewResourceEntryKey(RESOURCE, fooResource.MY_VIEW_NAME); String description = getViewResourceEntryKey(RESOURCE, fooResource.MY_VIEW_DESCRIPTION); TableViewDescriptor desc = TableViewDescriptor.newTableViewDescriptor(name, tableId, /*system*/ true, /*global*/ true, columns, criteria, /*match*/ true, description); // Add the descriptor to the list of all ootb views
13-53
ootbViews.add(desc); // Create additional TableViewDescriptors and add them to ootbViews as needed ... return ootbViews; }
In order for a table to be configurable it must be explicitly declared in the JSP. To do this, add a configurable="true" attribute to the describeTableTag. If a configurable table id that is different from the table id is required, the "configurableTableId" attribute can be used.
<jca:describeTable id="someTable" configurable="true" ... >
OR
<jca:describeTable id="someTable" configurableTableId="someConfigurableTableId" ... >
Customization of the configurable table can be removed by adding showCustomViewLink="false" to the renderTable tag. This will remove the "Customize..." link from the view drop down.
Example
<jca:renderTable model="${tableModel}" showCustomViewLink="false"/>
In some scenarios it may not make sense to allow the user to create multiple views. By adding singleViewOnly="true" to the describeTable tag, the view drop down will be replaced with a customize table icon that links directly to the edit wizard for the current view. If used, the name step should not be shown and only one view should be loaded OOTB.
Example
<jca:describeTable var="tableDescriptor" id="my.table" configurable="true" singleViewOnly="true" ... >
Configuring Tables - Linking the JSP Table to the Configurable Table Instance
Once the table is implemented, it needs to be registered in application context in order for the infrastructure to find it.
13-54
Example
<Service context="default" name="com.ptc.core.htmlcomp.tableview.ConfigurableTable"> <Option requestor="java.lang.Object" selector="my.table.id" serviceClass="com.ptc.my.ConfigurableTableImpl"/> </Service>
Though the initial configuration is via Java code (through the ConfigurableTable interface), at runtime, table view information is persisted in the database. The first time that a configurable table is requested, the infrastructure reads in the ConfigurableTable Java class, and persists this information in the database. This means that if changes are made to the configurable table implementation class (to change the OOTB views for example), the configurable table information needs to be cleared from the database in order for the changes to show up. To do this, run the following SQL commands:
DELETE FROM TableViewDescriptor; DELETE FROM ActiveViewLink; commit;
Note that this will delete all user view information from the system, so it should not be used in a production environment. In a production environment you will need to delete the loaded ActiveViewLink and TableViewDescriptor individually. This can be done while the system is running, and things should continue to work.
Configuring Tables - Optimizing a Query Based on the View
If a query should be optimized for a specific table view, a call can be made to get the current selected view for a given table id allowing the query to adjust accordingly.
//The result is the resource bundle key that has the localizable names of the view. String result = com.ptc.core.htmlcomp.components.TableViewBean.getCurrentView("car ambola.appcontext.report");
The AvailableAttributes.xml files define the attributes available for each type. Adding or removing attribute definitions from this file will affect the list of attributes available when creating or editing table views. The main AvailableAttributes.xml file is located at:
\wt_ma_services\modules\CoreHtmlComp\src_web\com\ptc\core\ htmlcomp\createtableview\AvailableAttributes.xml
It is recommended that you define customized attributes in a new file and then register that file as follows in your site.xconf:
<AddToProperty name="com.ptc.core.htmlcomp.createtableview.AvailableAttributesDig
13-55
To derive the list of available attributes, the available attributes factory first asks your configurable table instance for the list of available types. Using this type list it then builds a list of attribute definitions from those defined in AvailableAttributes.xml for each type.
Debugging
To view debugging information about available attributes, set the following Log4J properties:
log4j.logger.com.ptc.core.htmlcomp.createtableview.AvailableAttrib uteFactory=TRACE log4j.logger.com.ptc.core.htmlcomp.createtableview.AvailableAttrib uteCache=TRACE log4j.logger.com.ptc.core.htmlcomp.util.TypeHelper=TRACE log4j.logger.com.ptc.core.htmlcomp.createtableview.labels=TRACE
To view a listing of available attributes for a given type, use the following report:
http://<machine name>/<WindchillAppName>/netmarkets/jsp/carambola/createtableview/ availableAttributesReport.jsp
Attribute Labels
Any label defined in the AvailableAttributes.xml will be used first. After that the com.ptc.core.htmlcomp.jstable.JSStandardColumnDescriptorFactory is used. The JSStandardColumnDescriptorFactory can retrieve attribute labels for certain common attributes. It is not recommended to edit the JSStandardColumnDescriptorFactory to accommodate attribute labels for Windchill Client Architecture table views. If the JSStandardColumnDescriptorFactory can not find a label for the attribute, it will attempt to find a label in com.ptc.core.ui.componentRB using the JCA id as the key. If it still can not find a label for the attribute, it will use the label retrieved from introspection.
13-56
AvailableAttributes.xml Syntax
Map Tag Defines attribute id mappings between legacy JS Tables and Windchill Client Architecture ids. JS ids are defined in JSPropertyDataConstants and are needed to maintain backward compatibility with older CADX tables. Windchill Client Architecture ids should match those used for data utilities. Child of the Class tag.
Syntax Element Description
id jsId
name
The type. This can be either a hard or soft type and should be formatted as a TypeIdentifier. Required.
<Class name="wt.part.WTPart">
Attribute Tag Defines an attribute for the given type causing this attribute to be available to users when they are creating and editing table views. Child of the Class tag.
Syntax Element Description
id
Windchill Client Architecture id. This should match the id that id mappings for things such as validators or data utilities are mapped to. Required.
<Attribute id="description"/>
schemaId
If the id does not match the modeled attribute name, the schemaId should be set to the attribute name. This id needs to work with both webjects (logical attribute should exist) and BeanUtils (getter and setter should exist for the type).
<Attribute id="creator" schemaId="creator.name"/>
13-57
Syntax Element
Description
The type of the attribute. This will affect what kind of criteria is available when creating filter criteria. Displays a true or false dropdown. Displays the date picker. Displays a drop down of the enumerated type values. See enumClass. Displays a text field.
<Attribute id="iterationInfo.latest" type="boolean"/>
enumClass
When type is set to "list", an EnumeratedType class must be supplied to populate the list of possible values.
<Attribute id="category" schemaId="theCategory" type="list" enumClass="wt.change2.Category"/>
Include Tag Includes the attribute definitions defined within another Class tag. Child of the Class tag.
Syntax Element Description
name
Label Tag Defines a key and a resource bundle or EnumeratedType to retrieve the attribute's label from. Child of the Attribute tag.
Syntax Element Description
resource
13-58
Syntax Element
Description
enumClass
key
The label of my attribute is "???attribute id???" in the create/edit view wizard available column list Enable the table view label logging:
log4j.logger.com.ptc.core.htmlcomp.createtableview.labels=TRACE
Review the process used to find attribute labels and ensure the label for your attribute is defined in one of those locations. The column name in my table is incorrect Try enabling the common components label logging:
log4j.logger.com.ptc.core.components.labels=TRACE
It is up to the data utility defined to retrieve the label for the table column header. When I edit my OOTB view, my attribute does not appear as a selected column despite being included in the active view If you've edited your OOTB view definitions, you need to reset your table views. Otherwise it is possible that the table view class is loading OOTB views with incorrect ids. Ensure you are using the ids defined in DescriptorConstants.ColumnIdentifiers.
Configuring Tables Enable Scrolling
The table can be made scrollable by using the scroll attribute of the renderTable tag. You can provide a boolean value for this attribute. true value will provide scrolling whereas false does not.
<renderTable model="${tableModel}" scroll="true" />
If developers are writing any custom code that generates HTML (e.g. data utility generating HTML), then it should be ensured that the html is Section 508
13-59
compliant. Section 508 compliance standards provide guidelines to generate accessible HTML. The default HTML generated by Table component is complying to these standards.
Configuring Tables Enable Table Count
The number of objects in the table (count) is normally provided in the title bar area. You can remove this using the showCount attribute of the renderTable tag. It takes a boolean value. true value will provide the table count whereas false does not.
<renderTable model="${tableModel}" showCount="true" />
Table component gives us the flexibility to hide any of the column displayed the in the table as per the user requirement. This can be done by setting the value of the attribute hidden to true in the tag <jca:describeColumn> . By default, this value is false. The code for the same is as follows.
<jca:describeColumn id="number" hidden="true"/>
The Table footer can display View Entire List link, which would allow the user to see the entire data. When View Entire List link is displayed, Pagination is not displayed. To enable this link, specify viewAllLink parameter in <renderTable>.
<jca:renderTable model="${tableModel}" viewAllLink="netmarkets/jsp/work/listAssignments.jsp" helpContext="Overview_Assignments_Help" showPagingLinks="${tableShowPagingLinks}" pageLimit="${param.maxRows}"/>
You must specify the jsp name in the "viewAllLink" parameter. When the user clicks on "View All" in the Table footer, the user is taken to the JSP mentioned in this parameter and that JSP would display list of all items in the Table. All the Home -> Overview tables use "viewAllLink" parameter. You can disable the footer by adding "jcaPageModel.setPageFooter("false")" in the jsp after the include of begin.jspf.
Configuring Tables Customize Preferences
To see Table preferences, navigate to Utilities Page > Preference Manager. One can see a section of table related properties.
13-60
Assignment Table Size: Indicates the actual number of assignments to fetch. This preference is ignored if it is less then the overview table size. Overview Table Size: The overview sub tab under the home tab contains three summary tables with limited rows in them. This preference controls the number of rows in these tables. The default is seven. Paging Limit for Tables: Controls the number of rows to display per page in tables that have paging. It only affects tables that have paging turned on by default. The number of rows per page can be temporarily overridden by using the all link in the paging section. View All Table Size Limit: View All Table Size Limit
Tables can be configured so as to support "Freeze Column" and "Selected Only" view. It's a toolbar level menu which allows user to freeze columns there by switching to "Freeze column" menu as well as "Unfreeze" those there by switching to "Unfreeze Columns" menu. The "Freeze columns" menu can be configured either through view manager (for table with views) and through "isFreezable" attribute of tag "describeTable". (For tables without view) . The selected only menu allows user to select multiple rows across multiple pages. User when switches to "Selected only" view, can see the rows across multiple pages in "Full List" mode. The selected only view is enabled only when the table has rows which are multi selectable.
Limitations
None.
13-61
Sample Code
<%@ <%@ <%@ <%@ <%@ <%@ include file="/netmarkets/jsp/util/begin.jspf"%> taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> taglib uri="http://www.ptc.com/windchill/taglib/carambola" prefix="cmb"%> taglib uri="http://www.ptc.com/windchill/taglib/components" prefix="jca"%> taglib uri="http://www.ptc.com/windchill/taglib/core" prefix="wc"%>
<fmt:setLocale value="${localeBean.locale}"/> <fmt:setBundle basename="com.ptc.carambola.carambolaResource"/> <fmt:message var="tableName" key="PART_TABLE_LABEL"/> <fmt:message var="actionsName" key="ACTIONS_COLUMN_LABEL"/> <%-->Build a descriptor and assign it to page variable tableDescriptor<--%> <describeTable var="tableDescriptor" type="wt.part.WTPart" id="netmarkets.test.table" label="${tableName}" > <describeColumn id="name"/> <describeColumn id="number"/> </describeTable> <%-->Get a query command and assign it to page variable queryCommand<--%> <cmb:getTypeInstanceCommand var="queryCommand" descriptor="${tableDescriptor}"/> <%-->Get a table model using our descriptor and query command, assign model to page variable tableModel<--%> <getModel var="tableModel" descriptor="${tableDescriptor}" queryCommand="${queryCommand}"/> <%-->Render the table model<--%> <renderTable model="${tableModel}"/> <%@ include file="/netmarkets/jsp/util/end.jspf"%>
13-62
This table can be accessed by executing simple or advance search. This table can be accessed by clicking on Folders subtab from Program/Product/Project/Orga nization tab. This table can be accessed by clicking on Overview subtab on Home tab. This table can be accessed by clicking Edit structure action on any part info page. This table can be accessed by clicking Advanced Search.
Other Resources
Adding Actions and Hooking Them Up in the UI chapter (starting on page 11-1) Customizing the UI with Ajax (on page 10-4) Data Acquisition Configuration Properties (on page 12-2)
13-63
Background
A tree view is used to display hierarchical data organized in the form of a tree. In other words, Tree is a visualization of a hierarchy. In a tree structure, there are parent and child nodes. The hierarchy level is shown by indentation on the left side of the Tree nodes. Implementing a Windchill Client Architecture tree is the same as implementing a Windchill Client Architecture table. In tree, as opposed to specifying a service method or QuerySpec, a TreeHandler is specified to populate the content. Following are the few key salient features of a Windchill Client Architecture Tree with respect to a Windchill Client Architecture Table
Expand/Collapse Behavior
The expand/collapse functionality is used to traverse the hierarchy of the tree. Your expansion of the tree will be sticky within a session and will return to the default between sessions. You can expand or collapse a tree in two ways: By using the Expand and Collapse actions in the menu or toolbar. Expand action enlarged to show detail
13-64
If used in combination with the selection radio button/checkboxes, the selected nodes will only be expanded to the last level. If you try to expand or collapse without checking any nodes, then all the nodes will be expanded to the last level. By using the Expand/Collapse icons: Expand icon enlarged to show detail
The Expand icon will populate its next level children, where as the Collapse icon merely changes the node from an open to a closed state.
Scrolling Behavior
You will loose your sense of the structure if the tree is divided among pages and hence paging is inappropriate for trees. If there is large data to be presented, the tree can be made to scroll with column header remaining static.
Sorting Behavior
Columns in a tree will sort similarly to tables with the following exception: as the structure of the tree must remain intact the sorting will occur level-by-level. For example, in a folder tree when sorting alphabetically by name, first level folders are sorted as a group, then objects in individual folders are sort as a group, and so on.
Scope/Applicability/Assumptions
It is assumed that your <MyPage>.jsp file in which you are implementing the Windchill Client Architecture tree includes /netmarkets/jsp/begin.jspf file and /netmarkets/jsp/end.jspf files
13-65
Intended Outcome
Solution
Use Windchill Client Architecture Tree to display Windchill business objects in Tree format.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: JSP, JavaScript and Custom taglibs. The actions framework in the Windchill client architecture. Windchill Client Architecture Table component. Configuring views. Data acquisitions, Data Utility, GUI component.
13-66
Solution Elements
Description Your Windchill Client Architecture Tree implementation JSP file. DataUtilities and services are defined here. Action attributes defined here. Actions can be defined here. Action models can be defined here.
Another key constituent in the solution is the TreeHandler, which is responsible for populating the tree content. These are the methods of a TreeHandler that you must implement: ModelContext getModelContext() :- Get the handler's model context void setModelContext(ModelContext mc) throws WTException :- Sets the contextual information about the tree that is being built, like the descriptor, command bean etc. This should be initialized before data is requested from the handler. List getRootNodes() throws WTException :- Get the list of root nodes for the tree. Map<Object,List> getNodes(List parents) throws WTException :- Get a mapping of the child nodes for each of the parent nodes in the given list This is the only method that will be called for the expand action, so this method must be able to initialize the handler properly so that it can answer the question of what are the children of the parent. boolean isExpandNeeded(Object node, int level) throws WTException :Determines whether or not the given node needs to be expanded. The default implementation looks at the session state of the list of nodes already expanded or configured by the tag. boolean hasChildren(Object node) throws WTException :- Determines whether or not the given node should show the Expand icon if its collapsed. Override this method to improve performance or to get custom behavior. The default implementation calls the getNodes and sees if the size is larger than 0. void addExpandedNode(Object node) throws WTException :- Add a node to the expanded node list. This list is returned and used in session state to remember what the tree expansion is. Trees need to be carefully created because of their recursive nature that causes many queries to the database. The Treehandler class can save tree state information as private attributes on the class and reused for each getNodes call. In
13-67
addition, you can take advantage of knowing which tree rows are expanded by the user with the isExpandNeeded method. TreeHandlerAdapter is an abstract class which implements TreeHandler which you can extent. Following is an example getRootNodes() determine what the root nodes should be. The TreeHandler has access to the ModelContext, which can be used to access required information.
public List getRootNodes() throws WTException { NmCommandBean cb = getModelContext().getNmCommandBean(); WTPart part; NmOid oid = cb.getPageOid(); if (oid == null) { log.debug("No oid found in request, trying GOLF_CART"); part = getGolfCart(); }else { if (!oid.isA(WTPart.class)) { throw new ClassCastException("Expected part, but was: " + oid); } part = (WTPart)oid.getRef(); } if (part == null) { log.debug("Couldn't get part"); return null; }
The method first retrieves the NmCommandBean from the model context and extracts the primary oid from it. If no oid was requested from the user, then it uses the GOLF_CART part instead by calling the getGolfCart method. The getGolfCart method simply queries and returns the GOLF_CART. If the user did specify an oid in the request parameter, it checks to make sure the oid is a WTPart. Otherwise, it throws a ClassCastException. If its the expected oid, it continues by retrieving the part from the oid via the getRef method. This method inflates the referenced object, which then can be cast into a WTPart. The last thing it checks is if the part retrieved either from the oid or the GOLF_CART is null and if so return null. The configSpec variable is assigned the ConfigSpec of the part using the ConfigHelper class. This helper class contains a service that helps obtain Iterated objects from Mastered objects. Lastly, an immutable List containing the part is returned. getNodes(List parents) Get a mapping of the child nodes for each of the parent nodes in the given list. It can be called directly without calling the getRootNodes() method first. E.g. (expand action). This means that this method must be able to initialize the handler properly so that it can answer the question of what are the children of the parent. In the given example, the method first checks to see if the configSpec is not initialized from the previous method. If it isnt, then it calls the getDefaultConfigSpec method, which gets the default ConfigSpec from the
13-68
WTPart class via the ConfigHelper. A Map variable named result is then initialized. This will store the mapping of the child nodes for each of the parent nodes and is returned. A three-dimensional array is also initialized using the getUsesWTParts method from the WTPartHelper class. This method navigates from many used-by parts (parents) to their uses part masters (children) and applies a ConfigSpec to select the Iterations of the uses parts. It returns a 3D array of Persistable objects where the first dimension corresponds to the used-by parts passed in. The second dimension corresponds to the part usage links from the used-by part. The third dimension is a two element array where [0] is the WTPartUsageLink and [1] is the uses WTPart or WTPartMaster if the ConfigSpec did not select an iteration of the uses part. After the 3D array is initialized, it continues by iterating through the List of parent nodes. A 2D array of Persistable named branch is initialized that stores the child nodes of the given parent if any exist. If no children exist, it will continue to the next iteration. If children do exist, they are added to an ArrayList named children. Lastly, the parent nodes with its corresponding children are added to the Map, and the Map is returned.
public Map<Object,List> getNodes(List parents) throws WTException { if (configSpec == null) { configSpec = getDefaultConfigSpec(); } Map<Object,List> result = new HashMap<Object,List>(); //API returns a 3D array where the 1st dim is the parent parts, //the 2nd dim is the list of children for a given parent, //and the 3rd dim is 2 element array w/the link obj at 0 and the child part at 1 Persistable[][][] all_children = WTPartHelper.service.getUsesWTParts( new WTArrayList(parents), configSpec); for (ListIterator i = parents.listIterator(); i.hasNext();) { WTPart parent = (WTPart)i.next(); Persistable[][] branch = all_children[i.previousIndex()]; if (branch == null) { continue; } List children = new ArrayList(branch.length); result.put(parent,children); for (Persistable[] child : branch) { children.add(child[1]); } } log.debug("ParentsToChildren: " + result); return result; } private ConfigSpec getDefaultConfigSpec() throws WTException { return ConfigHelper.service.getDefaultConfigSpecFor(WTPart.class);
13-69
Custom tree handlers need to be registered. Following is a sample tree handler entry.
<Service context="default" name="com.ptc.core.components.beans.TreeHandler"> <Option requestor="your_object" selector="your_treeHandler" serviceClass="your_treeHandler_class" cardinality="duplicate"/> </Service>
If you want to show non-persistables in a Tree, you are recommended to return Element for getRootNodes & getNodes methods. If your Element doesnt have a valid ufid value available or obid attribute, you need to provide NmObject for each row object. This can be done in two ways. 1. Author a DataUtility which extends DefaultNmObjectUtility and override its getTargetObject() method which will return a NmObject for the row object. Please see the NmObject Utilities section in the Gathering the Data for the UI chapter on page 12-15 for more information. 2. Your Element will have an attribute named "nmObject" with its value an instanceof NmObject Otherwise, to show non-persistables, you can write a wrapper class extending from NmObject and override getOid() method to return proper NmOid.
You should include the necessary artifacts in your configuring JSP file e.g. /netmarkets/jsp/begin.jspf and /netmarkets/jsp/end.jspf file. You also need to declare tree taglib directive.
<%@ taglib uri="http://www.ptc.com/windchill/taglib/components" prefix="jca"%> <%@ include file="/netmarkets/jsp/util/begin.jspf"%> ----------<%@ include file="/netmarkets/jsp/util/end.jspf"%>
Configure Tree
This can be structured into three steps 1. Creating tableTree descriptor object using describeTableTree tag. a. This tag creates the tableTree descriptor object and assigns it to the page variable specified by the var attribute b. The id attribute stores the identifier for this table descriptor.
13-70
c. The label attribute is the localized label for this component and is displayed as the table header in the UI. d. The columns in the table are produced by adding the describeColumn subtag. The id attribute for this tag is used to look up default properties for the column.
id="wcaDemo_tree_example4" var="wcaDemo_tree_descriptor4" type="wt.part.WTPart" label="${treeName}" nodeColumn="number" configurable="true" expansion="full" helpContext="DEFAULT_HELP_PAGE" disableAction="false" summary="test"> <jca:setComponentProperty key="selectable" value="true"/> <jca:setComponentProperty key="actionModel" value="wcaDemo_tree_toolbar"/> <jca:describeColumn id="number" /> <jca:describeColumn id="name" /> </jca:describeTableTree> <jca:describeTableTree
2. Defining the component model by passing the tableTree descriptor into the getModel tag. a. This takes the tableTree descriptor to get the tableTree data and returns a model object that will be used to render the tree b. The tableTree descriptor variable must be specified in the descriptor attribute. c. The treeHandler attribute is used to specify the JAVA API service class that retrieves the tree data.
<jca:getModel var="wcaDemo_tree_model4" descriptor="${wcaDemo_tree_descriptor4}" treeHandler="wcaDemoTreeHandler1"/>
3. Rendering the tableTree by passing the model object into the renderTableTree tag. a. The variable for the model object specified in the getModel tag gets passed into the model attribute. b. If the model attribute is not specified, then a NmHTMLTableTree must be specified using the tree attribute instead.
jca:renderTableTree model="${wcaDemo_tree_model4}" showTreeLines="true" />
13-71
<%@ include file="/netmarkets/jsp/util/begin.jspf"%> ------<!-- TREE CONFIGURE START --> <%-->Build a descriptor and assign it to page variable treeDescriptor<--%> <jca:describeTableTree id="wcaDemo_tree_example4" var="wcaDemo_tree_descriptor4" type="wt.part.WTPart" label="${treeName}" nodeColumn="number" configurable="true" expansion="full" helpContext="DEFAULT_HELP_PAGE" disableAction="false" summary="test"> <jca:setComponentProperty key="selectable" value="true"/> <jca:setComponentProperty key="actionModel" value="wcaDemo_tree_toolbar"/> <jca:describeColumn id="number" /> <jca:describeColumn id="name" /> </jca:describeTableTree>
<%-->Get a component model for our tree<--%> <jca:getModel var="wcaDemo_tree_model4" descriptor="${wcaDemo_tree_descriptor4}" treeHandler="wcaDemoTreeHandler1"/>
<%-->Render the NmHTMLTableTree from the command<--%> jca:renderTableTree model="${wcaDemo_tree_model4}" showTreeLines="true" /> <!-- TREE CONFIGURE END --> ------<%@ include file="/netmarkets/jsp/util/end.jspf"%>
13-72
var
Yes
scope
request
No
type
No
Name of the main type of object displayed in this tree. This can be either a modeled or a soft type. When specified, the infrastructure will use the type to look up labels and other default values when it can't find them otherwise. A localized display label for this component The name of one of the modes defined in the com.ptc.core.ui.resoureces.Compone ntMode enum. The name of one of the component types defined in the com.ptc.core.ui.resoureces.Compone ntType enum. The name of the column that will be used to display node labels. The column value must be an NmString or a TextComponent.
label
No
mode
VIEW
No
componentType
TABLE
No
nodeColumn
name column
No
13-73
Req? No No
Description Whether or not this tableTree supports configurable views. The id to use to look up configurable views. If unspecified, then defaults to the tree id. Only used if configurable is set to "true" Determines whether to launch the view manager or view edit wizard. The edit wizard is launched directly when you have a tree that does not support having multiple views, but still wants to allow the user to select columns and set sort order. The name of the action model to use for toolbar actions. The name of the action model to use for menubar actions. The help context for this tree. No help icon will be displayed if no help context is specified.
singleViewOnly
false
boolean
No
toolbarName
No
menubarName
No
helpContext
No
13-74
Parameter targetObject
Default Value
Possible Values
Req? No
Description Allows the developer to provide more objects for a tree row. Typically, the infrastructure treats each index of the array returned by the getModel tag's API as a "row" object. This row object is passed to each column's DataUtility. If a different object is needed for some DataUtilities then that object can be specified as the targetObject in the describeTableTree or describeColumn tag. The original row object must have a getter method for the name specified as the target object. (i.e. targetObject="my_related_part" would mean the object needs a getMy_related_part() method). The target object will be used in the following places: The row object supplied to data utilities. The object that soft attributes will be extracted from The context object for the row checkbox
No No
Deprecated A localized summary of this table, which is used for accessibility compliance. Controls the initial expansion level of the tree. none (fully collapsed), one (first level of tree is expanded), full (tree is fully expanded). Flag to indicate enable or disable collapse/expand action.
expansion
full
No
disableAction
false
boolean
No
13-75
scope
request
No
descriptor
Yes
treeHandler
No
The selector for the TreeHandler to use to build the data model. The tree handler should be registered in application context
scope
request
No
13-76
Paramter model
Default Value -
Req? No The component model to create (and optionally draw) an NmHTMLTableTree from. If unspecified, then an NmHTMLTableTree must be specified using the tree attribute. The NmHTMLTableTree to render. If this is not specified, then a ComponentModel must be specified from which a tree will be created. The help context for this tree. No help icon will be displayed if no help context is specified. Whether or not to trail-enable links in the tree. The preference context for this tree Single Select mode. Use Radio buttons or checkboxes for the row selection. Determines whether or not to show the customize view link in the view drop down. Specifies that the table should use scrollbars to keep the header and actions in view when looking down at the items in the bottom of the table. Optionally show the count of objects in the table title area. Whether objectHandles are needed for each row. By default, the value of this attribute is false. Set to true to render a table for creating/editing multiple objects in a create/edit wizard. JavaScript method to execute after the table has been rendered or rerendered as a result of sorting etc.
tree
No
helpContext
No
false false
No No No
true
boolean
No
false
boolean
No
true false
boolean boolean
No No
afterJS
No
13-77
Possible Values
Req? No No Determines whether the tree is paged. The number of rows to display per page in the tree. Determines if tree lines will be displayed to show structure in the tree The maximum number of rows to display per page in the tree when the full list action is clicked. The number can be set to a level so as to keep the browser from crashing. It is used to get some out of the box features; explained in the Configuring Tree - useJSCA property section on page 13-88
false
boolean
No
fullListLimit
integer
useJSCA
false
boolean
-----</jca:describeTableTree>
-----</jca:describeTableTree>
13-78
Adding toolbar to a tree can also be achieved by using setComponentProperty tag. Its a helper tag that sets properties on the component descriptor managed by a parent describe tag. The key attribute and the value attribute are the key and value for the properties map of the target ComponentDescriptor, respectively. In order to add a toolbar, the key attribute must be set to actionModel and the value attribute must be set to the name of the action model that contains the toolbar actions. Please see the Windchill Client Architecture Action Framework Overview section in the Adding Actions and Hooking Them Up in the UI chapter on page 11-1 for more information.
<jca:describeTableTree id="wcaDemo_tree_example4" var="wcaDemo_tree_descriptor4" type="wt.part.WTPart" label="${treeName}" nodeColumn="number" configurable="true" expansion="full" helpContext="DEFAULT_HELP_PAGE" disableAction="false" summary="test"> <jca:setComponentProperty key="actionModel" value="wcaDemo_tree_toolbar"/> -----</jca:describeTableTree>
-----</jca:describeTableTree>
13-79
13-80
Custom data utilities need to be registered. Following is a sample data utility entry.
<Service name="com.ptc.core.components.descriptor.DataUtility"> <Option serviceClass="your_data_utility_class" requestor="your_object" selector="your_column_data_utility_id" cardinality="duplicate"/> </Service>
3. Custom view implementation helpContext keys need to be registered. Following is a sample entry.
<Service context=default name="com.ptc.core.htmlcomp.tableview.ConfigurableTable"> <Option serviceClass="your_ConfigurableTableImpl_class" requestor="your_object" selector="your_view_id" /> </Service>
13-81
4. When implementing getOOTBTableViews and defining out-of-the-box views, it is important to use the correct column ids. Column ids for common attributes are defined in com.ptc.core.components.descriptor.DescriptorConstants.ColumnIdentifiers. If the column is not found here, then it is best to use the available attribute report for the types contained in the table. Available Attribute Report:
http://<server>:<port>/<context>/netmarkets/jsp/carambola/creat etableview/availableAttributesReport.jsp
5. You can control the visibility of Customize link in the view drop down by using showCustomViewLink attribute of renderTableTree tag. false hides the link whereas true shows the link which is the default behavior.
<jca:renderTableTree model="${wcaDemo_tree_model6}" showCustomViewLink ="true" />
6. If the tree has only one view and you want to modify the columns (visibility, order etc), you need to set singleViewOnly attribute of describeTableTree tag to true.
<jca:describeTableTree id="wcaDemo_tree_example5" var="wcaDemo_tree_descriptor5" type="wt.part.WTPart" label="${treeName}" nodeColumn="number" configurable="true" singleViewOnly ="true" -----configurableTableId="wcaDemo_tree_viewId1"> --------
13-82
</jca:describeTableTree>
13-83
Custom helpContext keys need to be registered. Following is a sample helpContext key entry.
<Service context="default" name="wt.help.HelpTemplate"> <Option requestor="your_object" selector="your_help_context_key" resource ="online.cust.helpFile"/> </Service>
-----</jca:describeTableTree>
13-84
13-85
Windchill Client Architecture Tree with and without Tree Lines & Count
13-86
<jca:renderTableTree tree="${wcaDemo_tree_nmModel6}" model="${wcaDemo_tree_model6}"/> public static ArrayList<NmOid> getPartNonSelectables( NmModel nmModel ) throws WTException { ArrayList<NmOid> nmOid_list = null; NmDefaultHTMLTableTree table_tree = (NmDefaultHTMLTableTree)nmModel; NmDefaultHTMLTable table = (NmDefaultHTMLTable)table_tree.getTable(); for (int i = 0; i < table.getRowCount(); i++) { NmObject nmObj = (NmObject)table.getObject(i); if(nmObj instanceof NmPart){ NmPart nmPart = (NmPart)nmObj; //your logic goes here if((number_string.lastIndexOf("2")!= -1) || (number_string.lastIndexOf("4")!= -1) ) { if(nmOid_list == null) nmOid_list = new ArrayList<NmOid>(); //add the NmOid into the List nmOid_list.add(nmObj.getOid()); } } } return nmOid_list; }
Using this you can set the number of rows of a tree in a page and this will be applicable to all the trees across Windchill system. Its usage is highly discouraged and in the coming release this property will be deprecated.
13-87
For popup pages, the default scrollType is DOM. But, it is recommended to use Viewport. Also. it is recommended to use "Viewport" scrollType in case of non editable form fields.
13-88
If the tree is paginated, the row count message shown in the tree footer will be format 'X of Y total objects selected'. But for the full list trees the row count message will be 'X objects selected'. e. Actions can be performed on selections made across pages for a paginated tree. The tree toolbar level and menu level actions would be performed on all the selections that the user has made across all pages of the tree. f. Client side JavaScript function to fetch all selected object information. A JavaScript function named getSelectedItems() can be used to fetch selected objects from all the tree present in a page. Another function named getJCASelectedTableItems(tableId) can be used to fetch selected objects for a particular tree. 2. Clear all selections Clear across pages feature is used to clear all the checkbox selections across multiple pages. This feature is provided for the trees where paging is enabled. Clear all selection feature will be disabled if there are no checkbox selections available and it will get enable as soon as user selects checkbox. With this feature user can reduce the pain of deselecting checkboxes individually. 3. Preserving right-left scroll position For paging trees If the tree had no selected rows: If the user is on page X then, tree refresh resulted because of sort action will show the tree vertically positioned at the first row of the first page. If the tree had selected rows: When the tree is refreshed because of sort action, the tree will page to the page that contains the last of the pre-sort selected rows. The selected rows will be retained. If the tree is a scrolling tree, i.e. do not have pagination enabled or a full list tree If the tree had no selected rows: On sort action, the tree will be positioned at the first row in the tree. If the tree had selected rows: On sort action, the table will scroll to show the last row that was selected. The selections are retained
13-89
4. Multi column click to sort "Multiclick to sort" feature allows the user to sort multiple columns at a time there by pressing the shift key and then sorting. The limitation is maximum three columns are allowed to sort at a time. 5. Paging controls in table header User can add the paging links in header. This option can be set through preference manager. By default this option is disabled and if set it will display the paging links in header as well as footer. 6. Find In List One can find an object in tree.
Sample Code
Examples of Usage in Windchill Code Folder Browser table Type Picker Team Tree on Home-> Team Preference Manager Tree Tree Examples under Customization Tab
13-90
<?xml version="1.0" standalone="no"?> <AvailableAttributes> <Class name="<fully qualified class name>"> <Include name="<fully qualified super class name>"/> <Attribute id="<attribute name>"/> </Class> </AvailableAttributes>
Example:
<AvailableAttributes> <Class name="ext.myCompany.MyCompanyChangeIssue"> <Include name="wt.change2.WTChangeIssue"/> <Attribute id="myCompanyString"/> <Attribute id="myCompanyInt"/> <Attribute id="myCompanyTime"/> </Class> </AvailableAttributes>
Any attributes you include in this file will be available in all tables that include that class.
2. Modify site.xconf with the following command to include the new file in the attribute lookup.
xconfmanager -s com.ptc.core.htmlcomp.createtableview.AvailableAttributesDigest er.fileLocation=/com/ptc/core/htmlcomp/createtableview/Availabl eAttributes.xml,AvailableAttributesSite.xml
13-91
Attribute Tables
Objective
This design pattern provides developers with the information required for implementing the attributes table component for a given business object in information page. The Attribute Table component was developed to give the Windchill products consistency for displaying all necessary attributes of any object in details page. The component should also make developing attributes table much easier. Using this component, a developer only needs to configure attributes tables page only, while the main layout of the page is provided by the component.
Applicability
This design pattern should be used by a developer who is responsible for configuring the info page for some object in one of the Windchill products. This design pattern shows how to configured and where the configuration should be done for the attributes table.
Participants
The readers of this design pattern should have a basic understanding of JSP, tag libraries and JSTL.
Consequences
By following this design pattern the configuration of all attributes table for any business objects should be done in a consistent manner. This will make maintaining these attributes table much easier and more manageable task.
Solution Overview
The attributes table component was developed using the Windchill Client Architecture. This component provides a common layout for an objects attributes as it is displayed in any of the Windchill products. Using the attributes table component will provide consistency between all objects and Windchill products.
Packaging
The attributes table component itself is located in the Windchill vob under the CommonComponents module:
ProjectLink\NetMarkets\src_web\netmarkets\jsp\object\attribute.jsp (the default attributes table) ProjectLink\NetMarkets\src_web\netmarkets\jsp\util\ showSoftAttribute.jsp (the attributes table component)
13-92
Windchill\DevModules\CommonComponents\src\com\ptc\core\components\ beans\AttributesTableBean.java Windchill\DevModules\CommonComponents\src\com\ptc\core\components\ util\ComponentUtility.java Windchill\DevModules\CommonComponents\src_web\com\ptc\core\ components\tags\core\TypeBasedImportTag.java Windchill\DevModules\CommonComponents\src_web\WEB-INF\tags\ core.tag Windchill\DevModules\CommonComponents\src_web\WEB-INF\tlds\ components.tld
The default attributes table implementation have been added for parts and documents. However both these tables need to be reworked so that necessary or required attributes can be configured. For all the business objects that need to use the attributes table, the developer will need to create a new JSP that is configured for your type. All the details links to attributes table will lead to a servlet which will figure out which page to forward to based on the object type.
13-93
Creating a JSP
Your attributes.JSP will have only the describeAttributesTable tag and list of attribute names as id in describeProperty. Based on the configuration in the describeAttributesTable, the showSoftAttribute.jspf component will render the attributes table panel and its content. Here is the example of attributes.jsp for document object.
<jca:describeAttributesTable var="attributesTableDescriptor" mode=VIEW> <jca:describeProperty id="<Logical Form>" /> <jca:describeProperty id="<Logical Form>" /> </jca:describeAttributeTable>
The attribute values are based on logical attribute mapping using the mechanism in place for type instances. For a given object type, you can see what the logical attribute names are by using the LogicalAttributes.jsp. This JSP can be accessed from a running Windchill build; http://<machine>/<Windchill-appname>/meta/LogicalAttributeReport.jsp
In the type input field, type the fully qualified class name and click Submit. This should give you a listing of the attributes that can be used for the given object type. Either the logical or the external form can be specified, although the logical form is preferred.
Registering the JSP
For the info page servlet to know which JSP to forward to for your type, an entry for your JSP needs to be specified in a properties file that is used by the type based
13-94
service. The default properties file for this is typedservices.properties which can be found directly in codebase. The entries should be in the following format:
wt.services/rsc/default/com.ptc.netmarkets.util.misc.FilePathFacto ry/Attributes/wt.doc.WTDocument/0=/netmarkets/jsp/document/attribu tes.jsp wt.services/rsc/default/com.ptc.netmarkets.util.misc.FilePathFacto ry/Attributes/wt.part.WTPart/0=/netmarkets/jsp/part/attributes.jsp
Windchill/src/typedservices.properties.xconf file is the default xconf file used for type based application context lookups. For your type, you would create your own xconf file within your module that targets typedservices.properties.
13-95
<jca:describeProperty id="name"/> <jca:describeProperty id="number"/> <jca:describeProperty id="creatorName" /> <jca:describeProperty id="currentPrincipal" /> <jca:describeProperty id="cabinet"/> <jca:describeProperty id="cabinetName"/> <jca:describeProperty id="checkoutInfo.state" /> <jca:describeProperty id="comment"/> <jca:describeProperty id="displayIdentifier"/> <jca:describeProperty id="endItem"/> <jca:describeProperty id="folderName"/> <jca:describeProperty id="lifeCycleName" /> <jca:describeProperty id="usedBy"/> <jca:describeProperty id="version"/> <jca:describeProperty id="view" /> <jca:describeProperty id="viewName"/> <jca:describeProperty id="owner.id"/> <jca:describeProperty id="ALL_SOFT_SCHEMA_ATTRIBUTES"/>* </jca:describeAttributesTable>
Also, Edit action can be launched with below steps. The step to initially display can be set on request with this form.
startStep=<step id>
* ALL_SOFT_SCHEMA_ATTRIBUTES display all the soft attributes and its value. 2. Register your JSP so the info page servlet will know to forward to it. Add the following entry into codebase/typedservices.properties:
wt.services/rsc/default/com.ptc.netmarkets.util.misc.FilePathFa ctory/Attributes/wt.part.WTPart/0=/netmarkets/jsp/part/attribut es.jsp
3. Test your new jsp. The icons from the Home page or from the Folders page should lead to the new info page servlet. The URL will look something like this:
http://<machine>/<WindchillAppName>/servlet/InfoPage?oid=OR:wt. part.WTPart:62028
The servlet will look up which JSP to forward to in typedservices.properties. You should see the list of attributes name and its value in Third Level Navigation for attributes table.
13-96
Background
This section will describe making the name attribute server generated. This attribute is not server generated out of the box. It will make the name attribute behave exactly as the number attribute. This means the name attribute will also respond to other OIRs that only apply to number out of the box, including ServerPreGenerated and Immutable.
Scope/Applicability/Assumptions
Assume you have a need to have the name attribute be server generated.
Intended Outcome
The name attribute is server generated for all objects that have the ServerAssigned constraint specified in the OIR for name.
Solution
Create your own custom DataUtility for the name attribute and set up the required properties.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Data Utilities GUI Components Object Initialization Rules
Solution Elements
Description Contains the configuration information required. Contains the rule configurable attribute lists for each object type. codebase/com/ptc/core/rule/server/delegate/init/Rul eConfigurableTypeAttribute.properties
13-97
Element GeneratedNameDataUtility
Description The new Data utility that will be created during this procedure to enable Name to support server generation. An out of the box data utility that knows how to handle server generation for the number attribute. \codebase\netmarkets\jsp\document\ createDocumentSetAttributesWizStep.jsp
2. Find your object type. For this example we are looking for WTDocument and out of the box we have:
wt.doc.WTDocument=number,lifeCycle.id,lifeCycle,teamTemplate,te amTemplate.id,folder.id,organization.id
3. Notice that name is not an attribute that is available for rules so we need to add it in. In your site.xconf file add the following:
<Configuration targetFile="codebase/com/ptc/core/rule/server/delegate/init/Rul eConfigurableTypeAttribute.properties"> <Property name="wt.doc.WTDocument" default="name,number,lifeCycle.id,lifeCycle,teamTemplate,tea mTemplate.id,folder.id,organization.id"/> </Configuration>
Using the Object Initialization Rules administrator, add the following rules to the OIR for WTDocument:
<!-- set the name to a generated number --> <AttrValue id="name" algorithm="com.ptc.windchill.enterprise.revisionControlled.server. impl.NumberGenerator"> <Arg>{GEN:wt.enterprise.SequenceGenerator:WTDOCUMENTID_seq:10:0 }</Arg> </AttrValue>
13-98
<AttrConstraint id="name" algorithm="com.ptc.core.rule.server.impl.GatherAttributeConstraint s"> <Value algorithm="com.ptc.core.rule.server.impl.GetServerAssignedConstrai nt"/> <Value algorithm="com.ptc.core.rule.server.impl.GetImmutableConstraint"/> </AttrConstraint>
Note: For this purposes of this demonstration we will reuse the number generator that exists out of the box. You will probably want to replace this with your own custom generator. See the online help for the Object Initialization Rules Administrator for additional information.
Create your new Data Utility
The simplest way to get a data utility to use the server generation property is to extend the NumberDataUtility. The minimum amount of code you will need to write is to override the getColumnId method to return your column ID. In our case this is name. So we would create the following data utility.
package com.ptc.carambola.customization.examples.wizard; import com.ptc.core.components.descriptor.DescriptorConstants; import com.ptc.core.components.factory.dataUtilities.NumberDataUtility; public class GeneratedNameDataUtility extends NumberDataUtility { @Override protected String getColumnId() { return DescriptorConstants.ColumnIdentifiers.NAME; } }
By Default, for the wizards, the NumberDataUtility is returning a NumberInputComponent. For the purposes of this example this component is sufficient. If it is not sufficient for your purposes you can create a custom component. Please see the Implementing a Data Utility section on 13-8 for additional information.
Register your new Data Utility for your attribute
1. Since for this example we only want the name attribute behavior to be changed for documents we will create a new attribute we will call "documentName" to use. In your site.xconf file add the following:
13-99
<Configuration targetFile="codebase/com/ptc/core/components/components.dataUtilit ies.properties"> <Option serviceClass=" com.ptc.carambola.customization.examples.wizard.GeneratedNameDa taUtility" requestor="java.lang.Object" selector="documentName" cardinality="duplicate"/> </Configuration>
2. You will then have to modify the UIs for Document that display this attribute to include documentName instead of name. In the file createDocumentSetAttributesWizStep.jsp change
<jca:describeAttributesTable var="attributesTableDescriptor" ... <jca:describeProperty id="name" htmlId="NameInputId"/> ... </jca:describeAttributesTable>
To:
<jca:describeAttributesTable var="attributesTableDescriptor" ... <jca:describeProperty id="documentName" htmlId="NameInputId"/> ... </jca:describeAttributesTable>
If you wanted to modify the behavior of the name attribute for all object types you could simply configure the following with out changing any UIs.
<Configuration targetFile="codebase/com/ptc/core/components/components.dataUtilit ies.properties"> <Option serviceClass=" com.ptc.carambola.customization.examples.wizard.GeneratedNameDa taUtility" requestor="java.lang.Object" selector=" name" cardinality="duplicate"/> </Configuration>
Customization Points
None.
Limitations
Since Number is a String attribute this quick customization is only relevant for generated attributes of String Type that do not have a discrete set defined.
13-100
Packaged Samples
com.ptc.carambola.customization.examples.wizard.GeneratedNameDataUtility
13-101
If you want to test how a table works with JSCA vs JCA, you can toggle between the two with a URL parameter. If a developer wishes to test to see how a table works with JSCA vs JCA we have also provided a url param that can be added to toggle the table between JSCA and JCA. See example below: Example:
http://machinename.ptcnet.ptc.com/Windchill/netmarkets/jsp/user/li stCheckedOutWork.jsp?useJSCA=true
The useJSCA URL paramter name is case sensitive but the value is not case sensitive and it will accept any form of true and false. It will also accept 1 for true and 0 for false. JSCA is not enabled by default. You can use the url param above to test single pages. If you prefer to turn JSCA on as it will be when we ship you can modify the file
windchill\codebase\WEB-INF\tlds\components.tld
and remove the default that has been temporarily specified to turn jsca off (remove the line in bold below):
<attribute> ... <name>useJSCA</name> <required>false</required> <type>boolean</type> <default>false</default> </attribute>
Note: Old Netmarkets architecture Tables and Trees (those that were not converted to JCA) are currently using the JSCA rendering and do not at this time support any methods of going back to the JCA rendering. The current recommendation is that if you need an old legacy table to use JCA instead of JSCA you will need to convert the table to JCA and use the tag attribute as described above.
13-102
Icon Delegates
Objective
You want to author an IconDelegate to display icon for a Windchill object type.
Background
The purpose of object icons is to allow the user to readily distinguish between different Windchill business objects in the Windchill UI. Its possible to associate an icon with a Modeled type while modeling the class in Rational Rose. This icon will be used when an object of this type is displayed. In case of soft types, the Type Manager allows the user to associate an icon to be used to represent this soft type in the UI. If the icon specified is an invalid or blank, the icon of the parent type is used. This behavior is accomplished using IconDelegates. However, there are cases where the icons are determined dynamically by other factors, such as attributes on the object. The following table shows the OOTB IconDelegates available for some Windchill Types.
Windchill Type wt.part.WTPart wt.epm.EPMDocument wt.doc.WTDocument IconDelegate com.ptc.windchill.enterprise.part.commands.delegate. WTPartIconDelegate wt.epm.identity.EPMDocumentIconDelegate wt.doc.DocumentIconDelegate
If the user needs different icons on types (other than the OOTB) or for his own modeled/soft types, he needs to author custom IconDelegates for the respective type.
Scope/Applicability/Assumptions
User is not supposed to author custom IconDelegates for types for which OOTB IconDelegates exists.
Intended Outcome
User able to view the icons defined by his IconDelegate for the respective Windchill type objects.
Solution
Author custom IconDelegate for Windchill type to specify your icon.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following:
13-103
Solution Elements
Element <custom_IconDelegate>.java
Type java
xconf
1. You can extend either wt.fc.IconDelegate or an existing subclass of wt.fc.IconDelegate. 2. There are few APIs that you need to over-ride, where you have to put your icon determining logic.
13-104
a. These two APIs returns an IconSelector object, which holds the information of the icon for the specific Windchill object.
API Signature public IconSelector getStandardIconSelector() throws WTException, IllegalAccessException, InvocationTargetException; public IconSelector getOpenIconSelector() throws WTException, IllegalAccessException, InvocationTargetException; Get a selector for when the object is opened (for example when a folder is opened) Description Get the standard selector for the icon
b. This API returns the localized tooltip value that need to be shown for the icon.
API Signature public String getToolTip() Description The tooltip to be shown with the icon.
c. This API is needed to handle TypeInstances. In the method, you have to check whether the available TypeInstance has all the minimum required attribute values to determine icon and tool tip. If not there is a need to inflate the TypeInstance.
API Signature protected Boolean inflateRequired() Description Inflate Required, if TypeInstance doesn't have required attributes to calculate the icon/tool tip.
@Override protected boolean inflateRequired() { boolean need = super.inflateRequired(); TypeInstance ti = getTypeInstanceObject(); if(ti != null && !need){ //check you necessary attributes in TypeInstance // to determine to inflate it or not. } } return need; }
d. This API is needed to handle TypeInstances. In the method, you have to add all the attributes that drive icon/tool tip determination. This will make
13-105
sure that they are properly populated when you invoke getStandardIconSelector() or getOpenIconSelector().
API Signature protected void initAttributes(Set<AttributeTypeIdentifier> attributes) Description Update <AttributeTypeIdentifier> with attributes that drive-determining icon/tool tip.
@Override protected void initAttributes(Set<AttributeTypeIdentifier> attributes) { super.initAttributes(attributes); //add your attributes here }
3. IconDelegate defines a static helper method to create AttributeTypeIdentifier and TypeIdentifier objects that your subclass can use. e.g
AttributeTypeIdentifier NAME_ATI = getIdentifier("name", "wt.part.WTPart"); TypeIdentifier WTPART_TI = getIdentifier("wt.part.WTPart", null);
4. The getObject() API will convert the current TypeInstance to a Persistable, if not available. Hence its usage should be avoided in favor of getObject(false).
Coding Pattern
Many of the IconDelegate subclasses now use an internal "params" object to encapsulate whether or not they are working with a Persistable or a TypeInstance. The params object has simple properties that the icon resolution logic can use, regardless of whether the properties were populated from a Persistable or TypeInstance.
AttributeTypeIdentifier PERSONAL_CABINET_ATI = getIdentifier("personalCabinet", "wt.folder.Cabinet"); TypeIdentifier CABINET_TID = getIdentifier("wt.folder.Cabinet", null); protected void initAttributes(Set<AttributeTypeIdentifier> attributes) { super.initAttributes(attributes); attributes.add(PERSONAL_CABINET_ATI); } private static class ObjectParams { Cabinet cabinet = null; TypeInstance ti = null; ObjectParams(Cabinet cabinet){ if(cabinet != null) this.cabinet = cabinet; } ObjectParams(TypeInstance ti){
13-106
if(ti != null) this.ti = ti; } void reSetObject(Cabinet cabinet){ if(cabinet != null) this.cabinet = cabinet; } boolean isPersonalCabinet(){ if(cabinet != null){ return (cabinet.isPersonalCabinet()); }else{ return (Boolean)ti.get(PERSONAL_CABINET_ATI); } } } protected boolean inflateRequired() { boolean need = false; TypeInstance ti = getTypeInstanceObject(); if(ti != null){ need = super.inflateRequired(); if(!need){ if(ti.get(PERSONAL_CABINET_ATI) == null){ // should contain PERSONAL_CABINET_ATI need = true; } } } return need; } private ObjectParams getObjectParams(){ ObjectParams object_params = null; WTObject obj = super.getObject(false); TypeInstance ti = getTypeInstanceObject(); if (obj != null && obj instanceof Cabinet) {//Object is available object_params = new ObjectParams((Cabinet)obj); } else if(ti != null) {//TypeInstance is available if(inflateRequired()){ obj = super.getObject(true); if (obj != null && obj instanceof Cabinet) { object_params = new ObjectParams((Cabinet)obj); }else{ object_params = null; } } else { object_params = new ObjectParams(ti); } } return object_params; }
13-107
IconSelector icon = null; ObjectParams object_params = getObjectParams(); if(object_params != null){ boolean is_personal_cabinet = object_params.isPersonalCabinet(); if(is_personal_cabinet) icon = new IconSelector(PERSONAL_ICON); else icon = new IconSelector(SHARED_ICON); } if (icon == null) icon = super.getStandardIconSelector(); return icon; }
You need to register your custom IconDelegate in an xconf file and propagate into the WT_HOME/codebase/service.properties file via xconfmanager.
<Service context="default" name="wt.fc.IconDelegate"> <Option cardinality="duplicate" requestor="<your_type>" serviceClass="<your_IconDelegate>"/> </Service>
13-108
UI Validation
Objective
You want to hide an action or attribute in the UI based on some context information. You want to determine whether or not an action selected in the UI should be allowed to proceed based on some context information. You want to determine whether or not a user can proceed to the next step in a wizard or whether the entire wizard may be submitted, based on the data entered by the user in that wizard.
Background
UI Validation is intended to simplify the experience of the Windchill end-user. There are three categories of UI Validation that will each be discussed in further detail in this document.
Pre-Validation
The first category of UI Validation is referred to as Pre-Validation. This is the category of validation that most people will first associate with UI Validation. Pre-Validation is a term that describes the process of determining whether or not a UI Component should be available in the UI. An example of Pre-Validation would be disabling the check-in action for an object that is not checked-out. Pre-Validation can be applied to both actions and attributes in the UI. Of the three types of UI Validation, this type is the most often-used.
Post-Select Validation
A second category of UI Validation is Post-Select Validation. Post-Select Validation is the process of determining whether or not an action should be allowed to proceed once it is selected in the UI. An example of post-select validation would be displaying an error message and not allowing the checkout to proceed if a user tries to perform a checkout on an object that is already checked out. Post-Select Validation applies only to actions.
Post-Submit Validation
The final category of UI Validation is Post-Submit Validation. This type of validation is used exclusively in wizards or other forms where users enter data. An example of Post-Submit Validation would be stopping a user from moving to the next step in a wizard because the data theyve entered in the current step is
13-109
invalid. Post-Submit Validation applies only to wizard steps and wizard submissions.
Scope/Applicability/Assumptions
Pre-Validation - Suppose you want to hide an action in the UI from users who are not members of the current containers team. Post-Select Validation - After a user selects an action, you want to determine whether or not the target object is in a certain lifecycle state before allowing the action to proceed. Post-Submit Validation - After a user enters data in the first step of a wizard and tries to navigate to the next step, you want to determine whether or not the information entered on the first step is valid before allowing them to proceed.
Intended Outcome
Pre-Validation - Before the page is rendered, you are able to determine whether or not the user is a member of the current containers team. If not, the action is not displayed on the page. Post-Select Validation - After the user invokes the action, you are able to check the target objects lifecycle state. If the state is not the state you require, you can display a message to the user, and the action is not performed. Post-Submit Validation - When the user clicks next on the wizard, you get the data entered in the current step and are able to determine whether or not it is adequate to allow the user to proceed to the next step. If the data is inadequate or invalid, you can display a message to the user and not allow them to proceed to the next step.
Solutions
Pre-Validation - Determine whether the business logic is specific to a single action or attribute, or if the same logic could apply to multiple actions or attributes. If the logic is specific to a single UI Component (action or attribute), add the logic to a Validator. If the logic could apply to multiple UI Components, add the logic to a Filter. Finally, associate the Validator or Filter with the UI Component to ensure that the business logic is applied to that component. Pre-Validation in a Validator - Implement the performFullPreValidation() and performLimitedPreValidation() methods in a Validator to contain the desired business logic. Pre-Validation in a Filter - Implement the preValidateAction method in a Filter to contain the desired business logic.
Post-Select Validation - Implement the validateSelectedAction() and validateSelectedMultiSelectAction() methods in a Validator to define the desired business logic, and associate the Validator with the action.
13-110
Post-Submit Validation - Implement the validateFormSubmission() method in a Validator to define the desired business logic, and associate the Validator with the wizard step or the entire wizard.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: The actions framework in the Windchill client architecture. The Application Context or service.properties mechanism for registering delegates. A basic familiarity with the NmCommandBean and its methods will be helpful. The validation service is very generic in nature. It does not provide the APIs youll need in order to determine whether or not something is valid. The service will provide your validators or filters with the context data and form data you need to determine whether or not a UI Component is valid. But you will need to know what to do with that data in order to apply your validation business logic.
The Additional Resources section below includes references to many or all of these subjects.
Solution Elements
In addition to the solution elements involved in UI Validation, this section also contains some definitions of key terms (in bold italic).
Element StandardUIComponentValidation Service Type Java class Description Often referred to as the validation service. This is the service class that controls UI Validation. It receives validation requests from the client infrastructure and delegates to the appropriate validators and filters for validation results. It then passes the validation results back to the client infrastructure. Customizers and application developers should not have to interact directly with this class. UIValidationKey Java class Often referred to as a validation key. A UIValidationKey is used to identify the UI Component being validated. You can think of a UIValidationKey as having a one-to-one relationship with an action or attribute.
13-111
Element UIValidationCriteria
Description Often referred to as the validation criteria. The UIValidationCriteria is a bean class that contains the context (request, session) data which is passed from the client infrastructure to the validators and filters via the validation service. Most of the content in the UIValidationCriteria is taken directly from the NmCommandBean, although the objects are typically returned as WTReferences, as opposed to NmOids.
UIValidationResult
Java class
Often referred to as a validation result. A UIValidationResult represents one unit of validation. In other words, it associates a validation status with a UI Component (action or attribute). In cases where validation is being performed for the same action on multiple objects, a UIValidationResult can be associated with each object.
UIValidationResultSet
Java class
Often referred to as a result set. A UIValidationResultSet is just a collection of UIValidationResult objects. The result sets are used in situations where multiple validations are being performed at the same time. For example, if a validator was doing a pre-validation check for the same action on multiple objects, it could aggregate the validation results for each of the objects into a UIValidationResultSet.
UIValidationStatus
Java class
Often referred to as validation status. This is an enumeration used to determine if or how a UI component should be displayed in the UI. For example, there are values to indicate that an action should be hidden, that an action should be disabled, or that an action should be enabled.
UIValidationFeedbackMsg
Java class
Often referred to as a feedback message. This is a message that can be associated with a validation result. It is only used for post-select validation and post-submit validation. Any feedback messages associated with validation results returned by pre-validation will be ignored. Feedback messages can have different feedback types (FeedbackType.java) associated with them to indicate whether they are, for example, error messages, warning messages, or info messages.
13-112
Element UIComponentValidator
Description This is the interface that all validator implementations need to implement. However, validators should not directly implement this interface. Rather, they should extend DefaultUIComponentValidator. Each UI component can have zero or one valiadtors associated with it. Typically, a validator will contain logic specific to a single UI component. For more generic validation logic that applies to multiple UI components, a filter is typically used. Validators are called by the validation service to determine the validation status for a specific UI component. Customizers and application developers should not have to interact directly with this class.
DefaultUIComponentValidator
Java class
This is a default implementation of the UIComponentValidator interface. All validator implementations should extend this class. This is the interface that all filter implementations need to implement. However, filters should not implement this interface directly. Rather, they should extend DefaultSimpleValidationFilter or DefaultUniversalValidationFilter. Each UI component can have zero to many filters associated with it. Typically, a filter will contain generic validation logic that could apply to multiple UI components. For validation logic that is specific to a single UI component or a small set of UI components, a validator is typically used. There are two categories of filters: simple filters and universal filters. Simple filters are applied on a component-by-component basis. In other words, you have to choose which UI components the logic in a simple filter will apply to. Conversely, universal filters are applied to all UI components, which means you have to choose which UI components the logic in a universal filter *does not* apply to. Filters are called by the validation service to determine the validation status for a specific UI component. Customizers and application developers should not have to interact directly with this class.
ValidationFilter
Java interface
13-113
Element SimpleValidationFilter
Description This is the interface that all simple filter implementations need to implement. However, simple filters should not implement this interface directly. Rather, they should extend DefaultSimpleValidationFilter. Customizers and application developers should not have to interact directly with this class.
UniversalValidationFilter
Java intervace
This is the interface that all universal filter implementations need to implement. However, universal filters should not implement this interface directly. Rather, they should extend DefaultUniversalValidationFilter. Customizers and application developers should not have to interact directly with this class.
DefaultSimpleValidationFilter
Java class
This is a default implementation of the SimpleValidationFilter interface. All simple filter implementations should extend this class. This is a default implementation of the UniversalValidationFilter interface. All universal filter implementations should extend this class. This is an interface that all solution group implementations need to implement. A solution group is a special type of validator that is used for pre-validation based on the installed solutions. For example, if a given action should not be available if Windchill ProjectLink is not installed, that logic should be defined in a solution group.
DefaultUniversalValidationFilter
Java class
UIComponentSolutionGroup
Java interface
*actions.xml
XML file(s)
There are multiple satellite versions of actions.xml files (typically one per module), which contain action definitions. It is also in these files that we configure actions to include simple filters, and exclude universal filters.
*service.properties.xconf
XConf file(s)
There are multiple satellite versions of service.properites.xconf files (typically one or more per module), which contain class delegate registry entries. These files are where you register your validators, filters, and solution groups so that the validation service knows where to find them.
13-114
Pre-Validation Sequence
The pre-validation sequence begins with the client infrastructure (typically, but not exclusively, the StandardNmActionService) sending a list of UI components to the validation service. The expectation is that for each of those UI components, the validation service will return a validation result indicating the display status for the UI component. Each UI component is represented by a validation key. It is also expected that the Client Infrastructure passes context (session, request, or form) data to the validation service inside of a validation criteria object.
Client Infrastructure
Validation Service
Key
1. The Client Infrastructure calls the validation service, passing an action (represented by a validation key) corresponding to the page being rendered, and the context data (represented by a validation criteria instance). Once the validation service receives the validation request from the client infrastructure, the validation service iterates through each of the validation keys, and performs several tasks to determine the validation status for each of the keys. The first such task that the validation service performs is to see whether or not a given validation key represents a component that should be hidden, based on the PTC solutions that are installed. This is accomplished by referencing a cache of invalid validation keys that is created when the validation service is first started. To create the cache, the validation service simply calls all registered solution groups and asks for a list of invalid validation keys from each of them, based on the installed solutions.
13-115
If the cache of invalid solution-based keys contains the current validation key, the validation service sets the components status to hidden and does not perform any additional validation on the component. Otherwise, if the cache of invalid solution-based keys does not contain the current validation key, the validation service continues with its pre-validation checks.
Client Infrastructure
1 2a
Validation Service
Key
1. The Client Infrastructure calls the validation service, passing an action (represented by a validation key) corresponding to the page being rendered, and the context data (represented by a validation criteria instance). 2. For each validation key, the validation service performs a series of tasks to determine the validation status for that key. The tasks are executed in the following order: a. Check to see if the validation key is in the list of invalid keys for the installed solution set.
The second pre-validation check performed by the validation service is to see whether or not the component is hidden or disabled by the role-based UI service. The role-based UI service was introduced in 8.0 as a way for admin users to configure the display of UI components based on a users role. With the introduction of the UI Validation Service in 9.0, the role-based UI service has become a special delegate of the UI Validation Service.
13-116
If the role-based UI service returns a status of hidden or disabled, the validation service sets the components status correspondingly and does not perform any additional validation on the component. Otherwise, if the role-based UI service returns an enabled status, the validation service continues with its pre-validation checks.
Client Infrastructure
1 2a
Validation Service 2b
Role-Based UI Service
Key
1. The Client Infrastructure calls the validation service, passing an action (represented by a validation key) corresponding to the page being rendered, and the context data (represented by a validation criteria instance). 2. For each validation key, the validation service performs a series of tasks to determine the validation status for that key. The tasks are executed in the following order: a. Check to see if the validation key is in the list of invalid keys for the installed solution set. b. Check to see if the role-based UI service was configured to disable or hide the component. Assuming the role-based UI service says the component should be enabled, the validation service will next check to see if any filters are associated with the UI component.
13-117
To determine which filters should be applied to a UI component, the validation service references some additional cached data that is stored when the validation service is first started. The first cache referenced contains a list of all registered universal filters. When a filter is defined and registered as a universal filter, it is automatically applied to all UI components by default. If any universal filters are found in this cache, they are automatically added to the list of filters that will be applied to a given UI component. Although universal filters are applied to all UI components by default, there is support for configuring actions to ignore individual universal filters. (Currently, there is no similar support available for configuring attributes to ignore universal filters, meaning that any universal filter will always be applied to all attributes.) If you want to configure an action to ignore a universal filter, you do so in the actions definition in an actions.xml file. When the validation service is started, a second cache is created containing a map of actions and any universal filters they are configured to ignore. If an entry is found in this cache for a given action, the universal filters that are supposed to be ignored will be removed from the list of filters to be applied to the UI component. Finally, the validation service references a third cache to determine any additional filters that should be applied to a UI component. This third cache is a map that associates actions with simple filters. A filter that is defined and registered as a simple filter must be explicitly associated with an action in order for it to be applied to any actions. (Currently, there is no support for associating a simple filter with an attribute.) If you want to configure an action to use a simple filter, you do so in the actions definition in an actions.xml file. When the validation service is started, this third cache of actions and associated simple filters is created. To summarize, the algorithm used by the validation service to determine which filters should be applied to a given UI component, you could use the following formula: Filters per component = all universal filters ignored universal filters + associated simple filters
13-118
Once the list of filters is established, the validation service calls each of the filters to determine the validation status for the UI component. Please note that the order in which the filters are called can not be guaranteed. If any of the filters return a validation status of hidden or disabled, the validation service sets the components status correspondingly and does not perform any additional validation on the component. Otherwise if all of the filters applied to a given UI component return an enabled status, the validation service continues with its pre-validation checks.
Client Infrastructure
1 2a
Validation Service 2b
2c Role-Based UI Service
Applicable Filters
Key
1. The Client Infrastructure calls the validation service, passing an action (represented by a validation key) corresponding to the page being rendered, and the context data (represented by a validation criteria instance). 2. For each validation key, the validation service performs a series of tasks to determine the validation status for that key. The tasks are executed in the following order: a. Check to see if the validation key is in the list of invalid keys for the installed solution set. b. Check to see if the role-based UI service was configured to disable or hide the component. c. Check to see if any of the filters associated with the UI component indicate that the component should be disabled or hidden.
13-119
If none of the filters indicate that a UI component should be disabled or hidden, the final check performed by the validation service for a given UI component is to check to see if there is a validator associated with the UI component. A validator is associated with a UI component by creating an entry in a service.properties.xconf file that links the action id (for actions) or the descriptor id (for attributes) to the class name of the validator class that should be used for that component. If there is not a validator registered for the UI component, the component is enabled. Otherwise, if there is a validator associated with the UI component, the validation service calls that validator to get a validation status for the UI component.
Client Infrastructure
1 2a
Validation Service 2b
Applicable Filters
13-120
Key
1. The Client Infrastructure calls the validation service, passing an action (represented by a validation key) corresponding to the page being rendered, and the context data (represented by a validation criteria instance). 2. For each validation key, the validation service performs a series of tasks to determine the validation status for that key. The tasks are executed in the following order: a. Check to see if the validation key is in the list of invalid keys for the installed solution set. b. Check to see if the role-based UI service was configured to disable or hide the component. c. Check to see if any of the filters associated with the UI component indicate that the component should be disabled or hidden. d. Get the validation status from the validator, if there is one associated with the UI component.
13-121
At this point, the validation service has completed its validation checks for each UI component. If the client infrastructure passed a single UI component to the validation service to be pre-validated, the validation service will return a single validation result to the caller. If multiple UI components were passed to the validation service for pre-validation, the validation service will organize the validation results for each component into a validation result set, which contains one result per UI component. The validation result set is then returned to the caller.
Client Infrastructure
1 2a
Validation Service 2b
Applicable Filters
13-122
Key
1. The Client Infrastructure calls the validation service, passing an action (represented by a validation key) corresponding to the page being rendered, and the context data (represented by a validation criteria instance). 2. For each validation key, the validation service performs a series of tasks to determine the validation status for that key. The tasks are executed in the following order: a. Check to see if the validation key is in the list of invalid keys for the installed solution set. b. Check to see if the role-based UI service was configured to disable or hide the component. c. Check to see if any of the filters associated with the UI component indicate that the component should be disabled or hidden. d. Get the validation status from the validator, if there is one associated with the UI component. 3. Return the validation result or validation result set to the client infrastructure.
13-123
Client Infrastructure
Validation Service
Key
1. The Client Infrastructure calls the validation service, passing an action (represented by a validation key) corresponding to the page being rendered, and the context data (represented by a validation criteria instance).
After receiving a post-select validation request from the client infrastructure, the validation service checks to see if there is a validator associated with the specified action. As is the case with pre-validation, a validator is associated with an action by creating an entry in a service.properties.xconf file that links the action id to the class name of the validator class for that action.
13-124
If there is not a validator registered for the action, the user is permitted to perform the action. Otherwise, if there is a validator associated with the action, the validation service calls that validator to get a validation status for the action.
Client Infrastructure
Validation Service
Validator
Key
1. The Client Infrastructure calls the validation service, passing an action (represented by a validation key) corresponding to the page being rendered, and the context data (represented by a validation criteria instance). 2. The validation service checks to see if there is a validator associated with the action. If so, it calls the validator to get the validation status (permitted or denied) for the action.
After the validator returns its validation result, the validation service simply passes along the validation result returned by the validator to the client infrastructure. The client infrastructure will check to see whether that status is permitted or denied. If the status is permitted, the page or wizard is displayed. If the status is denied, the user is redirected to the previous page, and
13-125
if the validator returned a message indicating why the action was denied, that message is displayed to the user.
Client Infrastructure
Validation Service
3 Validator
Key
1. The Client Infrastructure calls the validation service, passing an action (represented by a validation key) corresponding to the page being rendered, and the context data (represented by a validation criteria instance). 2. The validation service checks to see if there is a validator associated with the action. If so, it calls the validator to get the validation status (permitted or denied) for the action. 3. The validation service passes the validation status (wrapped in a validation result) from the validator to the client infrastructure, which either displays the target page/wizard, or brings the user back to the page where the action was invoked.
13-126
Client Infrastructure
Validation Service
Key
1. The Client Infrastructure calls the validation service, passing an id associated with a wizard's "Next" or "OK" action (represented by a validation key), and the context data (represented by a validation criteria instance).
After receiving a post-submit validation request from the client infrastructure, the validation service checks to see if there is a validator associated with the wizards Next or OK action. As is the case with pre-validation and post-select validation, a validator is associated with a wizards Next or OK action by creating an entry in a service.properties.xconf file that links the action id to the class name of the validator class for that action. If there is not a validator registered for the action, the user is permitted to move to the next step or submit the entire wizard. Otherwise, if there is a validator
13-127
associated with the Next or OK action, the validation service calls that validator to get a validation status for the action.
Client Infrastructure
Validation Service
Validator
Key
1. The Client Infrastructure calls the validation service, passing an id associated with a wizard's next or OK action (represented by a validation key), and the context data (represented by a validation criteria instance). 2. The validation service checks to see if there is a validator associated with the "Next" or "OK" action. If so, it calls the validator to get the validation status (permitted or denied) for the action.
After the validator returns its validation result, the validation service simply passes along the validation result returned by the validator to the client infrastructure. The client infrastructure will check to see whether that status is permitted or denied. If the status is permitted, the user is allowed to proceed to the next step in the wizard, or complete the wizard submission. If the status is denied, the user restricted from moving to the next wizard step or submitting the
13-128
wizard, and if the validator returned a message indicating why the action was denied, that message is displayed to the user.
Client Infrastructure
Validation Service
3 Validator
Key
1. The Client Infrastructure calls the validation service, passing an action (represented by a validation key) corresponding to the page being rendered, and the context data (represented by a validation criteria instance). 2. The validation service checks to see if there is a validator associated with the "Next" or "OK" action. If so, it calls the validator to get the validation status (permitted or denied) for the action. 3. The validation service passes the validation status (wrapped in a validation result) from the validator to the client infrastructure, which either allows the user to proceed to the next step in the wizard or submit the entire wizard, or brings the user back to the wizard step where the action was invoked.
13-129
Pre-Validation Procedures
This section describes the steps you should perform for various operations related to pre-validation. This section contains the following procedures: Distinguishing between Pre-Validation Statuses on page 13-130 Implementing Solution-Based Pre-Validation on page 13-131 Implementing Role-Based Pre-Validation on page 13-134 Implementing Validation Filters on page 13-134 Implementing Validators for Pre-Validation on page 13-138
Depending on whether youre validating actions or attributes, the validation statuses youll return from your filters or validators will vary. This section describes some of the rules and best practices for determining which validation statuses to return in certain scenarios.
Action Pre-Validation Statuses
The validation service and client infrastructure currently support three statuses for pre-validated actions: enabled, disabled, and hidden. As you might suspect, an enabled status means that the action is visible to the user and selectable for the user. The disabled status means that the action is visible to the user, but not selectable (i.e., the action is grayed-out). And the hidden status means that the action is not visible at all to the user. Note that there is currently no support to disable actions rendered as icons (in a table header or table row, for example). If the validation service returns a disabled status for an action icon, the client infrastructure will simply hide the action icon. Whether youre implementing a filter or validator to perform pre-validation logic, youll be expected to return a validation status (either directly or wrapped in a validation result) to the validation service. (If you implement a solution group, the validation service automatically assigns a hidden status to all components deemed invalid by that solution group.) When trying to choose which status to return from your validator or filter, use the following rules of thumb: Always err on the side of enabling. If you cant determine conclusively whether or not an action should be available, give it an enabled status. Chances are there is additional validation that will occur down the line (whether it be another filter, a validator, or post-select validation) when there is more context information available that can disable or deny the user. Youre almost always better off showing a user an action they cant perform than hiding an action that they should be able to perform.
13-130
When trying to choose between hidden and disabled, ask yourself whether the action could ever be visible to the user in the current context. If the answer is yes, then the status should be disabled. For example, the check-out action is not valid for an object that is currently checked out. But if that same object wasnt checked out, the check-out action would be available to the user. In that case, a disabled status is appropriate. However, suppose you had an action that was only available to admin users, and your user is a non-admin. In that case, the action would never be available to that user, so a hidden status would be appropriate.
The validation service and client infrastructure currently support four statuses for pre-validated attributes: hidden (ATTR_HIDDEN), hidden value (ATTR_HIDDEN_VALUE), read only (ATTR_READ_ONLY), and visible (ATTR_VISIBLE). The hidden status means that the attributes name nor value is never displayed in the UI. The hidden value status means that the attributes name will be displayed, but not its value. The read only status is used to indicate that an attributes name and value are displayed, but that user may not modify the value. And the visible status is used to indicate that the attributes name and value will be displayed and that the user may modify the value when it is available in a form or wizard. To determine which status applies to your attribute under certain conditions, you should probably seek clarification from the customer, product manager, etc. There arent really any generic rules that can be applied to all attributes. You may recall that a single filter can be applied to multiple actions and attributes. So you may be wondering which status the filter should return in situations where it may be applied to both actions and attributes. In those situations, use the statuses reserved for actions (enabled, disabled, and hidden). The client infrastructure will treat enabled like visible, disabled like read only, and hidden like hidden.
Implementing Solution-Based Pre-Validation
As indicated in the Pre-Validation Sequence section, the first pre-validation check performed by the validation service is to determine whether or not the UI component should be hidden based on the installed set of Windchill solutions. For example, if Windchill PDMLink is not installed, certain actions should never be available. As a rule of thumb, this type of solution-based logic should NEVER be included in your validator or filter classes. You can assume that if your validator or filter has been called, the UI component being validated has already passed any applicable solution-based checks. Solution-based logic should be implemented in a solution group.
13-131
Implementing a solution group class is very easy. All you need to do is create a class that implements the UIComponentSolutionGroup Interface, and in your class, implement the getInvalidInstallKeys() method. In that method, you check to see which solutions are installed, and return a list of validation keys representing actions or UI components that should never be available based on the installed solutions. The class on the following page is an simple example of a solution group whose getInvalidInstallKeys() method checks to see if Pro/INTRALINK is installed. If Pro/I is installed, it returns a list of validation keys representing actions or components that should never be available.
package com.ptc.windchill.enterprise.myPackage;
import java.util.ArrayList; import java.util.List; import org.apache.log4j.Logger; import wt.log4j.LogR; import wt.util.InstalledProperties; public class MySolutionGroup implements UIComponentSolutionGroup { private static UIValidationKey listKey = UIValidationKey.newInstance("list", "change"); private static UIValidationKey crKey = UIValidationKey.newInstance("listChangeRequests", "change"); private static UIValidationKey cnKey = UIValidationKey.newInstance("listChangeNotices", "change"); private static UIValidationKey viewKey = UIValidationKey.newInstance("view", "change"); /* * DEFINE ADDITIONAL ACTIONS AND UI COMPONENTS AS NEEDED */ private static Logger logger = LogR.getLogger(MySolutionGroup.class.getName()); public List getInvalidInstallKeys() { if (logger.isDebugEnabled()){ logger.debug("ENTERING MySolutionGroup.getInvalidKeys"); } ArrayList invalidList = new ArrayList(); // if PRO-I is installed, the following UI components are not valid. if (InstalledProperties.isInstalled(InstalledProperties.PRO_I)){ invalidList.add(listKey); invalidList.add(crKey); invalidList.add(cnKey); invalidList.add(viewKey);
13-132
} /* * ADD ADDITIONAL SOLUTION-BASED CHECKS AS NEEDED */ if (logger.isTraceEnabled()){ logger.trace("RETURNING " + (List)invalidList); } if (logger.isDebugEnabled()){ logger.debug("EXITING MySolutionGroup.getInvalidKeys"); } return invalidList; } }
If youre wondering how to determine which values to include in the validation key factory methods, it depends on whether youre creating a validation key for an action or an attribute. If youre creating a validation key for an action, the first argument represents the action name (from *actions.xml) and the second argument represents the object type (from *actions.xml). For example, to create a validation key to represent the product action below, you would call UIValidationKey.newInstance(product, navigation);
<objecttype name="navigation" class="" resourceBundle="com.ptc.core.ui.navigationRB"> <action name="product" renderType="GENERAL"> <command class="netmarkets" method="servlet/Navigation?tab=product" windowType="page"/> </action> ...
If youre creating a validation key for an attribute, simply use the descriptor ID used for that attribute in the Windchill client architecture. For example, to create a validation key for the attribute whose descriptor ID is iteration, you would call UIValidationKey.newInstance(iteration);
Registering a Solution Group
Once you've created and built your solution group, the only thing left to do is register it. You register a solution group in *service.properties.xconf by creating an entry like this:
<Service context="default" name="com.ptc.core.ui.validation.UIComponentSolutionGroup"> <Option requestor="null" serviceClass="[your fully-qualified SolutionGroup class name]" selector="[any unique key, e.g., "ChangeMgmtSolutionGroup")]" /> </Service>
13-133
Once your solution group is registered, its logic should be checked any time the validation service is called to perform pre-validation. (Its results are actually cached after the first invocation.)
Implementing Role-Based Pre-Validation
The second pre-validation check performed by the validation service is to call the role-based UI service to see whether or not an admin user has configured a component to be hidden or disabled for certain users. This check is built into the validation service, so there is no work for a customizer to perform. For more information about configuring the role-based UI service as an admin user, please see the Customizing Role-Based UI Functions - Attribute Visibility section on page 9-8.
Implementing Validation Filters
Assuming the solution-based and role-based checks pass, the next thing the validation service will do when performing a pre-validation activity is to determine which filters apply to the UI component. As previously mentioned, a typical validation filter will contain pre-validation logic that applies to multiple UI components. So rather than duplicating this logic in multiple validators, a single filter can be created and the logic can be selectively applied to UI components or applied to all UI components.
Choose Your Filter Type Simple or Universal
The first thing youll need to decide when implementing a filter is whether it should be a simple filter or a universal filter. To do this, ask if your filter logic is more global in nature or if it only applies to a relatively small number of actions. If the logic applies to most actions, you would create a universal filter. In this case, the filter will be applied to all actions, although actions can always be configured to "opt out" of the filter. If your filter logic only applies to a small subset of actions, you would create a simple filter. In this case, you would need to individually configure actions where you want this filter applied. To implement, it is probably easier to start with a simple filter, and convert it to a universal filter later, if necessary. One additional consideration is that there is currently no support for applying a simple filter to attributes, nor is there support for configuring attributes to ignore universal filters. So if you have filtering logic that you want applied to attributes, your only choice is a universal filter. Just be conscious that any universal filter will be applied to all attributes, all the time, no matter what.
Implementing a Simple Filter
When implementing a simple filter, youll need to create a class that extends com.ptc.core.ui.validation.DefaultSimpleValidationFilter. Then simply override the preValidateAction() method to contain your validation logic and return a validation status.
13-134
The following class skeleton is an example of a simple filter that would hide an action if the context object is marked for delete. (NOTE: Obviously, this is an overly-simplified example. A production-quality class would have exception handling, logging, etc.)
public class MarkedForDeleteFilter extends DefaultSimpleValidationFilter{ @Override public UIValidationStatus preValidateAction(UIValidationKey key, UIValidationCriteria criteria){ // ENABLE by default UIValidationStatus status = UIValidationStatus.ENABLED; WTReference contextObj = criteria.getContextObject(); if (/*contextObj.isMarkedForDelete() == */ true){ status = UIValidationStatus.HIDDEN; } return status; } }
You implement a universal filter the exact same way as you would implement a simple filter, with one exception. When implementing a universal filter, you need to extend com.ptc.core.ui.validation.DefaultUniversalValidationFilter. Otherwise, the implementation is exactly the same as a simple filter. Suppose we wanted to implement the filter in the simple filter example as a universal filter instead. Here is what that class skeleton would look like as a universal filter: (NOTE: Obviously, this is an overly-simplified example. A production-quality class would have exception handling, logging, etc.)
public class MarkedForDeleteFilter extends DefaultUniversalValidationFilter{ @Override public UIValidationStatus preValidateAction(UIValidationKey key, UIValidationCriteria criteria){ // ENABLE by default UIValidationStatus status = UIValidationStatus.ENABLED; WTReference contextObj = criteria.getContextObject(); if (/*contextObj.isMarkedForDelete() == */ true){ status = UIValidationStatus.HIDDEN; } return status; } }
Registering Filters
Once you've created a filter, the next step is to register it. Depending on the type of filter you implement (universal or simple), your filter registry will differ. When providing a selector in your registry, the convention is to use the filter class name with replacing the first letter with a lower-case letter,
13-135
and eliminating the "filter" suffix (e.g., "MarkedForDeleteFilter" would have a selector of "markedForDelete"). The following details should clarify: To register a universal filter, in *service.proeprties.xconf, create an entry like this:
<Service context="default" name="com.ptc.core.ui.validation.UniversalValidationFilter"> <Option serviceClass="com.ptc.windchill.enterprise.markedfordelete.validat ors.MarkedForDeleteFilter" selector="markedForDelete" requestor="null" /> </Service> When registering a simple filter, the only difference is the name attribute of the Service element: <Service context="default" name="com.ptc.core.ui.validation.SimpleValidationFilter"> <Option serviceClass="com.ptc.windchill.enterprise.somepackage.validators. MarkedForDeleteFilter" selector="markedForDelete" requestor="null" /> </Service>
Once you've created and registered your filter, the last thing to do is to associate actions with your Simple Filter, or dissociate actions with your Universal Filter. This is done in *actions.xml. Dissociating actions from a Universal Filter In cases where you don't want a global filter to be applied to specific actions, you need to find those actions in *acitons.xml that and update them to include an excludeFilter element, as shown below:
<objecttype name="navigation" class="" resourceBundle="com.ptc.core.ui.navigationRB"> <action name="home" renderType="GENERAL"> <command class="netmarkets" method="servlet/Navigation?tab=home" windowType="page"/> <excludeFilter name="markedForDelete" /> </action> <action name="program" renderType="GENERAL"> <command class="netmarkets" method="servlet/Navigation?tab=program"windowType="page"/> <excludeFilter name="markedForDelete" /> </action> <action name="product" renderType="GENERAL"> <command class="netmarkets" method="servlet/Navigation?tab=product" windowType="page"/> <excludeFilter name="markedForDelete" /> </action> ...
13-136
Note: The name attribute of the excludeFilter element should correspond to the selector used to register the filter in *service.properties.xconf. Associating actions with a Simple Filter Suppose (hypothetically) you created and registered a simple filter called ProblemReportStatusFilter (and registered it with a selector of "problemReportStatus") that disabled actions if a problem report had a certain status. And suppose you wanted to apply it to a few actions. You would find the actions you want to apply your Filter to in *actions.xml and modify them to include includeFilter elements like this:
<objecttype name="problemReport" class="wt.change2.WTChangeIssue" resourceBundle="com.ptc.windchill.enterprise.change2.changeManagem entActionsRB"> <action name="create" > <command class=/> <includeFilter name="problemReportStatus" /> </action> <action name="edit" > <command class=/> <includeFilter name="problemReportStatus" /> </action> <action name="editModifyContentOnly" id="editModifyContentOnly"> <command class="/> <includeFilter name="problemReportStatus" /> </action> ...
Note: Again, the name attribute of the includeFilter element should correspond to the selector used to register the filter in *service.properties.xconf. Multiple Filter inclusions/exclusions for the same action In theory, an action can have any number of universal filters dissociated from it and any number of simple filters associated with it. You would just add as many includeFilter and excludeFilter elements as you need in *actions.xml. For example:
<action name="removeChangeTask" renderType="GENERAL" ajax="row"> <command onClick="removeChangeTask(event)" windowType="no_content" /> <includeFilter name="problemReportStatus /> <excludeFilter name="markedForDelete" /> <includeFilter name="someSimpleFilter" /> <excludeFilter name="someUniversalFilter" /> ... </action>
Note: The order of the includeFilter and excludeFilter elements does not matter, nor does it have any bearing on the order in which the filters are called.
13-137
Assuming the solution-based, role-based, and filter checks pass, the final thing the validation service will do when performing a pre-validation activity is to call the validator associated with a UI component. As previously mentioned, a typical validator will contain pre-validation logic that is unique to a single UI component or a small set of related components. In other words, it is possible to associate a single validator with multiple UI components, if the validation logic is identical for those components. But in that case, you may also want to consider a filter. The advantage of using a filter is that you would always have the option to add a validator at a later time if the logic for one of the components deviates from the others.
Limited Pre-Validation vs. Full Pre-Validation
There are actually two pre-validation methods defined in a validator one method is for limited pre-validation, and the other is for full pre-validation. The respective methods youll implement are called performLimitedPreValidation() and performFullPreValidation(). The distinction between limited pre-validation and full pre-validation is made for performance considerations. The client infrastructure will ask the validation service to perform limited pre-validation in situations where performance is essential. Currently, the only scenario when limited pre-validation is requested for actions is when the row-level action icons are being pre-validated in a table or tree. For attributes, limited pre-validation is always requested. As a validator developer, you dont need to figure out when limited pre-validation is called vs. when full pre-validation is called. You just implement both methods (performLimitedPreValidation() and performFullPreValidation()) in your validator and assume that the infrastructure will call the appropriate method under the given conditions. Its possible and, in many cases, likely that your performLimitedPreValidation() and performFullPreValidation() methods will have the exact same logic. Limited Pre-Validation Explained Consider a table that has 50 rows, with five row-level action icons in each row. Before the table is rendered, there will be 250 (50 rows x 5 actions) pre-validation checks performed to determine which actions should be available in each row. If each of those validation checks even takes .01 second, that means that 2.5 seconds will be spent on pre-validation alone before the page is even rendered. In this case, we are willing to sacrifice validation accuracy for performance. The client infrastructure will request limited pre-validation from the validation service in this case. The expectation is that your validator will not perform any expensive validation checks when limited pre-validation is invoked, erring on the side of enabling the action. In other words, suppose that you need to check some access permissions in order to really determine whether or not an action should be available to a user, but you know that access permissions are expensive to check. In your validators
13-138
performLimitedPreValidation() you would skip the access permission check and assume that the user has the appropriate permissions. The worst case scenario is that the action is displayed and enabled for the user, but once they try to invoke it, post-select validation performs a more complete check and denies the user from performing the action. This is what is meant by sacrificing accuracy for performance in limited pre-validation. Full Pre-Validation Explained On the other hand, suppose youre pre-validating an action in a drop-down list of actions in a table row, or on an info page. Since were using Ajax to populate these dropdown lists once the user selects them (as opposed to when the page is initially rendered), performance is not as critical. At most, well be validating several actions, but only for a single context object. In this case, it is acceptable to have slower performance in favor of validation accuracy. Considering the same example we described for limited pre-validation, if you need to perform some access permission checking to determine whether or not an action should be available to a user, you can afford to make that check in your validators performFullPreValidation() method. It may take longer to perform the check, but since the number of validations being performed before the page (or Ajax component) is rendered is manageable, the less-performant check is acceptable. Keep in mind that in many situations, your validators performFullPreValidation() and performLimitedPreValidation() method implementations will be identical.
Creating a Validator
Creating a validator class should be fairly simple. All you need to do is create a class that extends com.ptc.core.ui.validation.DefaultUIComponentValidator. The class below represents a skeleton for a simple validator class.
package com.ptc.windchill.enterprise.myPackage.validators; import com.ptc.core.ui.validation.DefaultUIComponentValidator; public class MyValidator extends DefaultUIComponentValidator{ //override one or more validation methods from DefaultUIComponentValidator }
Once youve created a validator class skeleton, if youre adding pre-validation logic for an attribute, youll want to implement the performLimitedPreValidation() method. If youre adding pre-validation logic for an action, youll want to implement both the performFullPreValidation() and performLimitedPreValidation() methods. As mentioned in the previous sections regarding limited pre-validation and full pre-validation, the implementations of
13-139
these two methods may be identical, or they may differ. The class on the next page contains some skeleton implementations of these methods.
public class MyValidator extends DefaultUIComponentValidator{ @Override public UIValidationResultSet performFullPreValidation() (UIValidationKey validationKey, UIValidationCriteria validationCriteria, Locale locale) throws WTException { UIValidationResultSet resultSet = UIValidationResult.newInstance(); // perform your business logic here // if you want to enable the action/component, do this: // resultSet.addResult(UIValidationResult.newInstance(validationKey, // UIValidationStatus.ENABLED)); // if you want to disable the action/component, do this: // resultSet.addResult(UIValidationResult.newInstance(validationKey, // UIValidationStatus.DISABLED)); // if you want to hide the action/component, do this: // resultSet.addResult(UIValidationResult.newInstance(validationKey, UIValidationStatus.HIDDEN)); return resultSet; } @Override public UIValidationResultSet performLimitedPreValidation() (UIValidationKey validationKey, UIValidationCriteria validationCriteria, Locale locale) throws WTException { UIValidationResultSet resultSet = UIValidationResultSet.newInstance(); // perform your business logic here // if you want to enable the action/component, do this: // resultSet.addResult(UIValidationResult.newInstance(validationKey, // UIValidationStatus.ENABLED)); // if you want to disable the action/component, do this: // resultSet.addResult(UIValidationResult.newInstance(validationKey, // UIValidationStatus.DISABLED)); // if you want to hide the action/component, do this: // resultSet.addResult(UIValidationResult.newInstance(validationKey, UIValidationStatus.HIDDEN)); return resultSet; } }
13-140
Registering Validators
Once youve created your validator and implemented the appropriate prevalidation method(s), the only thing left to do is to register it. You need to register your validator to associate it with the action or attribute it is intended to validate. When registering a validator for an action, you may make the association using the action name only, or using a combination of action name and object type. In most cases, using just the action name to identify your validator is sufficient and preferred. When registering a validator for an attribute, you make the association using the attributes descriptor ID. Basic Validator Registration To register your validator (using only the action name for an action), you need to add an entry to *service.properties.xconf like this:
<Service context="default" name="com.ptc.core.ui.validation.UIComponentValidator"> <Option requestor="null" serviceClass="[your fully-qualified Validator class]" selector="[action name/attribute descriptor ID]" /> </Service>
Note that in this case, the requestor attribute is null, meaning the actions object type is not used in the lookup.
Type-Based Validator Registration If you feel you have a case where it makes sense to register your validator using an actions object-type in addition to action name, it is very similar to registering a validator using only the action name. The difference lies in the requestor attribute in the properties entry. For validators that do not use an object type, the requestor attribute is set to null. For a validator to be registered using object type, the requestor value will be the fully-qualified class name of the type it is to be registered for. The class name that is used in the requestor attribute corresponds to a class name from actions.xml. For example, consider this fragment of an actions.xml file (NOTE: some text eliminated for readability):
<objecttype name="problemReport" class="wt.change2.WTChangeIssue" ...> <action name="create" > ... </action> ... </objecttype>
13-141
In this case, the action we're looking at is called create. Obviously, it's likely that there will be multiple actions defined in the system named create. However, the validation rules for each create action may be different, depending on the type of object being created. Therefore, it might make sense to have separate validators for the create action for, say, a Problem Report and the create action for a Part. Suppose we have a validator defined called com.ptc.windchill.enterprise.change2.validators.ChangeMgmtCreateWizardsVali dator that we want to register for create actions, but only if the action is to create a Problem Report. We could look at the actions.xml entry above and see that the create action for a Problem Report is actually defined for an objecttype whose name is problemReport and, more importantly, whose class is wt.change2.WTChangeIssue. By using that class value from actions.xml as the requestor attribute in our properties entry, we can tell the validation service that we only want to register our validator (com.ptc.windchill.enterprise.change2.validators.ChangeMgmtCreateWizardsVal idator) for create actions whose object type is wt.change2.WTChangeIssue, like this:
<Service context="default" name="com.ptc.core.ui.validation.UIComponentValidator"> <Option serviceClass="com.ptc.windchill.enterprise.change2.validators.Chan geMgmtCreateWizardsValidator" selector="create" requestor="wt.change2.WTChangeIssue" /> </Service>
That's really all there is to it. Basically, if you want to register your validator for an action, but only if that action is associated with a certain object type (in actions.xml), you use the class attribute from actions.xml as the requestor attribute in your properties entry.
A few notes:
This type-based lookup is currently only available for actions defined in actions.xml. It will not work for attributes or other UI components. For this to work, the class attribute from your actions.xml entry needs to be a concrete class (not an interface - there are many cases where the class attribute is currently set to wt.fc.Persistable). Changing an existing class attribute from an interface to a concrete class is OK in most cases. But you should check with the owner of the actions.xml file you're modifying before doing so.
Verifying Validator Registration There is a command line report you can run to see which validators are registered for a given action or attribute. If your validator is not appearing in this report, that means it is not registered correctly, and will never get called.
13-142
Examples follow: Finding a single validator (non-type based) Usage example 1 - find the validator registered for the pasteAsCopy action:
Y:\>java com.ptc.core.ui.validation.UIComponentValidatorFactory pasteAsCopy
Registered validators:
pasteAsCopy -> com.ptc.core.foundation.saveas.validators.PasteValidator
Finding multiple validators (non-type based) Usage example 2 - find the validators registered for the setState and pasteAsCopy actions:
Y:\>java com.ptc.core.ui.validation.UIComponentValidatorFactory setState pasteAsCopy
Registered validators:
setState -> com.ptc.windchill.enterprise.lifecycle.validators.SetStateValid ator pasteAsCopy -> com.ptc.core.foundation.saveas.validators.PasteValidator
Finding a single validator (type-based) Usage example 3 - find the validator registered for the create action whose objecttype name attribute in actions.xml is problemReport. (Note: method server must be running for type-based lookup)
Y:\>java com.ptc.core.ui.validation.UIComponentValidatorFactory create:problemReport
Registered validators:
create:problemReport(wt.change2.WTChangeIssue) -> com.ptc.windchill.enterprise.change2.validators.ChangeMgmtCreat eWizardsValidator
Finding multiple validators (mix of type-based and non-type based) Usage example 4 - find the validator registered for the pasteAsCopy action and the create action whose objecttype name attribute in actions.xml is problemReport. (Note: method server must be running for type-based lookup)
Y:\>java com.ptc.core.ui.validation.UIComponentValidatorFactory pasteAsCopy create:problemReport
Registered validators:
pasteAsCopy -> com.ptc.core.foundation.saveas.validators.PasteValidator
13-143
Creating a validator for post-select validation is exactly the same as creating a validator for pre-validation. See Creating a Validator on page 13-139 for details.
Implementing Post-Select Validation Methods
There are two post-select validation methods that can be implemented in a validator one for single-select actions and one for multi-select actions. The respective names of these methods are validateSelectedAction() and validateSelectedMultiSelectAction(). If youre adding validation for an action that could never be a multi-select action, you only need to implement the validateSelectedAction() method. If your action could possibly be a mutli-select action, you should implement both the validateSelectedAction() method and the validateSelectedMultiSelectAction() method. The only real distinction between the two methods is in the method signatures. validateSelectedMultiSelectAction() returns a UIValidationResultSet, whereas validateSelectedAction() returns a single result.
public class MyValidator extends DefaultUIComponentValidator{ @Override public UIValidationResult validateSelectedAction() (UIValidationKey validationKey, UIValidationCriteria validationCriteria, Locale locale) throws WTException { UIValidationResult result = UIValidationResult.newInstance(validationKey, UIValidationStatus.NOT_VALIDATED); // perform your business logic here // if you want to execute the action, do this: // result = UIValidationResult.newInstance(validationKey, UIValidationStatus.PERMITTED); // if you want to abort the action, do this: // result = UIValidationResult.newInstance(validationKey, UIValidationStatus.DENIED); // if you want to prompt the user for confirmation, do this: // result = UIValidationResult.newInstance(validationKey, // UIValidationStatus.PROMPT_FOR_CONFIRMATION);
13-144
return result; } @Override public UIValidationResultSet validateSelectedMultiSelectAction () (UIValidationKey validationKey, UIValidationCriteria validationCriteria, Locale locale) throws WTException { UIValidationResultSet resultSet = UIValidationResultSet.newInstance(); // perform your business logic here // if you want to execute the action, do this: // resultSet.addResult(UIValidationResult.newInstance(validationKey, // UIValidationStatus.PERMITTED)); // // if you want to abort the action, do this: // resultSet.addResult(UIValidationResult.newInstance(validationKey, // UIValidationStatus.DENIED)); // if you want to prompt the user for confirmation, do this: // resultSet.addResult(UIValidationResult.newInstance(validationKey, // UIValidationStatus. PROMPT_FOR_CONFIRMATION)); return resultSet; } }
13-145
Creating a validator for post-submit validation is exactly the same as creating a validator for pre-validation. See Creating a Validator on page 13-139 for details.
Implementing Post-Submit Validation Methods
There is only one post-submit validation method that can be implemented in a validator The respective name of the method is validateFormSubmission().This method is intended to be called after a wizard "next" or "finish" action is invoked, to determine whether or not the user-entered data is valid.
public class MyValidator extends DefaultUIComponentValidator{ @Override public UIValidationResult validateFormSubmission (UIValidationKey validationKey, UIValidationCriteria validationCriteria, Locale locale) throws WTException { UIValidationResult result = UIValidationResult.newInstance(validationKey, UIValidationStatus.NOT_VALIDATED); // perform your business logic here // if you want to execute the action, do this: // result = UIValidationResult.newInstance(validationKey, UIValidationStatus.PERMITTED); // if you want to abort the action, do this: // result = UIValidationResult.newInstance(validationKey, UIValidationStatus.DENIED); // if you want to prompt the user for confirmation, do this: // result = UIValidationResult.newInstance(validationKey, // UIValidationStatus.PROMPT_FOR_CONFIRMATION); return result; } }
13-146
There is an attribute on UIValidationCriteria that can be used to store access permissions retrieved by one validator or filter, to be used by a subsequent validator or filter. For example, suppose actionA, actionB, and actionC are all in the same action model, and all need to know whether or not the user has modify permissions in the current container. If the validator or filter for actionA is invoked first, it can query the AccessControlManager for the permissions and then store them in the UIValidationCriteria, so that the validators or filters for actionB and actionC do not need to perform the same query again. In general, if you need to check access permissions in a validator or filter, you should do the following: Check to see if the permissions are already stored in the UIValidationCriteria by calling the new UIValidationCriteria.getCachedAccessPermissions() method. If getCachedAccessPermissions() returns a non-null value, you can use those permissions for your validation checks If getCachedAccessPermissions() returns null, then you can query the AccessControlManager to get the permissions you need, and then store them in the UIValidationCriteria for subsequent validators by calling the setCachedAccessPermissions() method.
The intent of the cachedAccessPermissions attribute in UIValidationCriteira is that it store the result of AccessControlManager.getPermissions(). So in other words, you should write your validator or filter code to look like this:
// check to see if the access permissions have already been calculated... WTKeyedHashMap accessPermissions = criteria.getCachedAccessPermissions(); // if the access permissions have not been calculated yet, get the permissions and cache them for other // validators to use if (accessPermissions == null){
13-147
Additional notes regarding access permissions: wt.access.AccessControlManager has the following APIs available in singleand multi-object variants: hasAccess - returns true if the principal has the given access permission, otherwise returns false checkAccess - throws a NotAuthorizedException and emits an event for auditing purposes if the principal does not have the given access permission getPermissions - returns the set of permissions (AccessPermissionSet) granted to a principal
Use hasAccess or getPermissions to evaluate a users rights and continue (e.g., UI action validation code disables action based on the users rights) One way of checking to see if a user has access is to use one of the hasAccess APIs. Another way would be to have anyone that needs to check permissions for an object (or objects) call one of the two getPermissions APIs, and store the result in the UIValidationCriteria, for use by other validators that also need to check permissions for the same object(s) (assuming the domain, type & state of the object and the current principal remain the same), rather than calling hasAccess to evaluate access rights for each permission check. Even if the result was not stored, the getPermissions API would be useful for any validator that needs to check multiple permissions. AccessPermissionSet is a collection, and has a method to check if a specified permission is in the set:
boolean includes(AccessPermission permission) // Returns true if permissions in this set include rights for the specified permission.
The checkAccess APIs should NOT be used to see if the user has a specified permission, unless the intent is that an exception is to be propagated to the end user. If the NotAuthorizedException is caught and does not result in a user's action failing due to the lack of access rights, auditing of the exception should be disabled. See the Javadoc for more information.
Dont fall into the trap of having one validator registered for multiple unrelated actions. The result is lots of if/else branching and some very large methods. This can make maintenance difficult, and makes it much easier to introduce regressions. In general, the only times where you would use a single validator for multiple actions/components would be if those components share the exact same validation logic, or if you have an either/or scenario. What we mean by an either-or scenario is that in a given action menu, either actionA or actionB should appear, but never
13-148
both. For all other cases, the best practice is to register one validator per action/component.
Do Not Inflate WTReferences
You may be tempted to write validation code like this. Dont do it.
@Override public UIValidationResultSet performFullPreValidation (UIValidationKey validationKey, UIValidationCriteria validationCriteria, Locale locale) throws WTException { Persistable contextObject = validationCriteria.getContextObject().getObject(); WTContainer container = validationCriteria.getParentContainer().getReferencedContainer(); if (!contextObject instanceof WTPart){ ... } if (!container instanceof PDMLinkProduct){ ... } }
The code above in bold italic is performing a relatively costly operation of inflating the WTReferences held in the UIValidationCriteria to Persistables. There may be cases where inflating those objects is not avoidable, but there are also many cases where it can be avoided. If all you really need to know is if the context object or parent container is an instance of some class, you can use the isAssignableFrom() method instead, like this:
@Override public UIValidationResultSet performFullPreValidation (UIValidationKey validationKey, UIValidationCriteria validationCriteria, Locale locale) throws WTException { WTReference contextObjectRef = validationCriteria.getContextObject(); WTContainerRef containerRef = validationCriteria.getParentContainer(); if (!WTPart.class.isAssignableFrom(contextObjectRef.getReferencedClas s())){ ... } if (!PDMLinkProduct.class.isAssignableFrom(containerRef.getReferenced Class())){ ... } }
13-149
There may be cases where you are writing a validator or filter for a specific action on a specific page in a product where you need one of the attributes from UIValidationCriteria to perform your business logic. For example, suppose you're working on a 3rd level table on an info page, and in that table's toolbar, you don't want an action to appear if you're on an info page for a Generic Part. So you do the following (do not duplicate this code, but for the sake of an example...):
if (((WTPart)validationCriteria.getContextObject().getObject()).getGe nericType() .equals(GenericType.GENERIC)){ ...
And that may work fine in your test cases where you're only testing an action on part details pages. But what if that action also appears in the toolbar of one of the tables on the home page, or on the products list page? Then the code above will throw a NullPointerException from those pages, since validationCriteria.getContextObject() will (correctly) return null. There are a few things you can do to avoid this scenario. The first is to check and make sure that the values you're getting from UIValidationCriteria are not null. If a value is null, log a warning, and call super.[whatever method you're implementing](key, criteria, locale);. The other thing you can do is when performing comparisons, use the .equals operation on the "expected" value. For example:
if (ComponentType.WIZARD.equals(validationCriteria.getComponentType() )
NOT
if (validationCriteria.getComponentType().equals(ComponentType.WIZARD ))
In general, just because a null value doesn't allow validation to proceed in your use case, that doesn't mean it should be a showstopper in every use case.
Use the @Override Annotation
Its highly encouraged to use the Override annotation, whenever you over-ride methods of the ootb delivered classes.
UIValidationCriteria.toString()
UIValidationCriteria, the toString() is not over-ridden to give information of its content. You can use the following method for logging.
public String toString_heavy(Logger logger, Level level)
13-150
If the Level of the Logger matches with the Level provided, the method will return the information. Since the method performs some costly calculations, its suggested to use this it wisely.
13-151
Replace wt.part.DefaultValidateFindNumbersDelegate with the full path and name of the new delegate that was just created. e. Run "xconfmanager -Fpv" to propagate the changes. f. Create an rbinfo entry with the message you want to display when an error occurs.
3. If the customization rules pertaining to leading/trailing spaces have to be obeyed while loading data from a load file as well, then the following code samples provide an example of how to do this in the method
13-152
"getValue(String, Hashtable, HashTable, boolean)" of the file "Windchill\ DevModules\Foundation\src\wt\part\LoadPart.java". OOTB Implementation:
protected static String getValue( String name, Hashtable nv, Hashtable cmd_line, boolean required ) throws WTException { String value = LoadServerHelper.getValue(name,nv,cmd_line,required?LoadServerH elper.REQUIRED:LoadServerHelper.NOT_REQUIRED); if (value != null) { value = value.trim(); if (value.equals("")) { value = null; } } return value; }
Customized implementation allowing leading and trailing spaces while loading from a file:
protected static String getValue( String name, Hashtable nv, Hashtable cmd_line, boolean required ) throws WTException { String value = LoadServerHelper.getValue(name,nv,cmd_line,required?LoadServerH elper.REQUIRED:LoadServerHelper.NOT_REQUIRED); // Don't trim leading/trailing spaces if reading Find Number field. if(!name.equalsIgnoreCase("findNumber")) { if (value != null) { value = value.trim(); if (value.equals("")) { value = null; } } } return value; }
Sample Code
// /* * * * * * * * * Generated DefaultValidateFindNumbersDelegate%43C7A40F0161: Fri 03/07/08 10:41:32 bcwti Copyright (c) 2007 Parametric Technology Corporation (PTC). All Rights Reserved. This software is the confidential and proprietary information of PTC and is subject to the terms of a software license agreement. You shall not disclose such confidential information and shall use it only in accordance with the terms of the license agreement.
13-153
* * ecwti */ package wt.part; import import import import java.lang.String; wt.part.ValidateFindNumbersDelegate; wt.part.WTPartUsageLink; wt.util.WTException;
//##begin DefaultValidateFindNumbersDelegate%43C7A40F0161.doc preserve=no /** * Standard delegate to handle validation of Find Numbers, i.e., OOTB behavior, * which is doing nothing. * * <BR><BR><B>Supported API: </B>true * <BR><BR><B>Extendable: </B>true * * @version 1.0 **/ //##end DefaultValidateFindNumbersDelegate%43C7A40F0161.doc public class DefaultValidateFindNumbersDelegate implements ValidateFindNumbersDelegate {
private static final String RESOURCE = "wt.part.partResource"; private static final String CLASSNAME = DefaultValidateFindNumbersDelegate.class.getName(); //##begin user.attributes preserve=yes //##end user.attributes //##begin static.initialization preserve=yes private static final String SPACE = " "; private static final String HYPHEN = "-"; //##end static.initialization
// --- Operation Section --//##begin validateFindNumbers%43C6C7F300E8.doc preserve=no /** * * <BR><BR><B>Supported API: </B>false * * @param partUsageLinks * @exception wt.util.WTException **/
13-154
//##end validateFindNumbers%43C6C7F300E8.doc public void validateFindNumbers( WTPartUsageLink[] partUsageLinks ) throws WTException { //##begin validateFindNumbers%43C6C7F300E8.body preserve=yes //##end validateFindNumbers%43C6C7F300E8.body } //##begin validateFindNumbers%45A68DEC00D9.doc preserve=no /** * * <BR><BR><B>Supported API: </B>false * * @param findNumbers * @exception wt.util.WTException **/ //##end validateFindNumbers%45A68DEC00D9.doc public void validateFindNumbers( String[] findNumbers ) throws WTException { //##begin validateFindNumbers%45A68DEC00D9.body preserve=yes try { doValidation(findNumbers); } catch (WTPropertyVetoException wtpe) { throw new WTException (wtpe); } //##end validateFindNumbers%45A68DEC00D9.body } //##begin user.operations preserve=yes /** * Method to validate if the format of the "Find Number" field is correct or not. * The default logic allows only alphanumeric entries for this field. * A WTPropertyVetoException is thrown if the format of the string in this field does not * match the constraints imposed. The consequence of this Exception is that an error dialog * will be displayed with a message as defined in the rbinfo file. * This method can be customized to incorporate any constraint that the user might wish * to impose on this field. * @param findNumbersArray The value being entered (and validated) for the "Find Number" field * @throws WTPropertyVetoException */ private void doValidation(String[] findNumbersArray) throws WTPropertyVetoException { for(int j = 0; j < findNumbersArray.length; j++) { String a_FindNumber = findNumbersArray[j];
13-155
// Find Number can only be alphanumeric with the exception that the "Find Number" // string can contain a space (" ") or a hyphen ("-") as part of it. The string can // start or end with a space, but cannot start or end with an hyphen. // SPR 1457664 if (a_FindNumber != null) { for (int i = 0; i < a_FindNumber.length(); i++) { if(a_FindNumber.startsWith(HYPHEN) || (a_FindNumber.endsWith(HYPHEN))) { Object[] args = {a_FindNumber}; throw new WTPropertyVetoException( RESOURCE, wt.part.partResource.FIND_NUMBER_NOT_ALPHANUMERICAL_ERROR, args, new java.beans.PropertyChangeEvent( this, "findNumber", a_FindNumber, a_FindNumber )); } if (!Character.isLetterOrDigit(a_FindNumber.charAt(i))) { if((a_FindNumber.substring(i, i + 1)).equals(SPACE) || (a_FindNumber.substring(i, i + 1)).equals(HYPHEN)) { // We have already checked that the first and/or last character is not an hyphen // in the if-condition above. So, if the code gets into this block, we can be sure // that the hyphen is in the middle of the string and not at the beginning or end. // Also, if the character is a space, we are allowing it, so we can continue. continue; } else { Object[] args = {a_FindNumber}; throw new WTPropertyVetoException( RESOURCE, wt.part.partResource.FIND_NUMBER_NOT_ALPHANUMERICAL_ERROR, args, new java.beans.PropertyChangeEvent( this, "findNumber", a_FindNumber, a_FindNumber )); } } } } } } //##end user.operations }
13-156
14
Constructing Wizards
This chapter describes how to construct wizards. Topic Page
Windchill Client Architecture Wizard ..............................................................14-2 Wizard Processing...........................................................................................14-19 Building Wizards to Create a Single Object ...................................................14-38 Building Wizards to Edit a Single Object .......................................................14-90
14-1
Background
Wizards are popup windows that are used to guide you step by step through the process of creating an object, or performing an operation on an object. A wizard is a user interface consisting of a sequence of steps that lead the user through a specific task one step at a time. It might not be necessary to complete all the steps present in a wizard. Once the required information is provided, you can click FINISH / OK button to submit the data to the server. A wizard can consist of a single step or multiple steps. Each multiple steps wizard will have navigation buttons (BACK / NEXT) at the bottom, which you can use to navigate from one step to another. A clerk is a user interface consisting of a tab control that has two or more tabs. Data can be entered and the user can complete tabs in any order. A user may freely move from one tab to another, even if the current tab is not complete. A clerk is not meant to guide users sequentially through a task, and is typically used for frequent and easily accomplished tasks. The layout for single step wizards and multi step wizards will be different. The single step wizard will not have Step icons, Step links and Back / Next navigation buttons.
Multi-Step Wizard
14-2
Multi-Step Clerk
Scope/Applicability/Assumptions
A wizard should be used when you need to create / edit object(s) by performing any operations on it after collecting required information in a specific systematic manner. A table rendered within a wizard is JCA table and table rendered inside a picker is a JSCA table. Scrolling is enabled for table inside wizard as well as table inside picker. For the most part, clerks are implemented in the same fashion as that of wizards and the instructions in this document are applicable to both. Any
Constructing Wizards
14-3
differences are noted. Otherwise, the term "wizard" should be interpreted as either a wizard or a clerk and "wizard step" should be interpreted as either a wizard step or a clerk tab.
Solution
Use a Wizard or Clerk component.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Basic development, which involves HTML, JSP, JavaScript and Custom taglibs. Overview of Windchill Client Architecture tags. The actions framework in the Windchill client architecture. Action validation framework.
Solution Elements
Element
Type
Description
components.tld
tld
Tag Library Descriptor (TLD) file, which contains Wizard Tag and Wizard-Step Tag definition Run time Location: <Windchill>\codebase\WEB-INF\tlds\
wizard.js
Js
Contains all the necessary logic of how to move from one step to another and how to call methods defined for each of the steps. Run time Location: <Windchill>\codebase\netmarkets\tlds\javascript\ components
The jsp file in which your wizard implementation is defined. The jsp file, which contains contents of the wizard step. The actions for the wizard as well as each wizard step are defined in this XML file. The models for the list of buttons, to be displayed at the bottom of the wizard (i.e. the navigation area) are defined in this XML file.
14-4
Element
Type
Description
<resourceBundle>.rbInfo
rbInfo
This is another option where you can specify locale specific Strings and properties for wizard step and wizard actions. The java class, which will be executed after the wizard, is submitted. The wizard framework will pass on the data / information to this java class.
formProcessorController
java
Each step of the wizard and the wizard itself needs an action declaration for the associated page. Actions are grouped together using object types. These object types are declared inside of the <listofactions> tag contained in any one of the *actions.xml files. Windchill will expect all jsp pages related to this object type to be located in <Windchill>\codebase\netmarkets\jsp\<objecttype>. For the below specified example the location will be <Windchill>\codebase\netmarkets\jsp\ changeTask\. The create action is defined for the wizard page. Windchill will now expect create.jsp to be located in <Windchill>\codebase\netmarkets\jsp\changeTask\ folder. Since this action is for the wizard, you need to specify windowType as popup inside the <command> tag. The affectedAndResultingItemsStep action is defined for the wizard step. The corresponding jsp should be located at <Windchill>\codebase\netmarkets\jsp\ changeTask\ affectedAndResultingItemsStep.jsp. Since this action is for the wizard step, you need to specify windowType as wizard_step.
<objecttype name="changeTask" class="wt.change2.WTChangeActivity2"> <action name="create"> <command windowType="popup"/> </action> <action name="affectedAndResultingItemsStep"> <command windowType="wizard_step" /> </action> </objecttype>
Create a new jsp page inside <Windchill>\codebase\netmarkets\jsp\changeTask\ folder and name it as create.jsp. The first thing that you need to do is to declare the components tag library that contains the necessary tags for constructing the wizard and wizard steps. Next you need to include some files that will be used by the wizard infrastructure namely;
Constructing Wizards
14-5
/netmarkets/jsp/components/beginWizard.jspf and /netmarkets/jsp/components/includeWizBean.jspf. Define the wizard using the <wizard> tag. All the steps for this wizard will be defined inside <wizard> tag using <wizardStep> tag. Finally, include "/netmarkets/jsp/util/end.jspf" file to close the form.
<%@ taglib prefix="jca" uri="http://www.ptc.com/windchill/taglib/components" %> <%@ include file="/netmarkets/jsp/components/beginWizard.jspf"%> <%@ include file="/netmarkets/jsp/components/includeWizBean.jspf"%> <jca:wizard > <jca:wizardStep action="defineItemWizStep" type="object"/> <jca:wizardStep action="setAttributesWizStep" type="object" /> <jca:wizardStep action="affectedAndResultingItemsStep" type="changeTask" /> </jca:wizard> <%@ include file="/netmarkets/jsp/util/end.jspf"%>
Define a Clerk
Defining a clerk is exactly same as defining a wizard, the only difference in the case of a clerk is that you define the type as "clerk".
<jca:wizard type="clerk"> <jca:wizardStep action="defineItemWizStep" type="object"/> <jca:wizardStep action="setAttributesWizStep" type="object" /> <jca:wizardStep action="affectedAndResultingItemsStep" type="changeTask" /> </jca:wizard>
After defining the wizard type as "clerk", the wizard will be displayed as per the Clerk UI standards. Step indicators will not appear and step titles will be displayed as tabs. The Next and Previous buttons will not be displayed for Clerk. The user can navigate from any step to any step without entering the required fields. The validation for required fields will be done when the user clicks on the "OK" button. The user will be shown a message about required fields and will be taken to the appropriate steps, where required fields are not populated.
Specify localized Strings / properties for wizard step and wizard actions
changeTask.create.description.value=New Change Task changeTask.create.description.comment=Used as the label for the create action changeTask.create.title.value=New Change Task changeTask.create.title.comment=Used as the title for the create action changeTask.create.tooltip.value=New Change Task changeTask.create.tooltip.comment=Used as the tooltip for the create action changeTask.create.icon.value=../../wtcore/images/task_create.gif changeTask.create.icon.comment=DO NOT TRANSLATE
14-6
You can specify localized strings / properties in a <resourceBundle>.rbInfo file. The format of each entry should be <objectType>.<action>.<property>.<type> = <value>. For example, you can specify the height and width of the popup window in which the wizard will be displayed, using the following property: changeTask.create.moreurlinfo.value=width=800,height=700
Create the wizard step page
This can be any JSP page, which can contain any other component(s) as well as plain HTML contents.
Customization Points
This section contains the following topics: <action>.xml attributes <wizard> tag attributes <wizardStep> tag attributes Providing user defined buttons to Wizard Providing user defined form processor controller Providing server side validation before / after processing a wizard step Loading the wizard step content when it is visited Marking a wizard step as required Hiding a wizard step Displaying the hidden / dynamic step at runtime Providing user defined SUBMIT function Providing client side validations before a wizard step is displayed Providing client side validations after a wizard step is finished
<action>.xml attributes
Parameter id
Req? No
Constructing Wizards
14-7
Parameter afterJS
Default Value -
Req? No
Description Specify the javascript function name to invoke client side validation for a wizard step when step is finished. Specify the javascript function name to invoke client side validation for a wizard step when step is loaded. Specify the server validator name to invoke server side validation for a wizard step when step is loaded. Specify the server validator name to invoke server side validation for a wizard step when step is finished. Specifies that wizard step is to be downloaded when wizard is launched. Specifies that wizard step is to be hidden at first, or for the action to be rendered as non-clickable. Specifies that wizard step is required.
beforeJS
Any String
No
beforeVK
Any String
No
afterVK
Any String
No
preloadWizardPa ge hidden
true false
No No
required
false
false / true
No
Parameter buttonList
Req? No
Description The action model containing the list of buttons to display in the wizard. The default set is the DefaultWizardButtons action model. The FormProcessorController class that should be used to process the wizard when it is submitted. If not specified, DefaultFormProcessorController will be used.
formProcessorCo ntroller
DefaultFormPr ocessorControlle r
Any String
No
14-8
Parameter title
Default Value -
Req? No
Description The overriding title to display instead of the default title in the rbInfo file or action.properties file. This title will not be localized / internationalized by default. You need to take care of passing a localized title. The selector key to identify help file from services.properties file. Identifies whether wizard is of type clerk or not. If "clerk" is specified, the wizard will be displayed as per clerk UI. This allows for text to be displayed above the progress bar using the UI standard.
helpSelectorKey type
wizard
No No
progressMessage
Any String
No
Default Value -
Description The name of the action to include in the wizard parent tag. The type of the action to include in the wizard parent tag. The object handle to identify which object this step corresponds to. Only required if the wizard needs to create multiple objects. By default, no object handle is needed.
label
Any String
No
The label for the step. Note: Actions should already have labels. Only set this attribute if you want to override the action's label.
embeddedHelp
Any String
No
A small optional text help to be displayed on top of the wizard step content.
Constructing Wizards
14-9
Every button in the actionmodel should have a corresponding entry for its action in actions.xml file. If there is a separate java class written to render that particular button, than you can specify the name of that class and its method (which contains the rendering code) using the class and method attributes of <command> tag. For example:
<action name="revertButton" id="PJL_wizard_revert_to_default"> <command class="" method="" windowType="page" url="javascript:revertToDefault()"/> </action>
Note: For a clerk, only the OK and Cancel buttons are displayed by default. If new buttons are to be configured, the appropriate button model should be configured.
14-10
</jca:wizard>
Note: For more information see the Wizard Processing on page 14-19.
OR
<action name="setAttributesWizStepForCreateMultiPart" afterVK = "nameNumberValidation"> <command windowType="wizard_step"/> </action> <Service context="default" name="com.ptc.core.ui.validation.UIComponentValidator"> <Option requestor="null" selector="nameNumberValidation" serviceClass="com.ptc.windchill.enterprise.part.validator.CreateMu ltiPartNameNumberValidator" /> </Service>
You can configure the wizard such that the content of any wizard step is not loaded when the wizard is first initialized and loaded. You can load the contents of a wizard step when you try to visit that step. You may need this feature when the step is dependant on information gathered from a previous step. You can use preloadWizardPage attribute of <action> tag to achieve this. By default, the value of this attribute is true. For e.g.
<action name="setClassificationAttributesWizStep" preloadWizardPage="false"> <command windowType="wizard_step"/> </action>
Note: In the case of a clerk, all the steps will be loaded by default. The clerk does not have conditional display of steps (i.e. hidden steps), so all the steps would be preloaded.
Constructing Wizards
14-11
You can also mark a wizard step as required at runtime. You need to use a javascript function called setStepRequired which is defined in wizard.js file. You need to pass the id of the step. The default id of the step is in the format <type>.<action>. Use the value of the id attribute if it is defined explicitly while defining wizard step action. For e.g.
<script src="/netmarkets/javascript/components/wizard.js"></script> <table border="0"> <tr> <td align="left" valign="top" NOWRAP> <w:radioButton id="copy" name="<%=NmObjectHelper.CHOICE%>" value="<%=NmObjectHelper.CB_COPY%>" checked="true" onclick="removeStep(<type>.<action >);"/> </td> </tr> </table>
To implement first way of hiding a step, you can make use of the hidden attribute of <action> tag. For e.g. In <*-actions>.xml
<action name="setClassificationAttributesWizStep" hidden="true"> <command windowType="wizard_step"/> </action>
To hide a wizard step at runtime, you need to use a javascript function called removeStep which is defined in wizard.js file. You need to pass the id of the
14-12
step that needs to be removed. The default id of the step is in the format <type>.<action>. Use the value of the id attribute if it is defined explicitly while defining wizard step action. For e.g. In <your_wizardstep_page>.jsp
<script src="/netmarkets/javascript/components/wizard.js"></script> <table border="0"> <tr> <td align="left" valign="top" NOWRAP> <w:radioButton id="copy" name="<%=NmObjectHelper.CHOICE%>" value="<%=NmObjectHelper.CB_COPY%>" checked="true" onclick="removeStep(<type>.<action >);"/> </td> </tr> </table>
Note: Clerk does not make use the of conditional display of steps (i.e. hidden steps), so all the steps will be preloaded and displayed to the user.
In <*-actions>.xml
<action name="setClassificationAttributesWizStep" hidden="true"> <command windowType="wizard_step"/> </action>
In <your_wizardstep_page>.jsp
<script src="/netmarkets/javascript/components/wizard.js"></script> <table border="0"> <tr> <td align="left" valign="top" NOWRAP> <w:radioButton id="copy" name="<%=NmObjectHelper.CHOICE%>" value="<%=NmObjectHelper.CB_COPY%>" checked="true" onclick="insertStep(<type>.<action>);"/> </td>
Constructing Wizards
14-13
</tr> </table>
14-14
the value for the attribute "afterJS" while defining the action for that particular step. The next step will only be displayed if the specified function returns "true". For e.g. In <*-actions>.xml
<action name="setClassificationAttributesWizStep" afterJS =" validateStep"> <command windowType="wizard_step"/> </action>
Limitations
Windchill Wizard framework takes help from Windchill Action framework to pick up the localized wizard title either from the related .rbInfo file or from a action_<locale>.properties file. It uses the <objectType> and <action> to fetch the required value. The problem arises when you try to use url attribute of command tag (while defining the wizard action). If the value of the url attribute points to a jsp page whose name matches with some another action, the wizard framework will receive localized title corresponding to that action.
Constructing Wizards
14-15
<action name="createMultiPart" > <command class = "com.ptc.windchill.enterprise.part.forms.CreateMultiPartFormProcessor" method="execute" onClick="validateCreateLocation(event)" windowType="popup" url="/netmarkets/jsp/part/createPartWizard.jsp?wizardType=multiPart" /> </action>
In the above specified case, the wizard title for the action createMultiPart will be picked up from the property part.createPartWizard.title.value and not from the property part. CreateMultiPart.title.value. The workaround for this scenario is to use the title attribute of the wizard tag. If this attribute is specified, the wizard framework will not try to look in to any rbInfo or properties file. However, be sure that you provide a localized string as a title to wizard tag. For e.g.
<%@ taglib prefix="jca" uri="http://www.ptc.com/windchill/taglib/components"%> <%@ taglib uri="http://www.ptc.com/windchill/taglib/fmt" prefix="fmt"%> <fmt:setBundle basename="com.ptc.windchill.enterprise.part.partResource"/> <fmt:message var="createMultiplePartWizardTitle" key = "part.createMultiPart.WIZARD_LABEL" /> <jca:wizard helpSelectorKey="PartMultipleCreate" title="${createMultiplePartWizardTitle}"> </jca:wizard>
In the case of a clerk, while navigating between steps you may not get required fields in Server validators, so you need to take care and apply logic accordingly.
14-16
For example, while creating a new document the first step has a required field type (type of document). However, in a clerk the user is free to navigate between other tabs while clicking on other tabs, the user might not have selected required field type in the first step. In that case the server validator cannot get the value of the type attribute.
Constructing Wizards
14-17
Packaged Samples
Wizard example one (can be accessed through wizard actions on table examples):
<Windchill>\netmarkets\jsp\carambola\customization\examples\ wizard\newWizardExampleOne.jsp
Wizard example two (can be accessed through wizard actions on table examples):
<Windchill>\netmarkets\jsp\carambola\customization\examples\ wizard\wizardExampleTwo.jsp
Clerk example one (can be accessed through wizard actions on table examples):
<Windchill>\netmarkets\jsp\carambola\customization\examples\ clerk\clerkExampleOne.jsp
14-18
Wizard Processing
Objective
You have created a JSP wizard to gather information from a user about one or more object(s). You now need to create the code to process that information and perform a database operation(s) on the object(s).
Background
If your wizard uses one of the built-in button sets, when a user clicks the Finish, Apply, Save, or Check In button to submit the form, a javascript function is called that invokes the doPost() method of the WizardServlet. The WizardServlet loads the HTTP form data and other wizard context information, such as where the wizard was launched, into a NmCommandBean. It then passes the NmCommandBean to the FormDispatcher class. The FormDispatcher performs an RMI call to a FormProcessorController class in the MethodServer. The FormProcessorController partitions the form data into ObjectBeans. One ObjectBean is created for each target object of the wizard. It contains all the form data specific to that object and any form data that is common to all objects. The FormProcessorController then passes the ObjectBeans to classes called ObjectFormProcessors that perform the tasks appropriate to the wizard --- for example, creating a new object in the database, updating an object in the database, or checking in an object. ObjectFormProcessors, in turn, can call classes called ObjectFormProcessorDelegates to perform one or more subtasks. If your wizard is performing an operation on a single object you may need to create your own ObjectFormProcessor and/or ObjectFormProcessorDelegates to perform the tasks specific to your wizard. However, if your wizard is creating or editing an object, you may be able to take advantage of some processors that are delivered with the product for those purposes. See Building Wizards to Create a Single Object on page 14-38 and Building Wizards to Edit a Single Object on page 14-90 for more information. If your wizard has multiple target objects you may or may not also need to create your own FormProcessorController to control the order in which objects are processed.
Scope/Applicability/Assumptions
Assumes that you have already created the necessary JSPs, data utilities, GUI components, and renderers to display your wizard. Also assumes that you have created the necessary actions to hook up your wizard to the UI.
Intended Outcome
Perform a database operation(s) related to one or more Windchill object.
Constructing Wizards
14-19
Solution
Use the JSP client architecture framework and common components to process wizard form data and perform the appropriate database tasks for one or more object(s).
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Java programming Basic web development using HTML forms Familiarity with the Windchill service APIs or other APIs necessary to perform the tasks appropriate to the wizard
target object
Object(s) for which you are gathering data in your wizard. Some operation(s) will typically be performed on these objects in your wizard processing.
Solution Elements
Element WizardServlet
Description This is the class to which wizard form data gets posted and which sends the response page sent back to the browser after processing completes. Runtime location: <WT_HOME>/srclib/CommonCompone nts-web.jar
FormProcessorController
Classes implementing this interface instantiate and call ObjectFormProcessor(s) to execute wizard tasks. Runtime location: <WT_HOME>/srclib/CommonCompone nts.jar
14-20
Element DefaultFormProcessorControll er
Description A default implementation of FormProcessorController that should be sufficient for all single-object wizards. This controller partitions the HTML form data into ObjectBeans and passes those beans to ObjectFormProcessors. Wizards with multiple target objects may need to extend this class to control the order in which objects are processed. Runtime location: <WT_HOME>/srclib/CommonCompone nts.jar
ObjectFormProcessor
Classes implementing this interface perform the database and related tasks appropriate to the wizard using the form data. Each wizard will have only one ObjectFormProcessor class but multiobject wizards may have multiple instances of that class. ObjectFormProcessors may call ObjectFormProcessorDelegates to perform subtasks. Runtime location: <WT_HOME>/srclib/CommonCompone nts.jar
DefaultObjectFormProcessor
A default implementation of ObjectFormProcessor that contains the logic to execute ObjectFormProcessorDelegates and perform several other common tasks. This is the base class that should be extended by wizard-specific processors. Runtime location: <WT_HOME>/srclib/CommonCompone nts.jar
Constructing Wizards
14-21
Element ObjectFormProcessorDelegate
Description Classes implementing this interface are called by ObjectFormProcessors to perform processing subtasks. Multiple ObjectFormProcessorDelegates may be called by one processor and the same delegate may be used by multiple processors to handle a task common to multiple wizards. These are optional. Runtime location: <WT_HOME>/srclib/CommonCompone nts.jar
DefaultObjectFormProcessorD elegate
A default implementation of ObjectFormProcessorDelegate. This provides no-op behavior for methods a subclass may not need to implement. This is the base class that should be extended by task-specific delegates. Runtime location: <WT_HOME>/srclib/CommonCompone nts.jar
ObjectBean
A container for the form data specific to a specific target object and the data common to all objects. Provides methods to retrieve the form data for a given object. Runtime location: <WT_HOME>/srclib/CommonCompone nts.jar
ProcessorBean
A container for ObjectBeans that knows which ObjectBeans should be processed by the same processor instance and the order in which they should be processed. Runtime location: <WT_HOME>/srclib/CommonCompone nts.jar
FormResult
A class used to pass method results between server methods and from the server to the WizardServet. Runtime location: <WT_HOME>/srclib/CommonCompone nts.jar
14-22
The relationship between the main Java classes in the wizard processing framework is shown in the UML diagram below.
2. Start a database transaction block 3. Do the database operation. For example: for an object creation wizard, the object(s) would be stored in the database for an object edit wizard, the object(s) would be updated in the database
4. Postprocessing
Constructing Wizards
14-23
Do database or other tasks that need to be done after the main database operation but within the same transaction block so that the database operation will be rolled back if these task fail. These tasks typically require that the target object(s) be persisted beforehand. For example: share the object(s) to another container submit the object(s) to a workflow
5. End the database transaction block 6. Post-transaction processing Do tasks that need to be done after the transaction block is closed so that the entire database transaction will not be rolled back if the tasks fail. For example: check out an object
Additional database operations may be performed in this phase if desired. The tasks in each processing phase are performed by ObjectFormProcessors and ObjectFormProcessorDelegates. Every wizard must have an ObjectFormProcessor which should extend the DefaultObjectFormProcessor. This is the primary class that controls and performs the processing tasks appropriate to the wizard. Wizards may or may not have one or more ObjectFormProcessorDelegates that are called by the ObjectFormProcessor (via the DefaultObjectFormProcessor) to perform processing subtasks. ObjectFormProcessorDelegates should extend the DefaultObjectFormProcessorDelegate class. See Create any necessary ObjectFormProcessorDelegate classes for your wizard on page 14-36 for more information about ObjectFormProcessorDelegates. Both ObjectFormProcessor and ObjectFormProcessorDelegate classes have preProcess(), doOperation(), postProcess(), and postTransactionProcess() methods for carrying out tasks during each processing phase. Not every wizard will have tasks in every phase, so it is not necessary that every processor and every delegate implement all of these methods, if they extend from the default classes DefaultObjectFormProcessor and DefaultObjectFormProcessorDelegate, respectively. Those parent classes provide default implementations of each method. If an ObjectFormProcessor does implement one of these methods, it should call the super() method of the DefaultObjectFormProcessor, which will handle the calling of ObjectFormProcessorDelegates. The HTML form data will be passed to ObjectFormProcessors and ObjectFormProcessorDelegates in a list of ObjectBeans. An ObjectBean contains the data specific to one target object and the data common to all the target objects. For wizards with a single target object the list will contain only one ObjectBean. For wizards with multiple target objects the list will contain one ObjectBean for each target object and the ObjectBeans may be organized into a tree structure representative of the relationship between the objects and the order in which they
14-24
should be processed. The creation of ObjectBeans is handled by the FormProcessorController. The FormProcessorController also handles the opening, closing, and, if necessary, rollback of the database transaction and the calling of the ObjectFormProcessors. For the latter, the DefaultFormProcessorController uses objects called ProcessorBeans. Target objects with the same parent object, which are of the same type, and which have the same ObjectFormProcessorDelegates are placed into the same ProcessorBean. Each ProcessorBean also will have it's own instances of the ObjectFormProcessor and ObjectFormProcessorDelegates for the ObjectBeans it contains. ProcessorBeans may be organized into a tree structure to control the order in which objects are processed. (Wizards with a single target object will have only one ProcessorBean. ) The task flow of the DefaultFormProcessorController is as follows: 1. Call the preProcess() method of ObjectFormProcessor for the root ProcessorBean, passing it the ObjectBeans in the ProcessorBean. Then call the preProcess() method of the processors for the children of the root ProcessorBean, in the order in which they appear in the child list. Then call the preProcess() method for the children of the children, and so forth. 2. Do Transaction.start() 3. Call the doOperation() method of the ObjectFormProcessor for the root ProcessorBean and its children in the same way as preProcess(). 4. Call the postProcess() method of the ObjectFormProcessor for the root ProcessorBean and its children in the same way as preProcess(). 5. If steps 1-4 are successful, do Transaction.commit() 6. Call the postTransactionProcess() method of the ObjectFormProcessor for the root ProcessorBean and its children in the same way as preProcess(). If any method returns a status of FormProcessingStatus.FAILURE, the controller will call the setResultNextAction() method of the ObjectFormProcessor that failed so it can set information needed for the HTML response page. Note: ObjectFormProcessors should not open/commit additional transaction blocks in steps 3 or 4 as nesting of transactions is not recommended.
Constructing Wizards
14-25
The data specific to a given object should be contained either in a table row specific to that object or in a wizard step specific to that object. An example table where each row represents a part being created and each column is an attribute of the part is shown below.
Each wizard step must display one of these types of data: data in tabular format where each row represents a different object data that is specific to one and only one of the objects created data that is common to all objects created
A step cannot contain object-specific data for multiple objects unless it is in tabular format. In multiple-object wizards, the object to which an input field applies is identified by an "objectHandle" embedded in the name attribute of the HTML input field. For example:
<input id="null1188140328133" name="<someFieldIdString>!~objectHandle~430512131997223~! <someAdditionalText>" value="" size="60" maxlength="60" type="text">
In the example above, "430512131997223" is the object handle, "!~objectHandle~" is the required prefix, and "~!" is the required suffix. The HTML name attribute in which the object handle is embedded can be any string and the object handle may appear anywhere within the string. When the DefaultFormProcessorController loads the form data in to ObjectBeans, it will strip off the object handle (including the required prefix and suffix) from the name attribute and use the resulting string as the key for the value in the form data parameter maps. For example, to retrieve the form value for the input field above you would call ObjectBean.getTextParameter() with the following key:
<someFieldIdString><someAdditionalText>
The framework generates object handles on name attributes for you in one of two ways:
14-26
If data for the objects is being captured in tabular format, where each row represents an object and each column an attribute of the object, the handle will be dynamically generated for you if you put a "rowBasedObjectHandles" attribute on the renderTable tag:
<jca:renderTable model="<your model name>" rowBasedObjectHandles="true" />
The dynamically generated object handle will represent the time in nanoseconds when the row was created. Where all the data on a given wizard step is for the same object, you specify the object handle for that object on the wizard step action:
<jca:wizardStep action="setContextWizStep" type="object" objectHandle="<your object handle string>"
If data on the wizard step is common to all objects created, no object handle is needed on the input fields. The object handle associated to the data in an ObjectBean can be accessed by the ObjectBean.getObjectHandle() method. The FormProcessorController controls the order in which processors are called to process the ObjectBeans, as described in the sections below. Note that in the illustrations below, circles are used to represent ObjectBeans. Circles representing objects of the same type will have the same shading.
Multiple unrelated target objects
Typically, when a wizard has multiple unrelated target objects, the objects are the same type:
An example of such a wizard is that in which you can create multiple parts. This wizard has three steps: 1. Define Part User enters the type of parts to be created and other attributes common to all the parts being created. 2. Set Attributes User enters the name and number of each part to be created in tabular format. This table is dynamic in that the user can enter any number of parts. 3. Set Additional Attributes
Constructing Wizards
14-27
User enters some additional attributes common to all of the parts. If the user enters data for five parts, the DefaultObjectFormProcessorController will create five ObjectBeans. Each ObjectBean will contain the data from step 2 specific to the part it represents and the data from steps 1 and 3. Because there is no relationship between the parts and they can be created independently, none of the ObjectBeans will have parents or children. Since the same ObjectFormProcessor and ObjectFormProcessorDelegates will be used to process all the ObjectBeans and all the objects are of the same type, they will all be placed in the same ProcessorBean.
Multiple related target objects
Other wizards may have multiple related target objects. For example, you might have a wizard that creates a change notice and the change tasks related to that change notice. To create the associations between the change notice and the change tasks, the processor for the change notice will need to know how the objects relate to each other.
The change notice ObjectBean has three child ObjectBeans. The change task ObjectBeans have a parent ObjectBean and no children. In this case, you would need to write your own FormProcessorController to create the structure of ObjectBeans. This can be a subclass of the DefaultFormProcessorController. The default controller will create the ObjectBeans for you. You would override it's createObjectBeanStructure() method, which is given a flat list of all the ObjectBeans. In that method you would set the parents and children of the ObjectBeans. You pass back a list of all the root ObjectBeans. After you have created the ObjectBean structure, the DefaultFormProcessorController will call
14-28
the ProcessorBean.newCollection() method which will group the ObjectBeans into ProcessorBeans as follows:
In the diagram above the circles represent the ObjectBeans and the solid lines the relationships between them. The rectangles represent the two ProcessorBeans and the dotted line the relationship between them. Each ProcessorBean will have its own instances of the ObjectFormProcessor and the ObjectFormProcessorDelegates needed for the objects in it. If the processor for the root ProcessorBean is called "ProcessorInstance1" and the processor for the child ProcessorBean is called "ProcessorInstance2", the processor methods would be called as follows:
Method 1 ProcessorInstance1. preProcess (ObjectBean in Processor Bean 1) ProcessorInstance2. preProcess(ObjectBeans in Processor Bean 2) ProcessorInstance1.doOperation( ObjectBean in Processor Bean 1) ProcessorInstance2.doOperation( ObjectBeans in Processor Bean 2) ProcessorInstance1.postProcess(O bjectBean in Processor Bean 1) Task Performed create an instance of a WTChangeOrder2 and store it in the "object" attribute of the bean create three instances of WTChangeActivity2 and store them in the "object" attributes of the beans persist the WTChangeOrder2 persist the WTChangeActivity2 instances create the associations between the change notice and the change tasks
3 4 5
Constructing Wizards
14-29
Method 6 7 ProcessorInstance2.postProcess(O bjectBeans in Processor Bean 2) ProcessorInstance1.postTransacti onProcess(ObjectBean in Processor Bean 1) ProcessorInstance2.postTransacti onProcess (ObjectBeans in Processor Bean 2)
none
The tasks could be arranged differently. For example, you could create the associations in method 6 instead of method 5 with the same effect. Or, you could create an ObjectFormProcessorDelegate to create the associations in its postProcess() method. The framework offers the flexibility to modularize your code as best fits your wizard. Just be sure to arrange your tasks correctly relative to the start and end of the main transaction. Your structure of ObjectBeans could be more complex. For example:
As you can see from the diagram above, ObjectBeans will be placed in different ProcessorBeans if any of the following is true: the object in the ObjectBeans are different types the ObjectBeans have a different ObjectFormProcessor
14-30
(Note: at this time all the ObjectBeans in the wizard must have the same ObjectFormProcessor.) the ObjectBeans have a different list of ObjectFormProcessorDelegates the ObjectBeans have a different parent ObjectBean
The DefaultFormProcessorController will call the processors associated with each ProcessorBean starting at the root ProcessorBean and proceeding down the tree to the leaf ProcessorBeans.
This process consists of the following steps: Create your processor class Specify the processor class for the wizard on the wizard action Create any necessary ObjectFormProcessorDelegate classes for your wizard Specifying the ObjectFormProcessorDelegate(s) to be used in your wizard
Three processors for handling object creation and editing wizards are delivered with the product: com.ptc.core.components.forms.CreateObjectFormProcessor com.ptc.core.components.forms.DefaultEditFormProcessor com.ptc.core.components.forms.EditWorkableFormProcessor
These processors may be used as is or extended for your own purposes. If your wizard is not an object creation or editing wizard you will need to create your own ObjectFormProcessor. ObjectFormProcessors should extend the DefaultObjectFormProcessor class. You should place your form processing logic into the preProcess(), doOperation(), postProcess(), and postTransactionProcess() methods of the processor, as appropriate. Your methods should call the corresponding super method of the DefaultObjectFormProcessor, which will handle the calling of ObjectFormProcessorDelegates. These methods will be passed a single ObjectBean, which will contain all the form data from the wizard. The form data can be accessed using the getter methods of that object. The following getter methods are commonly used:
Constructing Wizards
14-31
public public public public public public public public public public
Map<String,List<String>> getChangedComboBox() Map<String,String> getChangedRadio() Map<String,String> getChangedText() Map<String,String> getChangedTextArea() Map<String,List<String>> getChecked() Map<String,List<String>> getUnChecked() List getRemovedItemsByName(String paramName) List getAddedItemsByName(String paramName) String getTextParameter(String key) String[] getTextParameterValues String key)
See the javadoc for more information. The "object" attribute of the ObjectBean represents an instance of the target object . Where appropriate, it should be set by one of your processor methods (most likely preProcess()) for use by downstream methods. Other information can be passed from one method to another using processor instance variables. The NmCommandBean object passed to these methods contains information about the page from which the wizard was launched and the object selected on the parent page when the wizard was launched. It also contains all the HTML form data but you should use the methods on the ObjectBean rather than the NmCommandBean to access that data. See the javadoc for NmCommandBean for more information. You pass the outcome of the preProcess(), doOperation(), postProcess(), and postTransactionProcess() methods back to the DefaultFormProcessorController using the com.ptc.core.component.FormResult object. Before returning, each of these methods should call FormResult.setStatus() to return the processing status. Three options are available: FormProcessingStatus.SUCCESS - if the method executed without error FormProcessingStatus.FAILURE - if the method encountered a fatal errors FormProcessingStatus.NON_FATAL_ERROR - if the method succeeded but encountered one or more problems that should be reported to the user.
The DefaultFormProcessorController passes the returned FormResult to its continueExecuting() method to determine whether processing should continue to the next phase or be aborted. By default, it will abort only if the status is FormProcessingStatus.FAILURE. If processing is to be aborted or after all processing competes successfully, the controller will call the setResultNextAction() method of the ObjectFormProcessor to set information in the FormResult needed to construct the response page sent back to the browser. This method should convey the following information: Whether the wizard window should be closed. Determined from the status and nextAction variables. Whether the window from which the wizard was launched should be refreshed.
14-32
Determined from the nextAction variable. The javascript you would like executed in the response, if any. Determined from the nextAction and javascript variables. Whether a new URL should be loaded into the launch window and, if so, what that URL should be loaded. Determined from the nextAction and URL variables. What feedback messages should be displayed to the user, if any. Determined from the feedbackMessages and exceptions variables. Feedback messages, if any, are displayed before executing any window operations or provided javascript. Exception messages are only displayed if status is FormProcessingStatus.FAILURE or FormProcessingStatus.NON_FATAL_ERROR. See the javadoc for the FormResult, FormProcessingStatus, and FormResultAction classes for more information. It is also possible for your ObjectFormProcessor's preProcess(), doOperation(), postProcess(), and postTransactionProcess() methods to throw exceptions. In that case, control will be returned to the WizardServlet which will set the variables of the FormResult as follows: status - FormProcessingStatus.FAILURE nextAction - FormResultAction.NONE exceptions - the thrown Exception
This will cause the response page to display the exception message in an alert window and then close the wizard window.
Specify the processor class for the wizard on the wizard action
You specify the ObjectFormProcessor class in the <command> subtag of the <action> tag for the wizard. Your action tag will be contained in a *actions.xml file. Here is an example of how you would specify the CreateDocFormProcessor class as your processor.
<action name="create"> <command class="com.ptc.core.components.forms.CreateObjectFormProcessor" windowType="popup" /> </action>
Constructing Wizards
14-33
ObjectFormProcessorDelegates may be used to carry out one or more subtasks in your wizard processing. Because the same delegate class may be called by multiple ObjectFormProcessors, they are typically used for tasks that are needed by multiple wizards. Here are some examples of how ObjectFormProcessorDelegates are used in the delivered product: Several object creation wizards have a checkbox named "Keep checked out after checkin." The ObjectFormProcessors for all these wizards call the same ObjectFormProcessorDelegate class to handle this checkbox and checkout the object after it is created if the box is checked. Wizards to create objects that are ContentHolders typically have a Set Attachments step to specific the documents that should be attached to the object. All these wizards call the same ObjectFormProcessorDelegate class to handle the persistence of the attachments. Many object creation wizards have an input field for a Location attribute to specify the object's folder. Because the processing of this input field is complex all these wizards call the same ObjectFormProcessorDelegate to set the folder on the object being created.
As shown in the examples above, a ObjectFormProcessorDelegate can handle the processing of one or many input fields. If your wizard does not have any HTML elements that are used in multiple wizards you may not need any delegates. However, they can be useful for modularizing your processing code also. ObjectFormProcessorDelegates should extend the class DefaultObjectFormProcessorDelegate. ObjectFormProcessorDelegates are instantiated by the DefaultFormProcessorController and passed to the ObjectFormProcessor. ObjectFormProcessorDelegates have preProcess(), doOperation(), postProcess(), and postTransactionProcess() methods just like ObjectFormProcessors. The delegates registered for the wizard will be called by the DefaultObjectFormProcessor during the different processing phases. The outcome of an ObjectFormProcessorDelegate method is passed back to the ObjectFormProcessor using a FormResult, just as the ObjectFormProcessor methods pass back their results to the FormProcessorController. Typically, a delegate will only pass back a status and, possibly, feedback messages in the FormResult. The ObjectFormProcessor will set and pass back the nextAction in the FormResult it sends to the FormProcessorController since it knows the launch context of the specific wizard in which the delegate is being used. Like ObjectFormProcessor methods, ObjectFormProcessorDelegate methods can throw exceptions. How these are handled depends on the ObjectFormProcessor calling it.
14-34
The names of the ObjectFormProcessorDelegate classes to be instantiated by the DefaultObjectFormProcessor, if any, are communicated in hidden input fields as follows:
<input name="FormProcessorDelegate" value="com.ptc.core.components.forms.NumberPropertyProcessor" type="hidden">
These hidden input fields can be created in several ways: If you have a delegate associated with a specific wizard step, the delegate can be specified in the command subtag of in the wizard step action. For example:
The wizard framework will then generate a hidden FormProcessorDelegate field in the wizard for any wizard using this step. If you have specified an object handle on the wizard step action, the name attribute of the hidden field will include the object handle so that the delegate will be called only for the target object associated with the step. If you have a specific input field that requires a delegate you can generate the hidden field in the data utility that creates the GUI component for the input field. It is recommended that the data utility return a subclass of AbstractGuiComponent to take advantage of the addHiddenField() method and the AbstractRenderer. After creating the GUI component in the data utility, call the method addHiddenField() in the AbstractGuiComponent class. For example:
LocationInputGuiComponent guiComponent = new LocationInputComponent(); guiComponent.addHiddenField (CreateAndEditWizBean.FORM_PROCESSOR_DELEGATE, "com.ptc.windchill.enterprise.folder.LocationPropertyProcess or");
The hidden input field will be generated for you by the AbstractRenderer automatically. If the field is associated with a step or table row that has an object handle, that object handle will be embedded in the HTML name attribute of the hidden field. If you choose to return a GUI component that does not extend Abstract GuiComponent, your GUI component and renderer would have to know how to render the necessary hidden field. You can include a hidden field for your delegate directly in your jsp file. However, one of the first two methods is preferred because it encapsulates the hidden field with its associated HTML input fields.
Constructing Wizards
14-35
This process consists of the following steps: Create your processor class Specify the processor class for the wizard on the wizard action Create any necessary ObjectFormProcessorDelegate classes for your wizard Specify the ObjectFormProcessorDelegate(s) to be used in your wizard Create a FormProcessorController, if needed Specify the FormProcessorController to be used in your wizard, if needed
The same as for a wizard with a single target object. See Create your processor class on page 14-31.
Specify the processor class for the wizard on the wizard action
The same as for a wizard with a single target object. See Specify the processor class for the wizard on the wizard action on page 14-33.
Create any necessary ObjectFormProcessorDelegate classes for your wizard
The same as for a wizard with a single target object. See Specify the processor class for the wizard on the wizard action on page 14-33.
Specify the ObjectFormProcessorDelegate(s) to be used in your wizard
The same as for a wizard with a single target object. See Specifying the ObjectFormProcessorDelegate(s) to be used in your wizard on page 14-35. Remember that an object handle must be embedded in the name attributes of the hidden fields specifying the delegates if you want the delegate to be used only for a given object.
Create a FormProcessorController, if needed
If the target objects of your wizard form a structure of related objects, you will need to create your own FormProcessorController to create a structure of the ObjectBeans. You should subclass the DefaultFormProcessorController to leverage its ability to partition the form data into ObjectBeans and ProcessorBeans and call the form processors. Typically, the only method you will need to override is the createObjectBeanStructure() method.
Specify the FormProcessorController to be used in your wizard, if needed
If you have created your own FormProcessorController, you should specify the controller to be used for your wizard on the wizard tag in your main JSP file for the wizard. For example:
<jca:wizard helpSelectorKey="change_createProblemReport" buttonList="DefaultWizardButtonsWithSubmitPrompt"
14-36
formProcessorController="com.ptc.windchill.enterprise.change2.form s.controllers.ChangeItemFormProcessorController">
Limitations
Only one ObjectFormProcessor class per wizard is supported at this time The framework does not support having data for multiple objects in the same wizard step unless it is in tabular format. It also does not support having data common to all the objects on the same step as object-specific data.
Constructing Wizards
14-37
Background
Windchill provides a framework for creating wizards and navigating between wizard steps. It also provides data utilities, GUI components, renderers, and validators for creating input elements in your wizard JSPs. Finally, it provides a framework for processing the data sent to the server when the wizard form is submitted. These frameworks and components are described in other documents listed in Prerequisite knowledge section of this topic on page 14-41. This document builds upon that information to describe how to develop and process wizards designed specifically to create Windchill objects. It will tell you how to use out-of-the-box components as building blocks to create your own wizards. Components you will typically make use of are: action definitions for wizard steps that are common to multiple wizards jsp and jspf files for wizard steps that are common to multiple wizards custom tags for managing wizard data and displaying elements on the page Java classes for processing the wizard data after the user submits the wizard
Scope/Applicability/Assumptions
Assume you have created a custom Windchill business object class or soft type and you want to develop a wizard that will allow users to create one instance of that object type in the database. The object to be created should be a Persistable. It may or may not implement the Typed, Foldered, and/or Iterated interfaces. Where this document makes reference to attributes that are not applicable to your object type you can ignore such implementation details. This document describes the reusable common components upon which most Windchill create wizards are based. If your custom type extends an existing Windchill business class, such as WTPart, WTDocument, or WTChangeIssue, there may be components more specific to those classes that could or should be used instead of the components described herein. These class-specific components are built on top of the common components described in this document. A discussion of those class-specific components is beyond the scope of this document. Be aware that you do not necessarily need to develop your own wizard to create instances of a custom type. If your type is a modeled or soft subtype of a Windchill business class for which a wizard with a type picker is already
14-38
available, you may be able to use the out-of-the-box wizard for your purposes. The out-of-the-box wizards will automatically find subclasses and soft types of a given base type such as WTPart or WTDocument and display those subtypes in the type picker so that a user can create instances of them. For example, if you have created a soft subtype of WTPart called MyPart, it will be displayed in the New Part wizard as follows:
Constructing Wizards
14-39
Input fields for any non-association attributes you have defined for your subtype will automatically be displayed on the Set Attributes step of the New Part wizard below the out-of-the-box attributes:
Attributes in the table will be ordered as follows: 1. Out-of-the-box attributes ordered as listed in the JSP file 2. Custom modeled attributes ordered alphabetically by display name 3. Custom soft attributes ordered alphabetically by display name If you want to order the attributes on this step differently, you will need to create a new jsp for this step specifically for your subtype but you can still use the New Part wizard.
14-40
However, if you need to associate other objects to your new object or require additional wizard steps, you will likely need to develop a custom wizard. This document describes the process of developing a wizard that creates a single object. See the Building Wizards to Edit a Single Object section on page 14-90 of the Windchill Customizers Guide for information on constructing a wizard to edit an object.
Intended Outcome
Add a single- or multi-step HTML wizard to the product that allows a user to create a business object in the database. The arrangement of steps and presentation of attributes within the wizard should be similar to that of other Windchill wizards to provide a consistent user experience.
Solution
Use common jsp, tag, javascript, and Java class components built on top of the jsp wizard framework to create a wizard for capturing user input and for processing that input and creating the object in the database.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Java programming Basic web development using JSPs , custom tags, and HTML forms How to create modeled or soft Windchill business object types. See the following chapters in the Windchill Customizers Guide for more information on creating your business object classes using the Information Modeler and Rational Rose: Getting Started With Windchill Customization chapter on page 3-1 Modeling Business Objects chapter on page 4-1 System Generation chapter on page 31-1 Developing Server Logic chapter on page 35-1
See the Type and Attribute Manager chapter of the Windchill Business Administrators Guide for more information on creating soft types and attributes. The use of actions to launch jsp pages and wizards. See the Adding Actions and Hooking Them Up in the UI chapter on page 11-1 for information on how to create actions. The Windchill framework for creating wizards and processing wizard data.
Constructing Wizards
14-41
See the rest of the Constructing Wizards chapter on page 14-1 for more information on this topic. Also, see the Adding Actions and Hooking Them Up in the UI chapter on page 11-1 for information on how to create actions. The use of tables and property panels to present information in the UI and how to acquire the data for these components. See the following chapters of the Windchill Customizers Guide for more information: Customizing HTML Clients Using the Windchill JSP Framework on page 10-1 Gathering the Data for the UI on page 12-1 Presenting Information in the UI on page 13-1
The use of data utilities, GUI components, and renderers to create HTML elements for presenting and editing object attributes within tables and property panels. See the Presenting Information in the UI chapter on page 13-1 for more information.
The use of the UI Validation Service for validating the users ability to perform actions and for validating the data entered in wizards. The Windchill service APIs or other APIs necessary to perform the data processing tasks appropriate to the wizard
This document will build on this knowledge and provide additional information on the components available to help you create and process wizards for the specific purpose of creating a Windchill business object in the database.
14-42
context
dependent attribute
An attribute whose value and/or display characteristics are wholly or partially determined by the value of another attribute (called the "driver attribute") via an object initialization rule (OIR), access control policy, or other mechanism. An attribute whose value drives the value and/or display characteristics of another attribute (called a "dependent" attribute) via an object initialization rule (OIR), access control policy, or other mechanism. An object attribute defined in a Java class. An object type defined in a Java class. Hard types are typically modeled using Rational Rose and may extend out-of-the-box Windchill business object classes. A Java class or soft type defining the attributes and behavior of the business object(s) you want to create. An attribute of the object defined in the Windchill Type and Attribute Manager client. These attributes are not defined in the Java business object class and are stored in database tables separate from the table for the business class. An object type defined using the Type and Attribute Manager rather than in a Java class. Soft types may extend other soft types but all have a hard type as their root type. The object you are creating in your wizard.
driver attribute
soft type
target object
Solution Elements
Element Tags All the tags below are defined in the <WT_HOME>/codebase/WEB-INF/tlds/components.tld file. See the javadoc for the Windchill Client Architecture Common Components tag library and the javadoc for the tag handlers listed below for more information on the tags and their attributes. Type Description
Constructing Wizards
14-43
Element initializeItem
Type Tag
Description Initializes some data for the object being created using attribute values passed on the tag and the launch context of the wizard. This data is stored as hidden fields in the HTML form data and in the HTTPRequestData parameter map of the NmCommandBean. Tag handler: com/ptc/core/components/tags/co mponents/InitializeItemTag
describeAttributesTable
Tag
Builds a table descriptor for a twocolumn table of object attributes used for entering attribute values. The left column is the attribute name and the right is the attribute value.
See the javadoc for the DescribeAttributesTableTag for more information. Tag handler: com/ptc/core/components/tags/co mponents/DescribeAttributesTabl eTag
14-44
Element describePropertyPanel
Type Tag
Description Builds a table descriptor for a twocolumn panel of object attributes. The left column is the attribute label and the right is the attribute value. Typically used to display read-only information gathered in previous wizard steps or from the launch context but can also be used for input fields.
Tag handler: com/ptc/core/components/tags/co mponents/DescribePropertyPanel Tag getModel Tag Acquires the attribute data needed for an attributes table or property panel previously defined by a describeAttributesTable or describePropertyPanel tag. Tag handler: com/ptc/core/components/tags/co mponents/GetModelTag renderPropertyPanel Tag Renders a property panel previously defined using describePropertyPanel and getModel tags. Tag handler: com.ptc.core.components.tags.pro pertyPanel.RenderPropertyPanelT ag renderTable Tag Renders a table previously defined using describeAttributesTable and getModel tags. Tag handler: com/ptc/core/components/tags/co mponents/RenderTableTag
Constructing Wizards
14-45
Element wizard
Type Tag
Description Specifies the action pointing to the main JSP for the wizard and defines the steps contained in the wizard. Tag handler: com/ptc/core/components/tags/co mponents/WizardTag
wizardStep JSPs
Tag
Specifies the action pointing to the main JSP for the step.
The following jsp and jspf files can be used to create and display components common to many create wizards. Unless otherwise noted, they are located in the <WT_HOME>/codebase/netmarkets/jsp/object and <WT_HOME>/codebase/netmarkets/jsp/components directories. createEditUIText includeWizBean jspf file jspf file Contains some UI text common to create and edit wizards. Defines the CreateAndEditWizBean called during the generation of jsp pages to access wizard data. A JSP for the Set Context wizard step. This step contains a context (container) picker and should be included in a create wizard for a WTContained object if the container cannot be determined from the launch context and/or you want to allow the user to choose a container. defineItemWizStep jsp file A default JSP that you may be able to use for the Define Object step of your wizard if it should contain a read-only property panel for the context name, a type picker, and a driver attributes table for entering attribute values.
setContextWizStep
jsp file
14-46
Element setAttributesWizStep
Description A jsp file that can be included in the jsp for your Set Attributes wizard step. This will get the model data for and render your attributes panel and tables if you have named them per the instructions in this document. A jsp file that can be included in the jsp for your Set Attributes wizard step if your object type is a FormatContentHolder. It does the same things as the jsp above but, in addition, will render input fields for capturing primary content. Location: <WT_HOME>/codebase/netmark ets/jsp/document
setAttributesWizStepWithContent .jspf
jspf file
Beans CreateAndEditWizBean Java class; Runs in the servlet engine and the Method Server This bean is available to your jsps if you include the includeWizBean jspf file. It has getter methods for wizard data set by the initializeItem tag such as the operation, default container, the base type, and so forth.
Javascript validateCreateLocation() A javascript method you can specify on the onClick parameter of the wizard action for wizards that can be launched from a folder browser toolbar. This checks to make sure that the user does not have more than one folder checked and that the user has not checked an object that is not a folder. If either is the case, a popup error message is displayed. Location: <WT_HOME>/codebase/netmark ets/javascript/util Java Classes You can use the classes below to help create and process your wizard. They are located in the <WT_HOME>/codebase/WEB-INF/lib/wncWeb.jar file.
Constructing Wizards
14-47
Element CreateAndEditModelGetter
Description A class that may be called via a getModel tag to generate the data for property panels and attributes tables in create wizards. A class that may be called to validate the data in the Set Context wizard step. A class that may be called to validate the data in the Define Object wizard step. A class that may be called to validate the data in the Set Attributes wizard step. A class that may be used or extended to process your wizard form data. Extends DefaultObjectFormProcessor. A class that may be extended to implement various processing subtasks. A container for the form data specific to one target object and for the data common to all objects. Provides methods to retrieve the form data for the associated object. A wizard creating only one object will have only one ObjectBean. A class used to pass method results between server processor methods and from the server to the WizardServlet.
ContextWizardStepValidator
Java class; runs in the Method Server Java class; runs in the Method Server Java class; runs in the Method Server Java class; Runs in the Method Server
DefineObjectStepValidator
SetAttributesStepValidator
CreateObjectFormProcessor
Java class; Runs in the Method Server Java class; runs in the Method Server
FormResult
14-48
Create validators for the wizard data Create a form processor class and/or delegates to process the wizard data after submittal
The tasks noted as required are always required. The other tasks may or may not be needed, depending on the requirements of your wizard. If you have attributes in your wizard that cannot be displayed by the standard Windchill dataUtilties, GUI components, and renderers you also may need to write Java classes for those functions.
Laying out your wizard steps and attributes
When laying out the steps and attributes of a Windchill object creation wizard, it is important to keep in mind the interdependencies between the object type, container context, organization context, folder location, default life cycle, and, possibly, other attributes of your new object. These interdependencies can result from: type definitions object initialization rules (OIRs) access control policies (ACLs)
Type Definitions Many wizards allow a user to create one of several object subtypes derived from a given base type. You can define soft subtypes and soft attributes in the Attribute and Type Manager at the organization or site level. This means that the organization container of the object must be known before the list of available object types is displayed and the input fields for soft attributes are rendered. Also, the default type for some Windchill business types is determined by preferences which can be set at the container, organization, and site levels so these must also be known. Access Control Policies The object types which a given user has permission to create are defined by the access control policies for the administrative domain to which the object belongs and by ad hoc rules. Administrative domain is typically, although not always, determined by the objects folder. In addition, access rules can be further refined based on the initial state of the default life cycle for the object type. Object Initialization Rules Object initialization rules are defined by object type at the site, org, and/or container levels. Such rules can dictate whether or not the server assigns an attributes value or it is entered by the user; what the default value of an attribute is, if any; whether the value is editable; and other display characteristics of an attribute. Attributes for which OIRs are defined in the out-of-the-box product include:
Constructing Wizards
14-49
Organization Number Name (variant parts only) Folder location Life cycle template Team template Versioning scheme
These OIRs may be modified or deleted by customizers and additional OIRs for other attributes may be written by customizers. These actual and potential interrelationships between properties are illustrated in the following diagram, where the shaded boxes represent wizard elements.
As you can see from this diagram, the relationships between various object properties can become complex and circular. For example, to display an input field for folder location you must know the default folder set by the OIR, which requires knowledge of the type of object being created. However, to display a picker with the available object types you must know the administrative domain, which is determined by the folder. This document will refer to attributes whose values affect the values of other attributes as driver attributes. The affected attributes will be called dependent attributes. Driver attribute values must be determined upstream of any attribute
14-50
values dependent on them. By upstream we mean either from the wizard launch context, entered by the user on a previous wizard step, or, in some cases, entered by the user in a table or panel on the same step but above that of dependent attributes. Any time a driver attribute value is changed, the downstream parts of the wizard must be refreshed if they contain dependent attributes and have been preloaded. Refer to the Loading the wizard step content when it is visited section on page 14-11 for information on pre-loaded and non-preloaded steps. The exact nature of the interrelationships between attributes depends on how a site defines its OIRs and access control policies. The wizards delivered by PTC are set up to gather attribute information in an order consistent with the access control rules and OIRs defined out-of-the-box and with anticipated common customizations. They make certain assumptions about how a customer site has set up its OIRs and ACLs. These include the following: A site has OIRs defining the default life cycle for different object types OIRs are only defined for base types such as WTPart or WTDocument and not defined differently for subtypes of the base types
If these assumptions do not hold or your site introduces additional attribute dependencies via its OIRs or access control policies, the layout of wizard steps and attributes may need to be customized to ensure that driver attributes are always upstream of their dependent attributes. The standard layout of Windchill wizards is as follows: 1. Set Context step (for WTContained objects only) This step typically has only one input field, which is a picker for the owning container of the object being created. The selected container will be used to select the appropriate OIRs for other attributes. In many cases, the container is determined from the launch context of the wizard and this step is not needed. For example, if the wizard is launched from the folders page of a product, the container is assumed to be that product. 2. Define Object step The body of this step typically contains three sections: a read-only context property panel, a type picker, and a driver attributes property panel. Refer to
Constructing Wizards
14-51
the illustration below. All of these sections are optional, depending on the type of object being created.
Context panel Read-only information about the object being created that is derived from the launch context or entered on previous wizard steps. If the object is WTContained this typically displays the container for the new object
Type picker The base type for the wizard is derived from an attribute on the InitializeItem tag or, if none, from the object type associated with the wizard action. (More about the InitializeItem tag later.) If you want to allow users to create either the base type or a subtype of the base type you would include a type picker in your wizard. The list of types available in the type picker is typically determined as follows: 1. Compute the list of hard and soft subtypes of the base type. Soft subtypes are the instantiable soft types defined for the base type in the given organization container.
14-52
2.
Determine the default life cycle and initial life cycle state for the base type and each subtype based on the composite object initialization rules for the type in the given container. Determine a default folder location context for the new object. If a folder was selected on the launch page (for example, the wizard is launched from a folder browser and a folder is checked in the folder table or highlighted in the left pane) that folder will be used. Otherwise, if a folder is defined by an OIR for the base type and given container, that will be used. Otherwise, the default (top-level) cabinet for the objects container is used. (There are a few exceptions to these rules.) Based on the default initial life cycle state and the folder location, determine whether the user has create permission for each type. If not, filter that type from the list. Display the remaining types in the picker.
3.
4.
5.
The default value for the type picker is determined from a preference for some base types, as follows:
Base Type WTPart Preference Create and Edit -> Part Create Default Type Create and Edit -> Document Create Default Type Create and Edit -> Problem Report Create Default Type Create and Edit -> Change Request Create Default Type Create and Edit -> Change Notice Create Default Type
WTDocument
WTChangeIssue (ProblemReport)
For all other wizards, the base type is used as the default type. When the user selects a type in the type picker, javascript is executed that refreshes the driver attributes panel below it and all following wizard steps. This is necessary because object type can affect which jsps are used for subsequent steps as well as the attribute input fields displayed. When objects are being created from a template, such as creating a document from a template, the type picker is replaced by a template picker and the type of the new object is determined from the template. Driver attributes
Constructing Wizards
14-53
This property panel displays input fields for attributes that can drive the values of and/or constraints on other attributes to be entered by the user. If a value in this panel is changed, all subsequent wizard steps are automatically refreshed based on the new attribute value(s). Therefore it is important to place all driver attributes in this section. If the preference Display -> Expose Organization is set to true and the object is OrganizationOwned, this panel should include a picker for the organization attribute of the object. Although organization id does not drive the value of other attributes out-of-the-box, customers often want to set up such dependencies. The object type indicates which other attributes should be included, if any. 3. Set Attributes step This step is where information for most non-driver attributes for the object is gathered. It generally consists of two to four parts, which may include the following: a read-only context property panel, primary content input fields (for FormatContentHolder objects only), an attribute input table, and
14-54
checkboxes for processing directives specific to the object type. Refer to the illustration below.
Context panel Read-only information about the object being created that is derived from the launch context or data entered on previous wizard steps. This will usually contain the object type. If the new object is WTContained it will also display the container name. If the new object is OrganizationOwned and the preference Display -> Expose Organization is set to true it will also display the organization id.
Primary content Wizards to create objects that are FormatContentHolders, such as WTDocuments, should have a section for the user to enter the primary content item. .
Constructing Wizards
14-55
Typically contains all the soft and hard attributes for the object type that were not entered on previous steps, except for part classification attributes, which are entered on a following step. Note that one of the attributes typically presented in this table is folder location. As stated earlier, folder location drives administrative domain which, in turn, drives access control policies which, in turn, drives the list of object types available for creation by the user. The list of types presented in the Define Object step is based on a default folder derived from the launch context. The user could potentially select a different folder location in this step for which the access control policies vary. Thus it is possible the user could select a folder for which s/he does not have permission to create the selected type. If this happens, an error message will be displayed when the user clicks OK. Checkboxes This section contains checkboxes to provide processing instructions for the new object. These include:
Checkbox label Applicability Description
for new RevisionControlled objects for creating documents from templates for creating document templates
If checked, the system checks out the object after creation If checked, the new document is checked out and downloaded If checked, the new template is immediately available for use
Your wizard may contain additional steps pertinent to the type of object being created. Steps for which common components are available are: Classification attributes step This step only applies to WTParts and subtypes thereof when PartsLink is installed. It is a dynamic step that only appears if the part is classified. It allows the user to modify the classification attributes of the part. It displays the classification of the part in view mode at the top and then
14-56
includes a table of input fields for classification attributes. Refer to the illustration below.
Attachments step This step is typically included when creating objects that are ContentHolders. It allows the user to attach documents, links, and other content to the new object. See the Attachments section in the Customizing HTML Clients Using the Windchill JSP Framework chapter on page 10-16 for information on incorporating this step.
Some object types may require additional steps to capture other information needed to create the object. No jsp files are provided for such unique wizard steps. However, you can develop your own jsp files for unique steps using the same table, property panel, and javascript components used in the jsp files for common steps.
Constructing Wizards
14-57
By default, the name attribute of the action points to the main jsp page for your wizard relative to codebase/netmarkets/jsp, unless a url attribute is specified on the command tag. Therefore, for the action above, the system would expect to find a jsp file named <WT_HOME>/codebase/netmarkets/jsp/<objecttype name>/<your wizard action name> to use for the main page of your wizard. We recommend that you name your action (and main wizard jsp file) create. If you will have more than one create action for your objecttype based on launch point or other criteria, you can add a suffix to the action name to qualify it, as shown below: createFrom<launch point> create<type of object> Example: createFromWorkspace Example: createSharedDocument
The command class is the java class that should be called to process the wizard data. Typically, this will extend CreateObjectFormProcessor. See Creating Your Form Processor and Form Processor Delegates section on page 14-75 for more information. Note that it is not necessary to specify a method attribute in the command tag if your form processor class extends DefaultObjectFormProcessor or CreateObjectFormProcessor.
14-58
ajax
None
Specifies what portion of the parent page should be refreshed when the wizard processing completes. The value page refreshes the entire page (equivalent to not using ajax). The value component refreshes the table from which the wizard was launched. The value row refreshes one or more table rows. To use the value row your form processor must tell the system which rows (objects) need to be added. See Creating Your Form Processor and Form Processor Delegates section on page 14-75 for more information.
UIComponent
None
References an entry in roleaccessprefs.xml (uic name) used to specify role-based access to the wizard action.
Here is an example action for launching a creation wizard for MyPart objects:
<objecttype name="myPart" class="ext.part.MyPart" <action name="create" uicomponent="CREATE_MYPART" ajax="row"> <command class="com.ptc.windchill.enterprise.part.forms.CreateMyPartF ormProcessor" onClick="validateCreateLocation(event)" windowType="popup"/> </action>
The validateCreateLocation() javascript method shown in the action above is applicable to create wizards that can be launched from a folder browser. See the Solution Elements section on page 14-43 for more information. See the Adding Actions and Hooking Them Up in the UI chapter on page 11-1 for more information on actions and the command tag attributes. In addition to creating the wizard action, you will need to create text for the action name, wizard window title, action tooltip, etc. This is described in the section of Windchill Customizers Guide referenced above.
Constructing Wizards
14-59
Creating actions and/or service property entries for your wizard steps
Each wizard step requires an action. You may be able to use out-of-the-box action definitions for wizard steps that are common to multiple wizards. The following wizard step actions are defined out-of-the-box.
Step Set Context Object Type object Action definition / File location / Associated JSP page
<action name="setContextWizStep" id="setContextWizStep" preloadWizardPage="true" required="true" afterVK="setContextWizStep"> <command windowType="wizard_step"/> </action>
Action file: <WT_HOME>/codebase/actions.xml Associated jsp page: <WT_HOME>/codebase/netmarkets/jsp/object/setContextWizStep.jsp Define Object object
<action name="defineItemWizStep" id="defineItemWizStep" preloadWizardPage="false" required="true" afterVK="defineItem" resourceBundle="com.ptc.core.ui.componentRB"> <command windowType="wizard_step" url="servlet/TypeBasedIncludeServlet?contextAction=d efineItemWizStep"/> </action>
Action file: <WT_HOME>/codebase/actions.xml Associated jsp page: <WT_HOME>/codebase/netmarkets/jsp/object/defineItemWizStep.jsp Set Attributes object
<action name="setAttributesWizStep" afterVK="setAttributesWizStep" id="setAttributesWizStep" preloadWizardPage="false" required="true" resourceBundle="com.ptc.core.ui.componentRB"> <command windowType="wizard_step" url="servlet/TypeBasedIncludeServlet?contextAction=s etAttributesWizStep"/> </action>
Action file: <WT_HOME>/codebase/actions.xml Associated jsp page: None Set Classificatio n Attributes part
<action name="setClassificationAttributesWizStep" id="setClassificationAttributesWizStep" hidden="true" required="true" preloadWizardPage="false"> <command windowType="wizard_step"/> </action>
14-60
The associated jsp page shown in the table above is a default jsp that may be used for the step. Note there is no default jsp for the Set Attributes step, although there is a common action definition. Note that the Set Classification Attributes step is marked as hidden. It is dynamically inserted into the wizard if the user clicks the Choose Classifications radio button on the Set Attributes step. It is dynamically removed if the user clicks the Do Not Classify radio button to unclassify the part. If these action definitions meet your requirements you do not need to define your own actions for your wizard. However, you will need to define your own action for a wizard step if either of the following is true: you need to define additional or different tag attributes for an action For the Set Context and Set Classification Attributes steps only: you need to use a different jsp page for your step. For the Define Object and Set Attributes steps, you can use a different jsp for your step without defining your own action through use of the TypeBasedIncludeServlet described below. Your step is unique to your wizard
The table below shows action tag parameters relevant to create wizard steps:
Action attribute tag name id Req? yes no Default value None <action type>.<act ion name> false Possible values any string any string Description The name of the action. Used as the name attribute on wizard step tags. Used to identify the step in certain javascript functions. If not specified the id <action type>.<action name> will be used. Specifies whether the user must navigate to the step or not. The Finish button will not be enabled until the user has completed all required steps. Specifies the name of a javascript function to call when the wizard step is loaded Specifies the name of a javascript function to call when the user clicks Next or OK on the wizard step. Can be used to do client-side validation of the form data. The name of a validator key specifying a Method Server validator to be called when the user navigates to the step using the Previous or Next button.
required
no
beforeJS afterJS
no
None None
beforeVK
no
None
any string
Constructing Wizards
14-61
Req? no
Description The name of a validator key specifying a Method Server validator to be called after the user clicks Next or Finish on the step. Can be used to do server-side validation of the form data. Specifies that the wizard step is to be downloaded when wizard is launched rather than when the user navigates to the step. Pre-loading wizard steps will make it faster to move to the next step. However, you should not preload wizard steps that are dependent on information gathered in previous steps.
preloadWizardPa ge
no
true
true or false
Note that the windowType attribute of the command subtag should always be set to wizard_step.
Creating service.properties Entries for the Define Object and Set Attributes Steps
You will notice that the command tag for both the Define Object and Set Attributes wizard step actions above contain a url attribute referencing the TypeBasedIncludeServlet. The TypeBasedIncludeServlet allows the system to look up the correct jsp page to use for a wizard step or part of a wizard step onthe-fly given an action name and the type of object to be created. Using this servlet for the url for wizard steps allows: wizards for different object types to share the same step action definition reuse of the same wizard action and main wizard jsp for different object types if the wizards are identical except for steps that use the TypeBasedIncludeServlet for jsp lookup. Typically this is most useful when you want to use the same wizard to create different subtypes of a base type.
For the Define Object step a default jsp is available, but you can override this by use of the TypeBasedIncludeServlet and still use the common action definition for your step. For the Set Attributes step, use of the TypeBasedIncludeServlet allows you to specify different step jsps for the different object types that might be selected by the user in the Define Object step without creating a new action for the step or a new wizard. The TypeBasedIncludeServlet looks up the correct jsp using ApplicationContextServices and service.properties files. It locates the file entry for the service com.ptc.netmarkets.util.misc.FilePathFactory that has a selector matching the contextAction parameter on the url in the action tag and a requestor object type matching the type of object the user has chosen to create. The value of that entry gives the path of the jsp page for the step, relative to <WT_HOME>/codebase. Entries are formatted as follows: Xconf file:
14-62
<Resource context="default" name="com.ptc.netmarkets.util.misc.FilePathFactory"> <Option requestor=" <object type to be created> >" resource=" <jsp file path relative to WT_HOME/codebase>.jsp" selector="<contextAction parameter on url>"/> </Resource>
For example, say you want to use the jsp page <WT_HOME>/codebase/netmarkets/jsp/ext/part/myPart/setAttributesWizStep.js p for the Set Attributes step of wizards when the user elects to create an object of type ext.part.MyPart. You would add the following entry to a type-based services properties xconf file:
<Resource context="default" name="com.ptc.netmarkets.util.misc.FilePathFactory"> <Option requestor="ext.part.MyPart" resource= /netmarkets/jsp/ext/part/myPart/setAttributesWizStep.jsp selector="setAttributesWizStep"/> </Resource>
The service.properties files searched by the TypeBasedIncludeServlet are those listed in the following two properties in the codebase/wt.properties file:
wt.services.applicationcontext.TypeBasedServiceProviderFromProp erties.defaultPropertyFiles wt.services.applicationcontext.TypeBasedServiceProviderFromProp erties.customPropertyFiles
See the Adding a Custom Service Provider Property File section on page 5-27 for more information on service property files.
Creating Your Step JSP Pages
Standard includes for step jsps Wizard steps that are not preloaded should include the following directives at the top of the jsp page:
<%@ include file="/netmarkets/jsp/components/beginWizard.jspf"%> <%@ include file="/netmarkets/jsp/components/createEditUIText.jspf"%> <%@ include file="/netmarkets/jsp/components/includeWizBean.jspf"%>
Most wizard steps will also use tags in the components.tld tag library and so will also need to include that as follows:
<%@ taglib prefix="jca" uri="http://www.ptc.com/windchill/taglib/components"%>
Constructing Wizards
14-63
Non-preloaded steps should also have the following directive at the bottom of the step jsp:
<%@ include file="/netmarkets/jsp/util/end.jspf"%>
If a step is preloaded, none of these are needed. Attribute Input Tables and Panels Object creation wizards typically have property panels and/or tables for entering attribute values. These are implemented using describePropertyPanel and describeAttributesTable tags containing a describeProperty tag for each attribute to be displayed. The ids on the describeProperty tags identify the attribute you want to be displayed. Property Report The Property Report lists all the attributes defined for a given object type (for example, wt.doc.WTDocument) and whether or not a data utility is available for it. The property report can be accessed at: http://<WINDCHILL_HOSTNAME>/<WEBAPP NAME> /netmarkets/jsp/property/propertyReport.jsp. If you have a custom attribute for which no data utility, GUI component, and/or renderer exists you may need to write your own to display the attribute. Keep in mind that many of the attributes shown in the Property Report are not settable by the user and would not be appropriate to display in a create or edit wizard. The describePropertyPanel and describeAttributesTable tags for input fields should always have a mode parameter of CREATE and a componentType parameter of WIZARD_ATTRIBUTES_TABLE. This tells the dataUtilities to generate a special name attribute for each input field. The CreateObjectFormProcessor will recognize and set all attributes with such a special name attribute automatically after the wizard is submitted. The special name attributes consist of the following parts: <context information>___<AttributeIdentifier and other information about the attribute>___<input field type> (Note that the keys in the Maps returned by such methods as getTextArea(), getChangedTextArea(), getComboBox(), etc. of the ObjectBean class include only the text between the ___ separators.) These name attributes are not easily parsed and are not intended for use other than by the CreateObjectFormProcessor. If you want to set an attribute yourself in your form processing code and want to create a name for your attribute that you can identify, you can do one of two things: Create or override the data utility used for the attribute and call the setColumnName() method of the GUI component to set the name attribute. If there is a wrapper tag available for the GUI component you want to use, you could display the attribute outside of a table or panel using the wrapper
14-64
tag for the GUI component. In the name attribute of the wrapper tag you would specify the HTML name attribute for the input field. Using this method you would need to supply the attribute default value in the wrapper tag. See the javadoc for the wrappers tab library for the available GUI component wrappers. See the file WT_HOME/codebase/netmarkets/jsp/carambola/tags/tags.jsp for examples of how to use wrapper tags. Data acquisition The method getItemAttributes() in the class com.ptc.core.components.forms.CreateAndEditModelGetter is used by the getModel tags in all out-of-the-box wizards to acquire the data needed to populate attribute input tables and read-only tables in wizards. This is a TypeInstancebased method that can be used for custom tables also and should be adequate for most purposes.
Set Context Step JSP Page
If your wizard has a Set Context step, the out-of-the-box step jsp listed in the Solution Elements section on page 14-43 will usually suffice. The only time it might be necessary to develop your own step jsp is if you need to capture additional attribute values before you can display attributes presented on the Define Object step. For example, assume that: Your wizard launch point has no folder context You do not have any OIRs that set a default folder location for new objects You have defined access control policies denying users create permission for certain object subtypes. These policies are based on the administrative domain associated with the folder in which the new object is located.
In this case, the object container will have no effect on folder selection and you may want the user to select a folder location so the list of types available to him/her can be accurately determined. In this case you may want to put a folder input field on a step prior to the Define Object step. You could either add this input field to the Set Context step or add a additional step to the wizard to capture folder location either before or after the Set Context step. (Either way, you will also need your own JSP for the Define Object step so can you set the administrative domain parameter on the type picker based on the users folder selection in the Set Context step.) If you do develop your own Set Context jsp and want it to have a container picker, we recommend that you include the out-of-the-box jsp in it rather than copying the contents of the out-of-the-box jsp to your page. This will ensure your page will continue to behave correctly even if the context picker is modified in a future release.
Constructing Wizards
14-65
As stated in the Laying out your wizard steps and attributes section on page 14-49 your wizard may not need a Define Object step. If it does need one, you may be able to use the default jsp listed in the Solution Elements section on page 14-43. Even if you cannot use the default jsp as is, you may be able to reuse sub-jsps that it incorporates. The suggested name for this step JSP is: defineItemWizStep.jsp or defineItemWizStepFor<object type>.jsp (if there is more than one of these step jsps in the directory) If the Define Object step is the first step in your wizard or nothing in this step is affected by data on prior steps you can preload it. Otherwise, you should indicate it should not be preloaded in the step action. Typically, if your wizard has a Set Context step this step should not be preloaded. The default jsp (<WT_HOME>/codebase/netmarkets/jsp/object/defineItemWizStep.jsp) for this step contains a property panel with the following sections (from top to bottom of panel): A read-only subpanel displaying the container name. If your new object type is not WTContained you will need to modify this. A type picker If your wizard does not require a type picker or it needs to be configured differently than the default, you will need to develop your own step jsp. A driver attributes subpanel for input of the objects owning organization, if the new object type is OrganizationOwned. Note this is only displayed if the preference Display -> Expose Organization is set to true. If the new object is not OrganizationOwned the default JSP will display nothing in this subpanel. This subpanel is contained in a sub-jsp file that is looked up at runtime using the TypeBasedIncludeServlet. If you need to display additional attributes or dont want to display an organization picker, you need only write a jsp containing this panel and register it with a type-based service.properties file entry as described in the How to create a step with no driver attributes section on page 14-70 and the How to create a step with additional driver attributes section on page 14-70. You can still use the default JSP page for the step. The default Define Object Step jsp includes a number of other jsps located in <WT_HOME>/codebase/netmarkets/jsp/components and
14-66
driverAttributesSetup.jspf
Constructing Wizards
14-67
The sections below describe how to perform common customizations of this step. Please remember that you should always place your custom jsp and jspf files in a directory under wtSafeArea, as described in the Managing Customizations chapter on page 5-1.
How to create a step without a read-only property panel
1. Create a new main jsp file for the step 2. Copy the contents of the file <WT_HOME>/netmarkets/jsp/object/defineItemWizStep.jsp into your new file. 3. Delete the following line from the file:
<%@ include file="/netmarkets/jsp/components/defineItemReadOnlyPropertyPane l.jspf"%>
How to modify the contents of the read-only property panel in the step
1. Create a new main jsp file for the step. 2. Copy the contents of the file <WT_HOME>/netmarkets/jsp/object/defineItemWizStep.jsp into your new main jsp file.
14-68
3. Delete the following line and replace it with your custom describePropertyPanel tag that includes the attributes you want to display:
<%@ include file="/netmarkets/jsp/components/defineItemReadOnlyPropertyPane l.jspf"%>
Alternatively, you could include a new jspf file that contains your describePropertyPanel tag instead of placing it in-line. See the Sample Code section on page 14-84 for an example.
How to create a step without a type picker
1. Create a new main jsp file for the step. 2. Copy the contents of the file <WT_HOME>/netmarkets/jsp/object/defineItemWizStep.jsp into your new file. 3. Delete the following line from the file:
<jca:configureTypePicker/>
The type picker can be modified to filter certain types from the list, specify a different default value, etc. The configuration parameters are described in the javadoc for the ConfigureTypePicker tag. To specify different picker parameters you will need to: 1. Create a new main jsp file for the step, as described above. 2. Copy the contents of the file <WT_HOME>/netmarkets/jsp/object/defineItemWizStep.jsp into your new file. 3. Add the following line to the top of the file:
<%@ taglib uri="http://www.ptc.com/windchill/taglib/picker" prefix="p"%>
Constructing Wizards
14-69
4. Add pickerParam subtags to the configureTypePicker tag as shown in the javadoc for the ConfigureTypePickerTag. See the Sample Code section on page 14-84 for an example.
How to create a step with no driver attributes
For this you do not need to create a new wizard step JSP. Create an entry in a type-based service properties xconf file pointing to the jsp file defineItemAttributesPanelEmpty, as follows:
<Resource context="default" name="com.ptc.netmarkets.util.misc.FilePathFactory"> <Option requestor="< object type to be created>" resource=/netmarkets/jsp/object/defineItemAttributesPanelEm pty.jsp selector="defineItemAttributesPanel"/> </Resource>
For this you do not need to create a new wizard step JSP, just a new sub-JSP file for the driver attributes, as follows. 1. Create a new JSP file containing describePropertyPanel, getModel, and renderPropertyPanel tags for your driver attributes. (Note this must be a .jsp file and not a .jspf file.) Use the file <WT_HOME>/codebase/netmarkets/jsp/object/defineItemAttributesPanel.js p as an example and list the attributes you want to display in the describePropertyPanel tag. Because the output of this jsp is parsed and inserted dynamically into the page, it must not contain any display text or HTML besides the three tags listed above. 2. Create an entry in a type-based service properties xconf file pointing to your new jsp file as follows:
<Resource context="default" name="com.ptc.netmarkets.util.misc.FilePathFactory"> <Option requestor="< object type to be created>" resource=<path to your jsp page > selector="defineItemAttributesPanel"/> </Resource>
Because the attributes on this step vary by object type, you will need to create your own main jsp for this step. However, once you describe the contents of the page there are jsp components available to help you acquire the data models for and render the elements. The suggested name for this step jsp is: setAttributesWizStep.jsp or
14-70
setAttributesWizStepFor<object type>.jsp (if there is more than one of these step jsps in the directory) If your wizard does not have a type or template picker and nothing on prior steps affects the attributes displayed on the Set Attributes step it can be preloaded. Otherwise, you should indicate this step should not be preloaded in the step action. Typically, the latter is the case. Typically, in the main jsp file for this step you will do the following, in this order: 1. Include the file /netmarkets/ jsp/components/setAttributesReadOnlyPropertyPanel.jspf, which inserts a describePropertyPanel tag for a read-only property panel displaying: the objects owning container (if the object is WTContained) the object type organization id (if the preference Display -> Expose Organization is set to true)
2. Include a describeAttributesTable tag listing the attributes you want to display in the input table. The mode attribute of the tag should be set to CREATE. You should also set the following attributes if you want to use the out-of-thebox jspf file described in the next step for getting the table model and rendering the table.
Attribute Value
var id scope
You can make use of the Property Report described in the section Attribute Input Tables and Panels earlier in this section to obtain the ids for the attributes you want to include in your table. Also, refer to theAttribute Handling section on page 13-2 and the Soft Attributes and SCAs section on page 13-21 of the Presenting Information in the UI chapter for a description of some server calculated attributes (SCAs) that you might want to include. If your object is a subtype of WTPart and you want to include a classification picker in your table, you would add the following property to your table:
<jca:describeProperty id="classification.id" label="${classificationLabel}"/>
and you must include the following hidden fields in the page:
<input id="selectedClfNodes" type="hidden" name="selectedClfNodes" >
Constructing Wizards
14-71
3. If your object is a FormatContentHolder and you want to capture primary content input on this step, include the file /netmarkets/jsp/document/setAttributesWizStepWithContent.jspf. This contains the tag primaryAttachmentWithMSOI, which will render input fields for capturing primary content. (See the Attachments section in the Customizing HTML Clients Using the Windchill JSP Framework chapter on page 10-16 for more information on this tag.) It also acquires the data for and renders the read-only property panel and the attributes input table, providing you have followed the naming conventions described in this section. If your object is not a FormatContentHolder, include the file /netmarkets/jsp/components/setAttributesWizStep.jspf. This does the same things as setAttributesWizStepWithContent.jspf except that it does not include a primaryAttachments tag. 4. .Include any checkboxes you desire to gather processing information. If your object is RevisionControlled and you want to include a Keep checked out checkbox, you can include the following jsp to display it:
/netmarkets/jsp/components/keepCheckedOutCheckbox.jspf
An example jsp is shown in the Sample Code section on page 14-84. To create steps that deviate from the normal pattern described above, see below.
How to create a step without a read-only property panel
Instead of including the file setAttributesReadOnlyPropertyPanel.jspf include your own jspf file with a describePropertyPanel tag for the panel or include a describePropertyPanel tag for the panel directly in your step jsp at the same location as the include. Your describePropertyPanel tag should include describeProperty tags for the attributes you want to display. Keep in mind that only property values that have been captured on previous steps can be displayed. Set the mode attribute of the tag to VIEW. Also set the following tag parameters if you want the setAttributesWizStep.jspf file to obtain the table data and render the panel for you.
Attribute Value
var id scope
14-72
JSPs for these steps are available out-of-the-box. You need only include the step action in your main wizard JSP page.
The ContextWizardStepValidator just validates that the form data contains a valid container object reference. The DefineObjectStepValidator and SetAttributesStepValidators look at all the form data with the special name attribute described in the Creating Your Step JSP Pages section on page 14-63, Attribute Input Tables and Panels. They validate the data against all constraints that were defined for the attributes in the Rose model or Type Manager. They do that by calling the preProcess() method of the
Constructing Wizards
14-73
ObjectFormProcessor class for the wizard, which creates a in-progress instance of the object and validates all its attributes. The Set Classification Attributes step uses the same validator as the Set Attributes step. No validator is provided or needed for the attachments step. If the out-of-the-box validator classes meet your needs you can use them by specifying the selector strings shown in the entries above as the values of the afterVK attributes of your wizard step actions. If you need to do additional validation, you can write your own validators, typically subclassing the standard validators. Note that all the form data can be accessed from the UIValidationCriteria parameter passed to the validator by calling UIValidationCriteria.getFormData(). The validateFormSubmission() method should return a UIValidationResult with a status of UIValidationStatus.PERMITTED if all the form data is valid or a status of UIValidationStatus.DENIED if one or more attribute values are not valid. In the latter case, the user will be returned to the wizard step just completed to correct the invalid values. Feedback messages to be displayed to the user should be added to the UIValidationResult using the UIValidationResult.addFeedbackMsg() method.
See the Sample Code section on page 14-84 for example JSP pages.
InitializeItemTag
The InitializeItem tag initializes some data for the object being created from the launch context of the wizard and the attributes passed to the tag. This information includes: type of operation (create or edit) the base type of the object being created default container initial value for the type picker type instance identifier for the object being created
14-74
See the <initializeItem> Tag Parameters section on page 14-82 for the attributes of this tag. The only required attribute is operation, which should be set to ${createBean.create} for object creation wizards.
Wizard tag
This tag has wizardStep subtags describing the steps of the wizard. The action parameter of these subtags points to the action defined for the step. If you are using the predefined action definition for a step, be sure the action parameter matches the name parameter of the action See Creating actions and/or service property entries for your wizard steps on page 14-60 for more information. The wizard tag also defines the buttons to be used Typically, wizards will use one of the two following button sets defined in codebase/actionmodels.xml: DefaultWizardButtonsNoApply (for multi-step wizards) NoStepsWizardButtons (for single-step wizards)
However, other buttons sets are available in actions.xml and custom button sets can be defined. The wizard tag has an optional formProcessorController attribute. This should not be needed for single-object create wizards. See the Windchill Client Architecture Wizard section on page 14-2 for more information on the wizard tag.
Attachment Step Requirements
See the Attachments section of the Customizing HTML Clients Using the Windchill JSP Framework chapter on page 10-16 for information on the elements that must be included to incorporate this step.
Constructing Wizards
14-75
The class com.ptc.core.components.forms.CreateObjectFormProcessor is available as a default form processor for wizards creating Persistable objects. This class may be extended as necessary to meet your purposes.
The CreateObjectFormProcessor does the following: preprocess() method extracts all of the ObjectBean form data that has a special name attribute as described in the Attribute Input Tables and Panels section on page 14-64. creates a TypeInstance for the new object and applies the attribute values from the form to it, validating the values against any constraints defined for the attributes in the Type Manager or Rose model
14-76
converts the TypeInstance into a Persistable and sets it as the object attribute on the ObjectBean calls super.preProcess() to call the preprocess() methods of any FormProcessorDelegates registered for the wizard
doOperation() method calls super.doOperation() to call the doOperation() methods of any FormProcessorDelegates registered for the wizard calls PersistenceHelper.manager.store() to store the Persistable in the database
setResultNextAction() method (called by the DefaultFormProcessorController) if the status of the FormResult is SUCCESS or NON_FATAL_ERROR, sets the nextAction on the FormResult to FormResultAction.REFRESH_OPENER; if the wizard was launched from a folder browser it also sets the refreshInfo attribute of the FormResult as follows: action = NmCommandBean.DYNAMIC_ADD oid = newly created object location = folder of new object
As a result, if launched from a folder browser, the wizard will be closed and the new object will be dynamically added to the folder in the right pane of the browser without refreshing the entire launch page; if not launched from a folder browser, the entire launch page will be refreshed. Any feedback messages put in the FormResult will be displayed to the user. Note that the ajax attribute on the wizard action must be set to row for dynamic row refresh to occur; if not set the entire launch page will be refreshed regardless of the values in the dynamicRefresh attribute. If the status set on the FormResult is FAILURE, sets the nextAction to FormResultAction.NONE. This will return the user to the wizard page on which OK was clicked.
Note the CreateObjectFormProcessor does not implement postProcess() or postTransactionProcess() methods so these are inherited from the DefaultObjectFormProcessor. See the javadoc for more information. If you are extending an existing Windchill business class, there may be a processor specific to that class that you should use or extend instead of
Constructing Wizards
14-77
CreateObjectFormProcessor. Some of these are shown in the table below. Consult the javadoc for these classes for more information on their behavior.
If your class extends: WTPart Use processor class: If creating a wizard to be launched from a workspace: com.ptc.windchill.enterprise.part.forms.CreatePartFrom WorkspaceFormProcessor If creating a wizard to be launched from the Edit Structure client: com.ptc.windchill.enterprise.part.forms.CreatePartFromT abularInputProcessor All other single-object creation wizards: com.ptc.windchill.enterprise.part.forms.CreatePartFormP rocessor WTDocument For creating a document from a template: com.ptc.windchill.enterprise.doc.forms.CreateDocFromT emplateFormProcessor For creating a document template: com.ptc.windchill.enterprise.doc.forms.CreateDocTempl ateFormProcessor For all other single-object create wizards: com.ptc.core.windchill.enterprise.doc.forms.CreateDocFo rmProcessor WTChangeIssue WTChangeRequest2 WTChangeOrder2 WTChangeActivity2 WTVariance com.ptc.windchill.enterprise.change2.forms.processors.C reateProblemReportFormProcessor com.ptc.windchill.enterprise.change2.forms.processors.C reateChangeRequestFormProcessor com.ptc.windchill.enterprise.change2.forms.processors.C reateChangeNoticeFormProcessor com.ptc.windchill.enterprise.change2.forms.processors.C reateChangeTaskFormProcessor com.ptc.windchill.enterprise.change2.forms.processors.C reateVarianceFormProcessor.
If the behavior of one of the provided form processors meets your needs, you do not need to write your own processor, just specify that processor as the value of the class attribute of the command subtag of your wizard action. If it does not meet your needs, you should write a subclass of it to process the wizard form data. Note that you do not need to create your own processor if you only want to provide special code for setting an attribute. In that case, you need only to write a FormProcessorDelegate to handle this task. Remember to register the
14-78
FormProcessorDelegate in a hidden form field and make sure that the attribute input field does NOT have a special name attribute that will be recognized by the CreateObjectFormProcessor. See the Attribute Input Tables and Panels section on page 14-64 for more information. If you create your own processor, be aware that its preProcess() method will be called by the standard validator classes after each wizard step. Make sure you do not modify the database in this method. Here are some of the more common cases where you may need to write your own ObjectFormProcessor class and the methods you would override to handle them: Case 1: You need to perform a different action when the wizard closes. For example, perhaps you want to load a new page when the wizard closes instead of refreshing the launch page. Or, perhaps your wizard can be launched from multiple points and you want refresh the launch page in one case and load a new page in another case. Solution: Subclass the out-of-the-box processor and override the setResultNextAction method. From the NmCommand.getCompContext() method you can obtain information about the launch context of the wizard. Here is an example of how this is done for the create baseline client:
String compContext = cb.getCompContext(); if (compContext != null) { try { NmContext compContextObj = NmContext.fromString(compContext); Stack<NmContextItem> contextItems = compContextObj.getContextItems(); for (NmContextItem contextItem : contextItems) { String action = contextItem.getAction(); if ("addToBaseline".equals(action) || "addToBaselineSingle".equals(action) || "addToBaselineStep".equals(action)) { < set some next action > } } . . .
Note that if your wizard is launched from a table and you have specified ajax=row on the wizard action, you must set the refreshInfo attribute on the FormResult to tell the system what rows to refresh. Typically, the attributes of the DynamicRefreshInfo object will be as follows: action = NmCommandBean.DYNAMIC_ADD oid = the NmOid of the object that was created location = the NmOid of the table object containing the new row. Typically, this will be a folder.
Constructing Wizards
14-79
If you have used an ajax attribute of page or component you do not need to set the refreshInfo attribute. See the Customizing the UI with Ajax section in the Customizing HTML Clients Using the Windchill JSP Framework chapter on page 10-4 and the javadoc for the FormResult, FormProcessingStatus, and FormResultAction classes for more information. Case 2: You need to do some post processing after the object is persisted. For example, change object wizards have a dialog to allow the user to submit the object to workflow immediately after creation. For this, they need to perform another operation after the object is created. In some cases, this kind of requirement can be handled by creating an ObjectFormProcessorDelegate for the input field and implementing a postProcess() or postTransactionProcess() method on it that will be called automatically by the infrastructure. However, in other cases you may prefer for your form processor to handle this. For example, you cannot control the order in which FormProcessorDelegates are called so if operation ordering is a requirement you would need to do the operations in the form processor. Solution: Subclass the CreateObjectFormProcessor and override the postProcess() or postTransactionProcess() method (which are inherited from DefaultObjectFormProcessor) to perform your operation. (Note that if you put a Keep checked out checkbox in your wizard by including the keepCheckedOutCheckbox.jspf file, this will be processed automatically by the KeepCheckedOutDelegate. You do not need to handle this). Case 3: You need to use a special API to persist the object. For example, change objects are persisted using the StandardChangeService2 class, which handles some life cycle and foldering tasks in addition to persisting the object. Solution: Subclass the out-of-the-box processor and override the doOperation() method. In your method you cant call the super method, but you should still make sure the doOperation() method of any registered FormProcessorDelegates are called. You can accomplish that by calling the processDelegates() method inherited from DefaultObjectFormProcessor. For example:
FormResult doOperationResult = new FormResult(); doOperationResult.setStatus(FormProcessingStatus.SUCCESS); doOperationResult = processDelegates(DO_OPERATION, clientData, objectBeanList); if (!continueProcessing(doOperationResult)) { return doOperationResult; } try { < persist the object > } catch(WTException e)
14-80
Note that delegates are called after form processor tasks in most processing phases, but in the doOperation phase they should be called before the form processor does its tasks. This is to allow delegates to perform operations after all attributes have been set but before the object is persisted. Case 4: You need to set attributes on the new object programmatically You may have attributes that you need to set on the object before it is persisted which are not exposed in the UI. Solution: There are alternate ways to handle this. Create a FormProcessorDelegate and implement its preProcess() method. In that method, set the attribute values on the object in the ObjectBean. Add a hidden form field to your wizard jsp specifying the name of your delegate, which will be automatically instantiated by the framework. For example:
<input type="hidden" name=" ${createBean.formProcessorDelegateConstant}" value=" <path name of your delegate> ">
Subclass the out-of-the-box processor and override the preProcess() method. You can call the createItemInstance() method of the superclass to create the Persistable for you and then set the attributes you desire on the Persistable. For example:
FormResult preProcessResult = new FormResult(FormProcessingStatus.SUCCESS); for (ObjectBean objBean: objectBeans) { FormResult objectResult = new FormResult(FormProcessingStatus.SUCCESS); objBean.setObject(createItemInstance(clientData, objBean, objectResult)); preProcessResult = mergeIntermediateResult(phaseResult, objectResult); if (!continueProcessing(preProcessResult)) { return preProcessResult; } Object newObj = objBean.getObject(); < set additional attributes on the new object here> } // Call processDelegates() which will call registered processor delegates delegatesResult = processDelegates(DO_OPERATION, clientData, objectBeanList); preProcessResult = mergeIntermediateResult(preProcessResult, delegatesResult); if (!continueProcessing(preProcessResult)) {
Constructing Wizards
14-81
return preProcessResult; }
Note that the above example is written so that the processor could be used for wizards creating more than one object. In general, it is probably preferable to use the delegate approach for setting your attributes rather than the subclass approach as it will insulate you from any modifications that might be made to the CreateObjectFormProcessor preprocess() method in the future.
14-82
<p:pickerParam name="seedType" value="wt.part.WTPart| org.r_and_d.SoftPartType1/> <p:pickerParam name="filterType" value="wt.part.WTPart|org.r_and_d.SoftPartType1| org.r_and_d.SoftPartType1B"/> <p:pickerParam name="showRoot" value="false"/> </jca:configureTypePicker>
Parameter seedType
Possible Value any Windchill type identifier string (logical or external) any Windchill type identifier string (logical or external)
Req? No
Description The top-level type that should be used to generate the list of types. For example, "wt.part.WTPart". May include more than one of these parameters. The type that should be selected by default. For example, "wt.part.WTPart." May be a string, such as "Select a Type" rather than a type name.
defaultType
For certain types the default is taken from a preference (see Background on page 14-38) For all other wizards, the base type is used. None
No
filterType
any Windchill type identifier string (logical or external) true (to display hierarchy) false (to display flat list)
No
A type that should be excluded from the type list. For example, "SoftPartType1". The descendants of the filter type are also excluded. May include more than one of these parameters. Indicates whether the type list should be displayed as a flat list or in hierarchical form.
displayHierarch y
false
No
showRoot
true
true (to display seed types) false (to not display seed types)
adminDomainR efString
domain associated with the default folder location (see Background on page 14-38)
No
String representation of the administrative domain reference that should be used for access-control filtering of the type list. For example, "wt.admin.AdministrativeDomain:7"
Constructing Wizards
14-83
Parameter type
Possible Value ROOT_TYPES (only seedTypes will be displayed) SOFT_TYPES (only soft types will be displayed) MODELED_T YPES (only modeled types will be displayed BOTH (both modeled and soft types will be displayed)
Req? No
Description Indicates the kind of types to be displayed. Value should be one of the enum constant value defined in com.ptc.windchill.enterprise.picker.type .server.TypePickerTypes.
Sample Code Default JSP for the Define Object Wizard Step
Filename: <WT_HOME>/codebase/netmarkets/jsp/components/defineItemWizStep.jsp This jsp is mapped to the defineItemWizStep action for objecttype=object in <WT_HOME>/codebase/actions.xml. It is the default jsp that will be used for this step unless overridden for a specific type.
<%@ include file="/netmarkets/jsp/components/beginWizard.jspf"%> <%@ include file="/netmarkets/jsp/components/createEditUIText.jspf"%> <%@ include file="/netmarkets/jsp/components/includeWizBean.jspf"%> <%@ include file="/netmarkets/jsp/components/defineItemReadOnlyPropertyPanel.j spf"%> <jca:configureTypePicker/> <%@ include file="/netmarkets/jsp/components/defineItem.jspf"%> <%@ include file="/netmarkets/jsp/util/end.jspf"%>
JSP for the Define Object Step of the New Part Wizard
Filename: <WT_HOME>/codebase/netmarkets/jsp/part/defineItemWizStep.jsp
14-84
This example illustrates how to override the read-only context panel and to reconfigure the type picker.
<%@ page import="com.ptc.windchill.enterprise.part.PartConstants" %> <%@ page import="com.ptc.core.ui.componentRB" %> <%@ taglib uri="http://www.ptc.com/windchill/taglib/components" prefix="jca"%> <%@ taglib uri="http://www.ptc.com/windchill/taglib/picker" prefix="p"%> <%@ taglib uri="http://www.ptc.com/windchill/taglib/partcomponents" prefix="partcomp"%> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="http://www.ptc.com/windchill/taglib/fmt" prefix="fmt"%> <%@ include file="/netmarkets/jsp/components/beginWizard.jspf"%> <%@ include file="/netmarkets/jsp/components/createEditUIText.jspf"%> <%@ include file="/netmarkets/jsp/components/includeWizBean.jspf"%> <jca:describePropertyPanel var="defineItemStepContextPanelDescriptor" id="defineItemStepContextPanelDescriptor" scope="request" mode="VIEW" type="wt.part.WTPart"> <jca:describeProperty id="containerName" label="${createBean.containerLabel}"/> </jca:describePropertyPanel> <%-- Get the part types to filter from type picker selection list -%> <partcomp:PartCreateHelper var="partTypesToFilter" method="getPartTypesToFilter"/> <c:choose> <c:when test='${param.invokedfrom == "tabular_input"}' > <!-- If New Part client is invoked from Edit Structure, association constraints need to be enforced. (Please see the Javadoc for DefaultAssociationConstraintIT for more details). The list of creatable types needs to be filtered out to inlcude only the types allowed by association constrains. This is achieved by finding the list of valid (allowable) types using the getSeedPartTypes below and then setting the type picker's 'type' parameter to 'ROOT_TYPES' --> <!-- Get the seed part types. Usually, it is wt.part.WTPart but it can be a bunch of types if association contraints are in place -> <partcomp:PartCreateHelper var="seedPartTypes" method="getSeedPartTypes"/> <jca:configureTypePicker>
Constructing Wizards
14-85
<%-Type Picker picks up the default from Preferences. It does not have be set here. --%> <c:forEach var="item" items="${seedPartTypes}"> <p:pickerParam name="seedType" value="${item}"/> </c:forEach> <c:forEach var="item" items="${partTypesToFilter}"> <p:pickerParam name="filterType" value="${item}"/> </c:forEach> <p:pickerParam name="type" value="ROOT_TYPES"/> </jca:configureTypePicker> </c:when> <c:otherwise> <jca:configureTypePicker> <%-Type Picker picks up the default from Preferences. It does not have be set here. --%> <c:forEach var="item" items="${partTypesToFilter}"> <p:pickerParam name="filterType" value="${item}"/> </c:forEach> </jca:configureTypePicker> </c:otherwise> </c:choose> <%@ include file="/netmarkets/jsp/components/defineItem.jspf"%> <%@ include file="/netmarkets/jsp/util/end.jspf"%>
JSP for the Set Attributes step of the New Problem Report Wizard
Filename: <WT_HOME>/codebase/netmarkets/jsp/problemReport/create_details.jsp Elements typical to most Set Attributes step jsps are shown in bold.
<%@taglib uri="http://www.ptc.com/windchill/taglib/components" prefix="jca" %><%@taglib uri="http://www.ptc.com/windchill/taglib/fmt" prefix="fmt" %><%@taglib uri="http://www.ptc.com/windchill/taglib/changeWizards" prefix="cwiz" %><%@include file="/netmarkets/jsp/components/beginWizard.jspf" %><%@include file="/netmarkets/jsp/components/createEditUIText.jspf"
14-86
%><%@ include file="/netmarkets/jsp/components/includeWizBean.jspf" %> <!-- Setup the localization string constants --> <fmt:setLocale value="${localeBean.locale}"/> <fmt:setBundle basename="com.ptc.windchill.enterprise.change2.change2ClientResour ce" /> <fmt:message var="tableTitle" key="ATTRIBUTES_TABLE"/> <%@ include file="/netmarkets/jsp/change/setAttributesReadOnlyPropertyPanel.js pf"%> <%-->Build a table descriptor and assign it to page variable td<-%> <jca:describeAttributesTable var="attributesTableDescriptor" id="create.problemReportDetailsStep" mode="CREATE" scope="request" componentType="WIZARD_ATTRIBUTES_TABLE" type="wt.change2.WTChangeIssue" label="${tableTitle}"> <jca:describeProperty id="number" /> <jca:describeProperty id="name" /> <jca:describeProperty id="requester" inputFieldType="singleLine" /> <jca:describeProperty id="theIssuePriority"/> <jca:describeProperty id="theCategory"/> <jca:describeProperty id="description" /> <jca:describeProperty id="ALL_CUSTOM_HARD_ATTRIBUTES_FOR_INPUT_TYPE"/> <jca:describeProperty id="ALL_SOFT_NON_CLASSIFICATION_SCHEMA_ATTRIBUTES"/> </jca:describeAttributesTable> <cwiz:initializeSubmitNow/> <%@include file="/netmarkets/jsp/components/setAttributesWizStep.jspf"%> <script language='Javascript'> loadAllRemainingNonRequiredSteps(); </script> <%@include file="/netmarkets/jsp/util/end.jspf"%>
Constructing Wizards
14-87
<%@ include file="/netmarkets/jsp/components/includeWizBean.jspf"%> <script src='netmarkets/javascript/baseline/baseline.js'></script> <jca:initializeItem operation="${createBean.create}" baseTypeName="wt.vc.baseline.ManagedBaseline"/> <jca:wizard buttonList="NoStepsWizardButtons" helpSelectorKey="baseline.createHelp"> <jca:wizardStep action="setBaselineAttributesStep" type="baseline" /> </jca:wizard> %@include file="/netmarkets/jsp/util/end.jspf"%
14-88
Constructing Wizards
14-89
Background
Object edit wizards are typically launched by an action labeled Edit or Check Out and Edit. Developing a wizard to edit a business object is very similar to developing a wizard to create that business object. Many of the components you will use are the same. However, there are a few differences between create and edit wizards and some of these require different components or different component configuration. These differences include the following: Edit wizards do not allow users to change the container context, owning organization, folder location, or type of an object Some edit wizards do not allow the user to change the identity attributes on the master of an object (for example: name and/or number). Such changes must be made via a Rename or Edit Common Attributes client. Other master attributes may not be editable also. If the object being edited is a Workable and it is not checked out by the user when the edit wizard is launched, the wizard should check out the object automatically. The attribute input fields in edit wizards are pre-populated with the values that exist in the database for the object rather than the default values defined in the Rose model or Attribute and Type Manager. Edit wizards for Workables have different navigation buttons. Instead of an OK button they have Save and Check In buttons. The former saves the changes to the working copy of the object without checking in or iterating it. The second creates and checks in a new iteration of the object. Also, the Cancel button pops up a message reminding the user that the object will remain checked out.
Components available specifically for editing include: jsp and jspf files for wizard steps that are common to multiple wizards custom HTML tags for managing wizard data and displaying elements on the page Java classes for processing the wizard data after the user submits the wizard
14-90
Scope/Applicability/Assumptions
Assume you have created a custom Persistable business object class or soft type and you want to develop a wizard that will allow users to edit the attributes of one instance of that object type. The information in this document is applicable to editing both Workable and nonWorkable objects and both Typed and non-Typed objects. This document describes the reusable common components upon which most Windchill edit wizards are based. If your custom type extends an existing Windchill business class, such as WTPart, WTDocument, or WTChangeIssue, there may be components more specific to those classes that could or should be used instead of the components described herein. These class-specific components are built on top of the common components described in this document. A discussion of those class-specific components is beyond the scope of this document. Be aware that you do not necessarily need to develop your own wizard to edit instances of a custom type. If your type is a modeled or soft subtype of a Windchill business class such as WTPart, WTDocument, or Problem Report (WTChangeIssue) , you may be able to use the out-of-the-box edit wizard for your purposes. The out-of-the-box wizards will automatically display input fields for hard and soft attributes of custom subtypes on the Set Attributes step as shown below:
Constructing Wizards
14-91
Attributes in the table will be ordered as follows: Out-of-the-box attributes, ordered as listed in the JSP file Custom modeled attributes, ordered alphabetically by display name Custom soft attributes, ordered alphabetically by display name
If you want to order the attributes on this step differently or require additional fields on this step, you will need to create a new jsp for this step specifically for your subtype. However, you can still use the Edit Part wizard. If you want to add additional steps to an existing wizard , you will need to develop a custom wizard , but may be able reuse many of the steps/components of the existing wizard.
Intended Outcome
Add a single- or multi-step HTML wizard to the product that allows a user to update a business object in the database. The arrangement of steps and presentation of attributes within the wizard should be similar to that of other Windchill wizards to provide a consistent user experience.
Solution
Use common jsp, tag, javascript, and Java class components built on top of the jsp wizard framework to create a wizard for capturing user input and for processing that input and creating the object in the database.
Prerequisite knowledge
To achieve this objective, you need to be familiar with the Building Wizards to Create a Single Object topic (see page 14-38 for more information), especially the Prerequisite knowledge section is on page 14-43.
14-92
Solution Elements
Element Tags autoCheckOutItem Note: All of the tags in the Solution Elements section of the Building Wizards to Create a Single Object topic are also applicable to edit wizards. This tag is in addition to those. See Building Wizards to Create a Single Object on page 14-38 for more information. (The Solution Elements section is on page 14-43.) Tag Checks out the object to the current user if it is not already checked out. Adds an object reference to the working copy as an attribute of the current HTTPRequest, as a parameter in HTTPRequestData parameter map of the NmCommandBean, and as a hidden field in the DOM. The key to the working copy value is CreateAndEditWizBean.WORKING_COPY_RE F_PARAMETER_NAME. This tag should be put in the main JSP for the wizard immediately below the initializeItem tag. Tag library: <WT_HOME>/codebase/WEBINF/tlds/workinprogress.tld Tag handler: com.ptc.windchill.enterprise.wip.tags.AutoCheck OutObjectTag JSPs setAttributesWizStep jspf file A jsp file (also used for create wizards) that can be included in the jsp for your Set Attributes wizard step. This will get the model data for and render your attributes panel and table if you have named them per the instructions in this document. Runtime location: <WT_HOME>/codebase/netmarkets/jsp/compon ents setAttributesWizStepWithContent .jspf jspf file A jsp file that can be included in the jsp for your Set Attributes wizard step if your object type is a FormatContentHolder. It does the same things as the jsp above but, in addition, will render input fields for capturing primary content. Location: <WT_HOME>/codebase/netmarkets/jsp/docume nt Beans CreateAndEditWizBean Java class; Runs in the servlet engine and the Method Server This bean is available to your jsps if you include the includeWizBean jspf file. It has getter methods for wizard data such as the operation (create or edit) and working copy object reference. Type Description
Constructing Wizards
14-93
Type
Description You can use the classes below to help create and process your wizard. They are located in the <WT_HOME>/codebase/WEBINF/lib/wncWeb.jar file.
CreateAndEditModelGetter
A class that may be called via a getModel tag to generate the data for property panels and attributes tables in edit wizards. A class that may be called to validate the data in the Set Attributes wizard step. A class that may be used or extended to process wizard form data for nonWorkable objects. Extends DefaultObjectFormProcessor. A class that may be used or extended to process wizard form data for Workable objects. Extends DefaultObjectFormProcessor.
EditAttributesStepValidator DefaultEditFormProcessor
Java class; runs in the Method Server Java class; Runs in the Method Server
EditWorkableFormProcessor
The tasks shown in bold are always required. The other tasks may or may not be needed, depending on the requirements of your wizard. If you have attributes in your wizard that cannot be displayed by the standard Windchill dataUtilties, GUI components, and renderers you also may need to write Java classes for those functions.
Laying out your wizard
Because the attributes described as driver attributes in the Single-Object Create Wizards Best Practice are not editable, edit wizards generally have fewer steps.
14-94
They are also usually less complex because refresh of wizard fields when other field values are changed is not required. Edit wizards for non-change objects generally have one to three steps as follows: 1. Set Attributes Step This step is common to almost all edit wizards and is where the user edits most of the objects attributes. It generally contains one to three parts: a readonly context property panel, primary content input fields (for FormatContentHolder objects only), and an attribute input table. Refer to the illustration below.
Context panel Read-only information about the object being edited. This varies by object type. Typically, the object type is displayed. If the object is WTContained it also usually displays the container name. If the new object is OrganizationOwned and the preference Display -> Expose Organization is set to true it also typically displays the organization id.
Constructing Wizards
14-95
You will need to decide what, if any information needs to be displayed in this panel for your object type. Primary content Wizards to create objects that are FormatContentHolders, such as WTDocuments, should have a section for the user to modify the primary content item. Attribute input table This typically contains input fields for all the editable soft and hard attributes for the object type, except for part classification attributes, which are entered on a following step. A few non-editable attributes, such as Name in the illustration above, may be displayed at the top of the table in read-only mode. You will need to decide what attributes should be displayed in this table. 2. Set Classification Attributes Step This step only applies to WTParts and subtypes thereof when PartsLink is installed. It is a dynamic step that only appears if the part is classified. It allows the user to modify the classification attributes of the part. It displays the classification(s) of the part in view mode at the top and then includes a table of input fields for classification attributes.
14-96
3. Attachments Step This step only applies to objects that are ContentHolders. It allows the user to add and delete documents, links, and other content for the object. See the Attachments section of the Customizing HTML Clients Using the Windchill JSP Framework chapter on page 10-16 for information on incorporating this step.
Creating the Action for Your Wizard
An action is needed to launch your wizard. This task is very similar to creating an action for a create wizard. Refer the Creating the Action for Your Wizard procedure in the Building Wizards to Create a Single Object section on page 14-97. The only difference is that your form processor, specified on the class attribute of the command tag, will typically be one of the processors listed in Solution Elements section on page 14-93 or a subclass of one of those classes. We recommend you name your action (and main wizard jsp file) edit. If there will be multiple edit actions for your objecttype based on launch point or other criteria you can add a suffix further qualifying the action as shown below. For example: editFrom<launch page or table> edit<name for a subset of attributes being edited> Ex: editFromAttributesTable Ex: editAnnotations
Creating Actions and/or Service Property Entries for Your Wizard Steps
You may be able to use out-of-the-box action definitions for wizard steps that are common to multiple wizards. The following wizard step actions are defined outof-the-box.
Objecttype object
Action definition/ File Location/ Associated JSP Page <action name="editAttributesWizStep" id="editAttributesWizStep" preloadWizardPage="false" required="true" afterVK="editAttributes" resourceBundle="com.ptc.core.ui.componentRB"> <command windowType="wizard_step" url="servlet/TypeBasedIncludeServlet?contextAction=editAttributesWiz Step"/> </action> Action file: <WT_HOME>/codebase/actions.xml Associated jsp page: None
Constructing Wizards
14-97
Objecttype part
Action definition/ File Location/ Associated JSP Page <action name="setClassificationAttributesWizStep" id="setClassificationAttributesWizStep" hidden="true" required="true" preloadWizardPage="false" afterVK=editAttributes> <command windowType="wizard_step"/> </action> Action file: <WT_HOME>/codebase/ config/actions/PartManagementactions.xml. Associated jsp page: <WT_HOME>/codebase/netmarkets/jsp/part/setClassificationAttributes WizStep.jsp Note: This is the same action used for this step in part create wizards
attachments_s tep
attachments (ContentHolde r)
<action name="attachments_step" uicomponent="ATTACHMENTS" ajax="row" postloadJS="preAttachmentsStep" preloadWizardPage="false"> <command class="com.ptc.windchill.enterprise.attachments.forms.SecondaryAttach mentsSubFormProcessor" windowType="wizard_step"/> <includeFilter name="hideFromDTI" /> <includeFilter name="EDACompareFilter" /> </action> Action file: <WT_HOME>/codebase/config/actions/Attachments_actions.xml Associated jsp page: <WT_HOME>/codebase/netmarkets/jsp/attachments/attachments_step.js p
Note that the editAttributesWizStep action specifies the page as non-preloaded in case in is not the first step in the wizard and is dependent on an earlier step. However, if it is the first step the framework will preload it regardless of how it is specified on the action. Also note that the Set Classification Attributes step is marked as hidden. It is dynamically inserted into the wizard if the part is classified when the wizard launches. It is dynamically removed if the user clicks the Do Not Classify radio button in the "Set Attributes Step" to unclassify the part. If these action definitions meet your requirements you do not need to define your own actions for your wizard. However, you will need to define your own action for a wizard step if either of the following is true: You need to define additional or different tag attributes for the step action Your step is unique to your wizard.
14-98
Note that you can use your own JSP for the Set Attributes step without defining your own step action by use of the TypeBasedIncludeServlet described below. See the Creating Actions and/or Service Property Entries for Your Wizard Steps of the Building Wizards to Create a Single Object section on page 14-97 for more information on creating step actions.
Creating service.properties Entries for the Set Attributes Step
The Creating service.properties Entries for the Set Attributes Step of the Building Wizards to Create a Single Object section on page 14-99 describes how the TypeBasedIncludeServlet is used to look up the jsp that should be used for some wizard steps or portions of wizard steps. For edit wizards, the servlet is used to look up the jsp that should be used for the Set Attributes step. This allows you to use the common action definition for this step but still create and use your own step jsp. If you have multiple wizards that differ only by the content of this step, it also means you can use the same main wizard JSP and wizard action definition for all of them. This is often the case when creating wizards for different subtypes of the same base type. To specify which jsp should be used for this step for a specific object type you would include an entry like the following in a type-based service.properties file: Xconf file:
<Resource context="default" name="com.ptc.netmarkets.util.misc.FilePathFactory"> <Option requestor=" <object type to be edited> >" resource=" <jsp file path relative to WT_HOME/codebase>.jsp" selector="editAttributesWizStep"/> </Resource>
Note that the selector string matches the contextAction parameter on the URL in the step action. For example, to use the jsp page <WT_HOME>/codebase/netmarkets/jsp/ext/part/myPart/setAttributesWizStep.js p for the Set Attributes step when editing objects of type ext.part.MyPart you would add the following entry to a type-based service.properties xconf file:
<Resource context="default" name="com.ptc.netmarkets.util.misc.FilePathFactory"> <Option requestor="ext.part.MyPart" resource= /netmarkets/jsp/ext/myPart/setAttributesWizStep.jsp selector="editAttributesWizStep"/> </Resource>
Constructing Wizards
14-99
The describePropertyPanel and describeAttributesTable tags for input fields should have a mode parameter of EDIT. The componentType parameter is WIZARD_ATTRIBUTES_TABLE, just as for create. Using EDIT mode will cause input fields to be generated for each attribute in the table or panel by default. If you want a specific attribute to be displayed in readonly mode you can override the default mode by specifying a mode parameter on the describeProperty tag as shown in the example below:
<jca:describeAttributesTable var="attributesTableDescriptor" scope="request" id="create.setAttributes" mode="EDIT" componentType="WIZARD_ATTRIBUTES_TABLE" type="wt.part.WTPart" label="${attributesTableHeader}"> <jca:describeProperty id="name" mode="VIEW"/>
Because the attributes on this step vary by object type, you will need to create your own main jsp for this step. However, once you describe the contents of the page there are jsp components available to help you acquire the data models for and render the elements. These are the same components that are used for create wizards. The suggested name for this step jsp is: editAttributesWizStep.jsp or editAttributesWizStepFor<object type>.jsp (if there is more than one of these step jsps in the directory) This step is very similar to the Set Attributes wizard step for create wizards. Typically, it will include the following: 1. A describePropertyPanel tag for the read-only attributes panel at the top of the step. This tag should have a mode parameter of VIEW. Also set the following tag attributes if you are including setAttributesWizStep.jspf file to obtain the data for and to render your panel:
Attribute Value
var
attributesStepReadOnlyPanel
14-100
Attribute
Value
id scope
2. A describeAttributesTable tag for editing hard and soft attributes. The mode of this tag should be set to EDIT. (See the section Attribute Input Tables and Panels above for how to make individual attributes view-only.) You should also set the following tag attributes if you want to use the out-of-thebox jspf file described in the next step for getting the table model and rendering the table.
Attribute Value
var id scope
If your object is a subtype of WTPart and you want to include a classification picker in your table, you would add the following property to your table:
<jca:describeProperty id="classification.id" label="${classificationLabel}"/>
and you must include the following hidden fields in the page:
<input id="selectedClfNodes" type="hidden" name="selectedClfNodes" > <input id="selectedClfNodesDisplayName" type="hidden" name="selectedClfNodesDisplayName" >
3. If your object is a FormatContentHolder and you want to allow users to edit the primary content input on this step, include the file /netmarkets/jsp/document/setAttributesWizStepWithContent.jspf. This contains the tag primaryAttachmentWithMSOI, which will render a section for editing of primary content. See the Attachments section of the Customizing HTML Clients Using the Windchill JSP Framework chapter on page 10-16 for information on this tag. It also acquires the data for and renders the read-only property panel and the attributes input table, providing you have followed the naming conventions described in this section. If your object is not a FormatContentHolder, include the file /netmarkets/jsp/components/setAttributesWizStep.jspf. This does the same things as setAttributesWizStepWithContent.jspf except that it does not include a primaryAttachment tag.
Constructing Wizards
14-101
Note that these JSPFs are also used for create wizards. See the Sample Code section on page 14-107 for an example page.
Adding Set Classification Attributes and Attachments Steps
JSPs for these steps are available out-of-the-box. You need only include the step action in your main wizard JSP page. Customization of these steps is not recommended.
This validator works exactly like the SetAttributesStepValidator for create wizards --- it also calls the preprocess() method of the wizard form processor to validate the data against all constraints that were defined for the attributes in the Rose model or Type Manager. If the out-of-the-box validator class meets your needs you can use it by specifying the selector string shown in the entry above as the value of the afterVK attribute of your wizard step action. If you need to do additional validation, you can write your own validator, typically subclassing the default validator. The Set Classification Attributes step uses the same validator as the Set Attributes step. No validator is provided or needed for the attachments step.
Creating Your Main Wizard JSP Page
This should look much the same as that for a create wizard, with the differences noted below. See the Sample Code section on page 14-107 for example JSPs.
AutoCheckOutItem Tag
If your target object is a Workable and your wizard can be launched for an object that is not already checked out via a Check Out and Edit or other action, you should include an autoCheckOutItem tag in your main jsp immediately below the initializeItemTag.
<%@ taglib prefix="wip" uri="http://www.ptc.com/windchill/taglib/workinprogress"%> . . . <wip:autoCheckOutItem/>
14-102
This tag will check out the object to the current user before opening the wizard. See the Solution Elements section on page 14-93 for more information.
InitializeItemTag
Like create wizards, edit wizards require an initializeItem tag. Instead of setting the operation attribute of this tag to ${createBean.create}, you should set it to ${createBean.edit}. The following tag attributes are not applicable to edit wizards: objectHandle, baseTypeName.
Wizard Tag
Typically, wizards for editing Workable objects will use one of the following two button sets: EditWizardButtons (multiple-step wizards) NoStepsEditWizardButtons (single step wizards)
These include Save and Check In buttons. For editing nonWorkable objects one of the following is usually used: DefaultWizardButtonsNoApply (multiple-step wizards) NoStepsWizardButtons (single step wizards)
These are all defined in <WT_HOME>/codebase/config/actions/actionmodels.xml. To include a Set Attributes step in your wizard you should provide a wizardStep tag with the action name editAttributesWizStep (if you are using the common step action shown in the Creating Actions and/or Service Property Entries for Your Wizard Steps section on page 14-97) or the action name you specified on your custom action. To include Set Classification Attributes and/or Attachments steps, use the action names shown for these steps in Creating Actions and/or Service Property Entries for Your Wizard Steps section on page 14-97).
Classification Step Requirements
If your wizard includes a Set Classification Attributes step you will need to dynamically load that step if the part being edited is classified. The js function loadClassificationStep() in <WT_HOME>/codebase/netmarkets/javascript/part/PartHelper.js is available to do that. In most cases this should be called indirectly by calling the onloadEditPartWizard() function when the wizard loads your main wizard jsp, as follows:
<script language="JavaScript" src="netmarkets/javascript/part/PartHelper.js"></script> .
Constructing Wizards
14-103
The onloadEditPartWizard() function calls loadClassificationStep() and also does some additional configuration for wizards launched from a workspace. You can use it regardless of whether your wizard can be launched from a workspace. If the Set Attributes step is not the first step in your wizard and it is not preloaded, you will also need to include the following in your Set Attributes step jsp:
<script language="JavaScript" src="netmarkets/javascript/part/PartHelper.js"></script> . . . <script language="Javascript"> Event.observe(window, 'load', loadClassificationStep); </script>
See the Attachments section of the Customizing HTML Clients Using the Windchill JSP Framework chapter on page 10-16 for information on the elements that must be included to incorporate this step.
14-104
Both of these processors do the following: preProcess() method same as the preprocess() method of the CreateObjectFormProcessor except that it creates a TypeInstance for a persisted object
doOperation() method calls super.doOperation() to call the doOperation() methods of any FormProcessorDelegates registered for the wizard` calls PersistenceHelper.manager.save() to store the Persistable in the database
Constructing Wizards
14-105
If the status of the FormResult is SUCCESS or NON_FATAL_ERROR, sets the next action to FormResultAction.REFRESH_OPENER; it also sets the refreshInfo attribute of the FormResult as follows: action = NmCommandBean.DYNAMIC_UPDATE oid = object that was edited location = object that was edited
As a result, if the edited object is displayed in a table row of the launch page and the ajax action on the wizard action was set to row, only the table row will be refreshed. If the ajax action was set to page or was not specified, the entire launch page will be refreshed. If the ajax action was set to component and the wizard was launched from a table toolbar, only that table will be refreshed. If the status set on the FormResult is FAILURE, sets the nextAction to FormResultAction.NONE. This will return the user to the wizard page on which OK was clicked.
EditWorkableFormProcessor.setResultNextAction() (called by the DefaultFormProcessorController) If the status of the FormResult is SUCCESS or NON_FATAL_ERROR and the Check In button was clicked
Sets the next action to FormResultAction.JAVASCRIPT and adds javascript to launch the check in action. If the edit action was launched from a table row, the table row will be refreshed when the checkin completes. If the edit action was launched from an info page, the info page of the new iteration will be displayed when the check in completes.
If the wizard was launched from the folder browser, sets the next action to FormResultAction.REFRESH_OPENER and adds dynamic refresh attributes to refresh the table row of the edited object If not launched from the folder browser, sets the next action to FormResultAction.LOAD_OPENER_URL and loads the url for the info page of the working copy
If the status of the FormResult is FAILURE sets the next action to FormResultAction.NONE
If you are extending an existing Windchill business class, there may be a processor specific to that class that you should use or extend instead of the DefaultEditFormProcessor or EditWorkableFormProcessor. These are shown in
14-106
the table below. Consult the javadoc for these classes for more information on their behavior.
If your class extents Use processor class
com.ptc.windchill.enterprise.change2.forms.process ors.EditProblemReportFormProcessor com.ptc.windchill.enterprise.change2.forms.process ors.EditChangeRequestFormProcessor com.ptc.windchill.enterprise.change2.forms.process ors.EditChangeNoticeFormProcessor com.ptc.windchill.enterprise.change2.forms.process ors.EditChangeTaskFormProcessor com.ptc.windchill.enterprise.change2.forms.process ors.EditVarianceFormProcessor
If one of the provided form processors meets your needs, you do not need to write your own processor --- just specify that processor as the value of the class attribute of the command subtag of your wizard action. If they do not meet your needs, you should write a subclass of one of them to process the wizard form data. See the Creating Your Form Processor and Form Processor Delegates section on page 14-75 for examples of cases where you may need to implement your own processor.netmarkets/jsp/components/beginWizard.jspf If you create your own processor, be aware that its preProcess() method will be called by the standard validator classes after each wizard step. Make sure you do not modify the database in this method.
Sample Code JSP for the Set Attributes Step of the Edit Part Wizard
Filename: <WT_HOME>/codebase/netmarkets/jsp/part/editPartAttributesWizStep.jsp
<%@ taglib uri="http://www.ptc.com/windchill/taglib/components" prefix="jca"%> <%@ taglib tagdir="/WEB-INF/tags" prefix="tags"%> <%@ page import="com.ptc.windchill.enterprise.part.partResource" %> <%@ page import="com.ptc.windchill.enterprise.part.PartConstants" %> <%@ include file="/netmarkets/jsp/components/beginWizard.jspf"%> <%@ include file="/netmarkets/jsp/components/createEditUIText.jspf"%>
Constructing Wizards
14-107
<fmt:setBundle basename="com.ptc.windchill.enterprise.part.partResource"/> <fmt:message var="classificationLabel" key="<%= partResource.CLASSIFICATION_LABEL %>" /> <fmt:message var="locationLabel" key="<%= partResource.LOCATION_LABEL %>" /> <fmt:message var="typeNameLabel" key="<%= partResource.TYPE_NAME_LABEL %>" /> <fmt:message var="minimumRequiredLabel" key="<%= partResource.MINIMUM_REQUIRED_LABEL %>" /> <fmt:message var="maximumAllowedLabel" key="<%= partResource.MAXIMUM_ALLOWED_LABEL %>" /> <%--> Read-only context panel <--%> <jca:describePropertyPanel var="attributesStepReadOnlyPanel" id="attributesStepReadOnlyPanel" scope="request" mode="VIEW" type="wt.part.WTPart"> <jca:describeProperty id="containerName" label="${createBean.containerLabel}"/> <jca:describeProperty id="partTypeName" label="${typeNameLabel}"/> <jca:describeProperty id="orgid" need="organization.id"/> </jca:describePropertyPanel> <%--> Attributes input table <--%> <jca:describeAttributesTable var="attributesTableDescriptor" scope="request" id="create.setAttributes" mode="EDIT" componentType="WIZARD_ATTRIBUTES_TABLE" type="wt.part.WTPart" label="${attributesTableHeader}"> <jca:describeProperty id="number" mode="VIEW" isInfoPageLink="false"/> <jca:describeProperty id="name" mode="VIEW"/> <jca:describeProperty id="version" mode="VIEW"/> <jca:describeProperty id="partType"/> <%--> Source uses a special data utility to hide the other options except 'Buy' if SUMA is installed and the part type is manufacturing or vendor <--%> <jca:describeProperty id="source"/> <%--> The following 3 are WADM specific attributes. They are hidden by the PartSolutionGroup logic if WADM is not installed. <--%> <jca:describeProperty id="<%=PartConstants.ColumnIdentifiers.WADM_CONTRACT_NUMBER%>"/ >
14-108
<jca:describeProperty id="<%=PartConstants.ColumnIdentifiers.WADM_JOB_AUTH_NUMBER%>"/ > <jca:describeProperty id="<%=PartConstants.ColumnIdentifiers.WADM_PHASE%>"/> <jca:describeProperty id="classification.id" label="${classificationLabel}"/> <jca:describeProperty id="minimumRequired" label="${minimumRequiredLabel}"/> <jca:describeProperty id="maximumAllowed" label="${maximumAllowedLabel}"/> <jca:describeProperty id="ALL_CUSTOM_HARD_ATTRIBUTES_FOR_INPUT_TYPE"/> <jca:describeProperty id="ALL_SOFT_NON_CLASSIFICATION_SCHEMA_ATTRIBUTES"/> </jca:describeAttributesTable> <%--> The following fields are necessary for the classification picker in the table above <--%> <input id="selectedClfNodes" type="hidden" name="selectedClfNodes" > <input id="selectedClfNodesDisplayName" type="hidden" name="selectedClfNodesDisplayName" > <%@ include file="/netmarkets/jsp/components/setAttributesWizStep.jspf"%> <%@ include file="/netmarkets/jsp/util/end.jspf"%>
Constructing Wizards
14-109
<fmt:message var="attributeStepLabel" key="product.editProductAttributesWizStep.title" /> <jca:initializeItem operation="${createBean.edit}"/> <jca:wizard buttonList="NoStepsWizardButtons" helpSelectorKey="PDMAdminProdEdit_help"> <%--> This step uses the common action definition. The JSP file for the step is, however, product-specific and hooked up using PartManagement-typedservices-properties.xconf <--%> <jca:wizardStep action="editAttributesWizStep" type="object" label="${attributeStepLabel}"/> </jca:wizard>
%@include file="/netmarkets/jsp/util/end.jspf"%
<%@ taglib prefix="jca" uri="http://www.ptc.com/windchill/taglib/components"%> <%@ taglib prefix="wip" uri="http://www.ptc.com/windchill/taglib/workinprogress"%> <%@ taglib uri="http://www.ptc.com/windchill/taglib/fmt" prefix="fmt"%> <%@ taglib uri="http://www.ptc.com/windchill/taglib/attachments" prefix="attachments" %> <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ include file="/netmarkets/jsp/components/beginWizard.jspf"%> <%@ include file="/netmarkets/jsp/components/includeWizBean.jspf"%> <%@ include file="/netmarkets/jsp/components/createEditUIText.jspf"%> <%--> PartHelper.js contains the onloadEditPartWizard method <--%>
14-110
<script language="JavaScript" src="netmarkets/javascript/part/PartHelper.js"></script> <% if(InstalledProperties.isInstalled(InstalledProperties.SCMI)) { %> <attachments:fileSelectionAndUploadApplet forceApplet='${param.addAttachments != null }'/>
<% } %>
<%--> The onload javascript method dynamically loads the classification step if the part is classified. It also disables the check in button when the wizard is launched from a workspace. <--%> <script language="Javascript"> Event.observe(window, 'load', onloadEditPartWizard); </script>
<fmt:setBundle basename="com.ptc.windchill.enterprise.part.partResource"/>
<%--> Reuse the same labels as for create part <--%> <fmt:message var="editAttributesWizStepLabel" key="part.createPartWizard.SET_ATTRIBUTES_WIZ_STEP_LABEL" /> <fmt:message var="attachmentsWizStepLabel" key="part.createPartWizard.ATTACHMENTS_WIZ_STEP_LABEL" />
<jca:initializeItem operation="${createBean.edit}"/>
<% if (request.getParameter("newInWorkspace") == null) { %> <%--> The part is not new in workspace. Do autoCheckout <--%> <wip:autoCheckOutItem/> <% } %>
<% if ((request.getParameter("newInWorkspace") != null) || (request.getParameter("checkedOutInWorkspace") != null)) { %> <script language="Javascript">newOrCheckedOutInWorkspace=true</script> <% } %>
Constructing Wizards
14-111
InstalledProperties.isInstalled(InstalledProperties.PARTSLINK)) { %> <c:set var="buttonSet" value="EditWizardButtons"/> <% } else { %> <c:set var="buttonSet" value="NoStepsEditWizardButtons"/> <% } %>
<%--> The Set Attributes step uses the common action definition. JSP file for the step is, however, part specific and hooked up using PartManagement-typedservicesproperties.xconf <--%> <jca:wizardStep action="editAttributesWizStep" label="${editAttributesWizStepLabel}" type="object"/> The
<jca:wizardStep action="setClassificationAttributesWizStep" type="part"/> <%--> The attachments step will get enabled or disabled based on the AttachmentsStepActionValidator hooked up to it <--%> <jca:wizardStep action="attachments_step" label="${attachmentsWizStepLabel}" type="attachments" />
</jca:wizard>
<%@include file="/netmarkets/jsp/util/end.jspf"%>
14-112
Constructing Wizards
14-113
14-114
15
Information Pages
This chapter describes how to customize information pages. Topic Page
Information Pages..............................................................................................15-2
15-1
Information Pages
Objective
You want to create an object information page specific to a given business object.
Solution
Use the Info Page Common Component with an info.jsp file associated to that object type.
Design Overview
There are many types of business objects in Windchill, plus potentially many soft types or modeled object types introduced by customers. Each type of object can potentially have its own associated information page, a page that displays information around a selected instance of that type. While the information associated with different object types can vary widely, it is important to maintain a common look and feel among the multitude of information pages. The info page component was developed to give the Windchill products consistency for displaying an object details page. The component is also intended to make developing an info page much easier. Using the component, a developer only needs to configure certain parts of the page (list of actions, which attributes to show, etc.) while the main layout of the page is provided by the component.
Applicability
This design pattern should be used for configuring the info page for some business object in one of the Windchill products.
15-2
Structure
Design Elements
The info page component Page title area Top attributes panel Visualization area Navigation menu Filter area Content area Global navigation Type-specific data
Information Pages
15-3
Actions list Recently visited list Auditing service Object attributes Status glyphs
Collaborations
The info page component controls the layout of the various other components on the page; page title area, top attributes panel, visualization area, navigation menu, filter area, and content area, as well as including the global navigation. The info page component supports type based lookups (including soft types) for the type specific data, attributes, 3rd level navigation menu. The info page component hooks up to the global navigation as appropriate (e.g.: tab highlighting) The info page component displays the correct action list based on object type The info page component registers the object in the recently visited list The info page component registers the user and the object in the auditing service for the view event The info page component does role based checking on attributes The info page component allows Status Glyph Indicators
Consequences
By following this design pattern the configuration of all objects info pages should be done in a consistent manner. This will make maintaining these info pages a much easier and more manageable task and have a consistent user model.
Implementation Overview
The info page component was developed using the Windchill client architecture. This component provides a common layout for an objects information page as it is displayed in any of the Windchill products. Using the info page component will provide consistency between all objects and Windchill products. The specific content that is displayed for any given object type will be configured by overriding certain elements in the context of the specific object types. Configurable portions of the page include things like which action list is used and which attributes are shown in the top attribute panel.
15-4
The default info page implementation will only contain the object icon, the name of the object, and possibly a link to the action list if one has already been configured
To display more than the default provides, you can create a new jsp that is configured for your type. All the details links (e.g. , ) will lead to the same servlet. As shown below, the TypeBasedInclude servlet receives the request for an info page and determines which navigator delegate to use. The navigator delegate determines which jsp to redirect to based on the object type and the state of the object. A jsp using the info page common component would include netmarkets/jsp/components/infoPage.jspf.
Information Pages
15-5
Status glyphs Help context Attributes displayed in the top attributes panel Third level navigation menus Actions contained in each third level navigation menu Default third level content table and table view
15-6
wt.services/rsc/default/com.ptc.netmarkets.util.misc.FragmentFa ctory/InfoPage/<fully qualified class path>/0=<jsp path relative to codebase>.jsp Here is an example of the xconf format: <Resource context="default" name="com.ptc.netmarkets.util.misc.FilePathFactory"> <Option requestor="<fully qualified class path>" resource="<jsp path relative to codebase>" selector="InfoPage"/> </Resource>
See the About the xconfmanager Utility section in the Windchill Utilities chapter on page 6-2 for more information.
To determine the set of available properties that can be displayed for an object type, you can use the property report.
Information Pages
15-7
To specify which actionmodel to use as the actions list for a specific class or softtype, use the attribute menufor as specified in the following example:
<!-- Part information page Actions list --> <model name="more parts actions" menufor="wt.part.WTPart"> <action name="view" type="object"/> <action name="viewDefaultRepresentationPV" type="wvs"/> <action name="viewDefaultRepresentationPVLite" type="wvs"/> <action name="launchPSE" type="explorer" /> <action name="launchABE" type="explorer" /> <action name="separator" type="separator"/> <action name="checkin" type="wip"/> <action name="checkout" type="wip"/> <action name="undocheckout" type="object"/> ..
For example:
<!-- your comment here --> <model name="<your_action_model_name>" menufor="<fully qualified classpath>"> <action name="view" type="object"/> </model>
Or, if you want to have multiple classes or soft types you can comma separate the list:
15-8
<model name="more meeting actions" menufor="wt.meeting.TraditionalMeeting,wt.meeting.MeetingCenterMee ting"> <action name="host" type="meeting"/> <action name="join" type="meeting"/> <action name="add_minutes" type="meeting"/> </model>
The info page uses what is registered in actionmodels.xml with menufor as the action list. You can override what is registered in actionmodels.xml by configuring the describeInfoPage with a different actionListName to use:
<jca:describeInfoPage actionListName="<action model name>" > </jca:describeInfoPage>
For example:
<Resource context="default" name="wt.help.HelpTemplate">
Information Pages
15-9
Selector is a help selector key that will be set on the describeInfoPage tag. In the above example it is PMPartStructureEdit_help. Resource is the help file location and is assumed to be an html file. The help file gets a base of $WT_HOME/codebase/wt/helpfiles/help_<locale> Hence in the above example where resource="online.pdm_prodmgmt.PMPartStructureEdit" the english help file will be:
$WT_HOME/codebase/wt/helpfiles/help_en/online/pdm_prodmgmt/PMPartS tructureEdit.html
Requestor is the class of the container context that the object is in. For example, parts could be created in either Products or Projects. If the help topic for parts in Projects had to be different from the help topic for parts in Products, an entry could be added with requestor="wt.projmgmt.admin.Project2". Once the above xconf entry is created, the help topic can be set on the info page by adding the selector on the describeInfoPage tag:
<jca:describeInfoPage helpContext="<help selector key>" > </jca:describeInfoPage>
Configure the Third Level Navigation Menus for your object type
The following is an example configuration of a third level navigation menu for the part info page:
<!-- Part information page 3rd level nav menu bar --> <model name="third_level_nav_part"> <action name="productStructure" type="object"/> <submodel name="general"/>
15-10
<!-- Related Objects --> <!-- History --> <!-- Collaboration -->
As you can see it is a combination of an action and submodels. An action in the 3rd level nav bar will be displayed as just a link. (e.g. Product Structure browser) A submodel in the 3rd level nav bar will be displayed as a drop down menu (e.g. Related Items menu) The General, Related Items, History and Collaboration menus are meant to be reused for all object types. Actions that do not apply for certain object types will be removed via action validation. So your action model would probably look something like this:
<!-- your comment here --> <model name="<your_action_model_name>"> <submodel name="general"/> <submodel name="relatedItems"/> <submodel name="history"/> <submodel name="collaboration"/>
</model>
<!-- General --> <!-- Related Objects --> <!-- History --> <!-- Collaboration -->
Then the image below would be the resulting 3rd level nav content (the action that led to the above jsp was added to the relatedItems submodel so that is why Related Objects is highlighted)
Information Pages
15-11
Setup
Parameter Attribute
Possible Values See section Specify the Attributes to include TBD Specify Status Glyphs to show in the Title Bar User defined. Specify the help context to use User defined in actionmodels. xml. User defined in actionmodels. xml. Set only if you want to override menufor setting in actionmodels. xml.
Req? No
statusGlyph
None
No
helpContext
None
No
navBarName
None
No
actionListName
The action model specified in actionmodels.x ml based on classname that is in the oid.
No
15-12
2. Register your jsp so the info page servlet will know to forward to it. Add the following entry into codebase/typedservices.properties:
wt.services/rsc/default/com.ptc.netmarkets.util.misc.FilePathFa ctory/InfoPage/wt.part.CoolPart/0=/netmarkets/jsp/coolpart/info .jsp
3. Test your new jsp. The icons from the Home page or from the Folders page should lead to the new info page servlet. The URL will look something like this:
http://<machine>/<WindchillAppName>/servlet/TypeBasedIncludeSer vlet?oid=OR:wt.part.CoolPart:62028
The servlet will look up which jsp to forward to in typedservices.properties. You should see the text that you typed into your jsp in step 1. 4. Now, lets add some content to your page. First, youll need the jca components taglib:
<%@ taglib uri="http://www.ptc.com/windchill/taglib/components" prefix="jca"%>
5. Then, youll need to describe a property panel that contains the attributes that apply for your object type. Using the property report on your build (see Property Report on page 14-64), find the attribute names you want to use:
<jca:describePropertyPanel var="propertyPanelDescriptor"> <jca:describeProperty id="name" /> <jca:describeProperty id="number" /> </jca:describePropertyPanel>
6. Next, describe the info page. Specify the third level nav, the help file, whether visualization applies, which property panel to use, and the status glyph families to be shown:
<jca:describeInfoPage showVisualization="true" helpContext="<cool_part_info_help>" navBarName="<third_level_nav_for_cool_part>" propertyPanel="${propertyPanelDescriptor}"> <jca:describeStatusGlyph id="statusFamily_Share" /> <jca:describeStatusGlyph id="statusFamily_General" /> </jca:describeInfoPage>
7. After setting up the describePropertyPanel and describeInfoPage tags include the infoPage.jspf. The component will acquire the necessary data (attributes, icon images, action models, etc.) and display the info page (attribute panel, title bar, 3rd level nav, etc.)
<%@ include file="/netmarkets/jsp/components/infoPage.jspf"%>
Information Pages
15-13
Or include the line, but with the navBarName value as an empty string:
<jca:describeInfoPage navBarName="" > </jca:describeInfoPage>
Known Uses
Many out-of-the-box business objects in Windchill have info pages that are built using the Info Page component. Here are a couple examples: WTPart codebase/netmarkets/jsp/part/info.jsp WTDocument codebase/netmarkets/jsp/document/info.jsp
15-14
16
Incorporating Pickers in JSP Clients
This chapter describes how to customize and configure pickers. Topic Page
Picker Interaction ............................................................................................. 16-2 Common Picker Configuration Options......................................................... 16-14 Configuring a Context Picker......................................................................... 16-18 Configuring an Item Picker ............................................................................ 16-24 Configuring an Organization Picker............................................................... 16-31 Configuring a Type Picker ............................................................................. 16-37 Configuring a User Picker.............................................................................. 16-50 Configuring a Participant Picker .................................................................... 16-57
16-1
Picker Interaction
Objective
You want to configure a property picker in some wizard step and manage interaction between that page and the picker.
Background
There are many types of business objects in Windchill, plus potentially many soft types or modeled object types introduced by the user. These types would predominantly would have some relationship with the other types. There are numerous instances when user creates or updates objects of such types using an user interface, he would need to specify the property value(s) derived from the other available objects of the same or different type. e.g. The business object like Part or Document are owned by a specific organization and hence at the time of their creation user needs to be able to specify an owning organization. This sort of user interaction is achieved through the use of property picker. The property picker simply aids in picking up a property from an existing business object. The user would pick an object by launching the picker and have its pro properties used to update visible and/or non-visible properties on the page. The following sketch illustrates this sort of interaction pictorially.
Scope/Applicability/Assumptions
Assume you have a customized type <myObjectType> object needing to be created. On the first step of the create wizard, you need to define a relation ship with an object of type <someObjectType>. This spawns a need to let user select the object he desires from a picker and have the attributes of these objects used to populate some content on the first step of the create wizard.
16-2
Intended Outcome
By following this design concept, the property picker user model would be consistent with the one that exists across the product at multiple places.
Solution
Follow the design concept as described to facilitate the picker interaction.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Basic development involving HTML forms, JSP, JavaScript based DOM manipulations, AJAX The actions framework in the Windchill client architecture The table component to list the objects. The wizard component in the Windchill client architecture
16-3
Solution Elements
Element Type Description
picker.tld
tld
Tag Library Descriptor (TLD) file, which contains Picker related Tag definitions. The propertyPicker,populate and pickerParam are the ones needed to be used to implement this design concept. Run time Location:
<Windchill>\codebase\WEB-INF\tlds\
create_step_<step no>.jsp
JSP
This JSP page provides the content for the specified step of the Create Wizard . This step would include the controls to launch a picker and populate values from the picked object. This JSP could as well render a javascript picker callback function to be executed once the picker OK action is executed. Run time Location:
<Windchill>\codebase\netmarkets\ <myObjectType>\create_step_<stepno>.jsp
<someObjectType>_picker.jsp
JSP
This JSP page defines a single step wizard with OK and Cancel actions for the wizard. The wizard step would render a content that presents a list of <someObject> in table or tree component. The user would select the object of interest by ticking the check boxes to select row(s) in the table. Run time Location:
<Windchill>\codebase\netmarkets\< someObjectType >\ <someObjectType>_picker.jsp
<someObjectType>_picker_st ep.jsp
JSP
This JSP page defines the content for the picker wizard step. This step can contain a table listing the objects of <someObjectType> or search criteria along with Run time Location:
<Windchill>\ codebase\netmarkets\< someObjectType >\ <someObjectType>_picker_step.jsp
16-4
Element
Type
Description
Actions.xml
XML
The file has definitions of all the actions. The action that launches picker need to get defined for the type <myObjectType>. The picker wizard step actions as well get defined in this file. JSP fragment to be always included by the picker implementation i.e. in <someObjectType>_picker_step.jsp Run time location:
<Windchill>\codebase\netmarkets\components\ picker.jspf
picker.jspf
JSPF
defaultPickedDataFetcher.jsp
JSP
Default Picker Data Fetcher available in the product. It uses the oids passed to get the specified attributes. The oid and attribute information is compiled into a string as JSON representation to be sent back as http response. Run time location:
<Windchill>\codebase\netmarkets\components\ defaultPickedDataFetcher.jsp
Author a JSP page named as <someObjectType>_picker.jsp. This JSP page must include a single step wizard using the wizard component of the Windchill Client Infrastructure. The jsp would look like this:
<%@ page errorPage="/netmarkets/jsp/util/error.jsp"%> <%@ page import=" . %> <jsp:useBean scope="request" > <!As the wizard step content might have a flexibility in presenting itself and can be controlled by the picker parameters, these parameters could be passed to the step using a bean with request scope <%@ include file="/netmarkets/util/beginPopup.jspf"%> <%@include file=/netmarkets/components/picker.jspf%> . .. .. <script language="JavaScript1.2"> <!sets a callback to javascript function on hitting ok action setUserSubmitFunction(onOK); </script> <%--> Wizard Step. <--%> <jca:wizard buttonList="OkCancelWizardButtons">
16-5
<jca:wizardStep action="<someObjectType>_picker_step " type="<someObjectType>"/> </jca:wizard> <!Javascript callback function for wizard OK action goes here <!- OK callback definition start .. <!OK callback definition end <%@ include file="/netmarkets/jsp/util/end.jspf"%>
The picker.jspf is needed to be included in the picker page always. It defines the following javascript window variables to track the pickerCallback and jcaPickerCallback functions. These windows variables are needed to be used in the OK action javascript user submit function . The setUserSubmitFunction is needed to be invoked to configure wizard OK action to invoke a javascript function. The javascript callback definition would be as well included in this page, the definition of this callback and any other definitions of functions the callback calls need to be placed preferably before the end.jspf is included.
Implement a Picker step
The picker step content would get defined by the codebase\netmarkets\< someObjectType >\<someObjectType>_picke_stepr.jsp. This step would render a search client or just a listing table to allow the user select the objects from. The details on how this could be done can be found out in the design pattern for Search Picker OR table component.
Provide definition of the javascript function to be invoked on OK action
The javascript callback definition would be as well included in this page, the definition of this callback and any other definitions of functions the callback calls need to be placed preferably before the end.jspf is included. This java script function has to fulfill the following responsibilities It would not have any arguments to it. It scans the page and sifts through the table or tree data to identify what objects have been selected, if any are selected builds an array of these objects. Invokes a pickedDataFetcher uri using AJAX and the array of objects selected passed over query string parameters as oid=<oid_value> parameters that the pickedDataFetcher URI can understand. The AJAX request returns the response
Use a picker
To use the existing picker, the user would have to perform the following procedures. Define the action to launch a picker
16-6
Create the visible input fields that need to be updated as a part of the picker interaction using the AbstractGuiComponent to the client page i.e. create_step_<step no>.jsp. See the Presenting Information in the UI chapter on page 13-1 for more information on how to use GUI components. The following describes how to add a textfield.
<% TextBox<SomeObjectType> name = new TextBox(); tab_tbox.setId("<SomeObjectType>Name_tbox_id"); tab_tbox.setName("<SomeObjectType>Name_tbox_id"); RenderingContext tab_rcontext = new RenderingContext(); %> <c-rt:set var="tbox" value="<%=<SomeObjectType> name %>"/> <c-rt:set var="tboxId" value="<%=<SomeObjectType> name .getId()%>"/>
Create the non-visible input fields that would be as well updated as a part of the picker interaction in the client page mentioned above.
<input id="<SomeObjectType>Reference" type="hidden" value=" " />
Use the PropertyPickerTag in client page, i.e. create_step_<step no>.jsp, utilizing the information from the Create HTML form elements to be updated using the picker section as follows
<p:propertyPicker propertyLabel="<SomeObject>" propertyField="${ tbox }" action=" launch<SomeObjectType>Picker " type="< myObjectType>"> <p:populate from="name" to="${ tboxId }" /> <p:populate from="oid" to="<SomeObjectType>Reference 2" /> <p:pickerParam name="pickerId" value="userPicker1" /> <p:pickerParam name="objectType" value="wt.org.WTUser" />
16-7
The above usage supposes that user would be interested in using the name and oid attributes from the information extracted for the pickedObject.
16-8
field
AbstractGuiComp onent
Yes
The AbstarctGuiComponent object like TextBox that would be used to render the form field that would be populated from picker object. The name of the action as it exists in actions.xml The type of the action for which the definition exists in actions.xml that would launch the picker. Rendering context to be used for the AbstractGuiComponent specified through a field attribute
name type
Yes Yes
renderingCont ext
RenderingContext
Yes
16-9
Parameter to
Default values
Possible values Any String value but adhering to HTML id attribute specification criteria
Required? Yes
Description HTML 'id' of the form input element to update on the parent page.
value
Yes
Sample Code
User can refer to the following code which is available in the product, it is a type picker. codebase\WEB-INF\tags\organizationPicker.tag - Defines the organizationPicker tag definition that uses internally the propertyPicker tag. Just a way to encapsulate abstract design concept. Following snippet of java scriptlet code, creates the visible and invisible form fields to be updated using the information from the picked objects
<%. String displayFieldId = id+SearchWebConstants.DISPLAY_FIELD_LABEL; RenderingContext rc = new RenderingContext(); TextBox tb = new TextBox(); tb.setId(displayFieldId); tb.setName(displayFieldId); tb.setValue(defaultValue);
16-10
if("true".equals(readOnlyPickerTextBox)) { tb.addJsAction("readonly","readonly"); } tb.setWidth(Integer.parseInt(pickerTextBoxLength)); tb.setMaxLength(Integer.parseInt(pickerTextBoxLength)); %> <input id="<%=id%>" name="<%=id%>" value="<%=defaultHiddenValue%>" type="hidden"/>
The following snippet of code propagates selectively the parameters passed to the organizationPicker tag to the propertyPicker tag
<p:propertyPicker label="${label}" field="${textbox}" action="callSearchPicker" type="search"> <p:populate from="${displayAttribute}" to="${displayFieldId}" /> <p:populate from="oid" to="${id}" /> <p:pickerParam name="pickerId" value="${id}" /> . </p:propertyPicker>
codebase\netmarkets\jsp\search\callSearchPicker.jsp - Defines the Picker Wizard codebase\netmarket\jsp\search\searchPicker.jsp - Defines the content for the Wizard step Following includes all the javascript code needed to manage the picker interaction.
<script language="javascript" src="<%=wncurl%>netmarkets/jsp/search/pickerSearch.js"> </script>
Following ensures that the search criteria and search results table are as well added to the step content.
<TABLE> <%@ include file="/netmarkets/jsp/search/pickerAttributes.jsp"%> .. <%@ include file="/netmarkets/jsp/search/searchResults.jsp"%> .
16-11
codebase\netmarkets\jsp\search\pickerSearch.js Defines the javascript functions needed to be used to manager this picker interaction Following javascript function defines the callback function being used on the Wizard OK action, it collects the selected objects using their oids and invokes the data fetcher URI using AJAX.
function getSelectedValue() { }
The AJAX callback function is defined below which is actually responsible to use the AJAX response as JSON object and populate information on the client page using the picker callback function
function updateParent() { . }
codebase\netmarkets\components\picker.jspf Defines picker interaction specific must include code, to be included in picker implementation. The following javascript snippet inserted in the jsp fragment ensures that certain javascript variables are always populated and available to be used in the Wizard OK action callback function.
<script type="text/javascript" > window.pickerCallback = "<%=request.getParameter("pickerCallback")%>"; window.pickedAttributes = "<%=request.getParameter("pickedAttributes")%>"; window.pickedDataFetcher = "<%=request.getParameter("pickedDataFetcher")%>"; </script> ..
Note: The user of the picker can as well specify his own set of callback function or data fetcher using the pickerParam tag <p:pickerParam name= pickerCallback value=myPickerCallback /> <p:pickerParam name= pickedDataFetcher value= jsp/components/myPickedDataFetcher.jsp />
16-12
Parameter
Default values
Possible values
Req?
Description
pickerCallback
jcaPickerCallBac k
no
The javascript callback function to be invoked by the picker page after the user has picked object(s) and activated ok action. This callback is defined in the client page and would accept a single argument only. If the client chooses for default acquisition for the data of the picked objects, then this argument would be an object with a property named pickedObject of type Array, each object of the Array being an object containing the properties of interest of the picked object. The array would have as many objects as the objects that the user has picked. The URI of the jsp page that would be delegated with a task of extracting the data for the picked objects and return the information in the form of a literal string using which the javascript object as understood by the callback function could be created.
pickedDataFetcher
URI
no
Following snippet ensures that all AJAX related javascript artifacts are available for re-use.
<script type="text/javascript" src="netmarkets/javascript/util/prototype.js"></script> <script type="text/javascript" src="netmarkets/javascript/components/wizard.js"></script> codebase\netmarkets\components\picker.jspf
16-13
Background
Configure a picker to only display a specific soft-type of parts (Product Areas). Allow user to enter criteria that includes name (not number) and library. Include criteria (that the user cannot see/edit) to retrieve libraries that are NOT in an state of obsolete AND that include certain specific words in the library description. The picker should show the product area name, not show its number, and also include the library that contains the part.
Scope/Applicability/Assumptions
Lets assume we need to launch a customized part picker from a JSP client which would have the capability to define the soft type as a seed for searching and also would respect seeded containers to search in. We would be using our OOTB item picker tag to launch it from a JSP page.
Intended Outcome
We should be able to launch an Item Picker which would be configured to search in for a soft type of part. This would have a name field as criteria for the picker where the user can filter results based on name of the part. The results table would contain customized view for this picker where the container and the name of the part would be shown. It would also respect seeded criteria which would filter the query based on criteria such that the part belongs to library which has certain words in the description and are not obsolete.
Solution
A custom JSP page would be written to launch this picker with appropriate seeded criteria. We would be using the Item Picker tag to launch the picker.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Basic development involving HTML forms, JSP, XML. Picker common components Table common component View creation
16-14
Solution Elements
Element Type Description
PickerAttributes.xml
XML
Runtime location - \codebase\pickerAttributes.xml Clear case location - \Windchill\DevModules\Search\ src_web\pickerAttributes.xml This file is used to customize the search criteria at picker page.
SearchResultsTable.pro perties.xconf
Xconf
Runtime location - \codebase\com\ptc\netmarkets\search\ SearchResultsTable.properties.xconf This file can be used to configure table view definition.
Procedure Customizing picker to have user defined criteria and result view
Customizing the picker search criteria
The search criteria for a picker can be customized by defining the attributes in PickerAttributes.xml file. This can be done by creating a new component id and then defining the search criteria as below.
<ComponentID id="customizedItemPickerForSoftPart"> <ObjectType id="WCTYPE|wt.part.WTPart|org.r_and_d.mypart"> <SearchCriteriaAttributes> <Attributes> <Name>name</Name> <DisplayName>NAME_LABEL</DisplayName> <IsSearchable>true</IsSearchable> </Attributes> </SearchCriteriaAttributes> </ObjectType> </ComponentID>
Here we have defined a new component id as customizedItemPickerForSoftPart. We have defined a single attribute to be searchable i.e. the name of the soft type.
Launching the picker with custom component id and user defined object type
The picker can be launched by passing the above component id to customize the search criteria as defined above.
<wctags:itemPicker id="customized_item_picker" objectType="WCTYPE| wt.part.WTPart|org.r_and_d.mypart" componentId=" customizedItemPickerForSoftPart "/>
We need to find objects within container based on some filter onto these containerss itself. Containers may be passed to the picker tag and objects would be queried within those containers only. The picker tag accepts a parameter named containerRef which can be a comma separated list of containers within
16-15
which we want to search. The container references can be passed as below. The comma separate list of the containers can be fetched by querying for containers in which the user wants to search.
<wctags:itemPicker id="genericPicker" objectType="WCTYPE| wt.part.WTPart|org.r_and_d.mypart" label="Part Picker using generic" containerRef="<container ref here>" componentId=" customizedItemPickerForSoftPart " showVersion="false"/>
Search result tables use the table common component and hence the column display can be configured by creating a new table view. Please refer [Crating Table View] for details regarding creating and configuring a new view. Then we can pass the view as below to the picker tab and search results table would be rendered with this view.
<wctags:itemPicker id="genericPicker" objectType="WCTYPE| wt.part.WTPart|org.r_and_d.mypart" label="Part Picker using generic" containerRef="<%=containerRefs.toString()%>" componentId="scenarioOnePicker" searchResultsViewId="wt.part.WTPart.customizedSearchView" showVersion="false"/>
The view id wt.part.WTPart.customizedSearchView should be configured to lookup the java class associated with this id which would define the table view. Please refer to configuring table views document. An example to configure this in SearchResultTable.properties.xconf file could be
<Service context="default" name="com.ptc.core.htmlcomp.tableview.ConfigurableTable"> <Option serviceClass="com.ptc.netmarkets.search.views.CustomizedPartVie w" requestor="java.lang.Object" selector=" wt.part.WTPart.customizedSearchView "/> </Service>
A new java class com.ptc.netmarkets.search.views.CustomizedPartView should be created which would define the view columns for this picker customization.
Sample Code
Launching the picker in <pickerlauncher>.jsp
<html> <body> <table> <tr> This is a customization where a hidden seed for container refs is feeded to the picker. </tr> <tr> <%-launching Item Masterpicker--%>
16-16
<wctags:itemPicker id="customPartPicker" objectType="WCTYPE|wt.part.WTPart|org.r_and_d.mypart" label="Custom Part Picker" containerRef="<%=containerRefs.toString()%>" componentId="scenarioOnePicker" searchResultsViewId="wt.part.WTPart.customizedSearchView" showVersion="false"/> </tr> </table> </body> </html>
The containerRefs passed above can be a list of comma separate containers from which we want to fetch the results. This parameter is optional and if not provided would launch picker to search in all containers.
16-17
Background
The context picker is used when you have a requirement to perform an operation that is based on certain context.
Scope/Applicability/Assumptions
It is assumed that your <MyPage>.jsp file in which you are putting tag includes /netmarkets/jsp/begin.jspf or /netmarkets/jsp/beginPopuf.jspf file and /netmarkets/jsp/end.jspf files.
Intended Outcome
You should see a text box and Find Button along with the specified label after using the tags for context picker. After clicking Find button, context picker will be launched.
16-18
On clicking Find button you should Context Picker for Project as:
Solution
Use the Context Picker Common Component in your JSP file to include Context Picker in your application.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Basic development involving JSP, JavaScript, Custom taglibs The management of RBINFO file customizations. Windchill xconfmanager concepts.
16-19
Solution Elements
Element
Type
Description
pickerAttributes.xml
XML file
You should use this file to customize the search criteria attributes for an object type for your picker. Runtime location: <WT_HOME>\codebase\ pickerAttributes.xml
searchClientResource.rbInfo
RBINFO file
You should use this file to localize the contents of the pickers. Runtime location: <WT_HOME>\src\com\ ptc\windchill\enterprise\search\client\ searchClientResource.rbInfo
contextPicker.tag
This file is contains the information about the supported parameters for this tag. Runtime location: <WT_HOME>\codebase\ WEB-INF\tags\itemPicker.tag
SearchableTypes.properties. xconf
You should specify component Id and corresponding object types in this file and then run xconfmanager. Runtime location: <WT_HOME>\codebase\com\ptc\ windchill\enterprise\search\server\ SearchableTypes.properties.xconf
custom.js
JavaScript file
You should specify custom pickerCallback function for picker in this file. Runtime location: <WT_HOME>\codebase\ netmarkets\jsp\search\custom.js
Note: You want to disable the type picker in the Context Picker.
16-20
Customization Points
Parameter id Default Value Possible Values Anything thats unique in a page Req? Yes Description An ID is associated with every picker in the calling application. This ID has to be unique for all pickers, whether of different types or same type, in one page. The id should not contain "." (dot) in the name. componentId determines the attributes that should appear in search criteria panel of the given picker. Name of the customized callback function that a user would have to implement. Its recommended that you should specify pickerCallback function in custom.js file Default value for textbox rendered by the picker. Default value of the hidden textbox associated with the picker. URL of the data fetcher file that will be used by the AJAX call to process the selected results. Label of the picker. Name of the attribute that should be the displayed in the picker textbox after selecting result from the context picker Value of the containerRef in which a user wants to restrict the search. Additional where clause if you want to filter search results on some specific criteria regardless of user input. This where clause will just get ANDed with the internal where clause. The title of picker.
componentId
pickerSearch
No
pickerCallback
Generated at the runtime if user has not specified this parameter (blank) (blank) <WebApp>/net markets/jsp/sear ch/pickedData.js p. Context Picker name
No
No No No
label displayAttribute
No No
containerRef baseWhereClaus e
(blank) (blank)
No No
pickerTitle
Contexts
Any value
No
16-21
Parameter editable
Req? No
Description This attribute defines whether you want to have Findbutton along with the textbox or not. This attribute defines whether the picker text box should be editable or not. This parameter is passed to define set of types that can be shown in Type Picker
false
true/false
No
Foundation.cont extPicker
No
inline
false
No
You should specify this parameter with value as true when you want to launch picker from a table level action or inline. This parameter contains a commaseparated list of the attributes that a user wants a picker to fetch. This is applicable only if inline is true. This parameter should be used to enable type picker in the picker. This parameter defines the picker type i.e. search picker or picker picker. In search picker, you will see search criteria in the picker and then you have to hit the search button to see the results however in case of picker picker you will directly see the results table without any search criteria. This parameter defines the length of the picker text box. This parameter allows user to define custom view id for the picker search results table. This parameter is used to define your own custom access controller. This parameter would accept the complete class name as the value. To specify multiple customAccessController you can pass on comma (,) separated list of the class names.
pickedAttributes
name
No
showTypePicker pickerType
true search
No No
25 (blank)
No No
(blank)
No
16-22
Parameter excludeSubType s
Req? No
Description This parameter is used to exclude sub types from the search.
Configuring Context Picker with your own typeComponentId in the type picker
<wctags:contextPicker id="contextPickerId" typeComponentId=" Foundation.myContextPickerComponentId" />
16-23
Background
The item picker is used when you have a requirement to select specific business object(s) depending upon certain criteria and use them in your application.
Scope/Applicability/Assumptions
It is assumed that your <MyPage>.jsp file in which you are putting tag includes /netmarkets/jsp/begin.jspf or /netmarkets/jsp/beginPopuf.jspf file and /netmarkets/jsp/end.jspf files.
Intended Outcome
You should see a text box and Find Button along with the specified label after using the tags for item picker. After clicking Find button, item picker will be launched.
16-24
Solution
Use the Item Picker Common Component in your JSP file to include Item Picker in your application.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Basic development involving JSP, JavaScript, Custom taglibs The management of RBINFO file customizations. Windchill xconfmanager concepts.
16-25
Solution Elements
Element pickerAttributes.xml
Description You should use this file to customize the search criteria attributes for an object type for your picker. Runtime location: <WT_HOME>\codebase\ pickerAttributes.xml
searchClientResource.rb Info
RBINFO file
You should use this file to localize the contents of the pickers. Runtime location: <WT_HOME>\src\com\ptc\ windchill\enterprise\search\client\ searchClientResource.rbInfo
itemPicker.tag
This file is contains the information about the supported parameters for this tag. Runtime location: <WT_HOME>\codebase\WEBINF\tags\itemPicker.tag
SearchableTypes.proper ties.xconf
You should specify component Id and corresponding object types in this file and then run xconfmanager. Runtime location: <WT_HOME>\codebase\com\ptc\windchill\ enterprise\search\server\ SearchableTypes.properties.xconf
custom.js
JavaScript file
You should specify custom pickerCallback function for picker in this file. Runtime location: <WT_HOME>\codebase\ netmarkets\jsp\search\custom.js
Note: You want to disable the type picker in the Item Picker.
16-26
Customization Points
Parameter id
Default Value
Req? Yes
Description An ID is associated with every picker in the calling application. This ID has to be unique for all pickers, whether of different types or same type, in one page. The id should not contain "." (dot) in the name. componentId determines the attributes that should appear in search criteria panel of the given picker.
componentId
pickerSearch
No
pickerCallba ck
Generated at the runtime if user has not specified this parameter (blank) (blank) <WebApp>/net markets/jsp/sear ch/pickedData.js p. Item Picker name
No
Name of the customized callback function that a user would have to implement. Its recommended that you should specify pickerCallback function in custom.js file Default value for textbox rendered by the picker. Default value of the hidden textbox associated with the picker. URL of the data fetcher file that will be used by the AJAX call to process the selected results. Label of the picker. Name of the attribute that should be the displayed in the picker textbox after selecting result from the item picker Value of the containerRef in which a user wants to restrict the search.
No No No
No No
(blank)
Any container
No
16-27
Req? No
Description Additional where clause if you want to filter search results on some specific criteria regardless of user input. This where clause will just get ANDed with the internal where clause. If you want to specify different baseWhereClause for say, Part and Document, then you can do so using following syntax: wt.part.WTPart$SEP$<where clause that will get ANDed with internal whereClause>$OBJ$wt.doc.WTDocum ent$SEP$<where clause that will get ANDed with internal whereClause>. If you dont specify the object type then the one supplied will be used for all the object type. The title of picker. This attribute defines whether you want to have Findbutton along with the textbox or not. This attribute defines whether the picker text box should be editable or not. This parameter is passed to define set of types that can be shown in Type Picker
pickerTitle editable
Item true
No No
No No
inline
false
No
You should specify this parameter with value as true when you want to launch picker from a table level action or inline. This parameter contains a commaseparated list of the attributes that a user wants a picker to fetch. This is applicable only if inline is true. This parameter determines whether to display version/iteration attributes in search criteria or not. This attribute determines the default object type in the item picker. This parameter should be used to enable type picker in the picker.
pickedAttrib utes
name
No
showVersion
true
No
wt.fc.Persistable true
No No
16-28
Parameter pickerType
Req? No
Description This parameter defines the picker type i.e. search picker or picker picker. In search picker, you will see search criteria in the picker and then you have to hit the search button to see the results however in case of picker picker you will directly see the results table without any search criteria. This parameter defines the length of the picker text box. This parameter allows user to define custom view id for the picker search results table. This parameter is used to define your own custom access controller. This parameter would accept the complete class name as the value. To specify multiple customAccessController you can pass on comma (,) separated list of the class names. This parameter is used to exclude sub types from the search.
25 (blank)
No No
(blank)
No
excludeSubT ypes
(blank)
No
Configuring Item Picker with your own typeComponentId in the type picker
<wctags:itemPicker id="itemPicker" typeComponentId=" Foundation.myPickerComponentId" />
16-29
16-30
Background
The organization picker is used when you have a requirement to select specific organization(s) depending upon certain criteria and use them in your application. Typical use case could be that you may want to find parts that are available in particular organization. In this case, you can have a organization picker and then through this you can select the organization and pass it on to the search criteria to perform search for parts.
Scope/Applicability/Assumptions
It is assumed that your <MyPage>.jsp file in which you are putting tag includes /netmarkets/jsp/begin.jspf or /netmarkets/jsp/beginPopuf.jspf file and /netmarkets/jsp/end.jspf files.
Intended Outcome
You should see a text box and Find Button along with the specified label after using the tags for organization picker. After clicking Find button, user picker will be launched.
16-31
Solution
Use the Organization Picker Common Component in your JSP file to include Organization Picker in your application.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Basic development involving JSP, JavaScript, Custom taglibs The management of RBINFO file customizations. Windchill xconfmanager concepts.
16-32
Solution Elements
Element
Type
Description
pickerAttributes.xml
XML file
You should use this file to customize the search criteria attributes for an object type for your picker. Runtime location: <WT_HOME>\codebase\ pickerAttributes.xml
searchClientResource.rbInfo
RBINFO file
You should use this file to localize the contents of the pickers. Runtime location: <WT_HOME>\src\com\ptc\ windchill\enterprise\search\ client\ searchClientResource.rbInfo
organizationPicker.tag
This file is contains the information about the supported parameters for this tag. Runtime location: <WT_HOME>\codebase\ WEB-INF\tags\userPicker.tag
custom.js
JavaScript file
You should specify custom pickerCallback function for picker in this file. Runtime location:
<WT_HOME>\codebase\ netmarkets\jsp\search\ custom.js
16-33
Customization Points
Parameter id
Default Value
Req? Yes
Description An ID is associated with every picker in the calling application. This ID has to be unique for all pickers, whether of different types or same type, in one page. The id should not contain "." (dot) in the name. componentId determines the attributes that should appear in search criteria panel of the given picker.
componentId
pickerSear ch
Any valid component id specified in pickerAttributes. xml Name of the callback function
No
pickerCallback
Generated at the runtime if user has not specified this parameter (blank) (blank) <WebApp >/netmark ets/jsp/sear ch/picked Data.jsp. Organizati on Picker Name
No
Name of the customized callback function that a user would have to implement. Its recommended that you should specify pickerCallback function in custom.js file
No No No
Default value for textbox rendered by the picker. Default value of the hidden textbox associated with the picker. URL of the data fetcher file that will be used by the AJAX call to process the selected results.
label displayAttribute
No No
Label of the picker. Name of the attribute that should be the displayed in the picker textbox after selecting result from the organization picker Value of the containerRef in which a user wants to restrict the search.
containerRef
(blank)
Any container
No
16-34
Parameter baseWhereClause
Req? No
Description Additional where clause if you want to filter search results on some specific criteria regardless of user input. This where clause will just get ANDed with the internal where clause. The title of picker. This attribute defines whether you want to have Findbutton along with the textbox or not. This attribute defines whether the picker text box should be editable or not. You should specify this parameter with value as true when you want to launch picker from a table level action or inline. This parameter contains a commaseparated list of the attributes that a user wants a picker to fetch. This is applicable only if inline is true. This parameter defines the picker type i.e. search picker or picker picker. In search picker, you will see search criteria in the picker and then you have to hit the search button to see the results however in case of picker picker you will directly see the results table without any search criteria. This parameter defines the length of the picker text box. This parameter allows user to define custom view id for the picker search results table. This parameter is used to define your own custom access controller. This parameter would accept the complete class name as the value. To specify multiple customAccessController you can pass on comma (,) separated list of the class names.
pickerTitle editable
Organizati on true
No No
false false
true/false true/false
No No
pickedAttributes
yesname
No
pickerType
search
No
25 (blank)
No No
(blank)
No
16-35
16-36
The application developer can control following features of the picker Picker Default values population Picker Action Definition Selected elements population on Target element
16-37
Example:
<p:typePicker id="document_type_picker" label="Type : " mode="SEARCH"> <p:pickerParam name="select" value="single" /> <p:pickerParam name="format" value="dropdown" /> <p:pickerParam name="defaultType" value="All Types" /> <p:pickerParam name="type" value="BOTH" /> <p:pickerParam name="displayHierarchy" value="false" /> <p:pickerParam name="showRoot" value="true" /> </p:typePicker>
In the above example a simple drop down type picker is defined with. Attributes: Id - This is required attribute used to distinguish between multiple TypePickers Label - Picker Label Mode Defines the mode in which the picker can be used. Default is SEARCH.
There are other optional attributes for this picker which are listed at the end of this section. Parameters: Select It has two possible values single and multi. Default is single.
16-38
defaultType Specifies the default value to be displayed. It accepts valid logical or external representation of Windchill Type Identifiers. It supports multiple values for multi select pickers and a single value for single select pickers. Type Possible values are ROOT_TYPES - only seeded types SOFT_TYPES - only soft types BOTH - Modeled and soft types (default value)
displayHierarchy It displays the picker elements in hierarchy. It is valid only for drop down format. It is false by default. showRoot - Accepts String representation of Boolean value. Shows the seedTypes as I level elements.</font></font>
There are other optional parameters for this picker which are listed at the end of this section.
Tree Format
In the tree format implementation the Picker Label, the Target element and find button are displayed. On the find button click event a popup window pops up with Windchill Type Identifiers displayed in tree format. If one or more types are selected and ok button is hit the selected value(s) are populated in to target element. If any type identifiers are present in the target element and user hits the find button then the type identifiers in the target element appear as pre-selected values in the tree, provided that the types are valid logical or external representation of Windchill Type Identifiers. If cancel button is hit in the popup
16-39
window no selection is done from the popup window and the target element contents remain unchanged.
Example:
<p:typePicker id="document_typePicker" label="Type : "> <p:pickerParam name="format" value="tree" /> <p:pickerParam name="defaultType" value="wt.doc.WTDocument| com.ptc.www.Agenda" /> <p:pickerParam name="defaultType" value="wt.doc.WTDocument| com.ptc.www.Plan" /> <p:pickerParam name="defaultType" value="WCTYPE| wt.pdmlink.PDMLinkProduct|Sub Product3" /> <p:pickerParam name="seedType" value="wt.doc.WTDocument" /> <p:pickerParam name="type" value="BOTH" /> <p:pickerParam name="showRoot" value="true" /> <p:pickerParam name="appOption" value="Mera Type$WCTYPE| wt.pdmlink.PDMLinkProduct|Sub Product3" /> </p:typePicker>
16-40
Table Format
In the table format of type picker the type identifiers are displayed in tabular format. The working of the Picker Label, the Target element and find button is same as in the case of Tree format except that, on the find button click event a popup window pops up with Windchill Type Identifiers displayed in tabular format. User can select one or more values and hit OK / Cancel button. Example:<p:typePicker id=" document_typePicker" label="Type : " > <p:pickerParam name="defaultType" value="wt.doc.WTDocument" /> <p:pickerParam name="seedType" value="wt.doc.WTDocument" /> <p:pickerParam name="format" value="table" /> <p:pickerParam name="type" value="BOTH" /> <p:pickerParam name="showRoot" value="true" /> </p:typePicker>
Overview
The TypePicker is defined with the help of TypePicker Tag. The attribute and parameter values supplied are used to populate an object of type TypeBean. This bean is used to carry the user-supplied information across. The different phases involved in a TypePicker component are as follows.
16-41
Ok Wizard action
If no element is selected, a JavaScript warning is displayed and the pop-up stays.</font></font> If some element is selected then it makes an Ajax call to the jsp specified via the pickerDataFetcher. The jsp will fetch all the selected elements that need to be populated in the target element. Calls pickerCallBack available in the calling jsp Update Target Element Close the pop-up
16-42
Customization Points
You can customize following areas of type picker. Target element Definition Picker Default values population Picker Action Definition Selected elements population on Target element Picker Element Content population
Single Multi
16-43
You can provide your own pickerCallBack function with following conditions The function signature should be user_call_back_function(JSON_Object, TypePicker_Id, TargetElement_Id). The function should be available where type picker component is inserted.
You can provide your own pickerDataFetcher function with following conditions It is to be a jsp file located in the <Windchill>/codebase and relative path is to be provided. It is not applicable for drop down.
id label mode
A required value. Used to distinguish between the multiple Type-Picker usages in a page Picker Label Defines in which mode the Type-Picker is going to be used. It should be one of the value defined in com.ptc.core.ui.resources.ComponentMode. Default value is SEARCH Target Element into which the picked element attribute will be populated. It should be a subclass of com.ptc.core.components.rendering.AbstractG uiComponent. Currently support TextBox and ComboBox. If not supplied the component will create a Target Element for the user
field
field ="${target_element}"
16-44
Attribute
Example
Description
renderContext
renderContext ="${rcontext}"
Object should be an instance of com.ptc.core.components.rendering.Rendering Context. If not supplied the component will create one for the user This is the objecttype in which the picker action is specified in *actions.xml (<Windchill>\ codebase\config\actions\EnterpriseUIactions.xml) This is the action name that is specified in *actions.xml for the picker action
objectType
actionName
The Following table describes all the supported parameters of a Type Picker Common Component.
Parameter Example Description
adminDomainRef
String representation of the administrative domain reference (wt.admin.AdminDomainRef). Used to check access control rights. String representation of the container reference (wt.inf.container.WTContainerRef). Used to populate types specified for this container String representation of State. (wt.lifecycle.State). Used while checking access control rights Accepts valid logical or external representation of Windchill Type Identifiers Multiple values supported. Required for mode = CREATE/EDIT/VIEW Accepts valid logical or external representation of Windchill Type Identifiers. Multiple values supported. The type and its descendants are filtered out from the picker element
containerRef
lifeCycleState
value ="RELEASED"
seedType
value = wt.part.WTPart
filterType
value ="coolPart"
16-45
Parameter
Example
Description
defaultType
value = wt.part.WTPart
For single select, it should be only one value. Accepts valid logical or external representation of Windchill Type Identifiers. Multiple values supported. It can support blank, "Select a Type" etc values also Localized Display name and value separated by a $ delimiter. Multiple values supported. It should be one of the enum constant value defined in com.ptc.windchill.enterprise.picker.type.s erver.TypePickerFormat. Possible values are dropdown, table, tree. Default value is dropdown Possible values are single and multi, the former being the default. It should be one of the enum constant value defined in com.ptc.windchill.enterprise.picker.type.s erver.TypePickerTypes. Possible values are ROOT_TYPES (only seedTypes will be displayed),SOFT_TYPES (only SOFT Types will be displayed), BOTH (MODELED & SOFT Types will be displayed) Default value is BOTH Accepts String representation of Boolean value. Valid only for dropdown format. Presents picker elements in hierarchy. Default value is false Accepts String representation of Boolean value. If true - only instantiables will be displayed. If false both instantiables and non-instantiables will be displayed. Default value is false Accepts String representation of Boolean value. Shows the seedTypes as I level elements
appOption
format
select type
displayHierarchy
value=true
showInstantiable
value=false
showRoot
value=true
16-46
Parameter
Example
Description
componentId
value=
ComponentId is defined as 'APP_ID+. +COMPONENT_NAME' . Valid APP_IDs are ProjectLink, Foundation, or PDMLink. Used for mode = "SEARCH" to find the I level types from <Windchill>\ codebase\com\ptc\windchill\enterprise\ search\server\SearchableTypes.properties. Passing null will default to Foundation.allSearch (Default)
16-47
\wcEnterprise\EnterpriseUI\src\com\ptc\windchill\enterprise\picker\type\ dataUtilities\type.dataUtilities.cat \wcEnterprise\EnterpriseUI\src\com\ptc\windchill\enterprise\picker\type\ dataUtilities\TypePickerNmObjectUtility.java \wcEnterprise\EnterpriseUI\src\com\ptc\windchill\enterprise\picker\type\ dataUtilities\TypePickerTreeHandler.java \wcEnterprise\EnterpriseUI\src\com\ptc\windchill\enterprise\picker\type\ server\server.mData \wcEnterprise\EnterpriseUI\src\com\ptc\windchill\enterprise\picker\type\ server\type.server.cat \wcEnterprise\EnterpriseUI\src\com\ptc\windchill\enterprise\picker\type\ server\StandardTypePickerService.java \wcEnterprise\EnterpriseUI\src\com\ptc\windchill\enterprise\picker\type\ server\TypePickerBean.java \wcEnterprise\EnterpriseUI\src\com\ptc\windchill\enterprise\picker\type\ server\TypePickerData.java \wcEnterprise\EnterpriseUI\src\com\ptc\windchill\enterprise\picker\type\ server\TypePickerFormat.java \wcEnterprise\EnterpriseUI\src\com\ptc\windchill\enterprise\picker\type\ server\TypePickerHelper.java \wcEnterprise\EnterpriseUI\src\com\ptc\windchill\enterprise\picker\type\ server\TypePickerServiceFwd.java \wcEnterprise\EnterpriseUI\src\com\ptc\windchill\enterprise\picker\type\ server\TypePickerService.java \wcEnterprise\EnterpriseUI\src\com\ptc\windchill\enterprise\picker\type\ server\TypePickerTreeModel.java \wcEnterprise\EnterpriseUI\src\com\ptc\windchill\enterprise\picker\type\ server\TypePickerTypes.java
JSP files
\wcEnterprise\EnterpriseUI\src_web\netmarkets\jsp\typepicker\ typePicker.jsp \wcEnterprise\EnterpriseUI\src_web\netmarkets\jsp\typepicker\ typePicker_dataFetcher.jsp \wcEnterprise\EnterpriseUI\src_web\netmarkets\jsp\typepicker\ typePicker_doer.jspf \wcEnterprise\EnterpriseUI\src_web\netmarkets\jsp\typepicker\ typePicker_includes.jspf
16-48
16-49
Background
The user picker is used when you have a requirement to select specific user(s) depending upon certain criteria and use them in your application. Typical use case could be that you may want to find parts which are created by certain user. In this case you can a user picker and then through this you can select the user and pass it on to the search criteria to perform search for parts.
Scope/Applicability/Assumptions
It is assumed that your <MyPage>.jsp file in which you are putting tag includes /netmarkets/jsp/begin.jspf or /netmarkets/jsp/beginPopuf.jspf file and /netmarkets/jsp/end.jspf files.
Intended Outcome
You should see a text box and Find Button along with the specified label after using the tags for user picker. After clicking Find button, user picker will be launched.
16-50
Solution
Use the User Picker Common Component in your JSP file to include User Picker in your application.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Basic development involving JSP, JavaScript, Custom taglibs The management of RBINFO file customizations. Windchill xconfmanager concepts.
16-51
Solution Elements
Element
Type
Description
pickerAttributes.xml
XML file
You should use this file to customize the search criteria attributes for an object type for your picker. Runtime location: <WT_HOME>\codebase\ pickerAttributes.xml
searchClientResource.rbInfo
RBINFO file
You should use this file to localize the contents of the pickers. Runtime location: <WT_HOME>\src\com\ptc\ windchill\enterprise\search\ client\ searchClientResource.rbInfo
userPicker.tag
This file is contains the information about the supported parameters for this tag. Runtime location:
<WT_HOME>\codebase\WEBINF\tags\userPicker.tag
custom.js
JavaScript file
You should specify custom pickerCallback function for picker in this file. Runtime location: <WT_HOME>\codebase\ netmarkets\jsp\search\ custom.js
16-52
Customization Points
Parameter id
Default Value
Req? Yes
Description An ID is associated with every picker in the calling application. This ID has to be unique for all pickers, whether of different types or same type, in one page. The id should not contain "." (dot) in the name. componentId determines the attributes that should appear in search criteria panel of the given picker. Name of the customized callback function that a user would have to implement. Its recommended that you should specify pickerCallback function in custom.js file Default value for textbox rendered by the picker. Default value of the hidden textbox associated with the picker. URL of the data fetcher file that will be used by the AJAX call to process the selected results. Label of the picker. Name of the attribute that should be the displayed in the picker textbox after selecting result from the user picker Value of the containerRef in which a user wants to restrict the search.
componentId
pickerSearch
Any valid component id specified in pickerAttribut es.xml Name of the callback function
No
pickerCallback
No
defaultValue defaultHiddenValue
(blank) (blank)
No No
pickedDataFetcher
No
label displayAttribute
No No
containerRef
(blank)
Any container
No
16-53
Parameter baseWhereClause
Req? No
Description Additional where clause if you want to filter search results on some specific criteria regardless of user input. This where clause will just get ANDed with the internal where clause. The title of picker. This attribute defines whether you want to have Findbutton along with the textbox or not. This attribute defines whether the picker text box should be editable or not. You should specify this parameter with value as true when you want to launch picker from a table level action or inline. This parameter contains a comma-separated list of the attributes that a user wants a picker to fetch. This is applicable only if inline is true. This parameter defines the picker type i.e. search picker or picker picker. In search picker, you will see search criteria in the picker and then you have to hit the search button to see the results however in case of picker picker you will directly see the results table without any search criteria. This parameter defines the length of the picker text box. This parameter allows user to define custom view id for the picker search results table.
pickerTitle editable
User true
No No
readOnlyPickerTextB ox inline
false
true/false
No
false
true/false
No
pickedAttributes
fullName
No
pickerType
search
search/picker
No
pickerTextBoxLength searchResultsViewId
25 (blank)
No No
16-54
Parameter customAccessControll er
Req? No
Description This parameter is used to define your own custom access controller. This parameter would accept the complete class name as the value. To specify multiple customAccessController you can pass on comma (,) separated list of the class names. This parameter is used to restrict the user search to active/deleted/active and deleted users only. This parameter is used to enable role drop down in user picker. If you want to use this parameter then you should specify the containerRef parameter from where the roles have to be fetched.
showUserType
ActiveOnly
No
showRoles
false
true/false
No
16-55
16-56
Background
The current way of picking of participants is limited to Users, Groups, and is not consistent across Windchill. The new Participant Picker Common Component gives consistent behavior across Windchill. Participant Picker gives you the ability to search Participants of type User, Group, and Organization. It provides a wide variety of search scope criteria using which you can narrow down the search.
Scope/Applicability/Assumptions
Using in Windchill Client Architecture table: You should define a Windchill Client Architecture action, and point the action to a JSP page that has participant picker tag. Provide the required attributes action Class and action Method to the participant picker tag. Add the Windchill Client Architecture action you created to the desired Windchill Client Architecture table. When you click the action, it will launch the Participant Picker Wizard. Select desired participant and click OK. The Picker will invoke the action Method of the action Class that you have provided. In that method, you will consume or process the selected participant in a desired way. Using Participant Picker in combination with Property Picker: The assumption is that you know how to use the Property Picker. The action attribute of your Property Picker should point to the JSP page that has participant picker tag. The required attribute action Class should (empty) and action Method should be JavaScript:${pickerCallback}(). ${pickerCallback} is the pickerCallback JavaScript function that you supplied to Property Picker. After you select the desired participants and click OK in the wizard, your pickerCallback JavaScript function will be invoked with JSON object containing the picked participants.
Intended Outcome
The selected participants are either populated in Windchill Client Architecture table, or a populated in text box of Property Picker.
Solution
Use the Participant Picker to search for participants, and add the selected participants to a Windchill Client Architecture table or text box in a Property Picker.
16-57
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: How to add Windchill Client Architecture actions to a Windchill Client Architecture table, how to dynamically update the table with selected participants. How to configure a Property Picker, how to author JavaScript picker Callback functions.
Solution Elements
Element
Type
Description
actionClass
Tag Attribute
Name of the action class that needs to be invoked for processing the selected Participants. Name of the action method that needs to be invoked for processing the selected Participants. This can take values "single" / "multi". When this is set to "single", one can select only one Participant at a time. Default is "multi". If this attribute is not passed or set to "multi", Picker will enable to select multiple Participants. Use this to set the default to any Participant type. The class com.ptc.core.components.bean s. PrincipalBean has four string constants defined, which one can be pass to this attribute. The constants are ALL_PARTICIPANT, USER, GROUP and ORG.
actionMethod
Tag Attribute
select
Tag Attribute
participantType
Tag Attribute
16-58
Element
Type
Description
singleParticipantType
Tag Attribute
Use this to set the default Participant type specified in the tag attribute participantType as the only supported type. This takes value true/false. When set to true, it will restrict to single type specified as in the attribute participantType. When set to false or left unspecified, the picker supports participant types ALL_PARTICIPANT, USER, GROUP, ORG. This map contains key, value pairs of association to be displayed in association drop down list. Keys are Java String literals that are returned to the user upon selection of any association. Value is a localized string that is displayed in association drop down list. The association you desire to be pre selected in the dropdown should be passed in this attribute. The localized string for Display Label of the association. Set this to "true" to get email Textbox rendered. You can type any comma or space separated emails that you desire to invite.
associationMap
Tag Attribute
defaultAssociation
Tag Attribute
associationLabel emailAllowed
16-59
Element
Type
Description
contextMap
Tag Attribute
The List of Context in which you wants to perform Search In. This map contains key, value pairs of contexts to be displayed in Search In drop down list. Keys are Java String literals that represent oid of the Windchill object. Value is a localized string that is displayed in Search In drop down list. The context you desire to be pre selected in the dropdown should be passed in this attribute. LDAP server's list is passed, to perform search. Default this attribute is not supplied. This map contains key, value pairs of contexts to be displayed in Service drop down list. Keys are Java String literals that represent the LDAP Server. Value is a localized string that is displayed in Service drop down list.
defaultContext
Tag Attribute
serviceMap
Tag Attribute
16-60
Customization Points
Parameter select
Req? No
Description There is a need to have the picker return only a single Principal, thus, the Apply button does not appear. Not all clients will allow an email string to be returned from the picker, some clients will only allow Principal objects to be returned.
emailAllowed
false
true/ false
No
16-61
Req? No No
Description Some clients want users to be able to assign Principals to create an assignment when selecting principals (such as role assignment, task assignment, etc.) If an assignment is desired along with the principal choice, there is a need to show this list. The client must be able to specify the label name, dropdown list choices, and default value for the dropdown. Not all clients that will use the picker will need the same set of Principal types. Some clients may only except certain types to be returned from the picker In Administrative clients its necessary to be able to select a specific context and have the Principals returned from that context, and from its parent contexts (i.e. the organization and site that contain the specified container) If there is only a single Search In context, the value should be displayed as read-only text (no dropdown).
associationLabel Empty No
singleParticipantT ype
Empty
true/ false
No
contextMap defaultContext
Empty Empty
No No
serviceMap
Empty
No
A specific parameter will have to be set by the application using the picker to specify that this attribute should be shown. This attribute is used to pick a specific LDAP to find Principals in. This attribute is primarily used by/in Administrative user interfaces where the end user knows which LDAP server they are interested in searching against. Label should be Service: when this is displayed.
16-62
You perform a search based on search criteria. Move desired participants to Participant List and click OK. The component invokes actionClass and actionMethod provided as attributes to the participant picker tag. You need to write actionMethod in the actionClass. Example code is given below.
16-63
public class NmPrincipalCommands2 implements Externalizable { public static ArrayList addPrincipal( NmCommandBean cb ) throws WTException { ArrayList list = new ArrayList(); String users = cb.getTextParameter(PrincipalBean.PARAM_SELECTED_PRINCIPALS); if (users != null) { int start = 0; int pos = users.indexOf("#", start); while (pos != -1) { String user = users.substring(start, pos); list.add(user); start = pos+1; pos = users.indexOf("#", start); } } } }
You should write a static method as actionMethod. It will take only one argument i.e., NmCommandBean. The selected participants are sent to this method as text parameters. With in the component these values are stored in hidden variable. The name of the hidden variable is defined as a static String in com.ptc.windchill.enterprise.picker.principal.PrincipalBean. To extract selected participants use PrincipalBean.PARAM_SELECTED_PRINCIPALS. This will return # separated DN (Distinguished Name).
Adding Association
To add association in the Participant picker, you need to provide three attributes as highlighted in the following sample. The attribute associationMap takes LinkedHashMap. You supply the key, value pairs to this map. Keys are the java String literals. When user selects an association, this key String literal is passed back to the actionMethod as text Parameter. Values are localized string displayed in the dropdown list. Component uses LinkedHashMap to retain the order in which the key value pairs are added while displaying in the dropdown list.
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%@ taglib uri="http://www.ptc.com/windchill/taglib/components" prefix="jca"%> <%@ page import="java.util.LinkedHashMap"%> <%@ page import = "com.ptc.windchill.enterprise.picker.principal.PrincipalBean"%> <% LinkedHashMap associationMap = new LinkedHashMap(); associationMap.put("GUEST", "Guest"); associationMap.put("MEMBERS", "Members"); associationMap.put("PROJECT MANAGER", "Project Manager"); %> <c:set var="associationMap" value="<%= associationMap %>"/> <c:set var="participantType" value="<%= PrincipalBean.USER %>"/> <jca:participantPicker actionClass="com.ptc.netmarkets.principal.NmPrincipalCommands2"
16-64
The above code will render association dropdown as shown in the following figure.
In the above example, you are trying to add a role to the participant. You move the desired participants to Participants List, select a role from the association list and click OK. The actionMethod code will now look like this.
public class NmPrincipalCommands2 implements Externalizable { public static ArrayList addPrincipal( NmCommandBean cb ) throws WTException { ArrayList list = new ArrayList(); String users = cb.getTextParameter(PrincipalBean.PARAM_SELECTED_PRINCIPALS); if (users != null) { int start = 0; int pos = users.indexOf("#", start); while (pos != -1) { String user = users.substring(start, pos); list.add(user); start = pos+1; pos = users.indexOf("#", start); } String role = cb.getTextParameter(PrincipalBean.PARAM_ASSOCIATION); ArrayList result = NmRoleHelper.service.addUsersToRole(cb, role, list); } return result; } }
You can extract the selected association from text parameter as highlighted in the above code.
16-65
The above code will render the email subscription field as shown in the following figure.
Sample JSP to launch the Picker and send back the picker values to a Textbox.
You can use Property Picker tag to render a Textbox and Find button to launch Participant Picker. The Find button has to declared in actions.xml as described in the above sections. The Property Picker by default provides a JavaScript call back function that will be invoked by the picker to send back the picked values from any picker. Property Picker also has an ability to define custom JavaScript function that can be invoked by pickers. For example:
<p:propertyPicker label="${label}" field="${textbox}" action="participantPickerSample2" type="participantpicker"> <p:populate from="${displayAttribute}" to="${displayFieldId}" /> <p:populate from="oid" to="${id}" /> <p:pickerParam name="pickerId" value="${id}" /> <p:pickerParam name="objectType" value="wt.org.WTGroup" /> <p:pickerParam name="componentId" value="${componentId}" /> <p:pickerParam name="pickedDataFetcher" value="${pickedDataFetcher}" /> <p:pickerParam name="pickerCallback" value="${pickerCallBack}" /> <p:pickerParam name="containerRef" value="${containerRef}" /> <p:pickerParam name="baseWhereClause" value="${baseWhereClause}" /> <p:pickerParam name="pickerTitle" value="${pickerTitle}" /> <p:pickerParam name="multiSelect" value="${multiSelect}" /> </p:propertyPicker>
16-66
Coming back to the Participant Picker, one can get the callback JavaScript function name as request parameter, when Participant Picker is launched from Property Picker.
<c:set var="pickerCallback" value="<%=request.getParameter("pickerCallback")%>"/> <jca:participantPicker actionClass="" actionMethod="JavaScript:${pickerCallback}()" participantType="<%= PrincipalBean.GROUP %>" <jca:participantPicker>
We pass a blank string to the actionClass attribute of Participant Picker. The JavaScript call back function name that we got from the request parameter is appended to the string JavaScript: and passed as value to actionMethod. This string JavaScript: is used internally in the picker to identify, as PickerCallBack mechanism is needed. When user selects the desired participants and clicks OK, the values are sent back to the JavaScript function as JSON object (as defined in Property Picker).
16-67
16-68
17
JSP Customization Scenarios
This chapter details various customization scenarios. Topic Page
Configuring a Picker to Offer Only Specific Soft Types Based on User-specified Criteria including Restricted Life Cycle States.................................................17-2 Building a Picker that Enables Users to Select Projects from an External Project DB .....................................................................................................................17-8 Pickers from table toolbar ...............................................................................17-13 Generating HTML Tags for ProductView Visualization Within a JSP Page .17-16
17-1
Configuring a Picker to Offer Only Specific Soft Types Based on User-specified Criteria including Restricted Life Cycle States
Objective
Configure a picker to only display a specific soft-type of parts (Datecode Release). Allow user to enter criteria which includes name, library and lifecycle state. The states shown to the user must only be ones that represent a state that the objects can have, not all LC states in the system. The user to be able to pick a value for the attribute "Release Stream" (Windchill 8.0, 9.0, etc). The picker should show the datecode name, not show its number, and also include the library that contains the part. The picker will be used in the process to create Affected Data relationships for a Change Request. Associated requirements:
Background
Invoking a picker with customized seeded criteria. Customizing the columns of a table
Problem scenario represents common customization scenario for Item Picker. Picker is common UI component used for searching for referenced objects and selecting one or more of them on calling application. You can customize criteria attributes and result table columns shown in picker. You can configure Item Picker to search for single or multiple object types. You can restrict search to only in particular container or container types.
Scope/Applicability/Assumptions
Item Picker can be launched from any JSP page using ItemPicker tag. Picker returns picked objects as a Jason object by calling JavaScript function on calling page. It is the responsibility of calling page to further act on this Jason object. Soft type of Part is Date code so its fully qualified external form would be like WCTYPE|wt.part.WTPart|org.r_and_d.DatecodeRelese
Intended Outcome
Datecode Release picker with Name, context and State as criteria attributes:
17-2
Solution
A custom JSP tag with appropriate parameters would be used to launch customized Item Picker. To choose the Library, Library Picker would be used.
Prerequisite knowledge
Using JSP tags Using xconfManager Updating XML document. Using rbInfo files
Description Location: <Windchill>\ codebase Location: <Windchill>\ codebase\ com\ptc\windchill\ enterprise\ search\server\ SearchableTypes.properties.xc onf
17-3
Element
Description Add your callback function in this file. Location: <Windchill>\ codebase\ WEB-INF\tags\ itemPicker.tag
itemPicker.tag
JSP tag
To show Item Picker you can use ItemPicker tag as shown below:
<%@ taglib prefix="wctags" tagdir="/WEB-INF/tags" %> <tr> <%-launching Item picker--%>
<wctags:itemPicker id="myItemPicker" label="Custom Item Picker" pickerTitle="Datecode Release" showVersion="false" objectType=" WCTYPE|wt.part.WTPart|org.r_and_d.myPart " showTypePicker="false" componentId="test.Customization" typeComponentId="Foundation.customization" searchResultsViewId="wt.part.WTPart.customizedSearchView"/> </tr> .
The important parameter are described below: ObjectType Fully qualified external form name of the object. ComponentId componentId to be used for configuring criteria attributes. See section below for details TypeComponentId - used for defining set of types and container types to be searched for. In our case this parameter is used to constraint our search only within Library containers.
17-4
ComponentId is resolved from pickerAttributes.xml file to pick up the list of attributes to be shown in picker criteria. Update pickerAttributes.xml as below:
<PickerAttributes> <ComponentID id="test.Customization"> <ObjectType id="WCTYPE|wt.part.WTPart| org.r_and_d.myPart"> <SearchCriteriaAttributes> <Attributes> <Name>name</Name> <DisplayName>NAME_LABEL</DisplayName> <IsSearchable>true</IsSearchable> </Attributes> <Attributes> <Name>containerRef</Name> <DisplayName>CONTEXT_LABEL</DisplayName> <IsSearchable>false</IsSearchable> </Attributes> <Attributes> <Name>state.state</Name> <DisplayName>STATE_LABEL</DisplayName> <IsSearchable>true</IsSearchable> </Attributes> </SearchCriteriaAttributes> </ObjectType> </ComponentID> </PickerAttributes>
Here we have defined search criteria attributes as name, context and state. DisplayName is resolved from rbInfo file : com\ptc\windchill\enterprise\search\ client\searchClientResource.rbInfo
Defining typeComponentId for constraining search to given container types
As per problem statement, we need to search only with in Library containers. This is achieved by passing typeComponentId. To configure typeComponentId add below property to <Windchill>\codebase\com\ptc\windchill\enterprise\search\ server\SearchableTypes.properties.xconf
17-5
Search result tables use the Windchill R9.0 table common component and hence the column display can be configured by creating a new table view. Please refer [Crating Table View] for details regarding creating and configuring a new view. Then we can pass the view as below to the picker tab and search results table would be rendered with this view.
<wctags:itemPicker id="genericPicker" objectType="WCTYPE| wt.part.WTPart|org.r_and_d.mypart" label="Part Picker using generic" containerRef="<%=containerRefs.toString()%>" componentId="scenarioOnePicker" searchResultsViewId="wt.part.WTPart.customizedSearchView" showVersion="false"/>
The view id wt.part.WTPart.customizedSearchView should be configured to lookup the java class associated with this id which would define the table view. Please refer to configuring table views document. An example to configure this in SearchResultTable.properties.xconf file could be
<Service context="default" name="com.ptc.core.htmlcomp.tableview.ConfigurableTable"> <Option serviceClass="com.ptc.netmarkets.search.views.CustomizedPartView" requestor="java.lang.Object" selector=" wt.part.WTPart.customizedSearchView "/> </Service>
A new java class com.ptc.netmarkets.search.views.CustomizedPartView should be created which would define the view columns for this picker customization.
Customization Points
Please refer [Item Picker Best Practice] for further customizing Item Picker.
Limitations
As per current implementation, Lifecycle State is not limited only to states that the object can have.
Sample Code
<%@ taglib prefix="wctags" tagdir="/WEB-INF/tags" %> <HTML> <BODY><TABLE> <tr> <%-launching Item picker--%>
17-6
<wctags:itemPicker id="myItemPicker" label="Custom Item Picker" pickerTitle=" Datecode Release" showVersion="false" objectType=" WCTYPE|wt.part.WTPart|org.r_and_d.myPart " showTypePicker="false" componentId="test.Customization" typeComponentId="Foundation.customization" searchResultsViewId="wt.part.WTPart.customizedSearchView"/> </tr> </BODY></TABLE> </HTML>
17-7
Building a Picker that Enables Users to Select Projects from an External Project DB
To configure a picker to fetch ProjDB data, by accepting criteria for name / id. Background
Configure a picker to talk to a non-Windchill database to fetch and display data. A user should be able to search the ProjDB database from Windchill to search for projects. Its only expected to get back the Project Id, Name and Title OR Short Description
Scope/Applicability/Assumptions
Since we are dealing with non-Windchill objects here, there are a number of points that we need to take care of while implementation. First thing is an assumption that user will be able to write a task or a webject which will fetch data from a non-Windchill database and yet return an IE Group. The framework requires an IE Group to render results. Since the records returned are not Windchill objects, the user will have to build a few attributes which are not exactly related to the data like NmOid. A user would have a JSP client from which to launch this picker
Intended Outcome
You should see a text box and Find Button along with the specified label after using the tags for user picker.
Since we need an object type for launching a generic picker as a required attribute we would be using wt.fc.Persistable. However this doesnt interfere with the working of the picker. Its just given to launch a generic picker.
17-8
a) On Click of the Find button the picker will get launched in a new window as shown in the screen shot below.
Solution
Use the ProjDb Picker Common Component in your JSP file to include ProjDB Picker in your application.
Prerequisite knowledge
To achieve this objective, you need to have a thorough understanding of the following: Basic development involving HTML forms, JSP, XML. Knowledge of writing a task and a webject to get data from a non-Windchill database Picker common components Table common component View creation Knowledge of Customizing the view to display and use data correctly from non-Windchill objects Knowledge of writing a data utility to fetch NmOid object
17-9
Solution Elements Element PickerAttributes.xml Type XML Description Runtime location - \codebase\ pickerAttributes.xml This file is used to customize the search criteria at picker page. SearchResultsTable.properties.xc onf Xconf Runtime location - \codebase\com\ ptc\netmarkets\search\ SearchResultsTable.properties.xconf This file can be used to configure table view definition. Procedure Launching and configuring a Generic Picker for searching non-Windchill data like ProjDB Projects Launching a picker with a single search criteria
A generic picker can be launched from any JSP page using the following tag. Here we are launching a picker for ProjDB data
<wctags:genericPicker id="projDBPicker" objectType="wt.fc.Persistable" componentId="projDBPickerId" pickedDataFetcher="/Windchill/netmarkets/jsp/search/projDataFetche r.jsp" displayAttribute="projId" label="ProjDB Picker using generic" pickerTitle="ProjDB" searchResultsViewId="wt.fc.Persistable.defaultPickerSearchView"/>
These attributes to the tag contain configuration information like, which view is configured for this picker search result table, what is the data fetcher jsp to be called etc.
Customizing the picker search criteria
The search criteria for a picker can be customized by defining the attributes in PickerAttributes.xml file. This can be done by creating a new component id and then defining the search criteria as below. For our ProjDb Picker, we can configure the ProjectId or Name here, as search criteria
<ComponentID id="projDBPickerId"> <ObjectType id="wt.fc.Persistable"> <SearchCriteriaAttributes> <Attributes> <Name>projId</Name> <DisplayName>Project ID</DisplayName> <IsSearchable>true</IsSearchable> </Attributes>
17-10
Search result tables use the Windchill R9.0 table common component and hence the column display can be configured by creating a new table view. Please refer Creating Table View Documentation for details of how to create and configure a new view. You can then pass the view as shown here to the picker tab to render search results table with this view.
<wctags:genericPicker id="projDBPicker" objectType="wt.fc.Persistable" componentId="projDBPickerId" pickedDataFetcher="/Windchill/netmarkets/jsp/search/projDataFetche r.jsp" displayAttribute="projId" label="ProjDB Picker using generic" pickerTitle="ProjDB" searchResultsViewId="wt.fc.Persistable.defaultPickerSearchView"/>
The view id wt.fc.Persistable.defaultPickerSearchView should be configured in SearchResultTable.properties.xconf file to lookup the java class associated with this ID. Example:
<Service context="default" name="com.ptc.core.htmlcomp.tableview.ConfigurableTable"> <Option serviceClass="com.ptc.netmarkets.search.views.ProjDbPickerResultTa bleView" requestor="java.lang.Object" selector="wt.fc.Persistable.defaultPickerSearchView"/> </Service>
A new java class com.ptc.netmarkets.search.views.ProjDbPickerResultTableView should be created which would define the view columns for this picker customization
Writing a data utility to get NmOid column in the results table to display a check box for selection
Since we are dealing with non-Windchill objects here, we need to populate this NmOid column by writing a special data utility. This data utility will have to be configured in the components.datautilities.properties file, for the specified searchResultsViewId as follows
<!ProjDB Picker Results Table --> <Option serviceClass=" com.ptc.netmarkets.search.utils.ProjDbPickerNmObjectDataUtility " requestor="java.lang.Object" selector=" wt.fc.Persistable.defaultPickerSearchView" //This value corresponds to the searchResultsTableViewId in the picker tag. cardinality=" duplicate "/>
17-11
Writing a data fetcher for displaying the selected value in the calling text box
You can configure a specific picked data fetcher for getting more information about the data displayed. In this file, from the selected OID, one needs to construct a string to be passed to the Json Object, used in Picker Callback function. A user gets a comma separated string from the request parameter attributes as follows projId,oid. Here the projId, is the display attribute configured in the picker tag. A user can passed multiple attribute names, and Click of OK button on the picker would return these in the request object, in the dataFetcher.jsp. The picker will also return the selected Oids, as a comma separated string, if multiselect is true, or as a single oid value if the picker is single select. The final string that needs to be constructed for the JSON object is as follows {"pickedObject": [{"oid":"MyTestOidFOrProjDB","<displayAttributeName>":"<selctedoid>"}]}
Sample Code
Launching Picker from any JSP
<html> <body> <table> <tr> This is a ProjDB picker. </tr> <tr> <%-launching Proj DB Picker --%> <wctags:genericPicker id="projDBPicker" objectType="wt.fc.Persistable" componentId="projDBPickerId" pickedDataFetcher="/Windchill/netmarkets/jsp/search/projDataFetche r.jsp" displayAttribute="projId" label="ProjDB Picker using generic" pickerTitle="ProjDB" searchResultsViewId="wt.fc.Persistable.defaultPickerSearchView"/> </tr> </table> </body> </html>
17-12
Background
The pickers from table toolbar are used when you have a requirement to launch pickers from some table level action and accordingly populate the tables or do some processing based on the results.
Scope/Applicability/Assumptions
Say you want to launch <your picker> from your table. It is assumed that your action jsp file <MyPage>.jsp file in which you are putting picker tag includes /netmarkets/jsp/begin.jspf or /netmarkets/jsp/beginPopuf.jspf file and /netmarkets/jsp/end.jspf files.
Intended Outcome
On click of the action, you should see the corresponding picker getting launched.
Solution
Use the specific picker Common Component in your JSP file to include the picker in your application.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Basic development involving JSP, JavaScript, Custom taglibs The management of RBINFO files customization. Windchill xconfmanager concepts.
17-13
Solution Elements
Element pickerAttributes.xml Type XML file Description You should use this file to customize the search criteria attributes for an object type for your picker. Runtime location: <WT_HOME>\codebase\ pickerAttributes.xml searchClientResource.rbInf o RBINFO file You should use this file to localize the contents of the pickers. Runtime location: <WT_HOME>\src\com\ptc\ windchill\enterprise\search\ client\ searchClientResource.rbInfo <your picker>.tag Custom JSP tag file This file is contains the information about the supported parameters for this tag. Runtime location: <WT_HOME>\codebase\ WEBINF\tags\<your picker>.tag custom.js JavaScript file You should specify custom pickerCallback function for picker in this file. Runtime location: <WT_HOME>\codebase\ netmarkets\jsp\search\ custom.js
Customization Points
Please refer to the <specific picker> Best Practice document for details regarding the parameters.
17-14
For pickers that are launched from table toolbar they should have at least following parameters in the tags.
inline=true pickedAttributes=<comma separated list of attribute names to be fetched> pickerCallback=<name of pickerCallback function> multiSelect=true
17-15
17-16
int clipboardIndex = visHelper.clipboardLinkIndex(); int printIndex = visHelper.printLinkIndex(); int repsOrMarkupsIndex = visHelper.viewRepsLinkIndex(); /** * Print the various HTML code fragments generated for each component. * Any HTML formatting code must be wrapped around each of the following lines **/ out.println(visData[thumbnailIndex]); out.println(visData[clipboardIndex]); out.println(visData[printIndex]); out.println(visData[repsOrMarkupsIndex]); }
17-17
17-18
18
Customizing the Product Structure Explorer (PSE)
This chapter describes how to customize the Product Structure Explorer (PSE). Topic Page
Customizing PSE Menus, Toolbars and Popup Menus.....................................18-2 Customizing PSE Table Display .......................................................................18-8 Customizing PSE for Soft Types.....................................................................18-13 Customizing PSE to Handle Modeled Subclasses ..........................................18-24 Customizing PSE Structure Queries................................................................18-31 Customizing Attribute Displays within Section Headings..............................18-35 Customizing Tabs - Configure Existing Tabs with Subtabs ...........................18-43 Allow Additional Steps During New Object Creation....................................18-45 Type Picker Display Customization................................................................18-47 Disabling Actions by Object Type ..................................................................18-49 Creating a Requirements Tab ..........................................................................18-51 Configurable Link Tables................................................................................18-67
18-1
Background
The definition of the PSE Menus, Toolbars and popup menus are interconnected. The definition of the user interface actions that appear in the toolbars and popup menus is inherited from the ActionAccess definition of the Menu Bar. The Menu Bar and Menu Items that are displayed do not change based on the mode (edit, draft or annotate) in which PSE is working, though items may become disabled if they are not relevant for the mode. The Toolbar does change based on the mode, as do the popup menus exposed in the tables. Only menu items that have an icon associated can appear in a toolbar. In the Task Tabs of PSE, a number of tables are defined, which have tool bars and popup menus. These are implemented in the exact same way as the main menu bar via ActionAccess definitions, but the menus are not displayed.
Scope/Applicability/Assumptions
Intended Outcome
You may want to change the content of the toolbar for a given mode; for example you may want to add the New Query Icon to the toolbar (before the Help icon) that is displayed in Draft Mode for the main PSE window, and also to add the actions Insert Existing and Insert New to the Uses Tab popup menu:
18-2
Solution
Change the appropriate element in
<Windchill>/codebase/config/logicrepository/xml/explorer/produc tstructure/PDMLinkExplorerMenus.xml
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Management of XML file customizations
Solution Elements
Element
Type
Description
PDMLinkExplorerMenus.xml
XML file
Holds the definition of the main PSE Application Menus, toolbars and popup menus that appear in the tree displays. Located in:
<Windchill>/codebase/config/logicreposito ry/xml/explorer/productstructure
ExplorerMenuItems.xml
XML file
Holds Menu Item definitions, referenced from the main application menu (PDMLinkExplorerMenus.xml) and ExplorerMenus.xml Located in:
<Windchill>/codebase/config/logicreposito ry/xml/explorer/structureexplorer
ExplorerMenus.xml
XML file
Holds Menu definitions for sub-menus referenced from the main application menu (PDMLinkExplorerMenus.xml) Located in:
<Windchill>/codebase/config/logicreposito ry/xml/explorer/structureexplorer
18-3
Element
Type
Description
ExplorerMenusForAttributeTa ble.xml
XML file
Holds the definition of the toolbars and popup menus for the Attribute Table on the Information Tab. Located in:
<Windchill>/codebase/config/logicreposito ry/xml/explorer/structureexplorer
ExplorerMenusForDocuments Tab.xml
XML file
Holds the definition of the toolbars and popup menus for the tables on the Documents Tab. Located in:
<Windchill>/codebase/config/logicreposito ry/xml/explorer/structureexplorer
ExplorerMenusForReplacemen tsTab.xml
XML file
Holds the definition of the toolbars and popup menus for all tables on the Replacements Tab. Located in:
<Windchill>/codebase/config/logicreposito ry/xml/explorer/structureexplorer
ExplorerMenusForUsesTab.x ml
XML file
Holds the definition of the toolbars and popup menus for all tables on the Uses Tab. Located in:
<Windchill>/codebase/config/logicreposito ry/xml/explorer/structureexplorer
ActionAccess
XML element
Holds the definition of a MenuBar, related Menus and MenuItems. Each ActionAccess element (i.e., MenuBar definition) must include all the actions that will be used in the related Toolbars and Popup Menus. Note: Adding new actions to the MenuBar definition is not supported. Contained in PDMLinkExplorerMenus.xml and ExplorerMenus*.xml
ModeToolBar
Defines a toolbar for a specific mode. Specifies the ApplicationMode (via an Import) and a list of MenuItemIdentifiers. Defines a popup menu for a specific mode. Simply specifies the mode and a list of MenuItemIdentifiers.
ModePopupMenu
18-4
Element
Type
Description
ExplorerMode MenuItemIdentifier
Sub-element of ModeToolBar or ModePopupMenu. Specifies the mode. Sub-element of ModeToolBar or ModePopupMenu. Identifies (through the id parameter) a defined Action.
18-5
This results in the New Query icon appearing in the toolbar as shown in Section Intended Outcome.
The results in the Replace with Alternate/Substitute appearing in the popup in the Uses Tab as shown the Intended Outcome section on 18-2.
Limitations
Adding new MenuItems to Menus, Toolbar or Popup menus for actions that are not defined is not supported, as PSE currently has no supported API to allow custom actions to be created. Also adding actions to tables for which they are not designed is not supported.
18-6
18-7
Background
With Windchill PDMLink Rev 9, PSE now provides the capability for users to customize the display of columns in tables. For example the Columns Details for the Uses Tab.
However, what a user can do is controlled within the bounds set in the PSE XML files that define the columns in each table.
Scope/Applicability/Assumptions
As these changes are being made to the PSE XML files, they will apply to all users of PSE.
Intended Outcome
The Rev 9 default display is that Number is a frozen mandatory column that is frozen (so it does not scroll) in the Uses Tab. Lets consider that we wish that Name is a mandatory attribute to display, that it and Reference Designator Range are frozen columns, Number is not frozen and is displayed though optional, Line Number is available but not displayed. As Number is optional, it will be removed from the tabular input search.
18-8
Solution
The CellDefinition element used in the PSE XML files has a number of attributes that control the display of columns in a table and dictate to what extent a user can change the tables appearance and behavior.
Attribute Description
If mandatory, the user may not hide the column Whether the column will be displayed, if it is not mandatory Whether the column may be frozen by the user Whether the column appears frozen by default In Draft and Annotate modes specifies if the cell will be used in Data Entry search.
Many of the PSE Tables including the Uses Tab Table are defined in the file
<Windchill>/codebase/config/logicrepository/xml/explorer/structure explorer/ExplorerForTablesAndPanels.xml
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Management of XML file customizations
18-9
Solution Elements
Element Type Description
ExplorerForTablesAndPanels.xml
XML file
Table CellDefinition
Defined the table and contents The attribute with its appropriate behavior to be displayed in the AttributeTable.
Procedure
The Table id ptc.wnc.exp.PartUsesLinkTabTable in the file: <Windchill>/codebase/config/logicrepository/xml/explorer/structureexplorer/Exp lorerForTablesAndPanels.xml is used to show the Uses Table BOM, when showing occurrences ptc.wnc.exp.PartUsesOccTabTable us used. By change the order of the CellDefinitions for the Table, and specifying appropriate values for mandatory, displayWhen NoPreferenceSet, pinnable, pinned and usedByTabularInput, the desired table can be formed.
<Table id="ptc.wnc.exp.PartUsesLinkTabTable" selectionMode="multi-non-contiguous" displayMode="view"> <CellDefinition id="name" pinned="true" mandatory="true" usedByTabularInput="true" displayModeOverride="edit"> <AttributeDefinition attributeId="name"> <Import id="ptc.wnc.exp.SurfaceAttrAction"/> </AttributeDefinition> </CellDefinition> <CellDefinition id="referenceDesignatorRange" pinned="true" mandatory="false" displayModeOverride="edit"> <Label> <Resource key="referenceDesignatorRangeLabel"/> </Label> <AttributeDefinition attributeId="referenceDesignatorRange"> <Import id="ptc.wnc.exp.RefDesRangeAttrAction"/> </AttributeDefinition> </CellDefinition> <CellDefinition id="number" pinned="false" mandatory="false" displayWhenNoPreferenceSet="true" usedByTabularInput="false" displayModeOverride="edit"> <AttributeDefinition attributeId="number"> <Import id="ptc.wnc.exp.SurfaceAttrAction"/>
18-10
</AttributeDefinition> </CellDefinition> <CellDefinition id="usedLineNumber" pinned="false" mandatory="false" displayWhenNoPreferenceSet="false" displayModeOverride="edit"> <Label> <Resource key="lineNumberLabel"/> </Label> <AttributeDefinition attributeId="usedLineNumber"
After this change has been made, the method server has to be re-started. The client UI may still not appear correct, this is because a user preference is used to hold the current table layout. To clear this use the File->Preference action and reset the column/window layout preferences. When PSE is restarted, the Uses Tab table should appear as shown in the Intended Outcome section on 18-8.
Customization Points
The definition of the PSE Structure with id ptc.pdm.pse.ExplorerTreeTable is to be found in:
18-11
<Windchill>/codebase\config\logicrepository\xml\explorer\ productstructure\PDMLinkExplorerForTablesAndPanels.xml
Also, if Windchill Supplier Management is installed, its tables are defined in:
<Windchill>/codebase\config\logicrepository\xml\explorer\ productstructure\ExplorerForTablesAndPanelsForSUMA.xml
18-12
Background
The selection of a type of Part in PSE typically automatically detects if soft types have been defined with the Type Manager. Attributes will automatically be prompted for, and displayed. This is achieved in the PSE XML files by entries referencing attribute definitions with ids of: ALL_SOFT_SCHEMA_ATTRIBUTES ALL_SOFT_CLASSIFICATION_ATTRIBUTES ALL_SOFT_USAGE_LINK_SCHEMA_ATTRIBUTES
Although these entries are useful, it is not possible to control the order of display. Also, some values may get set programmatically on the server, and so the user should not be allowed to specify values. Consider the simple example where WTPart has had an IBA myDescription added to the base definition. A myMechanical Part has been defined in the Type Manager with attributes of myCost and myWeight, WTPartUsageLink has been extended to have an IBA of myColor. The steps to insert a new myMechanical Part into an assembly would result in these screens.
18-13
The Insert New wizard would present a drop down of instantiable types. The user selects myMechanical part.
After the Name and other properties have been specified, the last step in the wizard will prompt for the IBAs, although the Attribute column can be sorted, the default order is not controlled.
The info Tab for myMechanical Part presents all attributes, but not in any sort of order. The attributes in the upper part of the display represent the fixed set applicable to identify that object; some of these may not be relevant. The attributes in the lower editable table include attributes inherited from WTPart and are in no controlled order.
18-14
The myColor attribute would not appear in the Uses Tab, but it might be useful for the user to see the value with the other UsageLink attributes. By customizing the PSE XML files, it is possible to explicitly define those attributes to be presented to the user. This typically impacts the Information Tab, and Part Creation and Insert wizards.
Scope/Applicability/Assumptions
As these changes are being made to the PSE XML files, they will apply to all users of PSE.
Intended Outcome
Considering the example described above.
When specifying the attributes of the New Part, the attributes in the last step of the wizard appear in the order defined in the PSE XML.
18-15
files.
The attributes in the lower table of the Information Tab can also be ordered.
The Uses BOM Table can be configured to show the Usage Link attribute.
Solution
For the dataType, defined a new ExplorerElementGroup with the context application of ptc.wnc.StructureExplorer. Within this element define the contents of the Attribute Tables. It is likely that if you are doing this customization you have many types of WTPart defined. Although these element definitions can be added to the file
18-16
<Windchill>/codebase/config/logicrepository/xml/explorer/structureexplorer/Exp lorerForTablesAndPanels.xml This file is getting large, and it is difficult to identify customer extensions. So the suggestion is to create a file per soft part type to hold the customization. The AttributeTables with ids ptc.wnc.exp.CreatPartTab3, ptc.wnc.exp.CreatePartNoUsageLinkTab3 and ptc.wnc.exp.EditPropertiesTable would be defined for each dataType. The addition of the attributes in the Uses Tab is achieved by including the appropriate CellDefinition for the table with id ptc.wnc.exp.PartUsesLinkTable in ExplorerForTablesAndPanels.xml
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: The management of XML file customizations
Solution Elements
Element
Type
Description
ExplorerForTableAndPanels.xml
XML file
Holds the definition of the PSE Tables and panels Located in:
<Windchill>/codebase/config/logicrepo sitory/xml/structureexplore
Specifies the application and data type that the definition is to be applied Defined the attribute table and contents The attribute with its appropriate behavior to be displayed in the AttributeTable. Remove=true is used to stop a property from appearing due to inheritance.
Procedure
Either create a new file representing the Soft Part (myMechanical.xml) in the directory:
Windchill>/codebase/config/logicrepository/xml/explorer/structuree xplorer
18-17
Windchill>/codebase/config/logicrepository/xml/explorer/structuree xplorer/ExplorerForTablesAndPanels.xml <?xml version="1.0" standalone="no" ?> <!DOCTYPE LogicRepository SYSTEM "/config/logicrepository/dtd/LogicRepository.dtd"> <LogicRepository> <ExplorerElementGroup> <LogicContext application="ptc.wnc.StructureExplorer" dataType="com.aprilia.www.myMechanical"/> <AttributeTable id="ptc.wnc.exp.CreatePartTab3"> <Table id="Table" displayMode="edit"> <!-- These 3 entries remove the inherited entries from WTPart --> <CellDefinition id="ALL_SOFT_SCHEMA_ATTRIBUTES"> <Placement remove="true"/> </CellDefinition> <CellDefinition id="ALL_SOFT_CLASSIFICATION_ATTRIBUTES"> <Placement remove="true"/> </CellDefinition> <CellDefinition id="ALL_SOFT_USAGE_LINK_SCHEMA_ATTRIBUTES"> <Placement remove="true"/> </CellDefinition> <!-- Add the entries for attributes on Parts and UsageLink in the specific order --> <CellDefinition id="myDescription"> <AttributeDefinition attributeId="com.aprilia.www.myDescription" imageName="wtcore/images/part.gif"> <Import id="ptc.wnc.exp.CreatePanelAttrAction"/> </AttributeDefinition> </CellDefinition> <CellDefinition id="myColor"> <AttributeDefinition attributeId="com.aprilia.www.myColor" imageName="com/ptc/windchill/explorer/config/images/usesTab.gif"> <Import id="ptc.wnc.exp.CreatePanelAttrAction"/> </AttributeDefinition> </CellDefinition> <CellDefinition id="myCost"> <AttributeDefinition attributeId="com.aprilia.www.myCost" imageName="wtcore/images/part.gif"> <Import id="ptc.wnc.exp.CreatePanelAttrAction"/> </AttributeDefinition> </CellDefinition> <CellDefinition id="myWeight"> <AttributeDefinition attributeId="com.aprilia.www.myWeight" imageName="wtcore/images/part.gif"> <Import id="ptc.wnc.exp.CreatePanelAttrAction"/> </AttributeDefinition> </CellDefinition> </Table>
18-18
<Import id="ptc.wnc.exp.NewObjectAttrTableAA"/> </AttributeTable> <AttributeTable id="ptc.wnc.exp.CreatePartNoUsageLinkTab3"> <Table id="Table" displayMode="edit"> <!-- These 2 entries remove the inherited entries from WTPart --> <CellDefinition id="ALL_SOFT_SCHEMA_ATTRIBUTES"> <Placement remove="true"/> </CellDefinition> <CellDefinition id="ALL_SOFT_CLASSIFICATION_ATTRIBUTES"> <Placement remove="true"/> </CellDefinition> <!-- Add the entries for attributes on Parts in the specific order --> <CellDefinition id="myDescription"> <AttributeDefinition attributeId="com.aprilia.www.myDescription" imageName="wtcore/images/part.gif"> <Import id="ptc.wnc.exp.CreatePanelAttrAction"/> </AttributeDefinition> </CellDefinition> <CellDefinition id="myCost"> <AttributeDefinition attributeId="com.aprilia.www.myCost" imageName="wtcore/images/part.gif"> <Import id="ptc.wnc.exp.CreatePanelAttrAction"/> </AttributeDefinition> </CellDefinition> <CellDefinition id="myWeight"> <AttributeDefinition attributeId="com.aprilia.www.myWeight" imageName="wtcore/images/part.gif"> <Import id="ptc.wnc.exp.CreatePanelAttrAction"/> </AttributeDefinition> </CellDefinition> </Table> <Import id="ptc.wnc.exp.NewObjectAttrTableAA"/> </AttributeTable> <AttributeTable id="ptc.wnc.exp.EditPropertiesTable"> <Table id="Table" displayMode="edit"> <!-- These 3 entries remove the inherited entries from WTPart --> <CellDefinition id="source"> <Placement remove="true"/> </CellDefinition> <CellDefinition id="partType"> <Placement remove="true"/> </CellDefinition> <CellDefinition id="ALL_SOFT_SCHEMA_ATTRIBUTES"> <Placement remove="true"/> </CellDefinition> <CellDefinition id="ALL_SOFT_CLASSIFICATION_ATTRIBUTES">
18-19
<Placement remove="true"/> </CellDefinition> <CellDefinition> id="ALL_SOFT_USAGE_LINK_SCHEMA_ATTRIBUTES"> <Placement remove="true"/> </CellDefinition> <!-- Add the entries for attributes on Parts and UsageLink in the specific order --> <CellDefinition id="myDescription"> <AttributeDefinition attributeId="com.aprilia.www.myDescription" imageName="wtcore/images/part.gif"> <Import id="ptc.wnc.exp.CreatePanelAttrAction"/> </AttributeDefinition> </CellDefinition> <CellDefinition id="myColor"> <AttributeDefinition attributeId="com.aprilia.www.myColor" imageName="com/ptc/windchill/explorer/config/images/usesTab.gif"> <Import id="ptc.wnc.exp.CreatePanelAttrAction"/> </AttributeDefinition> </CellDefinition> <CellDefinition id="myCost"> <AttributeDefinition attributeId="com.aprilia.www.myCost" imageName="wtcore/images/part.gif"> <Import id="ptc.wnc.exp.CreatePanelAttrAction"/> </AttributeDefinition> </CellDefinition> <CellDefinition id="myWeight"> <AttributeDefinition attributeId="com.aprilia.www.myWeight" imageName="wtcore/images/part.gif"> <Import id="ptc.wnc.exp.CreatePanelAttrAction"/> </AttributeDefinition> </CellDefinition> </Table> <Import id="ptc.wnc.exp.EditPropertiesTableAA"/> </AttributeTable> </ExplorerElementGroup> </LogicRepository>
This results in the attributes being requested in the Wizard and Information Tab as shown in Section Intended Outcome. To add the IBA to the Uses Tab, edit:
Windchill>/codebase/config/logicrepository/xml/explorer/structuree xplorer/ExplorerForTablesAndPanels.xml
18-20
</AttributeDefinition> </CellDefinition>
The method server will need to be re-started in order that these changes are applied.
Further customization
To extend the above example, consider adding the myDescription attribute to the Uses Tab. When editing this String attribute, the user may want to specify many characters, however to perform this in the space of the cell in a table is not easy. So, it is possible to associate a different renderer to this attribute that will popup a dialog when editing the value, allow the user to enter many lines of text. Edit:
Windchill>/codebase/config/logicrepository/xml/explorer/structuree xplorer/ExplorerForTablesAndPanels.xml
Just using the Golf Cart as an example, this will result in the following dialog being presented when the button is selected in the cell.
This renderer could also be applied to the attributes in the Information Tab.
18-21
Customization Points
In section Background there are a number of special attributes that are defined in LogicalAttributes.xml that allow PSE to display a number of attributes for a single definition. These include:
Logical Form Description
ALL_SOFT_ATTRIBUTES ALL_SOFT_CLASSIFICATION_A TTRIBUTES ALL_SOFT_NON_SCHEMA_ATT RIBUTES ALL_SOFT_SCHEMA_ATTRIBUT ES ALL_SOFT_NON_CLASSIFICATI ON_SCHEMA_ATTRIBUTES ALL_SOFT_NON_CLASSIFICATI ON_ATTRIBUTES ALL_SOFT_USAGE_LINK_SCHE MA_ATTRIBUTES ALL_SOFT_SCHEMA_ATTRIBUT ES_FOR_INPUT_TYPE
All IBAs persisted on the object All IBAs associated with the classification of the object. All IBAs persisted on the object that are not associated with the type of the object. All IBAs associated with the type of the object. All IBAs associated with the type of the object that are not also associated with the classification of the object. All IBAs persisted on the object that are not associated with the classification of the object In the context of a part, all IBAs on the part usage link(s) that are associated with the type of the part usage link All IBAs associated with the type specified in the filter, which may be a supertype of the actual object
In Rev 9, PSE uses ALL_SOFT_SCHEMA_ATTRIBUTES", "ALL_SOFT_CLASSIFICATION_ATTRIBUTES" and ALL_SOFT_USAGE_LINK_SCHEMA_ATTRIBUTES" in the definition of Information Tab attribute table (and also in the Create Wizard. In the Information Tab) Using ALL_SOFT_ATTRIBUTES instead of ALL_SOFT_SCHEMA_ATTRIBUTES or adding an entry for ALL_SOFT_NON_SCHEMA_ATTRIBUTES would allow attributes programmatically populated from CAD to be displayed.
18-22
18-23
Scope/Applicability/Assumptions
You have separately created your modeled subclass.
Intended Outcome
Instances of your modeled subclass will be detected and presented by PSE in the same manner as out-of-the-box modeled objects.
Solution
Make changes in the following three areas: LogicalAttributes.xml PSE Tables and Panels Customized command delegates
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: The management of XML file customizations The management of RBINFO file customizations
Solution Elements
Element
Type
Description
LogicalAttributes.xml
XML file
Used to configure modeled attribute mappings from a "logical form" to its "external form".
18-24
LogicalAttributes.xml
A LogicalAttributes.xml file, located in <Windchill>/codebase/LogicalAttributes.xml, is used to configure modeled attribute mappings from a "logical form" to its "external form". A mapping is required for all modeled attributes that represent an association from one object to another. For example some of the entries defined for the WTPart to WTPartMaster reference are:
<Class name="wt.part.WTPart"> <Property> <LogicalForm>defaultUnit</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| wt.part.WTPartMaster~MBA|defaultUnit</ExternalForm> </Property> <Property> <LogicalForm>masterReference</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| wt.part.WTPartMaster</ExternalForm> </Property> <Property> <LogicalForm>name</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| wt.part.WTPartMaster~MBA|name</ExternalForm> </Property> <Property> <LogicalForm>number</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| wt.part.WTPartMaster~MBA|number</ExternalForm> </Property> <Property> <LogicalForm>organizationReference</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| wt.part.WTPartMaster~MBA|organizationReference^WCTYPE| wt.org.WTOrganization</ExternalForm> </Property> <Property> <LogicalForm>organizationName</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| wt.part.WTPartMaster~MBA|organizationReference^WCTYPE| wt.org.WTOrganization~MBA|name</ExternalForm> </Property> <Property> <LogicalForm>usedLineNumber</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| wt.part.WTPartMaster~MBA|uses@WCTYPE| wt.part.WTPartUsageLink~MBA| lineNumber.value</ExternalForm> </Property> <Property> <LogicalForm>usedLink</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| wt.part.WTPartMaster~MBA|uses@WCTYPE| wt.part.WTPartUsageLink</ExternalForm> </Property> </Class>
18-25
Using the example that "ext.cust.CustPart" extends wt.part.WTPart, and "ext.cust.SubPartMaster" extends wt.part.WTPartMaster, the following should be added to the site-specific file called <Windchill>/codebase/LogicalAttributesSite.xml:
<Class name="ext.cust.CustPart"> <Property> <LogicalForm>defaultUnit</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| ext.cust.SubPartMaster~MBA|defaultUnit</ExternalForm> </Property> <Property> <LogicalForm>masterReference</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| ext.cust.SubPartMaster</ExternalForm> </Property> <Property> <LogicalForm>name</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| ext.cust.SubPartMaster~MBA|name</ExternalForm> </Property> <Property> <LogicalForm>number</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| ext.cust.SubPartMaster~MBA|number</ExternalForm> </Property> <Property> <LogicalForm>organizationReference</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| ext.cust.SubPartMaster~MBA|organizationReference^WCTYPE| wt.org.WTOrganization</ExternalForm> </Property> <Property> <LogicalForm>organizationName</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| ext.cust.SubPartMaster~MBA|organizationReference^WCTYPE| wt.org.WTOrganization~MBA|name</ExternalForm> </Property> <LogicalForm>usedLineNumber</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| ext.cust.SubPartMaster~MBA|uses@WCTYPE| wt.part.WTPartUsageLink~MBA| lineNumber.value</ExternalForm> </Property> <Property> <LogicalForm>usedLink</LogicalForm> <ExternalForm>MBA|masterReference^WCTYPE| ext.cust.SubPartMaster~MBA|uses@WCTYPE| wt.part.WTPartUsageLink</ExternalForm> </Property> </Class>
18-26
You do not need to add new modeled attributes to the LogicalAttributes.xml file, but you must add them to the appropriate PSE configuration XML files. Refer to Customizing PSE for Soft Types on page 18-13 for additional information. Note: When specifying new modeled attributes that are defined only for subclass objects, the corresponding "AttributeGroup" or AttributeTable or "Table defined in a "wt.part.WTPart" context should be copied to the appropriate subclass context. Only new modeled attributes need to be listed. Existing attributes will be inherited. For example, name and number will be inherited from WTPart. To remove attributes from a sub-classed panel that are inherited, use "<Placement remove="true"/>", E.g.
<AttributeDefinition id="containerName> <Placement remove="true"/>" </AttributeDefinition>
A good practice when adding element groups for customized objects is to put all customized changes in a separate file, rather than edit existing files. Name them consistently, e.g. CustomExplorerForTablesAndPanels.xml. Using the previous example of "ext.cust.CustPart" extends "wt.part.WTPart", the following AttributeGroup
<ExplorerElementGroup> <LogicContext application="ptc.wnc.StructureExplorer" dataType="wt.part.WTPart"/> <AttributeGroup id="ptc.wnc.exp.ViewPropertiesPanel" displayMode="view"> <CellDefinition id="number"> <AttributeDefinition attributeId="number"/> </CellDefinition> <CellDefinition id="organizationIdentifier"> <AttributeDefinition attributeId="organizationIdentifier"/> </CellDefinition> <CellDefinition id="name"> <AttributeDefinition attributeId="name"/> </CellDefinition> <CellDefinition id="versionIterationView"> <AttributeDefinition attributeId="versionIterationView"/> </CellDefinition> ... </AttributeGroup> </ElementGroup>
18-27
PSE uses a Command/CommandDelegate mapping to control some of its operations. The most notable example is the "Duplicate Action". To "duplicate" a customized class, you need to subclass the appropriate copy delegate. In the case of "CustPart", you need to create a class that is a subclass of wt.enterprise.CopyWTPartDelegate and handle the copying of your customized modeled attributes.
This document illustrates the steps with a simple example: a custom part class MyPart that extends wt.part.WTPart with a single string attribute myAttr.
Creating a Copy Delegate
As illustrated in the figure, you can simply extend wt.enterprise.CopyWTPartDelegate and override its newCopy() method. The purpose is to handle any custom attributes, in this particular case, myAttr. Heres how this method is implemented:
public final RevisionControlled newCopy( RevisionControlled object )throws WTException {
18-28
//##begin newCopy%461E645C0050f.body preserve=yes if (object == null) return null; MyPart new_copy = (MyPart) super.newCopy(object); MyPart original = (MyPart) object; String my_attr = original.getMyAttr(); if (my_attr != null) { try { new_copy.setMyAttr(original.getMyAttr()); } catch (WTPropertyVetoException e) { throw new WTException(e); } } return new_copy; //##end newCopy%461E645C0050f.body }
To instruct Windchill to use the custom copy delegate CopyMyPartDelegate as the copy delegate class for MyPart, the following line needs to be inserted into configuration file <windchill-installdirectory>/codebase/wt/enterprise/EnterpriseServerDelegate.properties.
wt.services/svc/default/wt.enterprise.CopyDelegate/null/<mypackage>.MyPart/0=<mypackage>. CopyMyPartDelegate/singleton
For more information, see the Customizing Localizable Display Names for Modeled Elements in the Generic UI Customizations chapter on page 9-3. Modeled enumerations will display the internal values of the enumerations, when rendered as a drop-down menu in PSE. To change the labels displayed in a dropdown menu, the corresponding RBINFO file for the enumeration should be
18-29
edited. For example, if you generate a class, "public final class MyEnum extends EnumeratedType" with values "apple", "dog", "cat" and you wish to change the display value in the drop-down menu, edit the file MyEnumRB.rbInfo like this:
# Entry Contents apple.value=Apples dog.value=Dogs cat.value=Cats
More information can be found in the Enumerated Types chapter on page 33-1.
Other Resources
Customizing PSE Table Display on page 18-8
18-30
Background
The dialog launched from the View->Query->New Query menu entry allows the user to construct a query that will locate objects in the structure that match the specified criteria. The out-of-the-box configuration allows specific attributes of WTPart to be queried.
Customers will create their own soft types of WTPart with their own attributes. In order to allow these to be used in the query, customization of the PSE XML files is required.
Scope/Applicability/Assumptions
As these changes are being made to the PSE XML files, they will apply to all users of PSE.
Intended Outcome
You may want to include the soft WTPart myPart in the searchable Types, and allow the attributes myCost and myDescription to be queried. As End Item,
18-31
Generic and Reference Designator are not relevant to this type, these are removed from the Property drop-down.
Solution
Add the appropriate element group in
<Windchill>/codebase/config/logicrepository/xml/explorer/structure explorer/ExplorerSearchableTypes.xml
The element group will define CellDefinitions (both additions and removals) for the AttributeGroup with id="ptc.wnc.exp.QuerySearchableAttrs " for the myPart type.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: The management of XML file customizations
18-32
Solution Elements
Element Type Description
ExplorerSearchableTypes.xml
XML file
Holds the definition of types and attributes that will be exposed in the New Query dialog. Located in:
<Windchill>/codebase/config/logicreposi tory/xml/structureexplore
LogicContext AttributeGroup
Specifies the application and data type that the definition is to be applied PSE locates all the attribute groups with id ptc.wnc.exp.QuerySearchableAttres, and uses the type inheritance to find all the properties (CellDefinitions) that will be displayed. The id of the property that will appear. Remove=true is used to stop a property from appearing due to inheritance.
Procedure
Edit the file ExplorerSearchableTypes.xml, before the final line </LogicRepository> insert the following lines:
<!-- New Query definition for soft type myPart --> <ExplorerElementGroup> <LogicContext application="ptc.wnc.StructureExplorer" dataType="com.aprilia.www.myPart"/> <AttributeGroup id="ptc.wnc.exp.QuerySearchableAttrs" displayMode="view"> <!-- Remove the following that would otherwise be inherited from WTPart Definition --> <CellDefinition id="endItem"> <Placement remove="true"/> </CellDefinition> <CellDefinition id="genericType> <Placement remove="true"/> </CellDefinition> <CellDefinition id="referenceDesignator"> <Placement remove="true"/> </CellDefinition> <!-- Add the specific attributes of myPart --> <CellDefinition id="myCost"> <AttributeDefinition attributeId="com.aprilia.www.myCost"/> </CellDefinition> <CellDefinition id="myDescription"> <AttributeDefinition attributeId="com.aprilia.www.myDescription"/> </CellDefinition> </AttributeGroup> </ExplorerElementGroup>
18-33
After the method server is restarted, this results in myPart appearing in the Type drop-down, with Property entries End Item, Generic and Reference Designator removed, and myCost and myDescription added, as shown in Section Intended Outcome. Alternatively, if the changes are to be made to other aspects of the PSE UI via XML customization, these additional lines can be added to an XML file that holds all the myPart customization.
Customization Points
It is valid to remove the WTPart definition from ExplorerSearchableTypes.xml, so Part does not appear in the type drop-down. However, no definitions of the properties will be inherited by the soft type definitions, so these will have to be added.
18-34
18-35
</CellDefinition> <CellDefinition id="source"> <AttributeDefinition attributeId="source"/> </CellDefinition> <CellDefinition id="partType"> <AttributeDefinition attributeId="partType"/> </CellDefinition> <SectionHeading allowAttrDetails="true"> <Label> <Resource key="Properties 2"/> </Label> </SectionHeading> <CellDefinition id="usedQuantityAmount"> <AttributeDefinition attributeId="usedQuantityAmount"/> </CellDefinition> <CellDefinition id="usedQuantityUnit"> <AttributeDefinition attributeId="usedQuantityUnit"/> </CellDefinition> <CellDefinition id="usedTraceCode"> <AttributeDefinition attributeId="usedTraceCode"/> </CellDefinition> <CellDefinition id="effPropagationStop"> <AttributeDefinition attributeId="effPropagationStop"/> </CellDefinition> <CellDefinition id="jobAuthorizationNumber"> <AttributeDefinition attributeId="jobAuthorizationNumber"/> <EnabledDependency inverted="false"> <Assembly assembly="wadm"/> </EnabledDependency> </CellDefinition> <CellDefinition id="contractNumber"> <AttributeDefinition attributeId="contractNumber"/> <EnabledDependency inverted="false"> <Assembly assembly="wadm"/> </EnabledDependency> </CellDefinition> <CellDefinition id="phase"> <AttributeDefinition attributeId="phase"/> <EnabledDependency inverted="false"> <Assembly assembly="wadm"/> </EnabledDependency> </CellDefinition> </AttributeGroup>
Adding the "allowAttrDetails=true" clauses produces the following output in the UI. Adding a SectionHeading creates the box around the group of attributes that follow the SectionHeading. The Label clause of the SectionHeading gives the text for the box.
18-36
The allowAttrDetails="true" clause enables the Details icon to show after the label and also enables a popup menu for the panel.
18-37
This is the Details dialog that displays after you click the Details icon after the label. The user can hide or show individual attributes, but cannot change the order of the attributes.
For example, the user can choose to hide the Location attribute within the Properties 1 section. This is now saved as a preference for this user and will stay this way the next time the user loads PSE.
18-38
18-39
Sample Code:
<AttributeGroup id="ptc.wnc.exp.CreateChild" displayMode="edit"> <SectionHeading id="ptc.wnc.exp.CreateChild.Responsibilities" allowAttrDetails="true" allowCollapsable="true"> <Label> <Resource key="responsibilitiesSectionLabel"/> </Label> </SectionHeading> cell definitions for the group here </AttributeGroup>
18-40
If you specify a SectionHeading before a group of attributes, those attributes will be enclosed in a border with a title specified by the <Label> tag. See Customizing the Display of Attributes in Groups on page 18-35 for more information on the <Label> tag. If the numberOfColumns is set to 1, a single column of attributes will display; if set to 2 two columns of attributes will display. In the example screenshot above, URL0: is a single attribute that happens to have two fields for input. Note that if any of the attribute in a section is required, the label on the border is also marked as required. Sample Code:
<AttributeGroup id="ptc.wnc.exp.CreatePartTab4" scrollable="true" displayMode="edit"> <SectionHeading numberOfColumns="1"> <Label> <Resource key="checkoutInfoStateLabel"/> </Label> </SectionHeading> <CellDefinition id="String0"> <AttributeDefinition attributeId="IBA|String0"/> </CellDefinition> <CellDefinition id="URL0"> <AttributeDefinition attributeId="IBA|URL0"/> </CellDefinition>
18-41
<SectionHeading numberOfColumns="2"> <Label> <Resource key="serialNumberValueLabel"/> </Label> </SectionHeading> <CellDefinition id="Boolean0"> <AttributeDefinition attributeId="IBA|Boolean0" required="true"/> </CellDefinition> <CellDefinition id="Integer0"> <AttributeDefinition attributeId="IBA|Integer0" required="true"/> </CellDefinition> <CellDefinition id="Real0"> <AttributeDefinition attributeId="IBA|Real0"/> </CellDefinition> <CellDefinition id="DateTime0"> <AttributeDefinition attributeId="IBA|DateTime0"/> </CellDefinition> </AttributeGroup>
18-42
The Object Attributes tab shows only those attributes that are attached directly to the selected part, not the link attributes.
18-43
The Usage Attributes tab only shows the link attributes. Note that the tab is not enabled when the top node is selected, because there is not a usage link so there cannot be any link attributes.
The Classification tab is only visible if the PartsLink module is installed. It displays all the classification attributes.
18-44
The first line duplicates the id of the WizardList you want to modify. The second line shows the addition of a new AttributeGroup inline, it could also be defined in another place then imported here similar to the original WizardList definition. The Placement segment indicates that your new AttributeGroup is to be shown after CreateChildPartTab2. You can also remove an AttributeGroup or AttributeTable from the original WizardList that you don't want to use. For example, the following xml removes the last step of the wizard (the AttributeTable that shows all the soft attributes):
<WizardList id="ptc.wnc.exp.CreateChildWizardList"> <AttributeTable id="ptc.wnc.exp.CreatePartTab3"> <Placement remove="true"/> </AttributeTable> </WizartList>
The ExplorerForTablesAndPanels.xml contains many good examples of how to create AttributeGroups or AttributeTables. Within either of these segments, define the list of CellDefinitions for each attribute you want to show. You could also redefine the existing AttributeGroups or AttributeTables and add or remove Celldefinitions using Placement segments. For example:
<AttributeGroup id="ptc.wnc.exp.CreatePartTab2"> <CellDefinition id="partType"> <AttributeDefinition attributeId="partType"/> <Placement insertKey="before" insertId="endItem"/> </CellDefinition> <CellDefinition id="genericType"> <AttributeDefinition attributeId=" genericType"/>
18-45
This example takes the existing AttributeGroup defined for the CreatePartTab2 step and adds the partType attribute before the endItem and removes the genericType attribute. Note that CreatePartTab2 is imported into both the CreateWizardList and the CreateChildWizardList so you will be modifying both wizards.
18-46
2. Locate the <ExplorerElementGroup> for which you want to configure this setting. The dataType attribute of the <LogicContext> element will define the Types this change will be effective for. 3. Locate the <AttributeGroup> element with id=ptc.wnc.exp.SearchCriteriaPanel 4. Add the parameter hideIfListSizeIsOne with true/false value. E.g.:
<AttributeGroup id=ptc.wnc.exp.SearchCriteriaPanel hideSingleValueTypePicker =false>
Note: This change will be effective for ALL instances of the GUI panel for the Type defined in the <LogicContext> element. Customizing for a User Creating a New Instance of a Type To configure this for situations where the user is creating a new instance of a Type, and the Type Picker is being populated with a list of Types to choose from, e.g. File >> New >> Part 1. Locate the following XML file:
ExplorerForTablesAndPanels.xml
2. Locate the <ExplorerElementGroup> for which you want to configure this setting. The dataType attribute of the <LogicContext> element will define the Types this change will be effective for. 3. Locate the <AttributeGroup> element with id=ptc.wnc.exp.CreatePartTab1 4. Add the parameter hideIfListSizeIsOne with true/false value. E.g.:
<AttributeGroup id= ptc.wnc.exp.CreatePartTab1 hideSingleValueTypePicker =false>
18-47
Note: This change will be effective for ALL instances of the GUI panel for the Type defined in the <LogicContext> element. Note: Dropdowns in the Find In Structure dialog and Create/Edit Query Wizard are not impacted by this change and will remain as they were.
18-48
2. Edit the ExplorerValidators.xml file. Create a <ValidatorDefinition> element for the group of types you wish to disable actions for. This will return false if the the type of the selected part matches one of the types referenced in the validator definition. E.g. for the three types above, you would define a validator as follows:
<ValidatorDefinition id="com.my.IsNotEqualToTypesABDVAL" validatorClass="com.ptc.windchill.explorer.structureexplorer.va lidators.IsValidTypeValidator" inverted="true"> <Import id="com.my.MyTypeATD"/> <Import id="com.my.MyTypeBTD"/> <Import id="com.my.MyTypeDTD"/> </ValidatorDefinition>
Note: It is important that the value for the validatorClass attribute of ValidatorDefinition be the exact class listed above, and that the the inverted attribute be set to true. 3. Edit the ExplorerActions.xml file. Add a <ValidatorEntry> element to the actions you wish to have disabled for the specified types.
<ActionDefinition id="ptc.wnc.exp.EditCommonAttrsAction" ... > ... <ValidatorEntry> <Import id="com.my.IsNotEqualToTypesABDVAL"/> </ValidatorEntry> ... </ActionDefinition>
This configuration will disable the Edit Common Attributes action in the PSE application whenever an part of type A, B or D is selected.
18-49
Validator isValidTypeValidator
The validator isValidTypeValidator is implemented by the class: com.ptc.windchill.explorer.structureexplorer.validators.IsValidTypeValidator. For a given set of type definitions, this validator will return true if the type of the currently selected part is in the aformentioned set. For example, if an instance of this validator is defined with type definitions for types A, B and D. When a part of type A, B or D is selected, the validator will return true. If a part of any other type, e.g. C, is selected, it will return false. A <ValidatorDefinition> which would return true if the selected type is A, B or D would be defined in the following way:
<ValidatorDefinition id="com.my.IsEqualToOneOfTypesABDVAL" validatorClass="com.ptc.windchill.explorer.structureexplorer.va lidators.IsValidTypeValidator"> <Import id="com.my.MyTypeATD"/> <Import id="com.my.MyTypeBTD"/> <Import id="com.my.MyTypeDTD"/> </ValidatorDefinition>
Conversely, a <ValidatorDefinition> which would return false if the selected type is A, B or D would be defined in the following way (note the inclusion of the inverted attribute):
<ValidatorDefinition id="com.my.IsNotEqualToTypesABDVAL" validatorClass="com.ptc.windchill.explorer.structureexplorer.va lidators.IsValidTypeValidator" inverted="true"> <Import id="com.my.MyTypeATD"/> <Import id="com.my.MyTypeBTD"/> <Import id="com.my.MyTypeDTD"/> </ValidatorDefinition>
The <Import> elements refer to <TypeDefinition> elements which would be defined as follows (assuming that each type is a direct child of WTPart):
<TypeDefinition id="com.my.MyTypeATD" typeId="WCTYPE|wt.part.WTPart|org.my.MyTypeA"/> <TypeDefinition id="com.my.MyTypeBTD" typeId="WCTYPE|wt.part.WTPart|org.my.MyTypeB"/> <TypeDefinition id="com.my.MyTypeDTD" typeId="WCTYPE|wt.part.WTPart|org.my.MyTypeD"/>
18-50
2. Locate the <TabSet> element and add an import for the new Requirements tab, and place it in the desired location:
<TabSet id="ptc.pdm.pse.ExplorerTaskTabSet" tabPlacement="top" tabIdWithFocus="ptc.wnc.exp.PropertiesTab">
18-51
<Import <Import <Import <Import <Import <Import <Import <Import <Import </TabSet>
2. After the <TabSet> element, define a <Tab> element for the Requirements tab:
<TabSet id="ptc.pdm.pse.ExplorerTaskTabSet" ... > ... </TabSet> <Tab id="mycom.wnc.exp.RequirementsTab" tabClass="com.ptc.windchill.explorer.structureexplorer.explorer .tabs.ShowTablesTab" enabledDeciderClass="com.mycom.windchill.explorer.structureexpl orer.deciders.RequirementsEnabledDecider"> <Label imageName="wtcore/images/change_action.gif"> <Resource key="requirementsTabLabel"/> </Label> <Panel> <Import id="mycom.pdm.pse.RequirementAssocTable"/> </Panel> </Tab>
Note: The id attribute for the Tab element must match the id specified in the import sub-element of the <TabSet> element defined above. The class defined for the enabledDeciderClass attribute of the Tab element, controls what types this tab will be enabled for when parts are selected in the structure tree. This must be implemented by the customer. The imageName attribute of the <Label> sub-element defines the icon to display on the tab. The <Resource> sub-element of <Label> refers to the defined text label for the tab. The <Panel> element contains an import to the defined table to be displayed.
18-52
2. After the <Tab> element definition for the Requirements tab, define the <AssociationTable> element.
<Tab id="mycom.wnc.exp.RequirementsTab" ... > ... </Tab> <AssociationTable id="mycom.pdm.pse.mycom.pdm.pse.RequirementAssocTable"> <Label> <Resource key="requirementsLabel"/> </Label> <Import id="mycom.wnc.exp.RequirementSAD"/> <Import id="mycom.wnc.exp.ChangeActionTabTable"/> <Import id="mycom.wnc.exp.ChangeActionAssocTableAA"/> </AssociationTable>
Note: The id attribute for the <AssociationTable> must match the id specified in the import sub-element of the <Tab> element defined above. The <Resource> sub-element of the <Label> element refers to the text label defined in the resource file to be used for the table.
2. Find the section in the file where the structure author definitions are defined. After the last <StructureAuthorDefinition> element, add the following definition for the Requirements:
<StructureAuthorDefinition id="mycom.wnc.exp.RequirementSAD"> <Import id="mycom.wnc.exp.PartToRequirementSD"/> </StructureAuthorDefinition>
Note:
18-53
The id attribute for the <StructureAuthorDefinition> must match the id specified in the import sub-element of the <AssociationTable> element defined above.
2. Find the section in the file where the structure definitions are defined. After the last <StructureDefinition> element, add the following definition:
<StructureDefinitionSimple id="mycom.wnc.exp.PartToRequirementSD" parentToChild="addressedPartMasterReference" childDisplayId="number"> <Import id="ptc.wnc.exp.WTPartTD"/> </StructureDefinitionSimple>
Note: The id attribute for the <StructureDefinitionSimple> must match the id specified in the import sub-element of the <StructureAuthorDefinition> element defined above.
To define the <Table> element for the Requirement type 1. Open the PDMLinkExplorerForTablesAndPanels.xml file from the following location:
18-54
<Windchill>/codebase/config/logicrepository/xml/explorer/produc tstructure
2. At the end of the file: a. Create the following <ExplorerElementGroup> as a sub-element of the <LogicRepository> element. b. Define a <LogicContext> sub-element of the <ExplorerElementGroup> with the data type of the Requirement. c. Define the <Table> element and the columns, <CellDefinition> elements, to be displayed in the table.
<LogicRepository> ... <ExplorerElementGroup> <LogicContext application="ptc.pdm.ProductStructureExplorer" dataType="wt.change2.ChangeAction"/>
<Table id="airbus.wnc.exp.ChangeActionTabTable" selectionMode="multi-non-contiguous" displayMode="view"> <CellDefinition id="number" mandatory="true" pinned="true"> <Label> <Resource key="reqNumberLabel"/> </Label> <AttributeDefinition attributeId="number"/> </CellDefinition> <CellDefinition id="effVector" mandatory="true"> <Label> <Resource key="reqValidityLabel"/> </Label> <AttributeDefinition attributeId="displayEffectivity"/> </CellDefinition> <CellDefinition id="theActionState" mandatory="true"> <Label> <Resource key="reqStatusLabel"/> </Label> <AttributeDefinition attributeId="theActionState"/> </CellDefinition> <CellDefinition id="owningChangeDirective" mandatory="true"> <Label> <Resource key="relatedCINLabel"/> </Label> <AttributeDefinition attributeId="MBA| owningChangeDirectiveReference^WCTYPE| wt.change2.WTChangeDirective~MBA|number" rendererClass="com.ptc.windchill.explorer.structureexplorer.ren derer.component.TypeIconifiedStringComponent"/> </CellDefinition> <CellDefinition id="satisfyPartMaster" mandatory="true">
18-55
<Label> <Resource key="fulfillingDSLabel"/> </Label> <AttributeDefinition attributeId="MBA| satisfyPartMasterReference^WCTYPE|wt.part.WTPartMaster~MBA| masterReference@WCTYPE|wt.part.WTPart~SCA|displayIdentifier" rendererClass="com.ptc.windchill.explorer.structureexplorer.ren derer.component.TypeIconifiedStringComponent"/> </CellDefinition> <CellDefinition id="oldActionReference" displayWhenNoPreferenceSet="false"> <Label> <Resource key="reqPredecessorLabel"/> </Label> <AttributeDefinition attributeId="MBA| oldActionReference^WCTYPE|wt.change2.ChangeAction~MBA|number" rendererClass="com.ptc.windchill.explorer.structureexplorer.ren derer.component.TypeIconifiedStringComponent"/> </CellDefinition> </Table> </ExplorerElementGroup> </LogicRepository>
Note: The dataType attribute of the <LogicContext> element defines the type of part which will be displayed in the table defined. The id attribute for the <Table> must match the id specified in the import subelement of the <AssociationTable> element defined above. The attributeId attribute of the <CellDefinition> element defines the qualified attribute data to be displayed in that cell. The rendererClass attribute of the <CellDefinition> element is optional and overrides the default renderer for the cell. The <Resource> sub-element of the <Label> element refers to the text label defined in the resource file to be used for column header.
18-56
A View Effectivity Log button. This button will open a browser window and display the effectivity log for the currently selected Requirement. The standard Revert button The standard Comment button The standard Revert button The standard Comment button
Popup menus are also defined for the table which contain menu items for the three new operations: Generate Requirements Fulfill Requirement View Effectivity Log
To define menus for the Requirements tab 1. Open the PDMLinkExplorerMenusForRequirementsTab.xml file from the following location:
<Windchill>/codebase/config/logicrepository/xml/explorer/produc tstructure
18-57
<Label imageName="com/ptc/windchill/explorer/config/images/child_add.g if"> <Resource key="fulfillReqLabel"/> </Label> <ToolTip> <Resource key="fulfillReqToolTip"/> </ToolTip> <Import id="mycom.wnc.exp.FulfillRequirementAction"/> </MenuItem> <MenuItem id="ViewEffLogMI"> <Label imageName="com/ptc/windchill/explorer/config/images/child_repor t.gif"> <Resource key="viewEffLogLabel"/> </Label> <ToolTip> <Resource key="viewEffLogToolTip"/> </ToolTip> <Import id="mycom.wnc.exp.ViewEffectivityLogAction"/> </MenuItem> <Separator/> <MenuItem id="RevertMI"> <Label imageName="com/ptc/windchill/explorer/config/images/revert.gif" > <Resource key="revertLabel"/> </Label> <ToolTip> <Resource key="revertToolTip"/> </ToolTip> <Import id="ptc.wnc.exp.RevertForAltAssocAction"/> </MenuItem> <Import id="ptc.wnc.exp.CommentAssocMI"/> </Menu> </MenuBar> <ModeToolBar id="ToolBarA"> <Import id="ptc.wnc.exp.EditAppMode"/> <MenuItemIdentifier id="ptc.wnc.exp.InfoPageAssocMI"/> <Separator/> <MenuItemIdentifier id="GenerateReqsMI"/> <MenuItemIdentifier id="FulfillReqMI"/> <MenuItemIdentifier id="ViewEffLogMI"/> </ModeToolBar> <ModeToolBar id="ToolBarB"> <Import id="ptc.wnc.exp.DraftAppMode"/> <Import id="ptc.wnc.exp.AnnotateAppMode"/> <Import id="ptc.wnc.exp.ReadOnlyAppMode"/> <MenuItemIdentifier id="ptc.wnc.exp.InfoPageAssocMI"/> <Separator/>
18-58
<MenuItemIdentifier id="GenerateReqsMI"/> <MenuItemIdentifier id="FulfillReqMI"/> <MenuItemIdentifier id="ViewEffLogMI"/> <Separator/> <MenuItemIdentifier id="RevertMI"/> <MenuItemIdentifier id="ptc.wnc.exp.CommentAssocMI"/> </ModeToolBar> <ModePopupMenu id="PopupMenuA"> <Import id="ptc.wnc.exp.EditAppMode"/> <MenuItemIdentifier id="GenerateReqsMI"/> <MenuItemIdentifier id="FulfillReqMI"/> <MenuItemIdentifier id="ViewEffLogMI"/> </ModePopupMenu> <ModePopupMenu id="PopupMenuB"> <Import id="ptc.wnc.exp.DraftAppMode"/> <Import id="ptc.wnc.exp.AnnotateAppMode"/> <MenuItemIdentifier id="GenerateReqsMI"/> <MenuItemIdentifier id="FulfillReqMI"/> <MenuItemIdentifier id="ViewEffLogMI"/> <Separator/> <MenuItemIdentifier id="RevertMI"/> <MenuItemIdentifier id="ptc.wnc.exp.CommentAssocMI"/> </ModePopupMenu> </ActionAccess> </ExplorerElementGroup> </LogicRepository>
Note: The id attribute for the <ActionAccess> element must match the id specified in the import sub-element of the <AssociationTable> element defined above. The <Resource> sub-element of the <Label> and <Tooltip> elements refers to the text label defined in the resource file to be used for column header.
Define the labels, tool tips and mnemonics for the Requirements tab
Define the text for the labels, tool tips and mnemonics used in the Requirements tab. 1. Open the ConfigurationResource.rbInfo file from the following location:
<Windchill>/codebase/config/logicrepository/xml/explorer/produc tstructure
18-59
requirementsTabLabel.value=Requirements # Change Item to Requirements table requirementsLabel.value=Requirements reqNumberLabel.value=Number reqValidityLabel.value=Effectivity reqStatusLabel.value=Status relatedCINLabel.value=Originating From fulfillingDSLabel.value=Fulfilled By reqPredecessorLabel.value=Predecessor generateReqsLabel.value=Generate Requirements generateReqsToolTip.value=Generate Requirements fulfillReqLabel.value=Fulfill Requirement fulfillReqToolTip.value=Fulfill Requirement viewEffLogLabel.value=View Effectivity Calculation Log viewEffLogToolTip.value=View Effectivity Calculation Log
Note: The property name defined in the file, e.g. <property name>.value, must match the key attribute of the <Resource> element in the XML configuration files.
2. Locate the <ExplorerElementGroup> element with a sub-element <LogicContext> with the application attribute value of 'ptc.pdm.ProductStructureExplorer'. The ActionDefinition elements will be added after the LogicContext element. 3. Define the appropriate element using the steps found in the following sections.
18-60
<ActionDefinition id="mycom.wnc.exp.FulfillRequirementAction" actionClass="com.ptc.windchill.explorer.structureexplorer.panel .actions.FulfillChangeActionForStructureWithIntermediateNodeAct ion"> <StructureAuthorAction> <Import id="mycom.wnc.exp.PartToRequirementSD"/> </StructureAuthorAction> <Import id="ptc.wnc.exp.IsValidInAllWithReadVAL"/> </ActionDefinition>
Note: The id attribute defined in the <ActionDefinition> must match the import id defined for the FulfillReqMI menu item defined in PDMLinkExplorerMenusForRequirementsTab.xml. The actionClass attribute will be defined based on the node structure for Change Items and Design Solutions. If the set of Design Solutions are immediately under the Change Item node, then the following class should be specified: com.ptc.windchill.explorer.structureexplorer.panel.actions.FulfillChangeActi onAction. If the set of Design Solutions are located two levels down from their Change Item node, then the following class should be specified: com.ptc.windchill.explorer.structureexplorer.panel.actions.FulfillChangeActi onForStructureWithIntermediateNodeAction. The import id in the <StructureAuthorAction> element must match the id of the structure definition defined in the ExplorerStructures.xml file. All parts located at the level defined by the actionClass will be considered potential Design Solutions for fulfillment and presented to the user in a picklist.
Define the ActionDefinition Element for the Generate Change Actions Action
This will define the Action Definition element for the Generate Change Actions action. As detailed above, locate the <ExplorerElementGroup> element with a subelement <LogicContext> with the application attribute value of 'ptc.pdm.ProductStructureExplorer'. After the LogicContext element, add an ActionDefinition element like the following:
<ActionDefinition id="mycom.wnc.exp.GenerateRequirementsAction" actionClass="com.ptc.windchill.explorer.structureexplorer.panel .actions.GenerateChangeActionsAction"> <Action/> <Import id="ptc.wnc.exp.IsValidInAllVAL"/> </ActionDefinition>
18-61
Note: The id attribute defined in the <ActionDefinition> must match the import id defined for the GenerateReqsMI menu item defined in PDMLinkExplorerMenusForRequirementsTab.xml.
Define the ActionDefinition Element for the View Effectivity Log Action
This will define the Action Definition element for the View Effectivity Log action. As detailed above, locate the <ExplorerElementGroup> element with a subelement <LogicContext> with the application attribute value of 'ptc.pdm.ProductStructureExplorer'. After the LogicContext element, add an ActionDefinition element like the following:
<ActionDefinition id="mycom.wnc.exp.ViewEffectivityLogAction" actionClass="com.ptc.windchill.explorer.structureexplorer.panel .actions.AssociationUrlAction"> <UrlAction selectionMode="single" urlBaseName="servlet/TypeBasedIncludeServlet?"> <UrlParameter value="oid={selected_oid}"/> </UrlAction> <Import id="ptc.wnc.exp.IsValidForHTMLLaunchMasterOkVAL"/> </ActionDefinition>
The id attribute defined in the <ActionDefinition> must match the import id defined for the ViewEffLogMI menu item defined in PDMLinkExplorerMenusForRequirementsTab.xml.
2. Modify the following implementation as necessary: Modify the common_ancestry string so that it matches the parent type hierarchy of the parts for which you want to view Requirements. In the static code block, add an entry to the type_id_list for each part type which you want to view the Requirements
18-62
import wt.services.applicationcontext.implementation.DefaultServicePro vider; import com.ptc.core.foundation.struct.common.StructureConstants; import com.ptc.core.meta.common.AssociationIdentifier; import com.ptc.core.meta.common.AssociationTypeIdentifier; import com.ptc.core.meta.common.AttributeTypeIdentifier; import com.ptc.core.meta.common.IdentifierFactory; import com.ptc.core.meta.common.TypeIdentifier; import com.ptc.core.meta.common.TypeInstanceIdentifier; import com.ptc.core.meta.type.common.TypeInstance; import com.ptc.windchill.explorer.structureexplorer.config.AbstractCon fig; import com.ptc.windchill.explorer.structureexplorer.deciders.EnabledDe cider; import com.ptc.windchill.explorer.structureexplorer.utility.CommonData ; public class RequirementsEnabledDecider implements EnabledDecider { private static IdentifierFactory identifierFactory = (IdentifierFactory) DefaultServiceProvider.getService(IdentifierFactory.class, "logical"); //$NON-NLS-1$ private static List<TypeIdentifier> type_id_list = new ArrayList<TypeIdentifier>(); private static String common_ancestry = "WCTYPE| wt.part.WTPart|com.mycom.MyPart|"; //$NON-NLS-1$ static { try { type_id_list.add( (TypeIdentifier)identifierFactory.get(common_ancestry + "com.mycom.CustomPartA")); //$NON-NLS-1$ type_id_list.add( (TypeIdentifier)identifierFactory.get(common_ancestry + "com.mycom.CustomPartB")); //$NON-NLS-1$ type_id_list.add( (TypeIdentifier)identifierFactory.get(common_ancestry + "com.mycom.CustomPartC")); //$NON-NLS-1$ type_id_list.add( (TypeIdentifier)identifierFactory.get(common_ancestry + "com.mycom.CustomPartD")); //$NON-NLS-1$ } catch(Exception e)
18-63
{ e.printStackTrace(); } }
public boolean isItemEnabled(TypeInstance node_ti, TypeInstance parent_node_ti, AbstractConfig item_config, CommonData common_data) { boolean enabled = true; if (node_ti != null) { enabled = isValidPart(node_ti); } return enabled; } /** * is this node a generic part or a configurable generic part? **/ public static boolean isValidPart(TypeInstance node_ti) { if (node_ti == null) { return false; } TypeInstanceIdentifier node_tii = (TypeInstanceIdentifier) node_ti.getIdentifier(); if (node_tii == null) { return false; } try { if (IsMastered(node_ti)) { return false; } TypeIdentifier type_id = trimTypeId((TypeIdentifier) node_tii.getDefinitionIdentifier()); for(TypeIdentifier spec_type_id : type_id_list) { if(type_id.isDescendedFrom(spec_type_id)) { return true; } } return false; } catch (Exception e)
18-64
{ return false; } }
/** * Assumes an iteration... * * isMastered is an unpersisted Iteration and a persisted Master. * @param ti * @return * */ private static boolean IsMastered(TypeInstance ti) { try { TypeInstanceIdentifier tii = (TypeInstanceIdentifier) ti.getIdentifier(); if (tii instanceof AssociationIdentifier) { tii = ((AssociationIdentifier) tii).getTail(); } if (!tii.isInitialized()) { AttributeTypeIdentifier master_ati = (AttributeTypeIdentifier) identifierFactory.get(StructureConstants.MASTER_REFERENCE_ID_ST R, tii.getDefinitionIdentifier()); Object object = ti.getSingle(master_ati); TypeInstanceIdentifier master_tii = null; if (object instanceof TypeInstanceIdentifier) { master_tii = (TypeInstanceIdentifier) object; } if (master_tii.isInitialized()) { return true; } } } catch (Exception ex) { return false; } return false; } private static TypeIdentifier trimTypeId(TypeIdentifier type_id) { if (type_id instanceof AssociationTypeIdentifier) {
18-65
18-66
The .rbinfo file ties the registry of the 3rd level navigation table to the link type that is implemented for the table, the table header, and the action title. %WT_HOME%/codebase/com/ptc/windchill/enterprise/ConfigurableLinkExam ples.xconf %WT_HOME%/codebase/com/ptc/windchill/enterprise/ConfigurableLinkExam ples-wt.properties.xconf
Caution: It is recommended that you install this example on a test machine. Uninstalling the example requires manually deleting entries from some files. See Uninstalling the Configurable Links Example on page 18-68 for more information.
18-67
Note: The actionmodels.xml file overrides the third-level navigation menus on the info page with the Configurable Link Examples menu on the end. If you have customized your third-level navigation menus, then these lists must match or your customizations will be overridden. As an alternative, you could add the Configurable Link third-level navigation to the actions entry for your info pages.
6. Save and close the %WT_HOME%/codebase/wt.properties file. 7. Restart the method server. The example has been uninstalled and the third-level navigation Configurable Link Examples will no longer display.
18-68
2. Define Action Names for the Relationship Tables. The next step is to set up a mechanism to display the relationship table corresponding to a configurable link. This is done by defining actions for each configurable link table. The file ConfigurableLinkExamples-actions.xml does this in the example provided. This file contains the action definitions for all configurable links in the OOTB example. In the UI, the table names (i.e., actions) are displayed in a dropdown menu. Clicking on an action will display a table that shows the relationship contained by that configurable link. The table can display the relationship either from the Role A side or from the Role B side, depending on how the action is set up.
18-69
To display the relationship from the Role A side, the URL associated with the action must point to: /netmarkets/jsp/object/configurableLinkRoleATable.jsp To display the relationship from the Role B side, the URL associated with the action must point to: /netmarkets/jsp/object/configurableLinkRoleBTable.jsp
To define a new action, follow the syntax within the <action /action> fragment. The name field for the action can be set to any meaningful name. The value used for this field will be used as the key to provide the display name for this action in the rbinfo file (see Creating labels for the table header and action title on page 18-71). After setting the name of this action, follow the rules above to define if this specific action will display the relationship table from the Role A or the Role B side. 3. Determining the location to display the actions. The actions created in step 2 above need to be defined in the appropriate area in order to display them. An action-model is used to provide this definition. In the OOTB example, the file ConfigurableLinkExamples-actionmodels.xml handles this aspect. The relationship tables for configurable links should be defined in the 3rd level navigation. steps 3a and 3b describe how to create a model, and then display it. The end result is that the UI for the 3rd level navigation will have a new menu option. The drop-down for this menu option will be the actions that display the relationship tables for configurable links. a. Defining a model i. First, define the action model by giving it a name "configLinkExamples" in the OOTB example. The resourceBundle definition after the name is the location of the resource bundle that contains the key-value pairs of the display names (see Creating labels for the table header and action title on page 18-71).
ii. Now that the name has been defined, a brief description can be provided. iii. Next, define all the actions (i.e., relationship tables) that are intended to be displayed under this action model. In the example, all actions defined in step 2 are under this model. iv. Finally, the model as a whole needs to be placed in the 3rd level navigation of the info pages of objects that intend to display it. In this example, it is intended to be displayed from the part and document info pages. That is done by overriding the pre-existing definition for the 3rd level navigation for these 2 objects, and this is described below. b. Displaying the model
18-70
The model "third_level_nav_part" contains the list of 3rd level navigation menus available for parts. OOTB, this model is defined in PartManagementactionmodels.xml, and the menu options are "general", "relatedItems", "history", "collaboration". In order to add the newly created configLinkExamples model to the info page of a part, the "third_level_nav_part" definition has been overridden to include this new model as well. An important point to keep in mind is that performing this step will override any previous customizations to "third_level_nav_part". In order to retain any previous customizations, copy the definition of the model being overridden ("third_level_nav_part" in this case) as it exists on the system into the newly created actionmodels file ("ConfigurableLinkExamplesactionmodels.xml" in this case). Then add the newly defined model ("configLinkExamples" in this case) to the overridden model ("third_level_nav_part") using the "submodel" tag. The same steps in step 3b would have to be followed to display the new menu option for configurable link tables in the 3rd level navigation menus of an info page of any other object (Document is also provided in the OOTB example). 4. Creating labels for the table header and action title Labels are created using a key-value pair in an rbinfo file. In the OOTB example, this is done in the configurableLinkExamplesResource.rbinfo file. This file ties the registration of the 3rd level navigation table to the link type that is implemented for the table, the table header and the action title. The tieup for the link type is done in the moreurlinfo field. The value for this field has the configurableLinkType set to the value of the "nodeName" defined in Step 1. The display text for the action title is set by defining the respective values for the action names created in step 2. This file must be compiled, and the compiled (.class) version of this file must be placed in %WT_HOME%/codebase/com/ptc/windchill/enterprise/object 5. Registering the Relationship Tables with a Validator. Once the actions have been defined, it is necessary to register each newly created action with the common validator in order to ensure that the logic behind the hide/display rules for the action title and relationship table work correctly. In the OOTB example, this is done in the ConfigurableLinkExamples-service.properties.xconf file. The source and target locations for this file are: Source: com/ptc/windchill/enterprise Target: %WT_HOME%/codebase/com/ptc/windchill/enterprise
Depending on the table being registered - Role A (parent) or Role B (child) (i.e., depending on the selector), the corresponding validator ConfigurableLinkParentTableActionValidator or
18-71
ConfigurableLinkChildTableActionValidator should be used respectively as the serviceClass. 6. Registering the actions and actionmodels files The next step is to add the newly created actions and actionmodels files (from steps 2 and 3 respectively) to the application wide list of actions/actionmodels files that are picked up by the actions service. This is done in the OOTB example by the ConfigurableLinkExamples-wt.properties.xconf file. An important point to keep in mind is that the newly created actions and actionmodels files (as part of the customization) now contain overrides to models that were originally defined OOTB. If this step of adding these new files is not performed, then the original definition of these models will be used by the application. In the OOTB example as described above, the "third_level_nav_part" model has been overridden to include the "configLinksExamples" submodel. It is important to perform Step 6 in such a way that these new files are added to the global definition after the OOTB definition. In this example, ConfigurableLinksExample-actionmodels.xml must be added after PartManagement-actionmodels.xml and DocumentManagement-actionmodels.xml. This is because the OOTB example overrides the definition of the "third_level_nav_part" and "third_level_nav_doc" models. All the actions and actionmodels files are placed in wt.properties (step 7) and the last definition of a specific model is what will take effect. If the newly created actions and actionmodels files are removed from wt.properties, or are not registered as required here in Step 6, or placed before the OOTB model definitions, then the OOTB behavior will be observed for the specific 3rd level navigation menus. 7. Collecting the registrations in Steps 5 and 6 together. For convenience in the installation process, the xconf settings (containing registrations such as those in steps 5 and 6) specific to a module are placed together in one file. In the OOTB example, this file is ConfigurableLinkExamples.xconf. This file references the files created in steps 5 and 6 above and puts them together in one location for the xconfmanager to pick up and propagate the changes. The xconfmanager places all actions and actionmodels files in wt.properties, and this is used eventually by the action service. The above steps create a customized Configurable Link Table. In order to install this, follow the instructions under the Installing the Configurable Links Example on page 18-67.
18-72
3. Update the product and/or library container templates to include the access control policy rules for the ConfigurableMastersLink and/or its soft types. Any new products or libraries created with the updated templates will automatically load the access control policy rules. Following is an example of an access control policy rule that can be added to a product or library templates that will grant the teamMembers permissions read, modify, create and delete ConfigurableMastersLink objects. More specific rules can be defined for soft types of ConfigurableMastersLink.
<AccessControlRule> <domainName>/Default</domainName> <externalTypeId>wt.configurablelink.ConfigurableMastersLink</ex ternalTypeId> <lifecycleState>ALL</lifecycleState> <WTPrincipalReference isInternal="true"> <groupName>teamMembers</groupName> <groupType>teamMembers</groupType> </WTPrincipalReference>
18-73
<grantPermissionSet> <AccessPermissionSet> <permissionField name="READ"/> <permissionField name="MODIFY"/> <permissionField name="CREATE"/> <permissionField name="DELETE"/> </AccessPermissionSet> </grantPermissionSet> </AccessControlRule>
18-74
19
Customizing Windchill MPMLink
Customizing Windchill MPMLink Overview...................................................19-2 General Windchill MPMLink Customizations..................................................19-5 Customizing the Process Plan Explorer ............................................................19-7 Customizing the Manufacturing Product Structure Explorer..........................19-19
19-1
This property will automatically rebuild the jar that contains all XML configurations. However you will need to restart your applet and clear you client Java cache. Any error in an XML file will prevent the jar from being built properly. To enable logging in the Method Server console add the following line to the file codebase\ WEB-INF\log4jMethodServer.properties.
log4j.logger.com.ptc.core.logic.LogicRepository=DEBUG
Note: When moving to new versions of Windchill, changes in the XML files will NOT be automatically migrated. Changes in these files should be clearly documented. See Setting Up a Directory Structure for Managing Customized Files and Text Tailoring in Chapter 5, "Managing Customizations" for more detailed recommendations.
19-2
<explorer>Main.xml <explorer>Structures.xml
Defines the general application layout (tree, tabs) Defines the navigation model for the application (tree hierarchy, selection to tabs). Defines the actions. Defines what are the visible attributes in the tree, tables and on panels (wizards). Defines the attributes that appear in your search criteria as well as the ones to display in your search results. Defines the different menu items and their associated action. Defines the menus and toolbars. Defines the different validators. A validator is used to enable/disable (grayed/not grayed) an action or a user interface element.
<explorer>Action*.xml <explorer>TablesAndPanels.xml
<explorer>ForSearch.xml
Tip: The following files are the default files recommended for customizing Windchill MPMLink. New customization files can be created provided these files use the same application ID: codebase\config\logicrepository\xml\explorer\customization
19-3
When creating customization files for a specific explorer it is recommended that you use the following locations: CustAssociativeBOMExplorerMain.xml: The default file for Manufacturing Product Structure Explorer customizations. You can use other files, but the application ID for all XML segments must be: ptc.cust.ProductStructureExplorer CustManufacturingStandardExplorerMain.xml: The default file for Manufacturing Standards Explorer customizations. You can use other files but the application ID for all XML segments must be: ptc.cust.StandardExplorer CustMfgResourceExplorerMain.xml: The default file for Manufacturing Resource Explorer customizations. You can use other files but the application ID for all XML segments must be: ptc.cust.ResourceExplorer CustProcessPlanExplorerMain.xml: The default file for Process Plan Explorer customizations. You can use other files but the application ID for all XML segments must be: ptc.cust.ProcessPlanExplorer
19-4
In certain configurations you may want to limit access to an explorer. For example, so that only manufacturing users can have access to the Manufacturing Product Structure Explorer, with all other users having access to the Product Structure Explorer. To set this configuration at the Product or Library level navigate to the Team tab and click the configure actions for roles icon.
To set this configuration at the Site or Organization level; Create a profile for manufacturing users, using the Profile tab, Add the individual users you wish to give access to the explorer to that profile.
To change the default unit for an individual attribute, such as time, cost or dimension, use the Type and Attribute Manager.
19-5
To change the base unit of measurement for a given system, for example to change all times to minutes, use the Measurement System Manager tab.
To change the default unit for a given attribute use the Attribute Definition Manager tab. Navigate to the attribute you would like to change, and enter the new value in the Override field.
19-6
In Windchill MPMLink Process plans are also used to create shop-floor Work Instructions. Work instructions are the step by step instructions that are used on the shop floor when producing, inspecting, repairing or maintaining parts. A work instruction is a dynamically generated HTML document that combines process plan information (sequences, operations, part allocations, resource allocations, time, etc.) and all related documents such as drawings, images and 3D sessions with annotations.
19-7
Info*Engine tasks are used to gather the information that is to be displayed in the work instruction, while the JSPs are used to arrange and format the display of that information.:
Location Description
Location of the JSPs used in work instructions. Location of the Info*Engine tasks used to collect work instruction data. Location of work instruction properties. Location of the work instruction style sheet. This file can be used to change the fonts used in work instructions, as well as the color of report titles.
headerWorkInstruction.jsp
Creates the logo image shown in the top corner of the work instructions report. Right next to the logo, it creates a table showing information about the process plan for the operations shown in the report. At the far right, it creates the assembly table information for which this process plan was associated. Creates the configuration specification table used in the work instructions report. Three types of configuration specifications are valid for this report: standard, baseline, and effectivity. The values shown are the ones for the expansion criteria that were applied to the data when the work instructions report was launched.
configSpecWorkInstruction.jsp
19-8
JSP
Description
operationHeaderWorkInstruction .jsp
Displays the information created in the sequenceHeaderWorkInstruction.jsp in the left margin. Creates the label number of the operation or sub-operation and places it next to the sequence number. Below the label number, it creates a table showing the name, number, version, and short description of that operation. Creates the table below the operations header. It shows details of the operation, including work centers used, times and costs. Creates the tables with the operation long description, its associated parts, its allocated resources, and its associated documents. If the value of the Displayed column in the documents table is Yes, the associated document is a recognized image to be displayed in the work instructions panel on the left of these detail tables. Image files that can be shown in work instructions must end with an extension specified by the following property:
com.ptc.windchill.mpml.WorkInstruct ionIllustrationFileExtensionAllowed
operationDetailHeaderWorkInstr uction.jsp
operationDetailWorkInstruction. jsp
sequenceHeaderWorkInstruction .jsp
When operations are part of a sequence, this JSP creates links to the branching and return operations. If the operation is a suboperation of another operation, this JSP creates links to the parent operation. Creates the footer area shown at the end of each operation section. This displays the present state of the operation, its status, its inspection, when it was first created, who updated the operation last, and the last date and time of the update.
footerWorkInstruction.jsp
19-9
JSP
Description
coreWorkInstruction.jsp
The core JSP that constructs the work instructions report. Processes the URL parameters and calls the Info*Engine tasks used to gather the data related to the operations found in a process plan. If the JSP is launched from a process plan, it calls
processPlanLogicWorkInstruction.jsp
This JSP also computes the parent and child relationship between operations, and the sequence branching and return operations. For each operation, it will call the JSPs that create the tables and displays the data returned by the Info*Engine tasks. operationLogicWorkInstruction.j sp Launches Info*Engine tasks that find all operations and standard procedures under an operation. Operations are sorted by operation label number. This JSP does not display items in the report. Launches Info*Engine tasks that find all operations, sequences, and standard procedures under an operation. The operations found are sorted by operation label number. This JSP does not display items in the report.
processPlanLogicWorkInstructio n.jsp
19-10
describeAttributes.xml
Each webject in this task creates a group where the values of the attributes are localized. These localized values are then displayed in the work instructions report. The webjects in this task query an operation for the data that is displayed in the work instructions report. The following data sets are collected: work center, process, parts, manufacturing capabilities, resources, and documents. Each set of data is stored in an Info*Engine group. The webjects in this task create a group containing all the first depth sub-operations and standard procedures found under a particular operation. The webjects in this task create a group containing information on the assembly associated to the process plan.
getOperationData.xml
getOperationsAndStProcedur esUnderAnOperation.xml
getProcessPlanAndAssembly Information.xml
19-11
Info*Engine Task
Description
getSequencesAndStProcedure sUnderAProcessPlan.xml
The webjects in this task create a group containing all the first depth sequences and standard procedures found under a process plan. The webjects in this task create a group containing the sub-operations and standard procedures found under a particular operation. It also sorts the operations and standard procedures in each level. Currently, the algorithm is not recursive; it goes up to a depth of 3 levels. That is, it will only find 3 levels of sub-operations and then stop regardless if there are more sub-operations. To get to deeper levels, follow the pattern applied in this task and add more levels accordingly. The webjects in this task create a group containing the sub-sequences and standard procedures found under a particular sequence. It also sorts the sequences and standard procedures in each level. Currently, the algorithm is not recursive; it goes up to a depth of 3 levels. That is, it will only find 3 levels of sub-sequences and then stop regardless if there are more sub-sequences. To get to deeper levels, follow the pattern applied in this task and add more levels accordingly.
sortingOperations.xml
sortingSequences.xml
com.ptc.windchill.mpml.WorkInstruc tionIllustrationNamePattern
Pattern that defines which representations should be displayed in work instructions. The name of the ProductView representations meant to be displayed in work instructions must start with the pattern specified in this property. The default is wi_illustration.
19-12
Property
Description
com.ptc.windchill.mpml.WorkInstruc tionIllustrationPpValue
Property used in the URL of work instructions when the process plan OID is not available. The default is Value_Not_Considered. Date format used in the effectivity configuration specification. The default is mm/dd/yyyy. Configures the list of image extension types that can be seen in work instructions. The default is .jpeg,.png,.tif,.gif,.bmp,.jpg
19-13
For example, to change from seconds to minutes, change to m. To change the time units for the steps in an operation: Modify the following JSPs, as required:
setupTimeUnit processingTimeUnit laborTimeUnit queueTimeUnit, teardownTimeUnit, waitTimeUnit, moveTimeUnit
For example, to change from seconds to minutes, change to m. To relocate a table in the work instruction: Navigate to the end of the following JSP:
coreWorkInstruction.jsp
19-14
Customizations
Description
Then create the column and display data in the following JSP:
operationDetailHeaderWorkInstru ction.jsp
Modify the following CSS file and the JSPs that use the definitions in the CSS file:
workInstructionStyles.css
To change the logo at the top of the work instruction, or in the operation table:
where <logo> is the full path to the logo .gif file found in the following folder: codebase\netmarkets\jsp\mpml. The default value is: ../../images/ptcLogo_workInstructions .gif corresponding to folder codebase\ netmarkets\images To add an image extension type: Add the extension type to the following property:
com.ptc.windchill.mpml.WorkInst ructionIllustrationFileExtensio nAllowed
19-15
3. Add the following XML fragments: Note: In this example inspectionNeeded and inspectionInterval are the attributes that are being added to the Insert New Operation wizard. Modify the code to suit the wizard you would like to customize, and to add your own customized attributes.
19-16
dataType="com.ptc.windchill.mpml.processplan.operation.MPMOpera tion"/> <AttributeGroup id="ptc.mpm.exp.CreateTab2" scrollable="true" displayMode="edit"> <CellDefinition id="inspectionNeeded"> <Label> <Resource key="inspectionNeededLabel"/> </Label> <AttributeDefinition attributeId="inspectionNeeded"/> </CellDefinition> <CellDefinition id="inspectionInterval"> <Label> <Resource key="inspectionIntervalLabel"/> </Label> <AttributeDefinition attributeId="inspectionInterval"/> </CellDefinition> </AttributeGroup> </ExplorerElementGroup>
4. Clear your Java cache and restart the Process Plan Explorer. In this example note that: The application ID used for this XML fragment is ptc.cust.ProcessPlanExplorer. This is the one recommended application ID for customizing the Process Plan Explorer. The default second creation wizard for the MPMOperation object, ptc.mpm.exp.CreateTab2, is defined in: codebase\config\logicrepository\xml\explorer\mpmexplorer\ MPMExplorerForTablesAndPanels.xml. To add more attributes to the same creation wizard, the same AttributeGroup ID, ptc.mpm.exp.CreateTab2, must be used. Only the cell definitions for the new attributes are added in this XML segment.
Tip: By default cell definitions need to be added after the default cell definitions. To specify a different location use the Placement tag.
<Placement insertKey="after|before" insertId="attributeName"replace="true|false"/>
For example:
<CellDefinition id="inspectionNeeded"> <Label> <Resource key="inspectionNeededLabel"/> </Label> <AttributeDefinition attributeId="inspectionNeeded"/> <Placement insertKey="after" insertId="folder"/>
19-17
</CellDefinition>
Note: Folder is the ID of the attribute after which the inspectionNeeded attribute is added.
For example, to have operation labels with three characters and which are increased by 5 (005, 010), put the following in site.xconf, and then run xconfmanager -pF: <Property name="wt.operationLabelIncrement" overridable="true" targetFile="codebase/wt.properties" value="5"/> <Property name="wt.operationLabelNumberOfCharacters" overridable="true" targetFile="codebase/wt.properties" value="3"/>
19-18
Tip: For more information and examples refer to the comments in the property file.
19-19
Use the following procedure to copy part attributes from the eBOM to the mBOM: 1. Navigate to the following directory:
\codebase\com\ptc\windchill\mpml\xconfs\ mpmlink.properties.xconfs
Where: <create or update> defines whether part attributes are copied over at the creation of the equivalent link for the downstream part (create), or when the equivalent link of the downstream part is updated (update). If <create> is used alone there is no synchronization between the upstream and downstream parts. To create a scenario where upstream and downstream parts are synchronized update the property to include both <create> and <update> options. <WTPart or WTPartMaster> defines whether the copied attributes are from the upstream iteration of the part (WTPart) or from the upstream part master (WTPartMaster). <attribute> is the attribute to be copied over during BOM transformation.
Tip: To keep the copied attributes specific to a product update the property must include the product library container. For example:
<Property name="com.ptc.windchill.mpml.copyOver.<create or update>.wt.part.WTPartMaster.<PDMLinkProduct.Product1>" default="WCTYPE|wt.part.<WTPart or WTPartMaster>~MBA| defaultUnit"/>
Where:
Note: To copy over multiple soft attributes, or attributes that are sub-classes of other attributes, you must include the full path to the attributes you want to copy over, using the delimiter specified in the following property:
<Property name="com.ptc.windchill.mpml.copyOverDelimeter" default=","/>
19-20
Defining Rules for the Add Children from Upstream BOM Window
When transforming an eBOM into an mBOM using the paste with associative links preference the following window appears:
Windchill MPMLink can be customized so that this window is automatically populated with certain options if a predefined set of rules has been met. This is done using a Windchill MPMLink delegate. For example, Windchill MPMLink is configured by default to populate the Add Options field with Add Selected Part if the copied upstream part has a Source value defined as Buy. Use the following procedure to change this behavior, or to add additional customizations: 1. Navigate to the following directory:
\codebase\com\ptc\windchill\mpml\xconfs\ mpmlink.properties.xconfs
3. Search for:
<Option cardinality="singleton" requestor="WCTYPE| wt.associativity.EquivalenceLink" serviceClass="com.ptc.windchill.mpml.MPMCopyOverEquivalenceLink Delegate"/>
4. Substitute "com.ptc.windchill.mpml.MPMCopyOverEquivalenceLinkDelegate" with the name of the class that implements the new behavior. Or modify the class itself to change the behavior.
19-21
19-22
20
Customizing Search Functionality
This chapter describes how to customize various aspects of the search functionality. Topic Page
Adding a Search Component.............................................................................20-2 Searching for Soft Types and Attributes ...........................................................20-6 Adding Attributes to the Search Pages..............................................................20-7 The SearchableAttributes.properties File ..........................................................20-8 Adding Actions to the Search Results Table.....................................................20-9 Changing the Layout of the Search Page ........................................................20-10 Adding a New Type to the Search User Interface...........................................20-11 Customizing the Layout of the Search Results Page.......................................20-12 Adding Different Formats for Exporting Search Results................................20-14 Customizing Index Search Capabilities ..........................................................20-15 Customizing Indexing Behavior......................................................................20-19 Windchill Client Architecture Search Customization .....................................20-24 Loading an OOTB Saved Query .....................................................................20-30 Search Elements and Associated JSPs ............................................................20-42
20-1
The following sections describe how to define a search component, then how to use it.
Out of the box, this file contains search component definitions that can be used as a guide for creating a new one. The first part of the search component definition is the Windchill solution with which the component is associated. This part can have one of the following five valid entries: Foundation WindchillPDM PDMLink ProjectLink ProI
These values are linked to the entries in <Windchill>/codebase/installed.properties that define the solutions that are installed on your system. If a component is defined with a solution that is not currently installed, it will not work as expected.
20-2
The second part of the search component definition is a unique key that you assign to it. This key is used to determine the object types and container types that will be used within this search component. An example provided with Windchill is the Foundation Container Search functionality. The Foundation Container Search functionality is an out-of-the-box search component that is used in Windchill PDMLink and Windchill ProjectLink to search for container type objects. The definition for this search component follows:
Foundation.containerSearch.0=wt.projmgmt.admin.Project2 Foundation.containerSearch.1=wt.pdmlink.PDMLinkProduct Foundation.containerSearch.2=wt.inf.library.WTLibrary
The value Foundation indicates that this search component can be used with any Windchill solution that is installed, because Foundation (i.e., Windchill Services) is installed with every Windchill solution. The value containerSearch is the key assigned to the component. Each object type is given a unique sequential numerical value as well.
You can also define for a search component the container types to which the search should be constrained. An example provided with Windchill is the sandbox1 picker constraints that are defined for Windchill ProjectLink as follows:
# Open Sandbox picker container constraints for use in ProjectLink ProjectLink.openSandboxConstraint.containerType.0= wt.inf.library.WTLibrary ProjectLink.openSandboxConstraint.containerType.1= wt.pdmlink.PDMLinkProduct
These definitions are almost identical to the definitions for the object picker, except for the addition of the containerType keyword to indicate the type of entry.
1.
The term sandbox is used in code and programmer documentation to refer to the functionality that allows you to make PDM data from a PDM environment (that is, Windchill Foundation & PDM or Windchill PDMLink) available to a project, and vice versa.
20-3
Using a Component
Once a component has been defined, it can be used as a picker. This can be done by calling the CommonSearchPicker.jsp page. The following query parameters can be used to modify the picker display and functionality: selectorType Specifies the type of selector used in the search results (for example, multi, single, or none). The default is multi (meaning that 1 or many objects can be selected in the search results table). componentId This parameter has two functions: To pass multiple object types that are designated as the "searchable types" that are available through this search picker, that is, the types that can be targeted by a search through this picker. To pass multiple container types to constrain a search (that is, to do a query for all of the objects in a specific set of container types).
The specified types and container types are configured for the search component using the SearchableTypes.properties file as described above. The componentId parameter is not required. If no componentId is specified, the aggregate list of searchable types for component name "allSearch" for all installed solutions is returned. The same behavior is true for container types. objectType Specifies the object type that the picker initially selects as the object type to search for (for example, wt.part.WTPart). This parameter is not required. If objectType is not passed, the search targets all of the searchable types that are available through this search picker (see the description of the componentId parameter above). In this case, the picker displays "All Item Types" in the Search For: field. It also presents a Find... button that enables the user to select a particular object type for the search. containerRef Specifies a container; the search component is then constrained to search within that container. The value is an OBID of the container. containerType Specifies a container type to which a picker is constrained. You can specify a container type in two ways: To pass a single container type, use the CONTAINER_TYPE SearchObjects Webject parameter. To pass 1 or more container types, add entries to the following properties file:
20-4
<Windchill>/codebase/com/ptc/windchill/enterprise/search/server/Searc hableTypes.properties This allows you to specify multiple container types based on a componentId passed through the Search-Objects Webject. If both a containerType and a componentId are passed, the value passed through the CONTAINER_TYPE parameter overrides the list of container types defined for the componentId. The following is a sample definition:
Foundation.allSearch.containerType.0= wt.inf.container.ExchangeContainer
In this example, Foundation.allSearch is the componentId value, and containerType is required to differentiate between a type and a container type. This allows the same componentId to be used to define a set of types and container types. frameTitleLabel The label that will be shown at the top of the search component. This is usually used to convey the purpose of the picker. showObjectTypeNonEditable Set this parameter to false to cause the picker to provide the Find... button along with the object type. This allows the user to change the object type for the search. This parameter is not required. If this parameter is not passed and objectType is passed, then the picker shows the object type as a text field with no Find... button. base_where_clause This parameter accepts a valid WHERE clause enclosed in braces. To determine the effective WHERE clause for the search, the picker will use AND and this WHERE clause with the search WHERE clause generated from input fields. This parameter is not required. showUserType Specifies whether active and/or deleted users will be displayed. Valid values are ActiveOnly, DeletedOnly, and ActiveAndDeleted. The default is ActiveOnly. Note: If a containerType and a componentId are passed for the container type list functionality, the container type is used and the componentId is ignored. Also, for container types, if a combination of object type and componentId, but no container type are passed, the container types are resolved using the componentId.
20-5
20-6
20-7
20-8
20-9
20-10
20-11
ii. Modify the search action executeActionDoer event, adding a new Copy element (shown in bold below) as follows:
<On at="end" event="executeActionDoer"> <if condition="%[frame#SavedQueryWhereClause]!="> <Copy from="true" to="%[bean#compositeTable.searchResults.%[context#type]#Dirty]"/> </if> <Copy from="%[request#where_clause]" to="%[frame#compositeTable.searchResults.%[context#type].where_clause]"/> <Copy from="%[attribute#propertyPanel.searchCriteria#memberOfContainer]" to="%[frame#com.ptc.windchill.enterprise.search.memberOfContainerParam]"/> <Copy from="%[attribute#propertyPanel.searchCriteria#adhocPageCount]" to="%[frame#adhocPageCount]"/> <Copy from="true" to="%[frame#com.ptc.windchill.enterprise.search.AdvancedSearchQuery]"/> <Remove to="%[frame#compositeTable.searchResults.%[context#type].paging_session_id]"/> <Remove to="%[frame#compositeTable.searchResults.%[context#type].page_offset]"/> <if condition="%[context#isPicker]!=true"> <Copy from="true" to="%[bean#propertyPanel.savedQueries#Dirty]"/> </if> <Remove to="%[frame#com.ptc.windchill.enterprise.search.useSortingTaskParams]"/> </On>
ii. Modify
<TaskParameter adhocValue="%[attribute#propertyPanel.searchCriteria#adhocPageCount]" function= "com.ptc.windchill.enterprise.search.client.CoFunction_Model_Param_AdhocPageCount" if="%[context#isPropertyPicker]!=true"/>
as
20-12
ii. Within that element, exchange the locations of the Search Criteria and the Search Results LayoutRow elements:
<!-- Search Criteria --> <LayoutRow id="layoutRow.searchCriteria.searchPage"> ... </LayoutRow>
and
<!-- Search Results --> <LayoutRow id="layoutRow.searchResults.searchPage"> ... </LayoutRow>
20-13
To make the new format available in the export client the "enumerator.formatType" element will need to be updated by inserting the new labelArea in the enumerator. Example for new format .abc:
<Enumerator id="enumerator.formatType"> <Insert ref="labelArea.formatType.csv" value="csv" /> <Insert ref="labelArea.formatType.xml" value="xml" /> <Insert ref="labelArea.formatType.html" value="html" /> <Insert ref="labelArea.formatType.abc" value="abc" /> .............. ............... </Enumerator>
20-14
20-15
FETCH_FIELDS Specifies a set of fields that are stored in Index Search to be retrieved as part of the query. The default fields that will always be requested is the ufid, which is used by Search-Objects to retrieve the results from the Indexed-Search from Windchill. SORTBY Specifies a set of attributes that are both specified to be returned by the query and that have sorting preferences defined. Multiple values can be specified for this parameter. If multiple values are specified, then the first value is the primary sort attribute, the second value is the secondary sort attribute, and so on. This parameter is optional. SORTED Specifies whether the current attribute to sort by should be sorted as descending or ascending. The default for this parameter is descending. This parameter is optional. FILTER_ACCESS When set the indexing engine will use a filter the result set to a 'Potential' read list. SPELL_CHECK If set to true, then Indexing Engine will attempt to validate spelling and suggest possible query terms. TYPE_CONTAINER Determines the set of base types to be used in the search from the incoming type parameter. QUERY_TYPE Determines the type of query to perform, Simple or Advanced. A Simple query sends the keyword to Index Search as a keyword only. An Advanced query sends the keyword as an Index Search query, so it must have valid syntax for an Index Search query. See the Instream SDK Query Language Parameters Guide for valid Index Search query syntax. MAX_DOCS Determines the maximum amount of documents to return from index search. MIN_HITS This parameter is ignored. CONTAINER_REF Filters the search results to those objects within the container reference. INSTANCE Specifies the name of the Windchill adapter. You can define the adapter name when you configure the adapter on the Info*Engine Property Administrator service form. This parameter is required.
20-16
COMPONENT_ID Specifies which client component is invoking the search. This parameter is used to select the list of classes to query against as defined in com/ptc/windchill/enterprise/search/server/SearchableTypes.properties. SEARCH_IN_USER_ORG Search only in containers (contexts) belonging to principal's org. AND_OR_OPERATOR Determines if the Index Search query uses SIMPLEANY (OR) or SIMPLEALL (AND). ATTRIBUTE_TYPE_CONTEXT Filters the search results by attribute type. UNFORMATTED This parameter is ignored. GROUP_OUT Specifies the name of the output group containing the results. If this parameter is omitted the name of the output group is constructed by appending the string "-Output" to the webject name. This parameter is optional. The resulting group is not access controlled, but can then be used to query Windchill for the appropriate objects, to include access control. The group could be combined with other criteria as well to perform a more specific search. Please see the Windchill Adapter Guide for more information around setting up SearchObjects and Query-Objects webjects.
These two are optional parameters. The default values are "sortBy" and "sorted", respectively. If the parameters are not present, or if the default values are used, no sorting is done. To specify the fields to sort by, set the SORTBY parameter value to any of the fields defined for the particular library. The default library (collection) provided in Windchill is wblib; the list of fields (for example, "name", "number", "title") is shown in the IndexSearch
20-17
Administration UI, on the Search page. To view all available fields, check the "Show All Fields" checkbox in Advanced Controls. If you specify a value in SORTBY that is not a default and does not match any of the library fields, then it is ignored and no sorting will be done. The SORTBY parameter is a case sensitive field. Hence for sorting the results based on number, and in ascending order, the parameters to add would be:
<ie:param name="SORTBY" data="number"/> <ie:param name="SORTED" data="ascending"/>
You can give multiple fields and their corresponding sort orders by space separated values. For example:
<ie:param name="SORTBY" data="name number"/> <ie:param name="SORTED" data="asc"/>
This would sort the results first on name and then number. For further information on the Indexed-Search webject, see the Windchill Adapter Guide.
20-18
IndexSearch Fields
In addition to the full text index of object metadata and content files, text can be indexed into specific IndexSearch fields. When text is indexed into fields, it is possible to restrict, or filter, query responses by entering search terms in data fields, such as title, number, date, and so on. These queries can be used in combination with a full text query or used alone to limit the types of documents returned. Windchill provides a Index Search Profile configured with the fields in the table below. If you want a library to contain additional fields, you must add those fields to the profile before data is indexed into the library. Refer to the Index Profile Features Management section of the InStream Configuration Guide for further information on setting up library fields. After the fields have been defined for the library, you can write a custom InstreamIndexDelegate subclass to populate the new fields with the appropriate data, or you can simply append them onto the following property in wt.properties:
wt.index.IndexFields= name,lifeCycleState,description,number,title,containerReference,modifyTimestamp
Notice that some attributes are indexed automatically and cannot be overridden.
Field
Description
Required
businesstype
This is the actual type of the object, it is used internally to filter queries in a more performant manner.
Yes
20-19
Field
Description
Required
iscontent
This is a flag to indicate if an index entry represents content or not. Could be used to filter by content vs metadata. This is the id of the ContentItem that is actually indexed. This is used as a way to keep track of multiple indexed items with one Windchill Object. The name of the indexed object. The number of the indexed object. This field contains all of the miscellaneous attributes for an object that are not defined in any other field. The lifecycleState of the object (In Work, Released, etc) The object reference of the container the object belongs to. The last modified stamp of the object The created timestamp of the object. This is a field that represents all of the soft attributes associated with an object. Note: The name of the field comes from the fact that soft attributes have sometimes been referred to as instance-based attributes (IBAs).
Yes
ufid
Yes
No No Yes
No No No No Yes
organizationreference
20-20
because fewer attributes would need to be processed and written to IndexSearch but this should be a secondary consideration when determining if creating a custom InstreamIndexDelegate is appropriate. To create a custom InstreamIndexDelegate, use Rational Rose to model your new class, making it extend the InstreamIndexDelegate class. Then generate the Java code and provide implementations for the following method signatures:
public void custom_getAdditionalMetaData( Indexable indexable, IndexingObject indexingObject ) throws WTException, IndexingException { public void custom_getAdditionalFieldData( Indexable indexable, IndexingObject indexingObject ) throws WTException, IndexingException {
These methods do nothing in the base class, so anything added will be additional functionality for the indexing system. There are examples below on how to call specific methods to write customized fields, or specify additional metadata on an indexed object. To put your custom InstreamIndexDelegate into action, you must update the service.properties file to reflect this change. Following is the default InstreamIndexDelegate entry:
# ##################################################### # The wt.index.IndexServiceDelegate service. # ########################################################### wt.services/svc/default/wt.index.IndexServiceDelegate/null/ wt.index.Indexable/0=wt.index.InstreamIndexDelegate/duplicate
As part of the changes introduced in 8.0, the ability to subclass the delegate by type is no longer supported. However, this functionality can easily be reproduced by logic in a customer IndexServiceDelegate. Also, the ability to define a delegate for a single library is no longer supported either, but fields that are not defined in a particular library are ignored, so sending additional information to IndexSearch is not an issue. For this example, assume that you have a custom InstreamIndexDelegate named InstreamSubClassIndexDelegate that you want to use to index. If you want to override the default InstreamIndexDelegate you must add the following line to service.properties:
wt.services/svc/default/wt.index.IndexServiceDelegate /null/wt.index.Indexable/0= wt.index.InstreamSubClassIndexDelegate/duplicate
(Note that you should actually enter only one line; the indentation shown here indicates a continuation of the preceding line, necessary for presentation of lines within the book.)
20-21
20-22
20-23
Objective
Scenario A: Allow user to add customized attribute to Criteria drop down Scenario B: Allow user to add new action for given type to search result table Scenario C: Allow user to add new customized type to search item picker
Background
Scenario A - An out-of-the-box user can search on all the modeled attributes as well as soft attributes for given Object Tyep. User can not see attributes that are added by modeling the Object in Rational Rose. Scenario B - The site-defined preference, /com/ptc/windchill/enterprise/search/allSearchTypes,determines the list of types that are to be included when a user searches across "all" Object types. This is the same list that a user can choose from within the Object Type picker for the Customize link on the Search page, and the Search For link onthe Advanced Search page Scenario C - The allSearchTypes preference defines a base list of types; outof-the-box searching rules include all soft types defined from one of these types. It does not, however, include any modeled subclasses. Any new modeled object type should be defined in the allSearchTypes preference to make it available for searches.
Scope/Applicability/Assumptions
Scenario A - New attributes are added to item by Rational Rose modeling. Scenario B - New actions are defined Scenario C - New item or object type is modeled in Rational Rose
Intended Outcome
Scenario A - Adding new criteria to search result table:
An out-of-the-box user will not get added extra attributes in Criteria drop down on advanced search page. Once user adds entry for logical attribute name for new
20-24
attributes in SearchableAttributesByType.properties, user can see new attribute criteria drop down.
In above case user has added new attribute Real and Real _Units which are added by rose modeling.
Scenario B - Adding new action to search result table.
Out-of-the-box there are fixed actions defined for all Object type on simple search page whereas on advanced search page Object Type specific actions are available on search result table. Out-of-the-box on simple search page Copy, Delete, Add to Project, Move, Reassign Life Cycle, Export actions are provided. We have to add action Set State on simple search page.
The allSearchTypes preference defines a base list of types; out-of-the-box searching rules include all soft types defined from one of these types. It does not, however, include any modeled subclasses. Any new modeled object type should be defined in the allSearchTypes preference to make it available for searches.
20-25
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Basic development involving HTML forms, JSP, XML, Java
20-26
Solution Elements
Element
Type
Description
Scenario A SearchableAttributesByType.properties
properties
Runtime location <Windchill>/codebase/com/ptc/windchil l/enterprise/search/server/SearchableAttr ibutesByType.properties Runtime <Windchill>/codebase/config/actions/se a rch-actionmodels.xml Runtime location <Windchill>/codebase/com/ptc/windchil l/enterprise/search/server/SearchableByT ypes.properties
Scenario B - search-actionmodels.xml
XML
Scenario C SearchableTypes.properties
properties
20-27
After adding the new type you should set the property com.ptc.windchill.search.refreshTypesFromProperties to "true" in wt.properties.
Sample Code Scenario A: Entries from SearchableAttributesByType.properties for new attribute part Type
advancedSearch.wt.part.WTPart=folderingInfo.cabinet,thePersistInfo .creat eStamp,iterationInfo.creator,defaultUnit,lock.locker,name,number,o wnership.owner,source,state.state,thePersistInfo.modifyStamp,itera tionInfo.modifier,view.id,organizationReference,Real
20-28
20-29
6. In this example, the SavedQueries tag is used, user can use any tag provided that user has to write handler for that tag and have to add the entry for that tag in several dtds. Add <!ELEMENT SavedQueries (SavedQuery*)> in: \Windchill\codebase\registry\ixb\dtds\standardX10.dtd\netmarkets.dtd and \Windchill\loadXMLFiles\standardX10.dtd 7. User can add multiple saved queries in single xml file, for that the SavedQuery tag will be repeted inside the SavedQueries tag.
Example: SavedQuery.xml
The contents of SavedQuery.xml would be something like the following.
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE SavedQueries SYSTEM "standardX10.dtd"> <SavedQueries> <SavedQuery> <name>Product</name> <description> ((null))</description> <owningClient>dcaSimpleSearch</owningClient> <SearchCriteria>
20-30
<CommonCriteria> <searchElement> <searchKey>searchClass</searchKey> <searchValue>wt.part.WTPart,wt.change2.WTChangeIssue,wt.change2.WT ChangeOrder2,wt.epm.EPMDocument,wt.change2.WTChangeRequest2,wt.doc .WTDocument</searchValue> </searchElement> <searchElement> <searchKey>searchInUserOrg</searchKey> <searchValue>null</searchValue> </searchElement> <searchElement> <searchKey>memberOfContainer</searchKey> <searchValue>null</searchValue> </searchElement> <searchElement> <searchKey>networkSearch</searchKey> <searchValue>false</searchValue> </searchElement> <searchElement> <searchKey>containerTypeList</searchKey> <searchValue>wt.pdmlink.PDMLinkProduct</searchValue> </searchElement> <searchElement> <searchKey>pageCount</searchKey> <searchValue>15</searchValue> </searchElement> <searchElement> <searchKey>search_keyword</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>relatedItemSearch</searchKey> <searchValue>false</searchValue> </searchElement> <searchElement> <searchKey>is_keyword_required</searchKey> <searchValue>null</searchValue> </searchElement> <searchElement> <searchKey>searchType</searchKey> <searchValue>wt.part.WTPart,wt.change2.WTChangeIssue,wt.change2.WT ChangeOrder2,wt.epm.EPMDocument,wt.change2.WTChangeRequest2,wt.doc .WTDocument</searchValue> </searchElement> <searchElement> <searchKey>savedQueryTableViewID</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>showResults</searchKey> <searchValue>&</searchValue> </searchElement> <searchElement> <searchKey>containerName</searchKey>
20-31
<searchValue></searchValue> </searchElement> <searchElement> <searchKey>name</searchKey> <searchValue>null</searchValue> </searchElement> <searchElement> <searchKey>organization</searchKey> <searchValue>null</searchValue> </searchElement> <searchElement> <searchKey>number</searchKey> <searchValue>null</searchValue> </searchElement> </CommonCriteria> <NetworkCriteria></NetworkCriteria> <CustomCriteria> <row className="com.ptc.netmarkets.search.rendering.guicomponents.Searc hPickerComponent" id="orgField"> <searchElement> <searchKey>pickerTextBoxLength</searchKey> <searchValue>25</searchValue> </searchElement> <searchElement> <searchKey>defaultValue</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>renderer</searchKey> <searchValue>com.ptc.netmarkets.search.rendering.renderers.SearchP ickerComponentRenderer</searchValue> </searchElement> <searchElement> <searchKey>containerRef</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>searchTermProducer</searchKey> <searchValue>com.ptc.netmarkets.search.stp.SearchPickerSearchTermP roducer</searchValue> </searchElement> <searchElement> <searchKey>pickerRef</searchKey> <searchValue>genericPicker</searchValue> </searchElement> <searchElement> <searchKey>objectType</searchKey> <searchValue>wt.org.WTOrganization</searchValue> </searchElement> <searchElement> <searchKey>displayValue</searchKey> <searchValue></searchValue> </searchElement> <searchElement>
20-32
<searchKey>calledFromAdvSearch</searchKey> <searchValue>true</searchValue> </searchElement> <searchElement> <searchKey>pickedAttributes</searchKey> <searchValue>name</searchValue> </searchElement> <searchElement> <searchKey>typeComponentId</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>pickerType</searchKey> <searchValue>search</searchValue> </searchElement> <searchElement> <searchKey>attTypeForOperator</searchKey> <searchValue>java.lang.String</searchValue> </searchElement> <searchElement> <searchKey>operatorValue</searchKey> <searchValue>=</searchValue> </searchElement> <searchElement> <searchKey>uiID</searchKey> <searchValue>orgField</searchValue> </searchElement> <searchElement> <searchKey>attrID</searchKey> <searchValue>organization.id</searchValue> </searchElement> <searchElement> <searchKey>searchResultsViewId</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>hiddenFieldName</searchKey> <searchValue>organization.idorgField</searchValue> </searchElement> <searchElement> <searchKey>pickedDataFetcher</searchKey> <searchValue>/Windchill/netmarkets/jsp/search/pickedData.jsp</sear chValue> </searchElement> <searchElement> <searchKey>defaultHiddenValue</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>isRenderedFromTable</searchKey> <searchValue>false</searchValue> </searchElement> <searchElement> <searchKey>showVersion</searchKey> <searchValue>false</searchValue> </searchElement>
20-33
<searchElement> <searchKey>baseWhereClause</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>showTypePicker</searchKey> <searchValue>false</searchValue> </searchElement> <searchElement> <searchKey>pickerId</searchKey> <searchValue>organization.idorgField</searchValue> </searchElement> <searchElement> <searchKey>readOnlyPickerTextBox</searchKey> <searchValue>true</searchValue> </searchElement> <searchElement> <searchKey>pickerCallback</searchKey> <searchValue>SearchPickerInputComponentCallback</searchValue> </searchElement> <searchElement> <searchKey>componentId</searchKey> <searchValue>pickerSearch</searchValue> </searchElement> <searchElement> <searchKey>pickerTitle</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>multiSelect</searchKey> <searchValue>false</searchValue> </searchElement> <searchElement> <searchKey>hiddenValue</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>isRequired</searchKey> <searchValue>false</searchValue> </searchElement> <searchElement> <searchKey>displayName</searchKey> <searchValue></searchValue> </searchElement> </row> <row className="com.ptc.netmarkets.search.rendering.guicomponents.Searc hTextBox" id="numberField"> <searchElement> <searchKey>operatorValue</searchKey> <searchValue>=</searchValue> </searchElement> <searchElement> <searchKey>uiID</searchKey> <searchValue>numberField</searchValue> </searchElement>
20-34
<searchElement> <searchKey>value</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>width</searchKey> <searchValue>20</searchValue> </searchElement> <searchElement> <searchKey>attrID</searchKey> <searchValue>number</searchValue> </searchElement> <searchElement> <searchKey>renderer</searchKey> <searchValue>com.ptc.core.components.rendering.renderers.TextBoxRe nderer</searchValue> </searchElement> <searchElement> <searchKey>searchTermProducer</searchKey> <searchValue>com.ptc.netmarkets.search.stp.SearchTextBoxTermProduc er</searchValue> </searchElement> <searchElement> <searchKey>isRequired</searchKey> <searchValue>false</searchValue> </searchElement> <searchElement> <searchKey>name</searchKey> <searchValue>numbernumberField_SearchTextBox</searchValue> </searchElement> <searchElement> <searchKey>attTypeForOperator</searchKey> <searchValue>java.lang.String</searchValue> </searchElement> <searchElement> <searchKey>displayName</searchKey> <searchValue></searchValue> </searchElement> </row> <row className="com.ptc.netmarkets.search.rendering.guicomponents.Searc hTextBox" id="nameField"> <searchElement> <searchKey>operatorValue</searchKey> <searchValue>=</searchValue> </searchElement> <searchElement> <searchKey>uiID</searchKey> <searchValue>nameField</searchValue> </searchElement> <searchElement> <searchKey>value</searchKey> <searchValue></searchValue> </searchElement>
20-35
<searchElement> <searchKey>width</searchKey> <searchValue>20</searchValue> </searchElement> <searchElement> <searchKey>attrID</searchKey> <searchValue>name</searchValue> </searchElement> <searchElement> <searchKey>renderer</searchKey> <searchValue>com.ptc.core.components.rendering.renderers.TextBoxRe nderer</searchValue> </searchElement> <searchElement> <searchKey>searchTermProducer</searchKey> <searchValue>com.ptc.netmarkets.search.stp.SearchTextBoxTermProduc er</searchValue> </searchElement> <searchElement> <searchKey>isRequired</searchKey> <searchValue>false</searchValue> </searchElement> <searchElement> <searchKey>name</searchKey> <searchValue>namenameField_SearchTextBox</searchValue> </searchElement> <searchElement> <searchKey>attTypeForOperator</searchKey> <searchValue>java.lang.String</searchValue> </searchElement> <searchElement> <searchKey>displayName</searchKey> <searchValue></searchValue> </searchElement> </row> <row className="com.ptc.netmarkets.search.rendering.guicomponents.Searc hTextBox" id="keywordField"> <searchElement> <searchKey>operatorValue</searchKey> <searchValue>=</searchValue> </searchElement> <searchElement> <searchKey>uiID</searchKey> <searchValue>keywordField</searchValue> </searchElement> <searchElement> <searchKey>value</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>width</searchKey> <searchValue>50</searchValue> </searchElement> <searchElement>
20-36
<searchKey>attrID</searchKey> <searchValue>keyword</searchValue> </searchElement> <searchElement> <searchKey>renderer</searchKey> <searchValue>com.ptc.core.components.rendering.renderers.TextBoxRe nderer</searchValue> </searchElement> <searchElement> <searchKey>searchTermProducer</searchKey> <searchValue>com.ptc.netmarkets.search.stp.KeywordSearchTermProduc er</searchValue> </searchElement> <searchElement> <searchKey>isRequired</searchKey> <searchValue>false</searchValue> </searchElement> <searchElement> <searchKey>name</searchKey> <searchValue>keywordkeywordField_SearchTextBox</searchValue> </searchElement> <searchElement> <searchKey>attTypeForOperator</searchKey> <searchValue>java.lang.String</searchValue> </searchElement> <searchElement> <searchKey>displayName</searchKey> <searchValue></searchValue> </searchElement> </row> <row className="com.ptc.netmarkets.search.rendering.guicomponents.Searc hDateComponent" id="createdField"> <searchElement> <searchKey>uiID</searchKey> <searchValue>createdField</searchValue> </searchElement> <searchElement> <searchKey>operatorValue</searchKey> <searchValue>=</searchValue> </searchElement> <searchElement> <searchKey>value</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>attrID</searchKey> <searchValue>thePersistInfo.createStamp</searchValue> </searchElement> <searchElement> <searchKey>renderer</searchKey> <searchValue>com.ptc.netmarkets.search.rendering.renderers.SearchD ateRenderer</searchValue>
20-37
</searchElement> <searchElement> <searchKey>attributeType</searchKey> <searchValue>1</searchValue> </searchElement> <searchElement> <searchKey>searchTermProducer</searchKey> <searchValue>com.ptc.netmarkets.search.stp.DateSearchTermProducer< /searchValue> </searchElement> <searchElement> <searchKey>isQueryBuilder</searchKey> <searchValue>false</searchValue> </searchElement> <searchElement> <searchKey>isRange</searchKey> <searchValue>false</searchValue> </searchElement> <searchElement> <searchKey>isRequired</searchKey> <searchValue>false</searchValue> </searchElement> <searchElement> <searchKey>sinceValue</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>displayName</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>attTypeForOperator</searchKey> <searchValue>java.lang.String</searchValue> </searchElement> </row> <row className="com.ptc.netmarkets.search.rendering.guicomponents.Searc hDateComponent" id="lastUpdatedField"> <searchElement> <searchKey>uiID</searchKey> <searchValue>lastUpdatedField</searchValue> </searchElement> <searchElement> <searchKey>operatorValue</searchKey> <searchValue>=</searchValue> </searchElement> <searchElement> <searchKey>value</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>attrID</searchKey> <searchValue>thePersistInfo.modifyStamp</searchValue> </searchElement> <searchElement> <searchKey>renderer</searchKey>
20-38
<searchValue>com.ptc.netmarkets.search.rendering.renderers.SearchD ateRenderer</searchValue> </searchElement> <searchElement> <searchKey>attributeType</searchKey> <searchValue>1</searchValue> </searchElement> <searchElement> <searchKey>searchTermProducer</searchKey> <searchValue>com.ptc.netmarkets.search.stp.DateSearchTermProducer< /searchValue> </searchElement> <searchElement> <searchKey>isQueryBuilder</searchKey> <searchValue>false</searchValue> </searchElement> <searchElement> <searchKey>isRange</searchKey> <searchValue>false</searchValue> </searchElement> <searchElement> <searchKey>isRequired</searchKey> <searchValue>false</searchValue> </searchElement> <searchElement> <searchKey>sinceValue</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>displayName</searchKey> <searchValue></searchValue> </searchElement> <searchElement> <searchKey>attTypeForOperator</searchKey> <searchValue>java.lang.String</searchValue> </searchElement> </row> </CustomCriteria> </SearchCriteria> </SavedQuery> </SavedQueries>
20-39
import wt.ixb.handlers.netmarkets.NMProjectConstants; import wt.ixb.handlers.netmarkets.NMIxResources; import wt.ixb.handlers.netmarkets.ProjectIXUtils; import wt.pom.Transaction; import wt.util.WTException; /** * This class is the handler for the <SavedQueries> tag. */ public class SavedQueryHandler extends ClassExporterImporterTemplate { private static final String _rb = "wt.ixb.handlers.netmarkets.NMIxResources"; private static final String OOTB_SAVED_QUERIES = "SavedQueries"; public SavedQueryHandler() { } public void exportObject(Object obj, Exporter exp) throws wt.util.WTException { Object[] params = {obj.getClass().getName()}; throw new WTException(_rb, NMIxResources.EXPORT_NOT_SUPPORTED,params); } /** * This controls the import of all the objects. * On exception all transactions are rolled back. */ public Object createObject(IxbElement elem, Importer imp) throws wt.util.WTException { ProjectIXUtils.checkTag(elem, OOTB_SAVED_QUERIES); WTContainerRef orgRef = imp.getTargetContainerRef(); imp.generalContext.put(IxbHndHelper.CONTAINER_SCOPE,orgRef); Transaction trx = new Transaction(); try { trx.start(); boolean firstTime = true; Vector parmSet = new Vector(); // Enumeration files = elem.getElements(orgTags.LOAD_XML_FILE); Enumeration files = elem.getElements(IxbHndHelper.XML_SAVEDQUERY); while(files.hasMoreElements()) { if(firstTime) { parmSet.add(IxbHndHelper.XML_SAVEDQUERY);
20-40
ProjectIXUtils.postFeedback(imp,_rb,NMIxResources.LOAD_TYPE,parmSe t.toArray(),NMProjectConstants.TYPE_LEVEL); firstTime = false; } IxbElement file = (IxbElement) files.nextElement(); imp.importElement(file); } if(!firstTime) { ProjectIXUtils.postFeedback(imp,_rb,NMIxResources.TYPE_LOADED,parm Set.toArray(),NMProjectConstants.TYPE_LEVEL); parmSet.clear(); } firstTime =true; ProjectIXUtils.postFeedback(imp,_rb,NMIxResources.ORG_IMPORT_SUCCE EDED,null,0); trx.commit(); return null; } finally { if(trx != null) { trx.rollback(); } } } public int getImportPriority() throws wt.util.WTException { return 42; } public Object findAmongExistingObjects(IxbElement obj, Importer imp) throws wt.util.WTException { return null; } public Object storeObject(Object obj, IxbElement elem, Importer imp) throws wt.util.WTException { //all objects are stored, by the handlers, this is just the driver. return obj; } }
20-41
Search element and their associated JSP for Simple Search Page
Search Advanced Search Saved Searches Keyword Show Results Results Per Page Search In Search For
searchNavigation
searchTextBox
Search In Search For Name Number Organization FileName Last Updated Created On Save This Search,Search,Clear Button Search Results Table Save This Search
/netmarkets/jsp/search/sho wContext.jsp /netmarkets/jsp/search/typ eChooser.jsp /netmarkets/jsp/search/sear chCriteria.jsp /netmarkets/jsp/search/sear chCriteria.jsp /netmarkets/jsp/search/sear chCriteria.jsp /netmarkets/jsp/search/sear chButton.jsp /netmarkets/jsp/search/sear chResults.jsp /netmarkets/jsp/search/cust omizeQuery.jsp
searchInContext
searchTextBox
searchPicker searchDate
20-42
Search element and their associated JSP for Advanced Search Page
Search UI Element Search Page Search Page Navigation Search Advanced Search Saved Searches Keyword Show Results Results Per Page Search In Search For Search sub Element Associated JSP /netmarkets/jsp/searc h/executeSearch.jsp /netmarkets/jsp/searc h/searchNavigation.j sp /netmarkets/jsp/searc h/commonSearch.jsp searchNavigation Associated Custom Tag (if any)
searchTextBox
Search In Search For Search For Type Picker Define Search Criteria for Archived Objects Options for Part advanced search SuMA sourcing contexts Criteria:
searchInContext
archivePanel
searchDDLComponent /netmarkets/jsp/searc h/sourcingContext.js p /netmarkets/jsp/searc h/queryBuilder.jsp /netmarkets/jsp/searc h/searchButton.jsp /netmarkets/jsp/searc h/searchResults.jsp /netmarkets/jsp/searc h/customizeQuery.js p
Select Search Criteria Save This Search,Search,Clear Button Search Results Table Save This Search
20-43
20-44
III
Business Logic Customization Section
Chapter
Page
Customizing Business Logic............................................................................. 21-1 Customizing Change Management ................................................................... 22-1 Customizing Life Cycle Administration ........................................................... 23-1 Customizing Workflow Administration............................................................ 24-1 Customizing Workgroup Managers .................................................................. 25-1 Customizing Windchill Visualization Services ................................................ 26-1 Report Generation ............................................................................................. 27-1 Customizing Event Audits ................................................................................ 28-1 Customizing Communication Tools ................................................................. 29-1
21
Customizing Business Logic
This chapter describes how to customize business logic. Topic Page
Identified Business Classes ..............................................................................21-2 Customizing Iteration and Version Identifiers ................................................21-17 Customizing a Bill of Materials ......................................................................21-19 Customizing User Preferences ........................................................................21-24 Writing a Servlet Helper to Use URLFactory Functionality...........................21-30 Updating a Master Through an Iteration .........................................................21-32
21-1
21-2
If an attribute of a wt.fc.IdentificationObject is modelled with the "Changeable" property set to "ViaOtherMeans", the Identity Service will consider that attribute part of the identity, and will require that the user have MODIFY_IDENTITY permission to change that attribute. The Identity Service will require MODIFY permission to change attributes whose models do not have the "Changeable" property set to "ViaOtherMeans". Attributes which are modelled as "Changeable Via Other Means" on the business object, but are not so modelled on the IdentificationObject, will not be protected by the MODIFY_IDENTITY permission.
21-3
21-4
21-5
IdentificationObject is a non-persistent class that holds the values of the identity attributes from a class that implements the Identified or UniquelyIdentified interface. For a particular business class that implements Identified, a subclass of IdentificationObject is modeled that has the same identity attributes as the business class. Instead of directly changing the identity attributes of the business object, the attributes of the IdentificationObject subclass are used to change the identity, and these values are then copied back to the business object, subject to validation logic and uniqueness constraints, when IdentityService.changeIdentity is called. Any class that implements the Identified interface must implement the getIdentificationObject method, which returns an instance of IdentificationObject that holds the current value of the identity attributes.
21-6
The following sequence diagram illustrates how a change orders identity is modified:
Identified
When a class implements the Identified or UniquelyIdentified interface, the identity attributes of the class must be modeled in a special way. Also, a single method on the Identified interface -- getIdentificationObject -- must be implemented. UniquelyIdentified has no methods to implement. wt.change2.WTChangeRequest2 is used to illustrate the step-by-step instructions. See the class diagram named "request" in the wt.change2 package of the Rose model for reference. 1. Add a public constructor that has arguments for each user-assigned identity attribute. WTChangeRequest2 has a constructor that has a single argument for the name attribute. Number is the other identity attribute but, because it is systemassigned, it does not need to be an argument of the constructor. In the initialize method that is called from the generated factory method for this constructor, the name attribute is initialized. Sequential system-assigned attributes, like numbers, should not be initialized in the constructor, but instead in the PersistenceManager PRE_STORE event processing right before the object is saved. This greatly improves the odds that elements in the sequence are not lost if the create action is aborted by the user. That is, system-assigned attributes are initialized only when it is certain that an object will be persisted. 2. Set the WriteAccess model property to "protected" for all identity attributes.
21-7
This action prevents general access to the setter methods, allowing only the IdentityService to update the identity attributes of an Identified object. Note: There may be cases where it is necessary to create an uninitialized instance of a class by calling the no-arg constructor, followed by calls to the setter methods to initialize the attributes. This is the case with WTPartMaster and WTDocumentMaster. In this situation, the identity attributes must have public WriteAccess instead of protected. To prevent the use of the setter methods after the object has been persisted, use the "Changeable" property. When set to the value "ViaOtherMeans", the Changeable property causes validation code to be generated in the setter method for the attribute, which allows the method to be used only if the object is not persistent. 3. Implement getIdentificationObject (part of the Identified interface) to return a new instance of the subclass of IdentificationObject that has been designed for this particular Identified class. In the case of WTChangeRequest2, there is a subclass of IdentificationObject called WTChangeRequest2Identity. Following is an example:
public IdentificationObject getIdentificationObject() throws WTException { //##begin getIdentificationObject%3536588B01EEg.body preserve=yes return WTChangeRequest2Identity.newWTChangeRequest2Identity( getNumber(), getName()); //##end getIdentificationObject%3536588B01EEg.body } The following section describes the role of IdentificationObject and how to extend it.
IdentificationObject
Throughout these instructions, the example of wt.folder.SubFolderLinkIdentity is used to illustrate each step. See the class diagram named "Identification" in the wt.folder package of the Rose model for reference. 1. Model a subclass of IdentificationObject in the same package. wt.folder.SubFolderLinkIdentity extends IdentificationObject. Notice that the subclass of IdentificationObject is in the same package as the class that implements Identified, namely SubFolderLink. This is a requirement because SubFolderLinkIdentity must call protected setter methods on SubFolderLink to change the value of its identity attributes.
21-8
2. Add public attributes for each user-assigned identity attribute. For every user-assigned identity attribute of the Identified class, add the same attributes to the subclass of IdentificationObject. In the case of SubFolderLinkIdentity, the identity attributes are subFolderName and parentFolderReference. Making the identity attributes public on the IdentificationObject allows any client to assign a new identity to an object through the IdentificationObject setter methods instead of the ones on the Identified object (see the preceding figure on modifying a WTChangeOrder2s identity). 3. Add a protected constructor that has an argument for the Identified object. The constructor is protected because it is intended to be invoked only in the getIdentificationObject method of the corresponding Identified class, in this example, SubFolderLink. Alternatively, the constructor can have an argument for each identity attribute instead of the entire Identified object. 4. Implement the code-generated initialize method to set the identity attributes from the Identified Object. For every modeled constructor, a static factory method is automatically generated that is implemented to call an initialize method. In this initialize method, call the identity attribute getter methods on the Identified object and set them to the IdentificationObjects identity attributes. That is, copy the identity attributes from the Identified object to the IdentificationObject. Following is an example:
protected void initialize( SubFolderLink link ) throws WTException { //##begin initialize%356993D30199.body preserve=yes setParentFolderReference((ObjectReference)link. getRoleAObjectRef()); setSubFolderName(link.getFoldered().getName()); //##end initialize%356993D30199.body }
5. Implement the getIdentity method. The getIdentity method is not used unless the subclass of IdentificationObject is for a UniquelyIdentified class. If your class implements only Identified, getIdentity can return any String representation of the identity attributes.
21-9
6. Implement the setToObject method. The setToObject method is invoked by the IdentityService to transfer the values of the identity attributes from the IdentificationObject to the Identified object. Following is the implementation of SubFolderLinkIdentity.setToObject:
public void setToObject( Identified obj ) { //##begin setToObject%356993A900B2s.body preserve=yes // All we have to set is the reference because the name // is managed by the SubFolder object. ((SubFolderLink)obj). setRoleAObjectRef(getParentFolderReference()); //##end setToObject%356993A900B2s.body }
This completes the implementation of the IdentificationObject subclass if the corresponding business class implements Identified. If it implements UniquelyIdentified, then the following two additional steps are necessary: 1. Override the getKeyClassName method. This method returns the name of the class that extends SemanticKey, which is used to store the key value that is subject to the uniqueness constraint for the UniquelyIdentified object. For the SubFolderLinkIdentity example, a private, static String constant is modeled and initialized to the value SubFolderLinkConstraint.class.getName(). Then getKeyClassName simply returns this String constant. 2. Ensure that getIdentity returns a String that represents the uniqueness constraint on the UniquelyIdentified object. Because getIdentity is an abstract method in IdentificationObject, every subclass must implement it. However, it is not actually used unless the subclass of IdentificationObject is for a UniquelyIdentified class. In this case, getIdentity is called to set the value of SemanticKey.key. Remember, this is the String that represents the uniqueness constraint on the UniquelyIdentified object. In this example, getIdentity returns the following string:
getParentFolderReference().getObjectId().getStringValue() + "+" + getSubFolderName();
This String is a combination of the parent folder and subfolder name. This indicates the uniqueness constraint on SubFolderLink is that no two subfolders in a given parent folder can have the same name.
21-10
The preceding figure illustrates the general case. Consider a specific example, WTPartMaster. WTPartMaster has two identity attributes: name and number. Number must be unique across all subclasses of WTPartMaster, so we must implement a SemanticKey. WTPartMasterKey extends SemanticKey and WTPartMasterIdentity extends IdentificationObject. The implementation of WTPartMasterIdentity.getKeyClassName returns "wt.part.WTPartMasterKey" and WTPartMasterIdentity.getIdentity returns the part number. So, whenever a WTPartMaster is saved, the value of the part number is stored in the WTPartMasterKey table. Any subclass of WTPartMaster also stores its number in the same SemanticKey table, WTPartMasterKey. Because there is a uniqueness constraint on the key attribute of the WTPartMasterKey class, unique part numbers are guaranteed across WTPartMaster and all its subclasses.
21-11
21-12
The CompositeUnique1 and CompositeUnique2 properties of a class create a unique index across multiple database columns. The following example is for wt.enterprise.RevisionControlled, which specifies that the master + version + iteration + checkout state attributes are unique as a whole.
When using the CompositeUnique property, only two unique indexes can currently be specified in the model. Additional attributes can be added to the index in the subclass by adding them after the "+".
21-13
21-14
Given a modeled class that implements the DatastoreSequence interface, the getNextSequence method returns a number that is represented as a String. The number value returned is incremented each time the getNextSequence method is invoked for the given sequence name. 2. Listen for the PRE_STORE event on the identified object. The service associated with the Identified object in question must listen for a PersistenceManager PRE_STORE event and assign the number value at this time. For example, for WTChangeRequest2, the ChangeService2 implements the following to assign numbers to change requests:
protected void performStartupProcess() throws ManagerException { //##begin performStartupProcess%35D1B483001F.body preserve=yes /* * Listen for a PersistenceManager PRE_STORE event * on a WTChangeRequest2 */ getManagerService().addEventListener( new ServiceEventListenerAdapter() { public void notifyVetoableEvent( Object event ) throws WTException { PersistenceManagerEvent pmEvent = (PersistenceManagerEvent)event; Persistable target = pmEvent.getTarget(); if (target instanceof WTChangeRequest2) { // assign a number WTChangeRequest2Identity idObj = (WTChangeRequest2Identity)target. getIdentificationObject(); idObj.setToObject(target); } } }, PersistenceManagerEvent.generateEventKey( PersistenceManagerEvent.PRE_STORE)); }
21-15
4. Create the sequence as a standalone datastore element, by modeling a class that implements wt.fc.DatastoreSequence. Set the datastore schema name, initial seed value, and increment value from the Rose model. Use the generated database script to create the datastore schema object. For more information, see How Rose UML Maps to Database Schema in the System Generation chapter on page 31-41. In this example, ChangeRequest2IdentitySequence implements DatastoreSequence. Following is an example for WTChangeRequest2:
21-16
Iteration identifiers are by default specified as being an integer series where this series contains whole numbers from a minimum to a maximum value. The default minimum is one (1) and the default maximum is the largest possible 32-bit positive integer value as defined by 2**31-1 (2,147,483,647). There is also a default specification of the delta between adjacent numbers, which is one (1) meaning that, if given 10, the next incremented integer value would be 11 by default. Version identifiers are by default specified as being a harvard series. A harvard series is one that is made up of subseries and is typically depicted as a stream of values delimited by a dot (for example, 1.1, 1.3.5, 1.2.1.1, and so on). Version identifiers must be specified as some sort of multilevel series where the harvard series is currently the only option. This is done to represent both in-lined versions and branched versions in one identifier that forms a version tree. In turn, the harvard series subseries are by default specified as being multi character series at level one and then, because there are no other levels specified, the default from there on is what was specified before for all levels. In this case, it would be multi character series for all levels. If level two was specified as an integer series then, starting at the beginning, every two levels would alternate from a multi character to integer series up to the specified depth as seen below.
wt.series.HarvardSeries.depth=16 wt.series.HarvardSeries.level.1=wt.series.MulticharacterSeries wt.series.HarvardSeries.level.2=wt.series.IntegerSeries
21-17
Multi character series are specified much like integer series where there is a minimum, maximum, and delta. By default, these properties specify A, Z, and 1, respectively. But there also is another property to specify the length of the multi character series. By default, this is three (3), which means that an identifier of this series would have a range from A to ZZZ, where incrementing from Z of a delta of one (1) would be AA, incrementing from AZ would be BA, and incrementing from ZZ would be AAA. Decrementing follows these same rules except in reverse. If a length of one (1) were specified instead of the default of three, this series would range from A to Z given the same other properties. Any character value for the minimum and maximum can be specified for a multi character series. But only integers can be specified for the minimum and maximum values of an integer series. For additional information, see the "Object Initialization Rules" chapter in the Windchill Business Administrators Guide.
21-18
Both of these reports are defined to be generated as an HTML page optimized for printing from a Web browser. Both the BOM generation and formatting can be customized as needed. A BOM report is generated using a template processor. The actual BOM information is generated entirely by Visitor objects. These objects are a means of specifying a "callback" operation for each node in a "tree" data structure. For example, a part structure contains Part objects linked together through the "uses" relationship. Starting from a top-level part, the entire part structure is traversed and a "visit" method is called on the Visitor object passing the current part object and the related usage information. This method can be overridden to provide customized BOM computation and formatting.
Customization
The remainder of this section describes an example of a BOM that is provided out-of-the-box with Windchill. Understanding this example provides a basis for implementing other BOM customizations. There are two types of customization for a BOM. BOM computation refers to the work that is done on each item as the structure is traversed. Windchill provides two types of BOM computation: hierarchy and parts list. The second customization is for formatting the output that is displayed to the user. This formatting is dependent on the type of information displayed.
21-19
The Hierarchy Visitor is an implementation that shows the quantity and unit attributes of the "usage" associations and visually indicates the hierarchical levels. The only computation that is required is to output this information. This class extends the TextOutputVisitor, which provides standard helper methods for outputting localizable messages to an output stream. In addition to providing the implementation for the "visit" method, this class defines the customization points for altering the format of the output. These methods are designed to be called at various points as the output is being generated.
public abstract class BOMHierarchyVisitor extends TextOutputVisitor { // Define methods that should be overridden to allow for // formatting customization protected abstract void preVisitWrite( int a_level ); protected abstract void postVisitWrite( int a_level ); public void preNavigateWrite() { } public void postNavigateWrite() { } }
The visit method performs a basic output of the part identity and usage information. The preVisitWrite() and postVisitWrite() calls are significant because they allow for formatting customization.
public boolean visit( Persistable fromNode, Link link, Persistable toNode, int level, boolean previouslyVisited ) throws WTException { PrintWriter out = getPrintWriter(); preVisitWrite(level); String partIdentity = ((WTPart) toNode).getDisplayIdentity(); if(link == null) { out.print(partIdentity); } else { // Display part and usage information as a // localized message Quantity quantity = ((WTPartUsageLink) link).getQuantity(); Object[] params = { new Double(quantity.getAmount()), quantity.getUnit().getDisplay(), partIdentity }; printLocalizedMessage(partResource.PART_USAGE, params); } postVisitWrite(level); return true; }
21-20
The BOMHierarchyVisitor class is abstract and therefore cannot be used directly. The formatting must be customized by implementing the preVisitWrite() and postVisitWrite() methods in a descendant class. The following class is a customization example for use when the BOM is displayed in an HTML page. It displays the hierarchical level through HTML heading tags. The methods preVisitWrite() and postVisitWrite() wrap the part information in and tags where n is the level number.
public class HtmlHeadingHierarchyVisitor extends BOMHierarchyVisitor { protected void preVisitWrite( int a_level ) { PrintWriter out = getPrintWriter(); out.print("<H"); out.print(a_level + 1); out.print('>'); protected void postVisitWrite( int a_level ) { PrintWriter out = getPrintWriter(); out.print("</H"); out.print(a_level + 1); out.print('>'); out.flush(); } }
Soft attributes on parts are displayed in the BOM reports automatically using the table view, but soft attributes on part usage link cannot be displayed automatically. The soft attributes on the part usage link are shown in the list of available columns, but to get the actual value to display, the corresponding report JSP file needs to be customized to indicate the specific soft attributes from the part usage link to display. As an example, if a soft attribute "LinkName" was added to part usage link, the values of that attribute can be displayed by 1. Set up a custom table view with that column as one of the selected columns. 2. Add the following to the describeTable section of the JSP:
<describeColumn id="IBA|LinkName" other settings for the column> /> targetObject="link" <any
After the customization is complete, you need only specify that the new customized class should be used when the BOM is generated. By default, the BOM template processors use the application services mechanism to instantiate a Visitor object that is used to generate the BOM. The service can be replaced by changing the appropriate entry in the services.properties file. Change the following entry in the file:
21-21
wt.services/svc/default/wt.part.BOMHierarchyVisitor/print/ wt.fc.WTObject/0=wt.part.HtmlNumberedHierarchyVisitor/duplicate
to:
wt.services/svc/default/wt.part.BOMHierarchyVisitor/print/ wt.fc.WTObject/0=wt.part.HtmlHeadingHierarchyVisitor/duplicate
Note the use of the "print" value in the "visitor" key in the service entry. Currently, the Windchill client code displays a BOM designed for printing within an HTML page and therefore uses the value "print". This key value is obtained from the URL parameters by the BOM template processor. If the client were customized to provide other types of BOM formats (by specifying different values in the URL), this key could be used for generating different formats. For example, an additional client function could be added for viewing a BOM with embedded graphics. A new value "graphic" could be used that is associated with a customized Visitor that will generate appropriate graphic output. Both types of formatting would then be available to the user.
Both the Hierarchy and Parts List Visitor objects are dependent on a depth first traversal of the part structure. The Hierarchy Visitor outputs the structure as it is traversed so the order in which part nodes are visited is significant. The Parts List computation relies on multiplying quantities between levels and storing the result
21-22
internally. If a part were to appear in separate branches of a structure and depth first traversal were not used, then the computed quantity for a subassembly can be overwritten before its component parts use that information.
21-23
Preference Definition
The preference definition contains all of the static information about a preference which is stored in the database. This definition contains a default value and the constraint (as in the IBA constraints) for what is allowed as a value instance. The preference API returns this default value if a preference value (in the form of a preference instance) is not located in the database. Display information used in the Preference Manager UI is also defined in the preference definition as resource bundle entries. The static information in the preference definition includes the following: Name Default Value Display Name Display Description Display Long Description Visibility (Hidden, Site, Org, Container, User, and User Only) The value handler for processing the preference values
Visibility
The preference definition contains a visibility flag to show who can see a given preference in the Preference Manager. HIDDEN- preference would be one that is not visible in the Preference Manager. SITE - preference is on that is visible only to the Site Administrator. ORGANIZATION - preference is one that is visible to the Site and Org Administrators. Each Org could have a separate instance of the value tied to that Org. CONTAINER - preference is one that would be visible to the Site and Org Administrators and the Container Manager. USER - preference is one that would be visible at all levels. USER_ONLY - preference is one that is settable only at the user level.
21-24
Preference Instance
The individual values are set within the preference instance. The preference instance ties the chosen context; Site, organization container, application container (such as a projects, programs, products, or libraries) or user to the preference definition with the value set for the context. If a preference instance is not found in a request for a preference, then the default value defined in the preference definition is returned.
Preference Category
The category is just a means of grouping preferences in the tree structure of the Preference Manager. An individual preference definition is contained within a preference category. A preference category can be contained within another category. This allows for a hierarchical view of the preferences. The preference category has no impact on the actual operation of the system, but is used in the administration of the preferences.
Preference Client
The client was added for UWGM to set preference values by Authoring Applications like AutoCAD, CATIA V5, etc. The default client name if not specified is WINCHILL, defined by the constant wt.preference.PreferenceClient.WINDCHILL_CLIENT_NAME.
21-25
organization; application contexts within the organization inherit preference values from the organization.
Note: User preferences may be inherited directly from the organization-level, from individual application contexts, or may be unique (settable only at the user level). Preference values can be set for each application context, or for an individual user, unless the preference value is locked at a higher level. For example, if a preference is not locked at the organization level, then it may have one value at the organization level, but individual products or projects within that organization could each specify a different value. Similarly, if a preference is not locked at an organization level, but is available at the user level, then individual users could each set different values for that preference. Preferences can be locked at any level above the individual user. If a preference is locked, then the value cannot be changed for those lower levels. A site or organization administrator can choose to delete all values for a particular preference that may be set at levels below the current context, usually prior to locking the preference. If a preference is not explicitly set for a particular application context, then the value for that preference is inherited from the level above. For example: If a preference is not set for a particular product or project, then the value set for that preference at the organization level is used. If the preference is not set at the organization level, then the value set for that preference at the site level is used. If no preference is set at any level, then the default value defined for that preference is used.
21-26
The above method will return the value at the user context if it exists, otherwise the value set at the container context and so on up the preference hierarchy. Other single preference value methods in the wt.preference package include:
public Object getValue( String definitionName, String clientName ); public Object getValue( String definitionName, String clientName, OrgContainer organization );
The first method retrieves value at the Site context, while the second method retrieves the value at the Organization context and if it does not exist, then the inherited value at the Site is returned. Multiple preference values can be retrieved at the same time. This is more efficient in database calls:
public Map<String, Object> getValues(WTContainerRef containerRef, Collection<String> definitionNames, Collection<String> categoryNames, String clientName, WTUser user)
Example:
Map<String,Object> preferenceMap = null; ArrayList<String> categories = new ArrayList<String>(); ArrayList<String> definitionNames = new ArrayList<String>(); definitionNames.add("PREFERENCE_DEFINITION_1"); definitionNames.add("PREFERENCE_DEFINITION_2"); definitionNames.add("PREFERENCE_DEFINITION_3"); definitionNames.add("PREFERENCE_DEFINITION_4");
Map <String, Object> preferenceMap = PreferenceHelper.service.getValues( containerRef, definitionNames, categories, clientName, user);
Adding Preferences
New preference definitions and categories are added using the LoadFromFile utility to load an XML based load file. This can be run with the following command:
21-27
An example XML preference load file which loads various preference definitions and preference categories is the Windchill/loadfiles/preference.foundation.xml load file. Example Preference Definition:
<?xml version="1.0"?><!DOCTYPE NmLoader SYSTEM "standardX10.dtd"> <NmLoader>
<csvPreferenceDefinition handler="wt.preference.LoadPreference.createPreferenceDefinition"> <csvname>PREFERENCE_DEFINITION_1</csvname> <csvvisibility>USER</csvvisibility> <csvcategoryName>UNASSIGNED</csvcategoryName> <csvdisplayName>com...PrefsRB:MYPREF_NAME</csvdisplayName> <csvdescription>com...PrefsRB:MYPREF_SHORT_DESC</csvdescription > <csvlongDescription>com...PrefsRB:MYPREF_DESC</csvlongDescripti on> <csvdefaultValue>false</csvdefaultValue>
</NmLoader>
Note: The <csvLinkPreferenceClientDefinition> entry is needed if the preference is to be visible in the Preference Manager UI. The <csvdisplayName>, <csvdescription>, <csvlongDescription> are in the form of rbinfo file/key pair separated by a colon : like the following:
wt.preference.preferenceResource:Unassigned
21-28
The preference category specified by <csvcategoryName> needs to exist otherwise the creation of the preference definition will fail. Example Preference Category:
<csvPreferenceCategory handler="wt.preference.LoadPreference.createPreferenceCategory"> <csvname>UNASSIGNED</csvname> <csvparentName></csvparentName> <csvdisplayName>wt.preference.preferenceResource:Unassigned </csvdisplayName> <csvdescription></csvdescription> </csvPreferenceCategory>
Sub-categories can be created by adding an existing category name to the <csvparentName> element.
21-29
The method bodies should take arguments and generate a proper resource path (such as, servlet/WindchillAuthGW), then pass this resource path to the URLFactory getHREF and getURL methods for generating the servlet HREF and URL.
The URLFactory in the JSP Environment section in the Additional Topics - Client Customization appendix on page E-7 gives more detailed reference information on URLFactory usage and encoding/decoding techniques to use in JSP development.
21-30
////////////////////////////////////////////////////////////////////// // This file is intended to give an example of how the URLFactory // and GatewayServletHelper may be used within // the JSP programming environment. To run this file, simply // place the file in the /Windchill/codebase/wtcore/jsp directory. // Extra whitespace as been left in for clarity and ease of reading. /////////////////////////////////////////////////////////////////////// %> <% /*** The WTContextBean is a JavaBean for use in Java Server Pages or Servlets that wish to use Windchill Java client or server APIs ***/ %> <jsp:useBean id="wtcontext" class="wt.httpgw.WTContextBean" scope="request"> <jsp:setProperty name="wtcontext" property="request" value="<%=request%>"/> </jsp:useBean> <% /*** The URLFactory is a JavaBean for use in the generation of HREFs used in Windchill JSP clients ***/ %> <jsp:useBean id="url_factory" class="wt.httpgw.URLFactory" scope="request" > <% url_factory.setRequestURL(request.getScheme(),request.getHeader("HOST"), request.getRequestURI()); %></jsp:useBean> <% // The response header for the output stream should be set to UTF-8 response.setContentType("text/html; charset=UTF-8"); // Below we also set the content type in the @page tag, since some // servlet engines %><%@ page import="wt.httpgw.*,java.util.HashMap" contentType="text/html; charset=UTF-8" %> <% // Here we want to generate a link to the Windchill home page through // the default authenticated gateway. For this we will utilize the // wt.httpgw.GatewayServletHelper class to generate a HREF which // from the current URLFactory will generate a link to this site. // %> <BR> <A HREF="<%= wt.httpgw.GatewayServletHelper.buildAuthenticatedHREF( url_factory ) %>">Windchill Home</A> <BR> <% // Perhaps you would like a link to your personal cabinet. In order to // do this, you must generate a link through the authenticated gateway // with a class/method and arguments to invoke like below
21-31
// String URL_PROCESSOR = "wt.enterprise.URLProcessor"; String TEMPLATE_ACTION = "URLTemplateAction"; // URLFactory and GatewayServletHelper uses HashMap for arguments HashMap map = new HashMap( ); map.put( "Action", "Create" ); // adds the action 'create' to the hashmap map.put( "Class", "wt.doc.WTDocument" ); // adds the class to apply the action // to. %> <A HREF="<%= wt.httpgw.GatewayServletHelper.buildAuthenticatedHREF(url_factory, URL_PROCESSOR, TEMPLATE_ACTION, map ) %>">Create a Document</A> <% // // // // // // // // // // // // // // For optimization, any links generated in the fashion described above could be generated reusing the HashMap and Strings already created. The Setup.jsp file located in codebase/wtcore/jsp/wt/portal/Setup.jsp does just this in the generation of the links thus reducing the overhead in String/HashMap object creation. In the FORM below we use the URLFactory to generate a link to the resource wtcore/jsp/sample.jsp. See the Javadoc for method prototypes. The URLFactory is smart enough to see how it is currently configured and return a String link which should work within the current environment. For the example below, since we are running the file from /WEB-APP/wtcore/jsp the link will generate simply "sample.jsp". Optionally we could have called url_factory.getHREF("wtcore/jsp/sample.jsp",request.getQueryString() ) if we wished to retain the current Query string.
%> <FORM ACTION="<%= url_factory.getHREF("wtcore/jsp/sample.jsp") %>" METHOD="POST"> <INPUT TYPE="text" NAME="Sample_Text" VALUE="<%= prev_value %>"> <INPUT TYPE="submit"> </FORM>
21-32
on the master are number and name. In addition to being master attributes, they are also identifying attributes. This means that they can be modified only by using the IdentityService after the object has been persisted. The Windchill reference implementation does not have an example of a master class with non-identifying attributes. Currently, there is no support for automatically persisting a master if its non-identifying attributes are updated using derived attributes on the iteration. That is, the attribute could be modified by calling its setter on the iteration, but the client would have to persist the master to save the changes. The following is a discussion of different ways master attributes can be exposed on the iteration and how changes to master attributes through the iteration can be persisted.
2. To make derived attributes read-only, set their WriteAccess to something other than Public.
21-33
21-34
21-35
21-36
22
Customizing Change Management
22-1
ChooseLifeCycleDelegate
ChooseLifeCycleDelegate is used within StandardChangeService2 by calling the protected method chooseLifeCycle. In the chooseLifeCycle method, the delegate is obtained from the Change2DelegateFactory. The chooseLifeCycle method is not called if the change object is already persisted, because it would already have a life cycle set. In the chooseLifeCycle method, the delegate mechanism is used only if a life cycle has not yet been set.
// In any of the saveChange... methods, such as saveChangeRequest: If changeItem is not persistent { ChangeServiceHelper2.service.chooseLifeCycle (changeItem); } // In chooseLifeCycle if changeItem has no lifecycle { Set the lifecycle using the delegate; }
When saving a change object, Windchill uses the ChooseLifeCycleDelegate mechanism to assign a life cycle if and only if the change object is not yet persistent and a life cycle is not assigned already. This means that the delegate mechanism is effective only when creating a new change object. As a customization, you could allow the user to select a life cycle from a drop-down list in the HTML page and then, because the life cycle would already be set, the delegate would not replace that life cycle. The DefaultChooseLifeCycleDelegate uses a property file entry to get the name of the life cycle that should be used.
ChooseFolderDelegate
ChooseFolderDelegate is used within StandardChangeService2. It is obtained from the Change2DelegateFactory. The Windchill vision of change management is that change issues, requests and orders should be visible in folders so that a user can easily look for issues (or suggestions), requests (issues that are being addressed), and orders (changes that have been made). The investigations, proposals, analysis activities, and change activities are tightly tied to other objects and they are not visible in folders. Because these related objects need the same access control and other attributes of their related object, which is in a folder, Windchill puts them in the same domain as the related object that is in a folder. The ChooseFolderDelegate assigns one ChangeItem to a folder/cabinet based on the folder/cabinet of another ChangeItem.
22-2
The SynchronizedDomainChooseFolderDelegate assigns a CabinetManaged object to the same domain as a CabinetManaged object or a Folderable object. It assigns a Folderable object to the same folder as another Folderable object. It throws an exception when asked to assign a Folderable object based on a CabinetManaged object. In addition, a listener is defined on the change2 service that listens for movement of change issues, request, and orders. It moves their child objects (analysis activities, change activities, change investigations, and change proposals) to the same cabinet into which the parent object was just moved.
ConcreteAssociationDelegate
ConcreteAssociationDelegate is used within StandardChangeService2. It is obtained from the Change2DelegateFactory. There are many subclasses of ConcreteAssociationDelegate. Each one takes two arguments: the two objects being linked. Each one returns the link object that links the two objects. There is no mechanism for adding additional values for attributes that belong on the link object, so this mechanism works best for link objects that have not been customized with additional attributes. One other complication with this delegate is that if you customize some of the main classes, you may have to add properties file entries that may not seem intuitively obvious. Assume that you customize change order (that is, make a subclass of wt.change2.WTChangeOrder2) in your myChange2 package within your customization package and call it MyChangeOrder. When looking up the appropriate subclass of wt.change2.ConcreteAssociationDelegate, the following entry in section 9 of wt.change2.change2.properties is being used when linking the change order to a change request:
wt.services/svc/default/wt.change2.ConcreteAssociationDelegate/ wt.change2.WTChangeOrder2/wt.change2.WTChangeRequest2/ 1=wt.change2.AddressedBy2Delegate/singleton
The reference to wt.change2.WTChangeRequest2 is in a field where inheritance is applied. In other words, if you subclassed wt.change2.WTChangeRequest2 as customization.myChange2.MyChangeRequest, then the delegate lookup process could still use this line in the properties file, because customization.myChange2.MyChangeRequest is a wt.change2.WTChangeRequest2. The reference to wt.change2.WTChangeOrder2 is in a field where inheritance is not applied. In other words, if you subclassed wt.change2.WTChangeOrder2 as customization.myChange2.MyChangeOrder, then the delegate lookup process could not use this line in the properties file because the string "customization.myChange2.MyChangeOrder2" does not match exactly the string "wt.change2.WTChangeOrder2".
22-3
DisplayIdentificationDelegate
DisplayIdentificationDelegate is used within StandardChangeService2. It is obtained from the Change2DelegateFactory. For further information, see the section on implementing new display identification delegates in the identity service description in the System Generation chapter on page 31-1.
22-4
23
Customizing Life Cycle Administration
This chapter describes how to customize the life cycle administration. Topic Page
Customizing the Display of Life Cycle Information.........................................23-2 Defining Customized Life Cycle Transitions....................................................23-3 Setting Up a Customized State-Based Versioning Scheme ..............................23-3
23-1
When displaying a string of states, this value is the separator between each of the states listed. Default is " - ".
CURRENT_STATE_BEGIN
When displaying a string of states, this value is the notation that a particular state is the current state. Default is "<B>".
CURRENT_STATE_END
When displaying a string of states, this value is the notation that a particular state is the current state. Default is "</B>".
DROPPED_STATE_BEGIN
This entry notes that the current state (usually dropped) is not found in the list of current states. Default is " [".
DROPPED_STATE_END
This entry notes that the current state (usually dropped) is not found in the list of current states. Default is "] ".
IS_AT_GATE
This value is used to indicate that Awaiting Promotion = true. Default is "Yes".
IS_NOT_AT_GATE
This value is used to indicate that Awaiting Promotion = false. Default is "No".
LABEL_BEGIN
This value is used when displaying any of the StateProcessor labels. Default is "<B>".
LABEL_END
This value is used when displaying any of the StateProcessor labels. Default is ": </B>".
STATE_LIST_BEGIN
When the list of states is provided along with other information, this entry differentiates the State list from other information in the display. Default is "(".
STATE_LIST_END
When the list of states is provided along with other information, this entry differentiates the State list from other information in the display. Default is ")".
HISTORY_LABEL
This entry is used when displaying a link to the Life Cycle History page. Default is "History".
23-2
HISTORY_NOTATION_BEGIN
When the history link is provided along with other information, this entry differentiates the History link from other information in the display. Default is " (".
HISTORY_NOTATION_END
When the history link is provided along with other information, this entry differentiates the History link from other information in the display. Default is ") ".
2. Build the runtime resource bundles for the customized packages by entering the following command from a windchill shell:
ResourceBuild wt.lifecycle.TransitionRB
The new transition will be added to the transitions that are available when you create or update life cycles using the Life Cycle Administrator. The new transition can be accessed programatically. You can invoke the navigate() method to find the valid transitions between states using that new transition, such as in the following code snippet:
WTKeyedMap rejectMap=new WTKeyedHashMap(); Set rejectSet = new HashSet(); State rejectState=State.toState("DESIGN"); rejectSet.add(rejectState); rejectMap.put(<life_cycle_managed>, rejectSet); WTKeyedHashMap returnMap = (WTKeyedHashMap) LifeCycleHelper.service.navigate (rejectMap, Transition.toTransition("MY_REJECT"), true);
The above call to navigate() returns the successor states to the DESIGN state on a life cycle managed object (<life_cycle_managed>), following valid MY_REJECT transitions.
23-3
Adding The Series To StateBasedVersioning.xml And Loading The File Making The Newly Added Version Schemes Available In The Lifecycle Administrator Creating A Lifecycle Template Which Uses The New Version Series Setting Up The Object Initialisation Rules How The Revision Scheme Can Be Used
23-4
Observe the warning that THIS WILL OVERWRITE THE EXISTING SERIES. Once the file has been loaded, you will receive a message: Successfully saved FileBasedSeries.
Making The Newly Added Version Schemes Available In The Lifecycle Administrator
Customize the Lifecycle Administrator, adding the two seeds as options to the Version Series drop-down. This is done using the enumcustomise utility found in <Windchill>\bin, and the file to modify is the Resource Bundle wt.series.SeriesRangeSelectorRB. Ensure that the key that you add matches the name of the seed you have defined in the StateBasedSeries.xml. Below is an example of how to add the PROTOTYPE seed, which we added as a seed and loaded in Step 1.
23-5
Finally, rebuild the jars in a Windchill shell with the following command:
<Windchill>\ant\bin\ant f <Windchill>\codebase\makejar.xml
Note that the extra series were added using the Default locale in the enumcustomize utility. This means that they will only be visible if the browser language is set to English (US).
23-6
In this instance, a lifecycle called prototype_released was created which uses the PROTOTYPE version series in the Prototype phase, and the RELEASED version series in the Released phase.
23-7
</AttrValue> <!-- set the team template --> <AttrValue id="teamTemplate.id" algorithm="com.ptc.core.foundation.team.server.impl.TeamTemplateAttributeAlgorithm" > <Arg>Default</Arg> </AttrValue> <!-- set the number to a generated number --> <AttrValue id="number" algorithm="com.ptc.windchill.enterprise.revisionControlled.server.impl.NumberGenera tor"> <!-- add a V prefix for variant parts --> <Value algorithm="wt.rule.algorithm.BooleanBranch"> <Value algorithm="wt.rule.algorithm.EqualsTest"> <Attr id="genericType"/> <Arg>variant</Arg> </Value> <Arg>V</Arg> <Arg></Arg> </Value> <!-- the sequence --> <Arg>{GEN:wt.enterprise.SequenceGenerator:WTPARTID_seq:10:0}</Arg> </AttrValue> <!-- set the version info to a generated version info --> <AttrValue id="MBA|versionInfo" algorithm="com.ptc.core.foundation.vc.server.impl.VersionInfoGenerator"> <Arg>wt.series.HarvardSeries</Arg> </AttrValue> </AttributeValues>
Note: <If this rule is defined at Site or Organization level, object initialisation rules defined at context level may need to be disabled.
23-8
23-9
Note: The version now shows rel_A, as defined in the StateBasedVersioning.xml file in the beginning.
Caution: This procedure should be performed immediately after installation, and before any objects are created in the Windchill system. If objects have already been created using a different versioning scheme, then the behavior when these objects are revised will be unpredictable.
23-10
24
Customizing Workflow Administration
Customizing Workflow HTML Templates .......................................................24-2 Customizing Change Management Workflow Process Templates ...................24-6 Customizing Promotion Request Workflow Processes...................................24-13 Customizing Workflow Events on an Object..................................................24-17 Customizing Workflow Task Pages ................................................................24-19
24-1
The functionality to perform all of these customizations is available through existing Windchill scripts, as seen in the standard Windchill HTML client. As a result, you can make these customizations without programming Java (possibly only one resource bundle change), but only editing HTML and some entries in a Windchill properties file. For both an overview and detailed information about customizing HTML clients, see the Customizing HTML Clients Using the Windchill JSP Framework chapter on page 10-1. This section discusses the HTML client only as it applies to workflow.
24-2
To customize a workflow HTML template, perform the following steps: 1. Create a workflow activity that you want to be represented by the customized HTML page with the workflow administrator applet. The action argument of the activities property page URL is specified by the type of workflow task (see the following figure).
For customizations, you can use the predefined HTML templates UserTask1.html through UserTask7.html, or create your own named templates, for example CustomTask.html. If you create your own task template, you must add an entry to the wt.properties file, as shown in the following example, to cause the new task to appear in the list of available tasks:
wt.clients.workflow.tasks.task.1=WfTask wt.clients.workflow.tasks.task.2=WfUpdateContent wt.clients.workflow.tasks.task.3=WfAugment wt.clients.workflow.tasks.task.4=review wt.clients.workflow.tasks.task.5=promote wt.clients.workflow.tasks.task.6=observe wt.clients.workflow.tasks.task.7=submit wt.clients.workflow.tasks.task.8=WfDefineProjects wt.clients.workflow.tasks.task.9=WfChgMgmt wt.clients.workflow.tasks.task.10=UserTask1 wt.clients.workflow.tasks.task.11=UserTask2 wt.clients.workflow.tasks.task.12=UserTask3 wt.clients.workflow.tasks.task.13=UserTask4
24-3
The default behavior of workflow task processing recognizes these tasks by their template name, for example, CustomTask. If you want to change the display name of your task, you should add entries to the wt.clients.workflow.tasks.TasksRB.rbInfo file as follows:
CustomTask.value="Customized Task Name" CustomTask.constant=MYCUSTOMIZEDTASK
The string "Customized Task Name" is displayed in the drop-down list and must be localized. The string "CustomTask" is the value of the action argument in the URL requests of the HTML page for a workflow activity of that type. 2. Add or modify the appropriate entries in the service.properties and htmltemplate.properties files. If you add an entry in the resource bundle, you must add a line similar to the following in the service.properties file:
wt.services/svc/default/wt.enterprise.TemplateProcessor/ CustomTask/java.lang.Object/ 0=wt.workflow.worklist.WfTaskProcessor/ duplicate
You must also add a line similar to the following in the htmltemplate.properties file:
wt.services/rsc/default/wt.templateutil.DefaultHTMLTemplate/ CustomTask/java.lang.Object/0= customizations.workflow.templates.CustomTask
3. Create or modify the HTML template file (customizations.workflow.templates.CustomTask). For examples, see the standard HTML template files listed in the htmltemplate.properties file. The Windchill scripts you can use are defined primarily by the wt.workflow.worklist.WFTaskProcessor and the wt.enterprise.BasicTemplateProcessor (see the Javadoc for further information).
24-4
The following are examples of useful functionality from the more commonly used Windchill scripts: From wt.workflow.worklist.WFTaskProcessor: To print workflow variables, use the following scripts:
To print information about the Process, Activity, and PrimaryBusinessObject in the same page, use the following script:
This script does not print any HTML code but switches the ContextObject of the TemplateProcessor. This means the scripts that follow this script in the HTML page can generate information about the new ContextObject (for example, attribute names and values of the primaryBusinessObject or a table of associated objects). From wt.enterprise.BasicTemplateProcessor: To create a link to another dynamically generated page, use the following script (see the Javadoc for further information):
To display the label and value of attributes of a Windchill object, enter the following scripts:
Attributes can be "name", "number", "checkoutInfo", "location", and so on. To display a subtemplate (for example, to display a usedBy-table), enter the following script:
Most of the time you will have to add entries in the properties files to create new actions and new related HTML template files that hold only a part of an HTML page (for example, a single table).
24-5
Template Change Issue Process Change Issue Process Change Issue Process
Robot
Sync on Request Association Listen for Request Disassociation Sync on Request Complete
24-6
The expression logic of change issue robots is illustrated in the following figure.
The following table explains the details of this figure; the numbers in the table correspond to numbers in the figure.
1a) This conditional router checks if the change issue is already associated to a change request. If so, the workflow continues to the conditional at 3a; otherwise, it proceeds to the sync robot at 1b. 1b) The Sync on Request Association robot waits until the event ISSUE_FORMALIZED is emitted for the primaryBusinessObject (the change issue), signaling the change issue has been attached to a change request. The workflow then continues to the conditional at 2a and the conditional at 3a simultaneously. 2a) This conditional router checks if the change issue has been immediately disassociated with the change request. If so, the workflow cycles back to 1a; otherwise, it continues to the sync robot at 2b. 3a) This conditional router checks the state of the associated change request. If it is in state Completed, the workflow continues to 3b (the end of the process). If it is in state Cancelled, the workflow loops back to a point near the beginning of the process. Otherwise, the workflow continues to the sync robot at 3b.
24-7
2b) The Listen for Request Disassociation sync robot listens for the event ISSUE_UNFORMALIZED on the primaryBusinessObject, signaling the change issue has been disassociated from its change request. This causes the sync robot at 3b () to terminate, and the workflow to loop back to the conditional at 1a.
3b) The Sync on Request Complete robot waits until the state of the associated change request changes. If the state is Completed, the workflow continues to 3b (the end of the process). If it is in state Cancelled, the workflow loops back to a point near the beginning of the process. Otherwise, the sync robot continues to wait for one of those two states.
Template
Robot
Change Investigation Process Change Analysis Process Change Proposal Process Change Order Process Change Activity Process
Sync on Request Submit Sync on Request Submit Sync on Request Submit Sync on Request Submit Sync on Request Submit
Before Release 5.1, the expression logic performed the following actions: 1. Determine the parent change request by navigating one or two levels of associations based on the change object: For a change investigation or change proposal, navigate the ResearchedBy association. For a change order, navigate the AddressedBy2 association. For an analysis activity, first navigate the DetailedBy association to obtain a change investigation or change proposal, then navigate the ResearchedBy association. For a change activity, first navigate the IncludedIn2 association to obtain a change order, then navigate the AddressedBy2 association.
2. Determine the current life cycle state of the change request. 3. Determine the current value stored in the Complexity attribute (for Sync on Request Submit only).
24-8
4. Based on the results of step 2 and step 3, either continue holding or move on to one of several possible activities that follow in the workflow. The following changes have been made to this logic: A new process variable named parentChangeRequest has been introduced in each workflow. It holds the parent request and is initialized when the workflow begins through a transition expression on the process Start transition. The following figure shows the expression synchronization robot as it existed before Release 5.1.
This robot has been replaced with a conditional router followed by the sync robot. The new robot, which has been changed to an object event synchronization robot, is shown in the following figure.
The object is the new change request process variable just described. The event is STATE CHANGE in each case. The conditional router contains exactly the same logic as the expression in the object event subscription robot. The purpose for this conditional router is to immediately check whether the state has already been reached. This helps avoid the race condition of the state being achieved prior to the instantiation of the synchronization robot. (In both figures, the parentChangeRequest variable is assumed to be initialized already.) The expression in the object event synchronization robot and conditional has been changed to use the workflow variable parentChangeRequest directly, rather than access the database repeatedly to determine the parent change request.
24-9
These changes resulted in the following performance improvements: Lookup time during each execution of the synchronization expression has been shortened as a result of saving the change request in a workflow variable. The synchronization expression executes only after the state of the change request has changed. As a result, there is a very good chance the proper state has been reached each time the expression runs.
Change Request Process 2 Change Request Process 2 Change Request Process 2 Change Investigation Process Change Proposal Process Change Order Process
Sync on Investigation Sync on Proposal Sync on Change Orders Sync on Analysis Activities Sync on Activities Sync on Change Activities
Before Release 5.1, the expression logic performed the following actions: 1. Determine which children objects are applicable to the synchronization. For example, in the Sync on Change Activities robot, all the change activities related to the change order are relevant. 2. Determine the life cycles states of all the relevant objects. 3. Based on the result of step 2, either continue holding or move on to one of several possible activities that follow in the workflow. Release 5.1 includes the following changes to this logic: The expression synchronization robot has been replaced with a conditional router followed by the sync robot. The sync robot has been changed to a new class event synchronization robot. The class differs depending on the particular synchronization robot, but the event is always STATE CHANGE. The conditional router contains exactly the same logic as the expression in the object event subscription robot. The purpose for this conditional router is to immediately check whether the state has already been reached. This helps avoid the race condition of the state being achieved prior to the instantiation of the synchronization robot.
24-10
This change resulted in the following improvements: The synchronization expression is executed only when an object in the proper class has changed state. As a result, the expression is executed only when there is a chance that the states of all related objects are in synchronization.
New Installations
A new Windchill installation will include the new Change Management workflow process templates. Be sure to load the "Change Management lifecycles and workflows" during the initial database load. For further information about loading data, see the Windchill Installation and Configuration Guide.
Existing Installations
If you are not concerned about overwriting existing demo workflow process or life cycle templates, you can simply initiate "java wt.load.Demo " and answer "no" to all questions except "Change Management lifecycles and workflows" (see the Windchill Installation and Configuration Guide for further information about loading data). You can ignore errors regarding the "Change Items" Domain and the example projects. However, to avoid these errors, remove all sections from ChangeManagement.csv except those for the Change Management workflow process templates and life cycle templates. If you do not want to overwrite the existing demo workflow process templates, PTC recommends that you perform one of the following options before loading the new workflow and life cycle templates: Rename the existing workflow and life cycle templates using the Workflow Administrator and Life Cycle Administrator. Rename the new workflow and life cycle templates by manually editing the ChangeManagement.csv file.
After loading the Release 5.1 workflow process and life cycle templates, you can restore them to their original state one at a time by clicking Delete Latest Iteration from the Workflow Administrator or Life Cycle Administrator page.
24-11
Code Impacted
The following code has been impacted by the enhancements: The workflow processes in loadfiles\ChangeManagement.csv, including the changes described in this section. wt.change2.process.ProcessHelper -- A new, overloaded version of the checkRequestFinished method has been added, which takes a change request and checks the state of the passed object. wt.change2.StandardChangeService -- The methods saveFormalizedBy and deleteFormalizedBy now emit the events ISSUE_FORMALIZED and ISSUE_UNFORMALIZED, respectively. wt.admin.AdminEventResource -- The ISSUE_FORMALIZED and ISSUE_UNFORMALIZED events were added to this resource bundle (and all of its language variants). wt.workflow.robots.synchEventResource -- The ISSUE_FORMALIZED and ISSUE_UNFORMALIZED events were added to this resource bundle (and all of its language variants). wt.notify.notify.properties -- The ISSUE_FORMALIZED and ISSUE_UNFORMALIZED events were added to this property file.
24-12
24-13
24-14
have to be locked before review tasks can be fired to the promotion review team members. The out-of-the-box conditional for locking has an expression similar to the below code snippet:
wt.maturity.PromotionNotice pn = (wt.maturity.PromotionNotice)primaryBusinessObject; try { wt.maturity.MaturityServerHelper.service.lockTargets( pn ); result = "Accepted"; } catch( Exception wte ) { result = "Rejected"; // send notification to owner }
The customized workflow should also have a similar locking mechanism before including the task for review. The second conditional does the actual promotion of the targets and has code like:
wt.maturity.PromotionNotice pn = (wt.maturity.PromotionNotice)primaryBusinessObject; try { wt.maturity.MaturityServerHelper.service.promoteTargets (pn); result="Approved"; } catch (wt.maturity.MaturityException me) { result="Rejected"; }
The promoteTargets API also takes care of the process of unlocking the targets before promoting them. This kind of an unlocking mechanism should also be incorporated in the customized workflow.
24-15
24-16
3. Rebuild the client JARs (see Rebuilding Client JARs in the Managing Customizations chapter on page 5-18). 4. Clear the Java Plug-in cache on your client machines. 5. Restart the Method Server. 6. Use the Workflow Process Editor to design a workflow template with a Synchronization robot, as shown below:
In the Synchronization robot properties window: a. Select object event b. Make sure MY_EVENT is listed in Event dropdown list. c. Choose MY_EVENT d. Write appropriate expressions in the initial and routing expressions. For more information on the Workflow Process Editor, see the Windchill Business Administrators Guide.
24-17
Where: MY_EVENT is the customized event as created above. Alternatively, any event selected in the Event dropdown list in the Synchronization robot properties window would be substituted in its place. PrimaryBusinessObject is the object on which we want to emit an event. In other words, the object on which the Synchronization robot is listening for MY_EVENT (the customized event).
Note: A customized event can be emitted from any customized code or from an expression robot. In handling an emitted event, there is no way to retrieve the valueMap Hashtable from the event, since the synchronization expression syntax does not provide a way to get the event object for an object-based event.
24-18
Specifying "all_activity_variables" will display all visible activity variables except for those named "special_instructions", "instructions", or "primaryBusinessObject". The customizer will be required to explicitly list these three activity variable names (if defined in the Workflow definer as such), in addition to the "all_activity_variables". For the Windchill R9.0 out-of-the-box templates, the default will render all_activity_variables. In addition, the Change Management template will also include the specification of the special_instructions activity variables. Describe Examples:
<tags:workItemInfo custom_variables="variable_name1,variable_name2{height:1}"/> <tags:workItemInfo custom_variables="all_activity_variables"/> <tags:workItemInfo custom_variables="all_activity_variables,special_instructions{widt h:50;height:5}"/>
24-19
If you specify to render a particular custom activity variable (other than special_instructions, instructions, or primaryBusinessObject) with the all_activity_variables, the specified custom activity variable will get rendered twice. Once the customizer has described and retrieved the property model (via the workItemInfo.tag), they will then need to specify where on the page to render the particular workflow activity variable's GUI component. This is done by including the taskPanelValue tag, along with the new property model and the list of variables to display at the desired location of the JSP. (Note: the list of variable names must match the names listed for tags:workItemInfo. That is, if "all_activity_variables" was specified, then this same name must be used to render the GUI Components for "all_activity_variables.) Render Examples:
<tags:taskPanelValue propertyModel="${propertyModel}" attrs="variable_name"/> <tags:taskPanelValue propertyModel="${propertyModel}" attrs="special_instructions"/> <tags:taskPanelValue propertyModel="${propertyModel}" attrs="all_activity_variables"/>
A customer may also choose to customize the task form template (i.e., the customized JSP) to only display individual components of the PBO. For example, they might want to include just the top attributes, affected data, affected end items, attachments, attribute detail (including soft or modeled), or related change items. The tag tablePageLink can be used to display one or more tables that are defined together in one custom jsp. The parameter path is the jsp that will be included. The tablePageLink tag can only be used once on a page to render one jsp file and it cannot be used on the same page as infoPageLink.
<tags:tablePageLink path="/netmarkets/jsp/change/affectedEndItemsTable.jsp"/>
24-20
The following table lists the paths that can be used for tablePageLink for a specific object.
PBO Component Path Available Function
Affected Data
/netmarkets/jsp/change/affectedDat aTable.jsp
Change RequestWTChangeRequest2 Change Issue or VarianceChangeIssue Change RequestWTChangeRequest2 Change Issue or VarianceChangeIssue Change TaskWTChangeActivity2 Change TaskWTChangeActivity2 Change RequestWTChangeRequest2 Change Notice WTChangeOrder2 Change TaskWTChangeActivity2 Change Issue or VarianceChangeIssue Promotion Notice PromotionNotice Change RequestWTChangeRequest2 Change TaskWTChangeActivity2 Change Issue or VarianceChangeIssue
/netmarkets/jsp/change/affectedEnd ItemsTable.jsp
Annotations
/netmarkets/jsp/annotation/annotati onChangeTable.jsp
24-21
PBO Component
Path
Available Function
Baselines
/netmarkets/jsp/object/relatedBaseli nes.jsp
Change RequestWTChangeRequest2 Change Notice WTChangeOrder2 Change TaskWTChangeActivity2 Change Issue or VarianceChangeIssue Change RequestWTChangeRequest2 Change Notice WTChangeOrder2 Change Issue or VarianceChangeIssue Change RequestWTChangeRequest2 Change Notice WTChangeOrder2 Change Issue or VarianceChangeIssue Promotion Notice PromotionNotice Change RequestWTChangeRequest2 Change Notice WTChangeOrder2 Change TaskWTChangeActivity2 Change Issue or VarianceChangeIssue Promotion Notice PromotionNotice Promotion Notice PromotionNotice
Contexts
/netmarkets/jsp/object/relatedConte xts.jsp
Discussion
/netmarkets/jsp/forum/discuss.jsp
Maturity History
/netmarkets/jsp/history/maturityHis tory.jsp
Promotion Items
/netmarkets/jsp/promotionRequest/ promotionItemsTable.jsp
24-22
PBO Component
Path
Available Function
Reassignment Related Changes /netmarkets/jsp/change/relatedChan ges.jsp Resulting Items Routing/Process /netmarkets/jsp/changeTask/resulti ngItemsTable.jsp /netmarkets/jsp/workflow/processH istory.jsp Subscriptions /netmarkets/jsp/subscription/object Subscriptions.jsp Change RequestWTChangeRequest2 Change Notice WTChangeOrder2 Change Issue or VarianceChangeIssue Change TaskWTChangeActivity2 Change RequestWTChangeRequest2 Change Notice WTChangeOrder2 Change TaskWTChangeActivity2 Change Issue or VarianceChangeIssue Promotion Notice PromotionNotice Change RequestWTChangeRequest2 Change Notice WTChangeOrder2 Change TaskWTChangeActivity2 Change Issue or VarianceChangeIssue Promotion Notice PromotionNotice
24-23
The following table lists the tag files that can be used to include tables. If there is a tablePageLink or infoPageLink these tags must precede it.
PBO Component Syntax for including on JSP
If the PBO is a PromotionNotice, the customizer may include the promotion objects table as follows:
<workItem:setPrimaryBusinessObject/> <workItem:promotionObjects/>
Note: The display of the routing history table currently includes the reassignment table as well. An SPR exists to allow the routing history table to be displayed independent of the reassignment history table. Reassignment Table To display the reassignment history table as embedded and expanded in the JSP:
<tags:reassignHistory showRH="Table"/>
24-24
<Service context="default" name="com.ptc.windchill.enterprise.change2.handler.AutomateCreateC hangeNoticeHandler"> <Option serviceClass="com.ptc.windchill.enterprise.change2.handler.Defa ultAutomateCreateChangeNoticeHadler" selector="DefaultHandler" requestor="null" cardinality="duplicate"/> </Service>
24-25
Clicking on Create Template opens up the following page using which the JSP file can be uploaded
Once the new template is uploaded, a new JSP file gets created in the codebase/netmarkets/jsp/customtemplates folder. The name of the new JSP will be generated based off a mapping mechanism, using the Container, PBO class, Activity Type, and JSP template name. (See Project 14216460 Workflow Task Forms). The JSP name will be generated using the mapping mechanism as follows:
<ContainerName>_<PBOType>_<ActivityType>_<Template Name>.jsp
Note: It's assumed that at least the out-of-the-box templates are present in the system. If no template is found due to deletion of templates then an exception will be raised.
24-26
25
Customizing Workgroup Managers
25-1
25-2
26
Customizing Windchill Visualization Services
This chapter describes how to customize Windchill Visualization Services. Topic Page
26-1
Custom Publishing
Objective
You want to initiate publishing from another product area or from custom code. You may also want to define alternative inputs to the creation of a representation such as naming, descriptions, or configuration specifications to an OOTB publishing mechanism (i.e. check-in driven and scheduled publishing).
Background
Out-of-the-box Windchill Visualization Services can create representations three ways. They are by manual creation from the Windchill UI, the check-in of a Representable (an object that can have Representations; i.e. EPMDocument, WTPart, WTDocument), and by a schedule job. This document will help explain how to initiate publishing in other ways such as custom code for workflows, from a custom UI, etc. This topic also explains how to customize the creation of representations from such existing mechanisms like the check-in of a Representable or by a schedule job. Unlike manual creation, there is no out-of-the-box way to specify special configuration specifications for publishing, or provide business specific information you may want to capture in the name or description of the Representation.
Scope/Applicability/Assumptions
Custom publishing should be used when there is a requirement to initiate publishing in Windchill from a non-standard way (something other than check-in, manual or schedule), or if you need to modify the input information for a Representation. Publishing can only be performed on wt.representation.Representable objects (i.e. EPMDocuments, WTPart, WTDocuments; including soft and hard typed children).
Intended Outcome
Using the information in this topic will allow end users to perform publishing in a manner in-line with their business requirement whenever the out-of-the-box publishing mechanisms are not sufficient.
Solution
Customize publishing by implementing public WVS APIs in custom code and making WVS aware of this custom code via appropriate WVS property changes.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Java Development
26-2
Standard WVS publishing setup and configuration WVS concepts such as Representable and Representation. Basic understanding of publishable business objects such as EPMDocuments, WTParts and WTDocuments and their relationships/structure. The use of configuration specifications (ConfigSpecs)
Note: The Additional Resources section on page 26-17 includes references to many or all of these subjects.
Solution Elements
Element Publisher.class
Description Contains api for doPublish needed for invoking publishing from code. Runtime Location: <Windchill>\ codebase\com\ptc\wvs\common\ui
PublisherAction.class
Class file
Used to create the optional actionString to be passed to the doPublish method in Publisher. See JavaDoc for details. Runtime Location: <Windchill>\ codebase\com\ptc\wvs\common\ui
VisualizationHelper.class
Class file
Contains helper apis such as findRepresentable and getRepresentation often needed in custom code. Runtime Location: <Windchill>\ codebase\com\ptc\wvs\common\ui
ScheduleJobs.class
Class file
Contains getCurrentContainer method needed when writing custom schedule jobs. Runtime Location: <Windchill>\codebase\com\ptc\wvs\ server\schedule
wvs.properties
Properties file
Contains specific properties used with the Windchill Visualization Service. Runtime Location: <Windchill>\ codebase
26-3
doPublish from Publisher class see Simple Publish on page 26-4 PublisherAction class for advanced use of doPublish see Advanced Publish on page 26-5
To invoke publishing from custom code or from an Expression Robot in a Workflow the key method to understand and use is the supported doPublish method in the com.ptc.wvs.common.ui.Publisher class.
public boolean doPublish(boolean viewableLink, boolean forceRepublish, String objectReference, ConfigSpec configSpec, ConfigSpec partConfigSpec, boolean defaultRep, String repName, String repDescription, int structureType, String actionString, int jobSource)
For more details on this method and its parameters, see the JavaDoc in <Windchill>\codebase\wt\clients\library\api\index.html.
Simple Publish
You have an EPMDocument instance with publishable data and you want to create a default Representation.
String objRef = ObjectReference.newObjectReference(myepmdoc).toString(); Publisher pub = new Publisher(); boolean result = pub.doPublish(false, true, objRef, (ConfigSpec)null, (ConfigSpec)null, true, null, null, Publisher.EPM, null, 0);
This simple example will simply add a publish job to the publishing queue for myepmdoc. The resulting default representation named default will be published using the As-Stored or Latest ConfigSpec as defined in wvs.properties (publish.configspec.default.useasstoredifavailable). Since the forceRepublish parameter was true, an existing representation with the same name would be replaced. If you wanted to programmatically provide a name for the representation, or insert useful business information into the description modify the parameters. For example:
Publisher pub = new Publisher(); boolean result = pub.doPublish(false, true, objRef, (ConfigSpec)null, (ConfigSpec)null, true, MyRep, My Description, Publisher.EPM, null, 0);
26-4
The only difference between this and the previous example is that the resulting default representation will have the name MyRep and have the description My Description. If you wish to retrieve a reference to an existing Representation, set the viewableLink parameter to true and the forceRepublish parameter to false. If there is an existing Representation with the repName you provided associated to the Representable, you can call getViewableObjRef() following a call to doPublish. This will provide a String object reference if the Representation was found. Otherwise null will be returned.
String repObjRef = null; Publisher pub = new Publisher(); if (pub.doPublish(true, false, objRef, (ConfigSpec)null, (ConfigSpec)null, true, MyRep, My Description, Publisher.EPM, null, 0)) { repObjRef = pub.getViewableObjRef(); }
In addition to getting the object reference of an existing Representation, you can also get an HTML fragment to use for launching ProductView to view the representation by using the getViewableLink() api following a call to doPublish. Again, viewableLink must be true, forceRepublish must be false, and a Representation with the name passed in for repName must exist on the Representable supplied by the objRef parameter.
String repLink = null; Publisher pub = new Publisher(); if (pub.doPublish(true, false, objRef, (ConfigSpec)null, (ConfigSpec)null, true, MyRep, My Description, Publisher.EPM, null, 0)) { repLink = pub.getViewableLink(); }
Advanced Publish
You have an EPMDocument instance with publishable data and you want to create a default Representation with your own configuration specification and have the publish job processed on the high priority publishing queue. The more advanced features of publishing require using the use of the PublisherAction class. See the JavaDoc for full details; a couple examples are shown below.
String objRef = ObjectReference.newObjectReference(myepmdoc).toString(); PublisherAction pa = new PublisherAction(PublisherAction.QUEUEPRIORITY, H); ConfigSpec configSpec = <MyHelper.getBaselineConfigSpec()>; Publisher pub = new Publisher(); boolean result = pub.doPublish(true, true, objRef, configSpec, null, true,
26-5
You have a WTDocument with several pieces of content. For example, doc1.doc, doc2.doc and doc3.doc are all content of your WTDocument and you only wish to publish doc3.doc (by default all docs would be published).
String objRef = ObjectReference.newObjectReference(mydoc).toString(); PublisherAction pa = new PublisherAction(PublisherAction.DOCUMENTFILE, doc3.doc); Publisher pub = new Publisher(); boolean result = pub.doPublish(true, true, objRef, (ConfigSpec)null, (ConfigSpec)null, null, null, Publisher.NONE, pa.toString(), 0);
Note: For WTDocuments, a ConfigSpec is not used and the structureType is Publisher.NONE. This sort of processing could be useful if you established a business practice of naming certain content files in a particular way if you wanted them to be published.
The association of Representables to Representations is one to many. The key concept when finding these relationships is to understand that when you have an EPMDocument (i.e. Representable) its Representations arent necessarily directly associated. In the case where an EPMDocument has an actively associated WTPart (i.e. option of creating associated parts in the workgroup manager was used when checking-in the EPMDocument), the Representations are linked to the WTPart. In all other cases the Representations are directly associated with the Representable (i.e. non-actively associated EPMDocuments, DynamicDocuments, WTParts, WTDocuments and MPMLink Representables).
findRepresentable
To simplify the concept discussed above, there is a method called findRepresentable in com.ptc.wvs.common.ui.VisualizationHelper. This method allows you to pass in a Representable and always get back the right Representable in the case where actively associated parts are involved. In the case where there
26-6
are no actively associated parts, it simply returns the object you passed in. The method signature is shown below:
public Representable findRepresentable(Persistable d)
If you have custom code that is dealing with Representables, it is a good practice to use this method so you can be sure to have the right Representable that is associated to the Representations. Also, note that if you pass in a Persistable that is not a Representable, the method will return null. You must have an instance of VisualizationHelper to use this method. For example:
VisualizationHelper vizHelper = new VisualizationHelper(); Representable repable = vizHelper.findRepresentable(d);
getRepresentation
In the com.ptc.wvs.common.ui.VisualizationHelper there are also some convenience methods for getting Representations from a Representable.
public Representation getRepresentation(Persistable d)
As noted previously, the relationship of Representables to Representations is one to many. However, one of the Representations may be noted as the default Representation. There will be 0 or 1 defaults. The above method will return the default Representation if one exists. Otherwise, null will be returned.
public Representation getRepresentation(Persistable d, String repName)
The method above will return the Representation associated to the Persistable with the name passed in to the repName argument. If there are no Representations or one cant be found with the supplied name, null will be returned.
public QueryResult getRepresentations(Persistable d)
This method will return all of the Representations associated to the Persistable passed in. If there are no Representations, null will be returned. All three methods in this subsection require that you have an instance of VisualizationHelper:
VisualizationHelper vizHelper = new VisualizationHelper(); Representation rep = vizHelper.getRepresentation(d);
Note: All three of the above methods make use of the findRepresentable method, so you do not need to worry about actively associated parts when calling it. Additionally, if the Persistable passed in is not a Representable, null will be returned.
26-7
Creating a custom schedule job step-by-step and using supported api getCurrentContainer from ScheduleJobs class see Custom Schedule Job Fundamentals on page 26-8 Incorporating the use of doPublish from the Publisher class in your custom schedule job see An Advanced Technique for Custom Schedule Jobs on page 26-10
In addition to the out-of-the-box Schedule Jobs, you can also create your own custom jobs. To do this, start by creating or adding to a custom class in the Windchill codebase; for example ext.wvs.CustomJobs. In this class create a method with the following signature:
public static WTList myCustomJob();
You can use whatever method name you want, but it is important that the method be public, static, return a WTList and accept no arguments. Then add the following to your wvs.properties.xconf file (edit as needed):
<Property <Property <Property <Property <Property default="MyCustomJob" name="myJob.description"/> default="ext.wvs.CustomJobs" name=" myJob.class"/> default="myCustomJob" name=" myJob.method"/> default="true" name=" myJob.enableOnContainers"/> default="myJob" name="schedulejobs<N>"/>
Line 1 (<Property default="MyCustomJob" name="myJob.description"/>) is what you see identify your custom job.
in the Scheduler UI to
Line 2 (<Property default="ext.wvs.CustomJobs" name=" myJob.class"/>) is the fully qualified class where your custom method resides. Line 3 (<Property default="myCustomJob" name=" myJob.method"/>) is the name of your custom method. or not the job code will have access to the container that the schedule job was initiated from. For example, the out-of-the-box schedule jobs only handle objects found in the container the schedule job was initiated from (i.e. Project, Product, Library, or Organization) because this value is set to true. If the value is set to false it would be the same as executing the job from the context of the Exchange container, no matter what container the schedule job was initiated from. Line 4 (<Property default="true" name=" myJob.enableOnContainers"/>) defines whether
Line 5 (<Property default="myJob" name="schedulejobs<N>"/>)is to display your custom job in the Publish Scheduler Administrator. In the name string you must replace the <N> with the integer that follows that last schedulejobsN that is already defined.
26-8
26-9
Note: This example contains the use of a BasicPageableQuerySpec and PagingSessions to avoid out of memory errors. See JavaDoc in the wt.query and wt.fc packages for details. This example would effectively ask for all latest iterations of any WTDocuments found in the current container to be published. In line six of the example the following method is used from com.ptc.wvs.server.schedule.ScheduleJobs:
public static WTContainerRef getCurrentContainer()
The result of this method will be null if the schedule job was initiated from the Exchange container (Site) or if the enableOnContainers value is false in the job definition (see line four of properties shown prior to the example above). If the value of enableOnContainers is true, then a WTContainerRef of the container the schedule job was initiated from will be returned. In the example code, this is used to filter the scope of the query to the Organization or the Product/Project/Library container the schedule job was initiated from. Note: You can have multiple custom schedule jobs. Just use another method name in the same class, or use a new class altogether. For example:
public static WTList anotherCustomJob();
Using the technique in the Custom Schedule Job Fundamentals section (see page 26-8) does not allow you to provide input to creating the Publish Job and specify the name of the Representation, description of the Representation, etc. Combining the concepts in the Procedure Invoking Publishing from Custom Code/Workflow section (see page 26-3) with the Custom Schedule Job Fundamentals section (see page 26-8) can open up a lot of flexibility for schedule jobs. The technique simply requires you to insert the use of the doPublish method from the Publisher class into your myCustomJob method. Since myCustomJob must return a QueryResult, simply return an empty QueryResult as the doPublish method will now cause Publish Jobs to be queued up for execution.
public static WTList myCustomJob() { WTList wt = new WTArrayList(); try { QuerySpec qs = new QuerySpec(WTDocument.class);
26-10
WTContainerRef cr = ScheduleJobs.getCurrentContainer(); if (cr != null) { ContainerSpec cs = new ContainerSpec(); cs.addSearchContainer(cr); qs.setAdvancedQueryEnabled(true); qs.appendWhere( WTContainerHelper.getWhereContainerIn(cs, WTDocument.class), new int[]{0}); } if (cr != null) qs.appendAnd(); qs.appendWhere(new SearchCondition(WTDocument.class, Iterated.LATEST_ITERATION, SearchCondition.IS_TRUE), new int[]{0}); Representable doc = null; String objRef; int offset = 0; BasicPageableQuerySpec bpqs = new BasicPageableQuerySpec(); bpqs.setPrimaryStatement(qs); bpqs.setOffset(offset); bpqs.setRange(1000); PagingQueryResult qr = (PagingQueryResult)PersistenceHelper.manager.find(bpqs); long sessionId = qr.getSessionId(); int total = qr.getTotalSize(); while (true) { while (qr.hasMoreElements()) { doc = (Representable)((Object[])qr.nextElement())[0]; objRef = ObjectReference.newObjectReference(doc).toString(); Publisher pub = new Publisher(); pub.doPublish(false, true, objRef, (ConfigSpec)null, (ConfigSpec)null, true, "My Rep", "My Description", Publisher.NONE, null, 0); } offset += qr.size(); if (offset >= total) break; PageableQuerySpec pqs = new PagingSessionSpec(sessionId); pqs.setOffset(offset); pqs.setRange(1000); qr = (PagingQueryResult)PersistenceHelper.manager.find(pqs); } if (sessionId > 0) PagingSessionHelper.closePagingSession(sessionId); } catch(Exception e) {e.printStackTrace();} return new wtl; }
This is the same example used in the Custom Schedule Job Fundamentals section (see page 26-8), but notice the use of the doPublish method shown in bold. This
26-11
custom job will now create Representations with the name My Rep and a description of My Description. Also, note that the returned WTList from the method is empty. Refer to the Procedure Invoking Publishing from Custom Code/Workflow section (see page 26-3) for see other useful ways to use the doPublish method.
Once publishing is configured for an Authoring Application (i.e. Pro/ENGINEER) publishing will occur out-out-of-the box for all EPMDocuments of that Authoring Application that are checked-in. Sometimes there are business reasons for filtering out some EPMDocuments from publishing based on some criteria. For example a certain lifecycle state, EPMDocumentType, EPMDocSubType, etc. Windchill Visualization Services has a code hook available where you can plug in code to filter on such criteria. In a custom class you can define a method with the following signature:
public static Boolean epmFilterMethod(EPMDocument epmdoc)
You can use whatever name you want in place of epmFilterMethod. Make sure the class that contains your custom method is accessible in the Windchill codebase (i.e. ext.wvs.MyFilterMethods). The next step is to add the class and method to wvs.properties.xconf. The following property is empty out-of-the-box. Update it to include your class and filter method in the format class/method.
<Property default="ext.wvs.MyFilterMethods/epmFilterMethod" name="publish.service.filterepmdocumentpublishmethod"/>
Once you make the change use the xconfmanager to propagate the changes to wvs.properties. Every time a check-in occurs where publishing of an EPMDocument would normally occur, this method will now be invoked. If the method returns Boolean.TRUE publishing will be attempted for the specific EPMDocument. If the method returns Boolean.FALSE, publishing will not be attempted.
26-12
This is another example where you can filter out the publishing of EPMDocuments that are in the LifeCycle state of InWork.
public static Boolean epmFilterMethod(EPMDocument epmdoc) { if (epmdoc.getLifeCycleState() != State.INWORK) { return Boolean.TRUE; } return Boolean.FALSE; }
Very similar to filtering publishing for EPMDocuments, there is a means for filtering for WTDocument publishing as well. For example, you may want to filter based on specific filenames, lifecycle state, container, etc. If the system has a worker configured for publishing specific WTDocument content, a custom filter method can be used to keep certain content from being published. In a custom class you can define a method with the following signature:
public static Boolean docFilterMethod(WTDocument doc, ContentItem ci)
You can use whatever name you want in place of docFilterMethod. Make sure the class that contains your custom method is accessible in the Windchill codebase (i.e. ext.wvs.MyFilterMethods). Notice that this method differs from the EPMDocument filter method signature by including ContentItem as a parameter. This method is called for each ContentItem associated to the WTDocument on check-in. It is also called for uploads. For example if you had a WTDocument with .doc file as primary content and a .xls file as secondary content, this method would be called twice; once with each content item (pending a worker was associated to both types of content). The next step is to add the class and method to wvs.properties.xconf. The following property is empty out-of-the-box. Update it to include your class and filter method in the format class/method.
<Property default="ext.wvs.MyFilterMethods/docFilterMethod" name="publish.service.filterdocumentpublishmethod"/>
Once you make the change use the xconfmanager to propagate the changes to wvs.properties.
26-13
Every time a check-in or upload occurs where publishing of WTDocument content would normally occur, this method will now be invoked. If the method returns Boolean.TRUE publishing will be attempted for the specific WTDocument ContentItem. If the method returns Boolean.FALSE, publishing will not be attempted. The following example shows how to filter if the WTDocuments description is Do Not Publish, or if the filename of the content starts with donotpublish.
public static Boolean docFilterMethod(WTDocument doc, ContentItem ci) { if (doc.getDescription().equals("Do Not Publish")) { return Boolean.FALSE; } if (ci instanceof ApplicationData) { String filename = ((ApplicationData)ci).getFileName(); if (filename.startsWith("donotpublish") { return Boolean.FALSE; } } return Boolean.TRUE; }
Using the techniques in the Filter Publishing for EPMDocument Check-in section (see page 26-12) and the Filter Publishing for WTDocument Check-in or Upload section (see page 26-13) do not allow you to provide input for creating Publish Jobs to specify the name of the Representation, description of the Representation, etc. Combining the concepts in the Procedure Invoking Publishing from Custom Code/Workflow section (see page 26-3) with the concepts in the Filter Publishing for EPMDocument Check-in (see page 26-12) and Filter Publishing for WTDocument Check-in or Upload (see page 26-13) sections can open up a lot of flexibility for check-in based publishing. The technique simply requires you to insert the use of the doPublish method from the Publisher class into the epmFilterMethod or the docFilterMethod shown in the previous subsections. Since the two filter methods must return a Boolean, simply return Boolean.FALSE and use the doPublish method to cause Publish Jobs to be queued up for execution.
public static Boolean epmFilterMethod(EPMDocument epmdoc) { if (epmdoc.getDocType().equals( EPMDocumentType.toEPMDocumentType("MANIKIN_POSTURE"))) { return Boolean.FALSE; } String objRef = ObjectReference.newObjectReference(epmdoc).toString(); Publisher pub = new Publisher(); pub.doPublish(false, true, objRef, (ConfigSpec)null, (ConfigSpec)null, "My Rep", "My Description", Publisher.EPM, null, 0);
26-14
return Boolean.FALSE; }
This is the same example used in the Filter Publishing for EPMDocument Checkin section (see page 26-12), but notice the use of the doPublish method shown in bold. This custom job will now create Representations with the name My Rep and a description of My Description. Also, note that the returned Boolean from the method is Boolean.FALSE. Refer back to the Procedure Invoking Publishing from Custom Code/Workflow (see page 26-3) for see other useful ways to use the doPublish method.
In addition to the filters specifically for EPMDocuments and WTDocuments described in the Procedure Customizing Check-in Based Publishing section (see page 26-12), Windchill Visualization Services has a more general hook that is called for anything that can be published (including EPM and WTDocuments). In addition to supporting the filtering of all Representables, this hook also includes publishing of pre-converted data. In a custom class you can define a method with the following signature:
public static Boolean filterMethod(Persistable p, Boolean publishFromDB)
You can use whatever name you want in place of filterMethod. Make sure the class that contains your custom method is accessible in the Windchill codebase (i.e. ext.wvs.MyFilterMethods). This method includes a publishFromDB parameter. This Boolean will come in as Boolean.TRUE if the publish is being invoked for data stored in Windchill, i.e. content of an EPMDocument or WTDocument object. The value will come in as Boolean.FALSE if the publish is for data not stored in Windchill, i.e. local data converted from the file system or data from the clipboard. You can use the value of publishFromDB to have your custom code handle the two cases specifically if you wish. The next step is to add the class and method to wvs.properties.xconf. The following property is empty out-of-the-box. Update it to include your class and filter method in the format class/method.
<Property default="ext.wvs.MyFilterMethods/filterMethod" name="publish.service.filterpublishmethod"/>
26-15
Once you make the change use the xconfmanager to propagate the changes to wvs.properties. Every time publishing would normally occur, this method will now be invoked. If the method returns Boolean.TRUE publishing will be attempted for the Persistable. If the method returns Boolean.FALSE, publishing will not be attempted. The following is a simple example of how to filter out publishing of the content if the Persistable is LifeCycleManaged and in its final phase of its LifeCyle:
public static Boolean filterMethod(Persistable p, Boolean publishFromDB) { if (!publishFromDB) return Boolean.TRUE; if (!(p instanceof LifeCycleManaged)) return Boolean.TRUE; try { if (LifeCycleHelper.service.isInFinalPhase((LifeCycleManaged)p)) { return Boolean.FALSE; } } catch (WTException wte) { wte.printStackTrace(); } return Boolean.TRUE; }
Note: In the above example the second line states that if the data requested for publishing is not from the Windchill DB, then just return true. For example if someone is publishing data on a WTPart that was uploaded from their local disk, we are saying we don't wish to filter this out and to simply return Boolean.TRUE.
An Advanced Technique for General Publishing
Combining the concepts in the Procedure Invoking Publishing from Custom Code/Workflow section (see page 26-3) with the Filtering All Publishing section (see page 26-15) you can open up additional flexibility for general publishing. The technique simply requires you to insert the use of the doPublish method from the Publisher class into the filterMethod shown in the previous subsection. Since the filter method must return a Boolean, simply return Boolean.FALSE and use the doPublish method to cause Publish Jobs to be queued up for execution. For example you want to provide specific naming information for publishes that were not made from Windchill stored data.
public static Boolean filterMethod(Persistable p, Boolean publishFromDB) { if (publishFromDB) return Boolean.TRUE; try { String objRef = ObjectReference.newObjectReference(p).toString(); Publisher pub = new Publisher(); pub.doPublish(false, true, objRef, (ConfigSpec)null, (ConfigSpec)null, true, Not From Windchill Data, , Publisher.NONE, null, 0);
26-16
Note: In the example above that the second line states that if we have publishing requested for data from Windchill stored data, just return Boolean.TRUE. For example if the request was to publish the primary content of a WTDocument we just want to return Boolean.TRUE.
Additional Resources
Java Development: http://java.sun.com The "Visualization Services" chapter in the Windchill Business Administrators Guide wvs.properties.xconf file in your <Windchill>\codebase directory.
26-17
26-18
27
Report Generation
This chapter describes report generation tools that provide the following functionality: Definition of a broad range of queries against Windchill data using a graphical interface rather than Java programming. Use of these queries to generate reports in several output formats, including HTML, XML, and CSV. Customization of queries and output formats, and re-use of queries and output formats from other customizations.
To author new queries using existing report formats, you need only be familiar with the UML model for the business objects of interest for the query and have an understanding of the query definition tool. Because the report generation tools build on the capabilities of the Windchill foundation and use HTML, CSS, XML, and XSL technologies, you should also be familiar with these areas to use the tools most effectively for customization. Topic Page
Overview ...........................................................................................................27-2 Basic Report Example .......................................................................................27-2 Import and Export of Report Templates..........................................................27-11 Customization Details .....................................................................................27-15 Cognos Presentation Customization................................................................27-38 Reporting Info*Engine Task Data Source Customization ..............................27-44 Report Loading................................................................................................27-50 ReportTemplate Data Source Customization ..................................................27-59 Reporting Input Page Customization ..............................................................27-63 Report Localization Customization.................................................................27-68 Report Selection List Customization...............................................................27-74
27-1
Overview
Reports are generated by applying presentation information to query result data. Queries are built using the Windchill Query Builder tool and stored as a report template business object in Windchill. When a report template query is executed, it operates against the current database and produces output in the form of Java objects or XML. Reports are generated from XML output by applying presentation transformations defined by XSLT (Extensible Stylesheet Transformation) stylesheets. The combination of XML and XSLT allows for a separation between data collection and formatting, thus facilitating separate customization of each. When defining report template objects, you can select from out-of-the-box XSLT formats or specify custom XSLT stylesheets to meet your formatting needs.
Query
The following steps show how to create the initial query for the report: 1. Create a new report template object and specify the query using the Query Builder user interface, as follows. (For detailed usage instructions, use the Query Builder online help.) a. From Report Manager, click the New button. The Query Builder interface appears (see figure below). b. To add classes for the query, click the Add button on the From tab. Select the Foldered and Cabinet classes. These classes will be used as the basis for the query.
27-2
c. Select the name attribute of these classes by clicking the Add button on the Select tab.
Report Generation
27-3
d. Every foldered object contains a reference to its cabinet. Add a reference join between the foldered object and its associated cabinet by selecting Query > Create Join. In the Create Join dialog box, select these classes and the Cabinet reference association, then click the OK button.
e. Add criteria for filtering the results to only a single cabinet. On the Criteria tab, set the following values, as shown in the following figure:
Field Value
27-4
f.
Preview the data to see if the query has been constructed properly by selecting Query > Preview. A figure similar to the following appears.
Report Generation
27-5
2. Execute this report as follows. a. Select Report > Generate. (The Generate Report action is also available when viewing the properties for a report template object.) b. From the report generation form, click Standard, HTML (with sorting), as the output format and click the Generate button.
27-6
Report Parameters
The initial report includes criteria for filtering the results based on cabinet name. In this example, the name is System. For most reports, it is desirable to have parameters that can be specified at execution time. This is accomplished using parameters in the criteria, as shown in the following steps: 1. Edit the Foldered report template to change the criteria to use a parameter, as follows: a. From Report Manager, select the Foldered report and then click the Update button to launch Query Builder. b. On the Criteria tab, change the value of the Type field from "Constant" to "Parameter" and specify a parameter name in the Name field, in this case, "Cabinet Name".
Report Generation
27-7
2. Execute the report, as follows: a. Select Report > Generate. The report generation form now specifies the parameter name, Cabinet Name. b. Enter a valid cabinet name in this field, in this case, System, and click the Generate button. If this field is left empty, the associated criteria is dropped. In this example, if the Cabinet Name field was left empty, the query would return all Foldered objects in any cabinet.
27-8
Another way to specify values dynamically is to use report parameter macros. Macros specify values that are derived by the system at report execution time. An example of a macro is CURRENT_USER_NAME. This macro returns the name of the current user and is useful for showing information related to the user running a report. Macros can be specified for constants and parameters within the Query Builder user interface. You can also enter macro names in the report generation form. The following are predefined macros:
Name Description Type
CURRENT_USER_NAME CURRENT_TIME
Name attribute of the current authenticated user. Current system time. The time is formatted as a Java string using SimpleDateFormat and the method server timezone (specified by wt.method.timezone).
String String
Report Generation
27-9
The following steps show how to put a macro in the report generation form: 1. Edit the Foldered report template to change the criteria to use a macro for the parameter default as follows: a. Select the Foldered report and then click the Update button to launch Query Builder. b. On the Criteria tab, change the value of the Default Value field from "System" to "CURRENT_USER_NAME" using the drop-down list.
c. Save the report template. 2. Execute the report by selecting Report > Generate. The report generation form now specifies the macro and the results show foldered items only in the current users personal cabinet. If demo data has been loaded, several example reports are available within the Windchill folder System/Reports. These sample reports provide examples of the types of reports that are possible. The following section contains more information on loading these sample reports.
27-10
csvfolder
Required. This entry is the location of the report templates in Windchill Explorer. If the specified folder does not exist, one is created. Required. Optional. Required. This entry specifies a path to the XML source file. This file is parsed and then validated against the QML DTD (<Windchill>/codebase/wt/query/qml /qml.dtd). The path is first assumed to be an absolute file path. If the file is not found, the path is then assumed to be relative to the <Windchill>/loadfiles directory. The XSLT designation; possible options include the following: DEL (delegation), which allows selection from a set of defined XSLT formats. URL, which offers selection of a customized XSLT stylesheet. No entry, which requires the user to select a format style at report template generation time.
csvxsltype
Report Generation
27-11
csvReportTemplate element
Description
csvservice
If the XSLT designation is DEL, this column is required. The formats currently available are as follows: HTML CSV TSV XML PDF HTMLWithSorting HTMLWithMerging MSWord2000Portrait MSWord2000Landscape
csvContainerPath
Optional. This column specifies a container where the report should be stored. If no value is specified, the site container is used by default. If the XSLT designation is URL, this column is required and should contain a URL pointing to a customized XSLT stylesheet. This column is used only if the XSLT designation is URL and, even then, is optional. It defines a second URL location for an XSLT stylesheet. Optional. This entry specifies an input page for the Report. Optional. This entry specifies a resource bundle for the Report.
csvurl1
csvurl2
csvinputPage csvresourceBundle
27-12
An out-of-the-box XML file, reporttemplates.xml, is provided along with several sample XML source files. These XML files are used for persisting sample report templates during wt.load.Demo. The reporttemplates.xml file is located in <Windchill>/loadFiles and the sample XML files are located in <Windchill>/loadFiles/reports. There are three options for using the LoadReportTemplate utility in standalone mode:
java wt.query.template.LoadReportTemplate
No parameters indicate that the default sample files defined earlier are being used.
java wt.query.template.LoadReportTemplate c:\loadReports.xml
The parameter indicates the relative path of a user-defined XML file. The ExportReportTemplate utility downloads multiple, persisted report template objects from the database to the relative file exportreports.xml. This file has the same structure as defined above. The ExportReportTemplate utility has three optional parameters: The first parameter specifies a string to use to search for report template objects by name. The "%" symbol can be used as a wildcard to match any number of characters in the name. If this parameter is not specified, all report template objects are exported. The second parameter specifies the path of the container in which to search. If this parameter is not specified, the site container is searched to find the report template. The third parameter specifies whether the container should be searched hierarchically. If the value is true, the criteria will match the specified container or any of its parent containers. If the value is false, only the specified container will be matched. If this parameter is not specified, a value of true is used.
Report Generation
27-13
The following example exports all report template objects in the site container that have a name starting with the characters "monthly":
java wt.query.template.ExportReportTemplate monthly%
The following example exports all report template objects in the Windchill PDM, default organization, and site containers that have a name starting with the characters "monthly":
java wt.query.template.ExportReportTemplate monthly% "/wt.inf.container.OrgContainer= DefaultOrg/wt.inf.library.WTLibrary=Windchill PDM"
The following example exports all report template objects in the Windchill PDM container that have a name starting with the characters "monthly":
java wt.query.template.ExportReportTemplate monthly% "/wt.inf.container.OrgContainer= DefaultOrg/wt.inf.library.WTLibrary=Windchill PDM" false
27-14
Customization Details
After a report exists, there are a number of ways to customize various aspects of the report. This section gives detailed information on the following items: Customizing the Query Customizing the Report Format Customizing the Report Generation Client Customizing the Report Generation URL Customizing Macros Customizing Query Builder Types
Report Generation
27-15
2. From the Select tab, click the Add button. Select the Location attribute and, under Persist Info, select the Last Updated attribute. (To add multiple attributes, hold the CTRL key while selecting them.)
3. Re-order the columns as necessary. 4. Preview the data to make sure the query is correct. 5. Save the query. The existing query is then overwritten. 6. Execute the report.
27-16
CSS Customization
All of the HTML report formats provided, except those derived from Microsoft Word, use a CSS1 stylesheet to specify font, color, size, and spacing details. Use of CSS1 allows these details to be separated from other aspects of page layout and placed into one or more re-usable stylesheets. Therefore, the easiest way to customize these aspects of the HTML reports is to edit the CSS files that they use. For further information about CSS1, refer to the W3C CSS1 specification, currently available at the following URL:1
http://www.w3.org/TR/REC-CSS1
Two CSS files are involved: htmlFormat4Print.css and htmlFormat4Screen.css. Both are located in <Windchill codebase>/templates/reports. The htmlFormat4Print.css file is intended to specify the appearance of HTML when printed and the htmlFormat4Screen.css file when viewed on screen. Actually, browsers do not support this aspect of CSS and, therefore, the printed output is controlled by htmlFormat4Screen.css as well. However, you may prefer htmlFormat4Print.css to htmlFormat4Screen.css, which is designed primarily for consistency with other Windchill HTML pages. To change the CSS stylesheet used by a report or to make larger changes to the output format than possible through CSS1, you must customize XSLT stylesheets as described in the next section.
XSLT Customization
As mentioned earlier, reports are produced by applying XSLT stylesheet transformations to XML query results. This includes all the out-of-the-box formats. XSLT stylesheets are capable of producing not only any HTML layout but also any other XML or text format. XSLT stylesheets are based on the concepts of templates and rules. Most XSLT stylesheets are largely composed of XML or HTML tags and text that are static; that is, included verbatim in the output. The remainder of the stylesheet is then composed of rules for computing the dynamic portion of the output from the input XML. Depending on the mix of templates and rules, the nature of XSLT customization can vary from simple HTML authoring to pure programming. For the definitive specification on XSLT, refer to the W3C XSLT specification, currently available at the following URL:2
http://www.w3.org/TR/xslt
For additional information about XSLT, refer to the What is XSLT? link and the Resources area currently available at the following URL:3
http://www.xml.com
1. 2. 3.
If you have difficulty with this URL, try the site URL www.w3.org. If you have difficulty with this URL, try the site URL www.w3.org. If you have difficulty with this URL, try the site URL www.xslinfo.com.
Report Generation
27-17
Stylesheets Provided
One technique for customizing the output format is to modify one of the XSLT stylesheets that are provided in <Windchill>/codebase/templates/reports/. These stylesheets are described in detail in the following table. Note: Within fields that specify an XSLT stylesheet in the Windchill UI, you must enter file paths that are relative to <Windchill>/codebase/. For example, excel97WebQuery.xsl must be referenced as "templates/reports/excel97WebQuery.xsl"
XSLT Stylesheet
Description
identity.xsl
XML
Performs the identity transformation on the XML query results; that is, it outputs the XML input. Produces comma-separatedvalues format (useful for reading into spreadsheets, and so forth). Produces tab-separated-values format (useful for reading into spreadsheets, and so forth). Produces a simple HTML format. Unlike the other HTML formats provided, this format does no extra formatting on numeric columns. Similar to simpleHtmlFormat.xsl except that sorting is provided through hyperlinks on the column headers. Similar to simpleHtmlFormat.xsl except that vertically duplicated cells are merged under certain conditions. This is a timeconsuming transformation compared to the others provided.
csvFormat.xsl
tsvFormat.xsl
simpleHtmlFormat.xsl
HTML
htmlWithSorting.xsl
htmlWithMerging.xsl
27-18
XSLT Stylesheet
Description
sortedHtmlAsXML.xsl
Produces the same results as htmlWithSorting.xsl except that the output is well-formed XML rather than traditional HTML, and the results contain additional non-HTML attributes. This is to facilitate application of further XSLT transforms (for example, mergeHTMLCells.xsl) to the result. Merges cells in HTML (which must be well-formed XML) similar to htmlWithMerging.xsl. Additionally, the input must have extra attributes annotations. This stylesheet is not intended for use directly on the query result XML. Instead, when applied to the results of sortedHtmlAsXML.xsl, the overall effect is to produce HTML with both sorting and merging. Microsoft Word 2000 HTML (Landscape) Produces a simple HTML format containing Microsoft Word 2000 metadata. When the result is dropped onto Microsoft Word 2000, the originally specified margins, table borders, and so on are preserved. Also, decimal tab stops are specified on floating point data columns. The result has landscape page orientation. Same as msw2000ls.xsl except the result has portrait page orientation.
mergeHTMLCells.xsl
msw2000ls.xsl
msw2000p.xsl
Report Generation
27-19
XSLT Stylesheet
Description
xslfo.xsl
Produces XSL Formatting Objects, an XML-based standard for high-precision page layout (see http://www.w3.org/TR/xsl). This is referred to as PDF format in standard format lists because the default is to postprocess this format to dynamically produce PDFs. This is done through Apache FOP (see http://xml.apache.org/fop) and is controlled by the following user preference: /wt/query/report/template/post procmap/application/xslfo+xm l This format is currently limited by the capabilities of FOP (for example, column widths must be provided rather than being computed from contents) and will improve in the future as FOP improves.
excel97WebQuery.xsl
Produces a version of Excel Web Query (.iqy) format compatible with both Excel 97 and higher. This Excel format records the URL from which the spreadsheet data came, and can refresh the data from the URL periodically or on demand. For best results with Excel 2000, set the MIME type for Excel Web Query (IQY) files to be application/x-excelweb-query; on downland, this format is then automatically loaded into Excel 2000 only. With Excel 97, you must save the downloaded file and select it from within the Excel 97 'Run Web Query...' command.
27-20
XSLT Stylesheet
Description
excel2000WebQuery.xsl
Produces a version of Excel Web Query (.iqy) format compatible only with the Excel version currently supported with Windchill. (For details about which third party products are supported, reference the Windchill Software Matrices.) It uses a new feature in Excel Web queries to attempt to preserve the formatting in the spreadsheet rather than that in the HTML URL data source.
Produce various types of charts corresponding to their names. The first result column is assumed to contain labels and the rest are assumed to contain chart data. Output is initially produced as SVG (Scalable Vector Graphics), a standard XML-based vector graphics format (see http://www.w3.org/TR/svg). Because this format requires a client viewer (for exampe, Adobe's free SVG Viewer available at http://www.adobe.com/svg/vie wer/install/main.html), the default is to post-process this format to rasterize the SVG into JPEG. SVG, JPEG, or PNG output formats can be selected by the following user preferences: /wt/query/report/template/post procmap/image/svg+xml /wt/query/report/template/post procmap/svgRasterizer/rasterF ormat
Report Generation
27-21
XSLT Stylesheet
Description
includes/linker.xsl
Provides an XSLT template, generateURLHref, that is used by the provided HTML and XSL FO formats to produce hyperlinks to Windchill objects from XML result nodes that contain additional attribute information provided by the query layer when entire Windchill objects are selected. Object, version, e-mail, and content download links are currently supported. The shared implementation behind excel97WebQuery.xsl and excel2000WebQuery.xsl. This stylesheet allows stylesheets which include it to specify the relative URL of an XSLT stylesheet that produces HTML tables. The produced Excel Web Query then obtains its data by executing the report (again) but using the specified HTML table format. Thus, by changing this HTML format, one can change the data that appears in Excel as a result of this Web query. Currently both excel97WebQuery.xsl and excel2000WebQuery.xsl use simpleHtmlFormat.xsl.
includes/excelWebQueryBase. xsl
27-22
XSLT Stylesheet
Description
includes/chart.xsl
The shared implementation behind barChart.xsl, lineChart.xsl, pieChart.xsl, and scatterChart.xsl. This stylesheet works by using Apache Batik (see http://xml.apache.org/batik) on the server to capture JChart graphics as SVG and optionally rasterize them. Note that custom charts and graphics can easily be captured as well by implementing wt.query.template.Chartable interface and replacing "wt.query.template.ChartCreat er" in this file with the name of the custom Chartable implementation. The shared implementation behind msw2000ls.xsl and msw2000p.xsl. The page size, margins, and orientation are all specified as inputs. This stylesheet is intended solely for inclusion from other stylesheets. The shared implementation behind htmlWithSorting.xsl and sortedHtmlAsXML.xsl. This stylesheet is intended solely for inclusion from other stylesheets. Provides an XSLT named template (that is, a macro) for localizing strings. The implementation uses an XSLT extension function to call back into Java to access Java resource bundles. This stylesheet is intended solely for inclusion from other stylesheets.
includes/msw2000.xsl
includes/htmlWith SortingBase.xsl
includes/localize String.xsl
Report Generation
27-23
XSLT Stylesheet
Description
includes/urlEncode.xsl
Provides an XSLT named template for URL encoding. The implementation uses an XSLT extension function to call WTURLEncoder.encode in Java. This stylesheet is intended solely for inclusion from other stylesheets.
Due to the template-based nature of XSLT, some modifications can be made to the provided stylesheets based almost solely on a knowledge of the intended output format (such as HTML). For example, the provided formats that use CSS1 stylesheets generate the references to these files using the following lines in the XSLT stylesheets:
<link rel="stylesheet" type="text/css" href="{$windchill}/templates/reports/htmlFormat4Screen.css" media="screen"/> <link rel="stylesheet" type="text/css" href="{$windchill}/templates/reports/htmlFormat4Print.css" media="print"/>
The only part of these lines that is not strictly HTML is the portion within the { } braces which, though similar to JavaScript expression usage, is actually an XSLT XPath expression. In this case, the expression is referencing the variable windchill, which was previously assigned the URL of the Windchill codebase.
27-24
The XML resource bundles used by the provided XSLT stylesheets are located at <Windchill codebase>/templates/reports/defReportRB_*.xml. If you decide to use this technique in your own XSLT stylesheets, see the XML resource bundles provided and the XSLT files provided for usage examples. Keep in mind the following issues: XML resource bundles must be well-formed XML. For further information, refer to XML.coms annotated XML specification, currently available at the following URL:4
http://www.xml.com/pub/axml/axmlintro.html
The W3C unannotated, original version of the XML specification is currently available at the following URL:5
http://www.w3.org/TR/REC-xml
The encoding listed in the <?xml ...?> header should match that actually used when saving the file and should be one supported by the XML parser used (Xerxes 1.2.2). For example, on Windows NT, you can use the Save as Unicode option in NotePad and specify an encoding of "unicode" in the XML resource bundle.
4. 5.
If you have difficulty with this URL, try the site URL www.xml.com. If you have difficulty with this URL, try the site URL www.w3.org.
Report Generation
27-25
New Formats
Besides modifying existing XSLT, you can also author entirely new XSLT stylesheets. The XSLT standard is still relatively new, however, and therefore editors that accurately display the actual appearance are not yet widely available. You can, however, author new stylesheets without any such tools using the following steps: 1. Author a sample of the intended output format. For example, use an HTML editor to produce a sample of the intended format; create a sample document in Microsoft Office and save it as HTML (this is how the Microsoft Wordbased HTML formats were created); or export an Adobe Illustrator drawing as SVG.6 2. Copy static pieces of the sample output to a skeleton XSLT stylesheet, editing or escaping them as necessary to ensure that they are well-formed XML. (All XSLT must be well-formed XML.) 3. Author XSLT to transform the input XML into the dynamic portions of the output, using the sample output as a guide. The number and complexity of transformations to be done in step 3 can vary greatly from one format to another and largely determine the effort involved in creating a new format. XSLT provides extensive capabilities for sorting, filtering, summing, and combining XML data. Additionally, you can provide XSLT extension functions and elements that call other languages, including Java and JavaScript. See the Saxon documentation for further details.
6.
The use of Apache Batik, as described in the various chart.xsl stylesheets (see the table in the section on Stylesheets Provided earlier in this chapter), provides an alternative means of producing SVG with minimal knowledge of XSLT.
27-26
Report Generation
27-27
If an entire Windchill top-level object (a Persistable) is selected, additional attributes are generated on the column tag element, including the object ID, branch ID (if the object is versioned), and classname of the object. WTUser objects also include email attributes. These attributes are generated primarily to facilitate generation of hyperlinks. Out-of-the-box XSLT stylesheets for HTML and PDF formats use these attributes whenever they are present to produce hyperlinks to the objects. Additional flexibility for generating hyperlinks is provided by use of the characters $$ in column names. If a column name containing $$ is specified through the Query Builder, an individual cell is not created for it; instead, the name is parsed as follows. If the part of the column name preceding $$ matches another column name that does not contain $$, its data is added to the other column as an attribute, which is determined by the part following $$. For example, assume the following columns are specified through Query Builder: Part Part$$branchID Part$$type
Each XML row would then contain a Part element like the following:
<Part branchID="dataFromBranchIdColumn" type="dataFromTypeColumn">dataFromPartColumn</Part>
Rows would not contain individual Part$$branchID or Part$$type columns. This functionality allows you to select the right data to obtain hyperlinks (as described earlier in this section) without having to select entire Persistable objects.
27-28
If the column type is java.util.Date, column data is formatted based on the HTTP request's Locale. In addition, the column element has a "value" attribute containing the raw Java string value. If other date-formatting customization is needed, this value could be used. The table below summarizes the data conveyed by the various top-level elements in the query result XML.
Element
Description
metadata
Meta-information about the query from which the data resulted and the user executing it. The request parameters used. Fully defines the details of the report template query which was made (see <Windchill codebase>/wt/query/qml/qml.dtd for further details). The query parameters used when executing the query. The column headers and types, and the rows of data.
auxData qml
actualParameters result
Report Generation
27-29
27-30
Both of the clients mentioned above rely on a wrapper API developed for XSLT processors. The API can be found in the wt.xml.xslt package entry in your installed Windchill Javadoc for more information. This API provides the following functionality: Independence from individual XSLT implementations (for example, Saxon, the XSLT processor library currently in use) A high-level abstraction for XML source that hides the details of a particular implementation (for example, String, Java IO stream, DOM, or SAX) A clean API for XSLT operations in Windchill Easy-to-use, high-level facilities for complex chaining of XSLT transformations
For additional capabilities beyond those provided through this API, you can use the standard JAXP (Java API for XML Processing) APIs, which are part of Java 2 v1.4, or access Saxon directly. For further information, see the Saxon Web page, currently available at the following URL:
http://saxon.sourceforge.net
Note, however, that the XSLT library bundled with Windchill may change in the future and that users of the Windchill XSLT and JAXP APIs will be affected less by any such change.
Report Generation
27-31
27-32
Report Generation
27-33
Description
jrb
Name of a Java resource bundle for localization of result column headers. The provided XSLT stylesheets are all capable of localizing the result column headers if the name of a Java resource bundle is provided to them. This is intended to allow for re-use of a single query to support multiple locales because the report template user interface provides no means of entering strings per locale. Specifies the format type: formatDelegate or formatCustom. This parameter is used only if the report template object has no XSL specification. Specifies the delegate name to obtain an XSL stylesheet from Windchill codebase. The delegate name must match a value specified in the dbservice.properties file. This parameter is used only if the report template object has no XSL specification and the format URL parameter has a value of "formatDelegate". Specifies a URL for a custom XSL stylesheet. This stylesheet is applied immediately to the query result and can generate direct output to the user, or output suitable for input to another XSL stylesheet. This parameter is used only if the report template object has no XSL specification and the format URL parameter has a value of "formatCustom".
format
delegateName
xsl1
27-34
Description
xsl2
Specifies a URL for a custom XSL stylesheet. This stylesheet is applied to the output of the first XSL stylesheet (specified by xsl1) and should generate output to the user. This parameter is used only if the report template object has no XSL specification, the format URL parameter has a value of "formatCustom", and the xsl1 URL parameter has been specified.
Customizing Macros
Customizing macros uses the standard Windchill application services delegation mechanism (for further information, see the Customizing service.properties topic in the Developing Server Logic chapter on page 35-24). This customization example creates a new macro to automatically compute a cutoff time. A new query is created that uses this macro and generates a report containing objects that have been modified within the last three days. Note that this example assumes you are familiar with Rational Rose and Windchill code generation, and have completed the previous customization examples. 1. Create a new implementation of the MacroExpressionProcessor interface using Rational Rose and Windchill code generation by performing the following steps: a. Create a new package or use an existing one. Name the package, for example, myPackage. b. Create a new class and inherit from the MacroExpressionProcessor interface in the wt.query.report package. Name the class, for example, TimeCutoffMacroProcessor. c. Generate the code for this class.
Report Generation
27-35
d. Fill in the implementation of the buildExpression( ) method. This implementation reads the current system time in milliseconds, computes the new time, and creates a new Date. The Date value is returned as a wt.query.DateExpression. This is necessary because of special handling of dates in SQL expressions to take into account Java representation of dates and timezone settings.
final int DAYS = 3; long currentSeconds = (System.currentTimeMillis() / 1000); long timeSeconds = currentSeconds - (60 * 60 * 24 * DAYS); java.util.Date time = new java.util.Date(timeSeconds * 1000); return new DateExpression(time);
e. Fill in the implementation of the getValue( ) method. This value is the actual Date value as computed in the preceding step. 2. Create a logical name for the macro and map it to the implementation class. For example, for logical name "TIME_CUTOFF" and class "myPackage.TimeCutoffMacroExpressionProcessor", the entry would be as follows:
wt.services/svc/default/wt.query.report.MacroExpressionProcessor/ TIME_CUTOFF/java.lang.Object/ 0=myPackage.TimeCutoffMacroProcessor/singleton
3. Create a new report query that uses the new macro by performing the following steps: a. Open the existing Foldered query and save it as a new query, for example, FolderedModified. b. Remove the criteria based on cabinet name. c. Add criteria. On the Criteria tab, set the following values as shown in the following table:
Field
Value
Foldered thePersistInfo.modifyStamp > TIME CUTOFF Note that the time cutoff macro now appears in the drop-down list.
27-36
To customize the list of Query Builder types, new entries can be added. For example, for the class myPackage.myClass, the entry would be as follows:
wt.services/rsc/default/wt.query.report.ClassName/ myPackage.myClass/java.lang.Object/0= myPackage.myClass
This is necessary only if the class does not implement the NetFactor interface, but does have subclasses that implement the Persistable interface.
Report Generation
27-37
Background
Cognos is a third party reporting tool that is integrated with Windchill. It exposes Windchill Data Source objects in Cognos that can be used in Cognos reports to retrieve data from Windchill. Cognos is used to format and present the data for your report.
Scope/Applicability/Assumptions
This documentation assumes that the Windchill Business Reporting (WBR) solution (i.e. Cognos) has been successfully installed and configured. The Windchill instance name is referred to as <WindchillInstanceName>. The Cognos root URL is referred to as <WBRHomeURL>. Typically, if the WBR solution is installed on <WBRHost>, then the <WBRHomeURL> would be http://<WBRHost>/cognos8/cgi-bin/cognos.cgi. It is assumed that you can login to <WBRHomeURL> and you have sufficient Cognos privileges to view Windchill Data Source objects and create reports. Assume you will name your new report <MyReport> and it will use the <MyDataSource> object to retrieve data from Windchill. It is also assumed that you will be able to create a Report object in Windchill in the Site context. The WBR solution provides several out-of-the-box Windchill Data Source objects. If custom Windchill Data Source objects are required for your report, see the Reporting Data Source customization best practice documentation in the ReportTemplate Data Source Customization on page 27-59 for more details.
27-38
Intended Outcome
The end result of this solution is the creation of your report in Cognos. A sample output of a report is shown below.
Solution
Use Cognos Report Studio to create a report using a Windchill Data Source.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Cognos Report Authoring JMX Console Basic Usage
Report Generation
27-39
Solution Elements
Element
Type
Description
Cognos Object
The Cognos object that is used to query data from Windchill. The Cognos object for a report that contains the definition of the query and specifies the presentation formatting. The Windchill object that is displayed to end users in the Windchill User Interface. It acts as a proxy to a corresponding Cognos Report object.
Cognos Object
Windchill Object
Procedures
This section contains detailed information about the following customization procedures:
Creating a Report
1. Login to Cognos using the <WBRHomeURL>. 2. Navigate to Public Folders > Windchill. 3. Launch Report Studio. 4. Select <MyDataSource> as the Data Source for the report. These appear in the Insertable Objects window under the Source tab. 5. Use Cognos Report Studio features to complete the report. 6. Save the report to top level Public Folders > Windchill folder as <MyReport>. 7. Verify the report in Cognos. Refresh the Public Folders > Windchill folder and the <MyReport> object should be listed. Use the Run with options action to run the report.
27-40
8. Expose your report to Windchill. Launch Java Console from installed Windchill shortcuts. There are two ways to do this: Make connection to Tomcat JVM instance. Select reporting management bean from the MBeans tab, Tree > com.ptc > WebAppContexts > <WindchillInstanceName> > Monitors > ReportingSystem. From the Operations tab, click exposeReports. Select the Edit Table button in Windchill Site/Reports to refresh the page.
9. View the <MyReport> Report in Windchill. The object will be displayed in the Site > Reports tab. Note that the Ready For Use column shows No for this object. This means that other users with read-only access will not see this report. The Ready For Use attribute can be used to limit report access to end users while the report is being developed. 10. Edit <MyReport> to make the Report accessible to end users. Select the Edit action, then Select Home for Display Context(s) and check the Ready For Use checkbox. Click OK to save these changes. <MyReport> will now be visible to all users with read access from both Site > Report and Home > Reports. 11. Verify the report in Windchill. Navigate to the Home > Reports tab and Select the View Report action for the <MyReport> object.
Creating a Report in a non-Site context
In the primary procedure above, the Cognos Report was created in the Windchill public folder in Cognos. This folder correlates to the Site context in Windchill and the Windchill Report object is created in this context. A variation of the primary procedure is to create the Cognos Report and correlated proxy Windchill Report in a non-Site context such as an organization. You will need to create a folder structure in Cognos that corresponds to the non-Site contexts that you wish to use in Windchill. For example, assume you have an organization <MyOrg> that contains a product <MyProduct> and you want to create a report, <MyProductReport>, in the <MyProduct> context. Prior to following the above primary procedure steps, create the following folders in Cognos 1. Under the Public Folders > Windchill folder, create a folder with the name, wt.inf.container.OrgContainer=<MyOrg>. 2. Under the Public Folders > Windchill > wt.inf.container.OrgContainer=<MyOrg> folder, create a folder with the name, wt.pdmlink.PDMLinkProduct =<MyProduct>. 3. In step 6.of the above procedure, save the report to the Public Folders > Windchill > wt.inf.container.OrgContainer=<MyOrg> > wt.pdmlink.PDMLinkProduct =<MyProduct> folder as <MyProductReport>.
Report Generation
27-41
4. In step 6, save the report to the "Public Folders > Windchill > wt.inf.container.OrgContainer=<MyOrg> > wt.pdmlink.PDMLinkProduct =<MyProduct>" folder as <MyProductReport>. 5. After exposing the report in step 8, the Windchill Report will be displayed in the "Product: <MyProduct> > Reports" tab.
Deleting a Report
A report that is no longer needed can be removed from the system by deleting both the Cognos and Windchill Report objects. Assume you want to delete <MyReport>. 1. Use the Cognos UI to browse to <MyReport> in the Public Folders > Windchill folder (if it is a non-Site context report, then it will be in a subfolder) and select the Delete action. 2. Then, use the Windchill UI to locate <MyReport> and select the Delete action. Note: The Reports tab table supports a multiple row delete action if the Reports tab is within a context and you have delete access rights for Windchill Report objects in that context.
Limitations
The Cognos report authoring capabilities are designed for many different types of Data Sources. The WBR integration uses XML Data Sources. These may have some limitations when compared to other types of Cognos Data Sources. In most cases, Cognos is able to implement the similar functionality for XML Data Sources, but there may be implications. For example, it is possible to use aggregate functions to summarize data, but this processing takes place in the Cognos server after all data has been received so this may cause performance and scalability issues. Cognos Reports have a one-to-one association with the Windchill Report business object. This object implements the AccessControlled interface so that standard Windchill access control can be applied. Note that there is no access control concept of execution rights. If a user has read access, then that user is also able to execute the report. The out-of-the-box access control policy for Windchill Report objects is specified for the Site context which provides Read access for all. Other access control rules will apply to Report objects based on type inheritance. For example, the Report object extends WTObject so at the Site level, Full access is granted for Administrators. Cognos Reports are subject to the Cognos servers access control policies. When Cognos is deployed as part of WBR, the integration does not alter Cognos default access control permissions, users, or groups apart from configuring Cognos to share Windchill LDAP for authentication. Further alteration to the access control permissions, users, or groups in Cognos must be done via Cognos tools, i.e. via their UI or API which is described in the Cognos documentation. For a good
27-42
overview, see the "Initial Security" chapter in the Cognos Administration and Security Guide.
Related Windchill Documentation Windchill Business Administration Guide Windchill System Administration Guide
Related Websites
http://support.cognos.com/support
Report Generation
27-43
Background
The Windchill Business Reporting (WBR) solution uses Data Source objects to retrieve data from Windchill. One type of Data Source is an Info*Engine task. An Info*Engine task is a text-based document that uses programmatic constructs to retrieve and manipulate Windchill data. The task must return its data in a tabular format (i.e. each element must have the same number of attributes) and task must be commented with special tags and syntax to define it as a WBR Data Source.
Scope/Applicability/Assumptions
This documentation assumes that the Windchill Business Reporting (WBR) solution (i.e. Cognos) has been successfully installed and configured. The Windchill instance name is referred to as <WindchillInstanceName>. The Cognos root URL is referred to as <WBRHomeURL>. Typically, if the WBR solution is installed on <WBRHost>, then the <WBRHomeURL> would be http://<WBRHost>/cognos8/cgi-bin/cognos.cgi. It is assumed that you can login to <WBRHomeURL> and you have sufficient Cognos privileges to view Windchill Data Source objects and create reports. Assume you have access to the Windchill server tasks directory, <WindchillHome>/tasks, to create an Info*Engine task <MyTask> in subdirectory <MyTaskPackage>. For WBR integration, you must also have access rights to update the reporting meta model. This document does not contain details on how to construct Info*Engine tasks. See the Info*Engine Users Guide for this information.
Intended Outcome
The end result of this solution is the creation of your Data Source that can be used to author Cognos reports.
Solution
Construct an Info*Engine Task Data Source.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Info*Engine Users Guide
27-44
Solution Elements
The Windchill APIs related to the Windchill business objects that will be used in the Info*Engine task JConsole User Interface Cognos User Interface
Element
Type
Description
<MyTask>
Info*Engine Task
3. Add WBR Data Source parameter information to the task comments. There can be zero or more parameter comments. Each specified parameter must exist on a single line. The syntax for the parameter comment is as follows:
@param <type> <name> <description>
where <type> is the parameter Java type, <name> is the parameter name, and <description> describes the parameter. The following are the allowed parameter types: java.lang.Boolean
Report Generation
27-45
4. Add WBR Data Source column information to the return task comment. The column information must be specified in the correct format for this task to be considered a Data Source. The syntax for the column comment is as follows:
@return <type> ${<variableName>} {columns: <columnList>}
where <type> is the Info*Engine task output type, <variableName> is a reference to the task variable that will be returned, and <columnList> describes the tabular format of the output. For more information on <type> and {<variableName>} consult section "SOAP Comments" in the Info*Engine Users Guide. The column is a comma separate list of one or more type and name pairs for each column in the tabular output. The type and name are separated by whitespace. The following are the allowed column types: java.lang.Boolean java.lang.Long java.lang.String java.sql.Timestamp java.util.Date java.lang.Double com.ptc.core.meta.common.FloatingPoint com.ptc.core.meta.common.Hyperlink java.math.BigDecimal
5. Add task as a method to a ReportTask type. Create a file named .delegateInfo in the same directory as the task file. The file should contain the following two lines:
repositoryType=com.ptc.windchill typeId=com.ptc.windchill.enterprise.report.ReportTask
6. Create and Install a package for <MyTask>. See Advanced User Topics > Packages in the Info*Engine Users Guide.
27-46
7. Update the Cognos model to recognize this new Data Source. Launch JConsole from installed Windchill shortcuts. Make connection to Tomcat JVM instance. Select reporting management bean from the MBeans tab, Tree > com.ptc > WebAppContexts > <WindchillInstanceName> > Monitors > ReportingSystem. From the Operations tab, click updateModel. 8. Verify that the Data Source exists in Cognos. Login to Cognos using the <WBRHomeURL> and launch Report Studio. Find <MyTask> Data Source under Windchill > Report Tasks > com.ptc.windchill.enterprise.report.ReportTask in the Insertable Objects window under the Source tab. The following is an example of task comments for a Data Source.
<!--com.infoengine.soap.rpc.def Report Task Example. @param java.lang.String param1 A string parameter named param1. @param java.lang.Long param2 A numeric parameter named param2. @return INFOENGINE_GROUP ${out} {columns: java.lang.String name, com.ptc.core.meta.common.Hyperlink url, java.util.Date deadline, java.math.BigDecimal duration} -->
Customization Points
Procedure Creating an Info*Engine Task Data Source under another Type
In the primary procedure above, the Info*Engine Task was created using the default reporting type, com.ptc.windchill.enterprise.report.ReportTask. The type correlates to the Windchill > Report Tasks > com.ptc.windchill.enterprise.report.ReportTask level of the Source tab. The Report task type can be used to group Data Sources logically. A variation of the primary procedure is to create the Info*Engine Task under another type, myPackage.MyReportTask. 1. This type will need to be added to the comma separated list of reporting types specified in the property com.ptc.windchill.enterprise.report.reportTaskClassNames 2. This property must be changed before executing step 7 of the Creating an Info*Engine Task Data Source procedure above. 3. In step 5 of the Creating an Info*Engine Task Data Source procedure above, the .delegateInfo entry for typeId should specify myPackage.MyReportTask.
Report Generation
27-47
4. In step 8 of the Creating an Info*Engine Task Data Source procedure above, the Data Source will now be available under Windchill > Report Tasks > myPackage.MyReportTask.
Procedure Deleting an Info*Engine Task Data Source
An Info*Engine Task Data Source that is no longer needed can be removed from the system by deleting it from Windchill and updating the Cognos model. Alternatively, the task comments can be removed so that it is not recognized as a Data Source. 1. To remove a task, uninstall the package and remove the XML file from the tasks directory. 2. Then, update the Cognos model using step 3 of the Creating an Info*Engine Task Data Source procedure above.
Limitations
The typeId in the .delegateInfo file maps to the SOAP class and the task file name maps to the SOAP method within that class. Both of these names should only contain characters valid for Java identifiers. In addition, the methods must all be unique for a given class. For a given typeId, each task name must be unique.
Sample Code
Examples of Usage in Windchill Code
There are several out-of-the-box reports that use Info*Engine Task Data Sources. These Data Sources are listed in the Windchill > Report Tasks > com.ptc.windchill.enterprise.report.ReportTask level of the Source tab. These Data Sources can be used for creating Cognos reports. However, directly modifying the associated Info*Engine Tasks is not supported.
Packaged Samples
A demo Info*Engine task Data Source, ContextItems, is available in the Windchill > Report Tasks > com.ptc.windchill.enterprise.report.ReportTask level of the Source tab. The task source is located in <WindchillHome>/tasks/com/ptc/windchill/enterprise/reports/ContextItems.xml. It retrieves the union of all Parts and Documents in a specified context.
Additional Resources
Related Best Practices
Reporting module
27-48
com.ptc.windchill.enterprise.report
None
Related Websites
Info*Engine Users Guide (Prerequisite) Info*Engine Administration and Implementation Guide Windchill System Administrators Guide
http://support.cognos.com/support
Report Generation
27-49
Report Loading
Objective
You want to load reporting objects into a Windchill Business Reporting (WBR) system.
Background
The Windchill Business Reporting (WBR) solution uses Windchill and Cognos objects in the system. Often times these objects are developed in another system such as a development system and then moved to another system where they are used in production. This document describes how these Reporting objects are loaded into a system. For Windchill business objects, the standard Windchill Data Loading mechanism is used. These tools are based on describing objects and their attributes in XML files. The loading is accomplished by instantiating the business objects, populating the attributes specified in the XML files, and using standard Windchill create APIs. For Cognos report objects, standard Cognos SOAP APIs are used. Cognos report attributes are specified in a Java properties file and the reports definition is specified in an associated XML file. These files are processed and the data is passed to a Cognos SOAP API for creating reports.
Scope/Applicability/Assumptions
This documentation assumes that the Windchill Business Reporting (WBR) solution (i.e. Cognos) has been successfully installed and configured. The Windchill instance name is referred to as <WindchillInstanceName>. The Cognos root URL is referred to as <WBRHomeURL>. Typically, if the WBR solution is installed on <WBRHost>, then the <WBRHomeURL> would be http://<WBRHost>/cognos8/cgi-bin/cognos.cgi. It is assumed that you can login to <WBRHomeURL> and you have sufficient Cognos privileges to view Windchill Data Source objects and create reports. Assume you have access to the Windchill server tasks directory, <WindchillHome>/tasks, to create an Info*Engine task <MyTask> in its associated sub-directory <MyTaskPackage>. Assume that this task has already been developed and tested on another source system, <WindchillSourceHome>. Assume you have access to the Windchill UI and the ReportTemplate, <MyReportTemplate> in the Site context of another source system, <WindchillSourceHome>. Assume you will load a new Windchill Report object, <MyReport>, and it will use the <MyReportTemplate> to retrieve data from Windchill. It is also assumed that you will be able to create a Report object in Windchill in the Site context. For WBR integration, you must also have access rights to update the reporting meta model.
27-50
Intended Outcome
The end result of this solution is the creation of your reporting objects into your WBR system.
Solution
Construct and execute load files for Reporting objects.
Prerequisite knowledge
Info*Engine Users Guide JConsole User Interface Cognos User Interface ReportManager User Interface Windchill Data Loading
Element
Type
Description
<MyTask>
Info*Engine Task
The Info*Engine task for retrieving and manipulating Windchill data. The Windchill object that specifies a query for retrieving Windchill data. The XML file that specifies a query associated with a Windchill ReportTemplate. The XML file that specifies data loading directives associated with a Windchill ReportTemplate. The Windchill object that is displayed to end users in the Windchill User Interface. It acts as a proxy to a corresponding Cognos Report object.
<MyReportTemplate> Windchill ReportTemplate <MyReportTemplateQML> Windchill ReportTemplate Query Definition <MyReportTemplateLoad> Windchill Data Load Specification <MyReport> Windchill Report
Windchill Object
XML File
XML File
Windchill Object
Report Generation
27-51
Element
Type
Description
XML File
The XML file that specifies data loading directives associated with a Windchill Report. The Cognos object for a report that contains the definition of the query and specifies the presentation formatting. The XML file that specifies the query and presentation associated with a Cognos Report. The Properties file that specifies attributes associated with a Cognos Report.
Cognos Object
<MyCognosReportXML> Cognos Report Query and Presentation Definition <MyCognosReportAttributes> Cognos Report Attributes
XML File
Properties File
1. Copy the task XML file, <WindchillSourceHome>/tasks/<MyTaskPackage>/<MyTask>.xml in <WindchillHome>/tasks/<MyTaskPackage>. This file could also be provided by PTC or another 3rd party developer. 2. Copy the associated .delegateInfo file in this same directory. 3. Create and Install a package for <MyTask>. See Advanced User Topics > Packages in the Info*Engine Users Guide. 4. Update the Cognos model to recognize this new Data Source. Launch JConsole from installed Windchill shortcuts. 5. Make connection to Tomcat JVM instance. 6. Select reporting management bean from the MBeans tab, Tree > com.ptc > WebAppContexts > <WindchillInstanceName> > Monitors > ReportingSystem. 7. From the Operations tab, click updateModel. 8. Verify that the Data Source exists in Cognos. Login to Cognos using the <WBRHomeURL> and launch Report Studio. 9. Find <MyTask> Data Source under Windchill > Report Tasks > com.ptc.windchill.enterprise.report.ReportTask in the Insertable Objects window under the Source tab.
27-52
1. Create the file, <WindchillHome>/loadFiles/reports/custom/<MyReportTemplateQML>.xml using the ReportManager Export action. This file could also be provided by PTC or another 3rd party developer. 2. Create a load file <WindchillHome>/loadFiles/custom/<MyReportTemplateLoad>.xml.
<?xml version="1.0"?> <!DOCTYPE NmLoader SYSTEM "standardX10.dtd"> <NmLoader> <csvReportTemplate handler="wt.query.template.LoadReportTemplate.createReportTempl ate"> <csvfolder>/Default</csvfolder> <csvname><MyReportTemplate></csvname> <csvdescription></csvdescription> <csvxml>custom/<MyReportTemplateQML>.xml </csvxml> <csvxslType></csvxslType> <csvservice></csvservice> <csvcontainerPath></csvcontainerPath> <csvurl1></csvurl1> <csvurl2></csvurl2> </csvReportTemplate> </NmLoader>
4. Verify the ReportTemplate exists in Windchill by launching ReportManager in the Site context. 5. Update the Cognos model to recognize this new Data Source. Launch JConsole from installed Windchill shortcuts. 6. Make connection to Tomcat JVM instance. 7. Select reporting management bean from the MBeans tab, Tree > com.ptc > WebAppContexts > <WindchillInstanceName> > Monitors > ReportingSystem. 8. From the Operations tab, click updateModel. 9. Verify that the Data Source exists in Cognos. Login to Cognos using the <WBRHomeURL> and launch Report Studio. Find <MyReportTemplate> Data Source under Windchill > Report Templates in the Insertable Objects window under the Source tab.
Procedure Loading a Windchill Report Object
Report Generation
27-53
<?xml version="1.0"?> <!DOCTYPE NmLoader SYSTEM "standardX10.dtd"> <NmLoader> <csvCreateReport handler="com.ptc.windchill.enterprise.report.LoadReport.createR eport"> <csvname><MyReport></csvname> <csvcontainerPath/> <csvdescription></csvdescription> <csvinputPage/> <csvresourceBundle/> <csvuiContext></csvuiContext> <csvreadyForUse/> <csvsoapClass/> <csvsoapMethod/> <csvreportTemplateName><MyReportTemplate></csvreportTemplateNam e> <csvreportTemplateContainerPath/> </csvCreateReport> </NmLoader>
3. Verify the Report exists in Windchill in the Reports tab of the Site context.
Procedure Loading a Cognos Report
1. Create the file, <WindchillHome>/loadFiles/cognosReports/custom/<MyCognosReportXML >.xml based on an existing Cognos Report. 2. Use Cognos Report Studio menu item Tools > Copy Report to Clipboard to copy the XML definition to the system clipboard. 3. Then, paste the clipboard contents into a text editor and save it to file. This file could also be provided by PTC or another 3rd party developer. 4. Create the file, <WindchillHome>/loadFiles/cognosReports/custom/<MyCognosReportAttri butes>.properties. The base names from this and the previous step must match exactly (e.g. MyCognosReport.xml and MyCognosReport.properties.
type=report defaultName=<MyCognosReport> #defaultDescription= #resourceBundle=
27-54
6. Verify the report in Cognos. Refresh the Public Folders > Windchill folder and the <MyCognosReport> object should be listed. Use the Run with options action to run the report.
Customization Points
Procedure Loading Multiple Task Data Sources
In the primary procedure Procedure Loading an Info*Engine Task Data Source above, a single Info*Engine Task is loaded. To load multiple tasks, repeat step 1 for each task. Each step in the remainder of the procedure only needs to be executed once. In the last step, verify that all Data Sources were loaded.
Procedure Loading Multiple ReportTemplate Data Sources
In the primary procedure Procedure Loading a ReportTemplate Data Source above, a single ReportTemplate is loaded. To load multiple ReportTemplates, in step 2, specify a separate csvReportTemplate element for each ReportTemplate. Each step in the remainder of the procedure only needs to be executed once. In the last step, verify that all Data Sources were loaded.
Procedure Loading Multiple Windchill Report Objects
In the primary procedure Procedure Loading a Windchill Report Object above, a single Windchill Report object is loaded. To load multiple Windchill Report objects, in step 2, specify a separate csvReport element for each object. Each step in the remainder of the procedure only needs to be executed once. In the last step, verify that all Windchill Report objects were loaded.
Procedure Specifying Windchill Report Object Attributes
In the primary procedure Procedure Loading a Windchill Report Object above, only the basic Windchill Report Object attributes are specified. The following are the additional attributes that can be specified. For additional information see the Report javadoc.
csvReport Element Description
csvname csvcontainerPath
Required. This entry specifies the Reports name. Optional. This entry specifies a container where the report should be stored. If no value is specified, the site container is used by default. Optional. This entry specifies a description of the Report.
csvdescription
Report Generation
27-55
csvReport Element
Description
Optional. This entry specifies an input page for the Report. Optional. This entry specifies a resource bundle for the Report. Optional. This entry specifies the UI context mask to be used to control where the Report is displayed in the Windchill UI. Optional. This entry specifies whether the Report is ready for use for end users. If no value is specified, the default value is false. Optional. This entry specifies the soap class if the Report uses a report task as its data source. This element is used along with the csvsoapMethod element to completely specify the report task. The Report must specify either a report task or ReportTemplate as its data source. Optional. This entry specifies the soap method if the Report uses a report task as its data source. This element is used along with the csvsoapClass element to completely specify the report task. The Report must specify either a report task or ReportTemplate as its data source. Optional. This entry specifies the ReportTemplate name if the Report uses a ReportTemplate as its data source. This element is used along with the csvreportTemplateContainerPath element to completely specify the ReportTemplate. The Report must specify either a report task or ReportTemplate as its data source. Optional. This entry specifies the ReportTemplate name if the Report uses a ReportTemplate as its data source. This element is used along with the csvreportTemplateName element to completely specify the ReportTemplate. The Report must specify either a report task or ReportTemplate as its data source.
csvreadyForUse
csvsoapClass
csvsoapMethod
csvreportTemplateNa me
csvreportTemplateCon tainerPath
In the primary procedure above, Procedure Loading a Cognos Report, a single Cognos Report is loaded.
27-56
To load multiple Cognos Reports, repeat steps 3 and 4, for each Cognos Report. Each step in the remainder of the procedure only needs to be executed once. In the last step, verify that all Cognos Reports were loaded.
Procedure Specifying Cognos Report Attributes
In the primary procedure Procedure Loading a Cognos Report above, only the basic Cognos Report attributes are specified. The following are the additional attributes that can be specified.
Property Name Description
type
Optional. This entry specifies the Reports type. The valid values are report, query, and reportTemplate. If not value is specified, then the default value is "report". Required. This entry specifies the Reports name. Optional. This entry specifies a description of the Report. Optional. This entry specifies the name of a Java resource bundle that is used to localize entries in the corresponding Cognos report specification XML file.
Limitations
For Cognos Report loading, there are load file directories that are used for Windchill out-of-the-box reports. These directories should not be used for custom load files. The reserved directories are <WindchillHome>/loadFiles/cognosReports and <WindchillHome>/loadFiles/cognosReports/<assemblyId> where <assemblyId> is a standard Windchill assembly ID such as wnc, pdml, pjl, etc.
Sample Code
Examples of Usage in Windchill Code
There are several out-of-the-box reports that use the load files described in this document. These are located in the <WindchillHome>/loadFiles, <WindchillHome>/loadFiles/reports, and <WindchillHome>/loadFiles/cognosReports directories.
Packaged Samples
A demo load file for Windchill ReportTemplate and Report objects is available in <WindchillHome>/loadXMLFiles/DemoReports.xml.
Additional Resources
Reporting Info*Engine Task Data Source Customization on page 27-44 ReportTemplate Data Source Customization on page 27-59
Report Generation
27-57
Related Websites
Info*Engine Users Guide Windchill Data Loading Reference and Best Practices Guide Info*Engine Administration and Implementation Guide Windchill System Administrators Guide ReportManager online help
http://support.cognos.com/support
27-58
The Windchill Business Reporting (WBR) solution uses Data Source objects to retrieve data from Windchill. One type of Data Source is a ReportTemplate. A ReportTemplate is a standard, persistent Windchill business object that is maintained via the ReportManager utility. This applet launches the Query Builder to create and edit a query that is stored as part of the ReportTemplate. When the ReportTemplate query is executed, standard Windchill APIs are used that apply all Windchill business logic (e.g. calling Windchill object methods, applying access control, etc.). Once a new ReportTemplate object is created it can be referenced from a Report object or exposed and used in the WBR solution as a custom Data Source.
Scope/Applicability/Assumptions
This documentation assumes that the Windchill Business Reporting (WBR) solution (i.e. Cognos) has been successfully installed and configured. The Windchill instance name is referred to as <WindchillInstanceName>. The Cognos root URL is referred to as <WBRHomeURL>. Typically, if the WBR solution is installed on <WBRHost>, then the <WBRHomeURL> would be http://<WBRHost>/cognos8/cgi-bin/cognos.cgi. It is assumed that you can login to <WBRHomeURL> and you have sufficient Cognos privileges to view Windchill Data Source objects and create reports. Assume you have access rights to create a ReportTemplate business object <MyReportTemplate> in the Site context. For WBR integration, you must also have access rights to update the reporting meta model. This document does not contain details on how to construct ReportTemplate queries. See the Query Builder online tutorial and help for this information.
Intended Outcome
The end result of this solution is the creation of your Data Source that can be used to author Cognos reports.
Solution
Use ReportManager and Query Builder to construct a ReportTemplate Data Source.
Prerequisite knowledge
Report Generation
27-59
Solution Elements
ReportManager User Interface Query Builder User Interface The Windchill data model for the area(s) related to the Windchill business objects that will be used in the ReportTemplate query JConsole User Interface Cognos User Interface
Element
Type
Description
Windchill Object
The Windchill object that specifies a query for retrieving Windchill data.
1. Navigate to the Windchill Site > Utilities and launch the Report Manager utility. 2. From the Report Manager UI, click New to launch Query Builder. 3. Create a ReportTemplate query and save. This creates a ReportTemplate business object in Windchill that can be used as a WBR Data Source. 4. Update the Cognos model to recognize this new Data Source. Launch JConsole from installed Windchill shortcuts. Make connection to Tomcat JVM instance. Select reporting management bean from the MBeans tab, Tree > com.ptc > WebAppContexts > <WindchillInstanceName> > Monitors > ReportingSystem. From the Operations tab, click updateModel. 5. Verify that the Data Source exists in Cognos. Login to Cognos using the <WBRHomeURL> and launch Report Studio. Find <MyReportTemplate> Data Source under Windchill > Report Templates in the Insertable Objects window under the Source tab.
Customization Points
Procedure - Creating a ReportTemplate Data Source in a non-Site context
In the primary procedure above, the ReportTemplate was created in the Site context. The Site context in Windchill correlates to the Windchill > Report Templates level of the Source tab. A variation of the primary procedure is to create the ReportTemplate in a non-Site context such as an organization.
27-60
1. Assume you have ReportTemplate create access in the organization <MyOrg>. 2. In step 1, navigate to the Utilities tab under <MyOrg> instead of the Site Utilities tab. 3. In step 5, the Data Source will now be available under Windchill > Report Templates > <MyOrg>.
Procedure Deleting a ReportTemplate Data Source
A ReportTemplate Data Source that is no longer needed can be removed from the system by deleting it from Windchill and updating the Cognos model. 1. Launch ReportManager from the context associated with the ReportTemplate, select the object, and click Delete. 2. Then update the Cognos model using step 4 of the above Creating a ReportTemplate Data Source procedure.
Limitations
None.
Sample Code
Examples of Usage in Windchill Code
There is no out-of-the-box functionality that depends directly on ReportTemplate Data Source objects. However, there are several out-of-the-box ReportTemplate objects and these are available in Cognos as ReportTemplate Data Source objects. These Data Sources can be used for creating Cognos reports. However, directly modifying these ReportTemplates is not supported.
Packaged Samples
A demo ReportTemplate Data Source object, PartList, is available. It can be loaded using the following command:
windchill wt.load.LoadFromFile d <WindchillHome>/loadXMLFiles/DemoReports.xml CONT_PATH /
Note that if these objects were already loaded, exceptions may occur when running this command. The PartList ReportTemplate object is a simple query for Parts that returns two columns with part number information. It will be created at the Site context and will be available in Cognos after executing the update model operation.
Related Customization Topics
Reporting Info*Engine Task Data Source Customization on page 27-44 Cognos Presentation Customization on page 27-38
Report Generation
27-61
Related Websites
ReportManager online help (Prerequisite) Query Builder online help (Prerequisite) Windchill System Administrators Guide
http://support.cognos.com/support
27-62
Background
The Windchill Business Reporting (WBR) solution supports reports with parameters. Both Windchill and Cognos viewers provide a basic input page that is presented to users to gather parameter values when the report is executed. Often times this input page requires customization for a better end user experience. There are two basic approaches for customizing input pages, use a standard Windchill Java Server Page (JSP) or use Cognos report functionality. The Windchill JSP approach can be used from the Windchill or Cognos viewers. The Cognos approach can only be used with the Cognos viewer.
Scope/Applicability/Assumptions
This documentation assumes that the Windchill Business Reporting (WBR) solution (i.e. Cognos) has been successfully installed and configured. The Windchill instance name is referred to as <WindchillInstanceName>. The Cognos root URL is referred to as <WBRHomeURL>. Typically, if the WBR solution is installed on <WBRHost>, then the <WBRHomeURL> would be http://<WBRHost>/cognos8/cgi-bin/cognos.cgi. It is assumed that you can login to <WBRHomeURL> and you have sufficient Cognos privileges to view Windchill Data Source objects and create reports. Assume you have access to the Windchill server JSP directory, <WindchillHome>/codebase/wtcore/jsp, to create the JSP input page <MyInputPage> in its associated sub-directory <MyInputPagePackage>. Assume you have access rights to edit an existing Windchill Report object, <MyReport> in the Site context.
Intended Outcome
The end result of this solution is the use of your custom input when executing a report.
Solution
Construct and specify a custom input page for reports.
Report Generation
27-63
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Java Server Page (JSP) Cognos Report Studio
Solution Elements
Element
Type
Description
The custom JSP page for specifying report input parameter values. The Windchill object that is displayed to end users in the Windchill User Interface. It acts as a proxy to a corresponding Cognos Report object.
27-64
%> Name: <input type="text" name="<c:out value='<%=paramName%>'/>" value="<c:out value='<%=defaultInputValue%>'/>" size="60"/><br /> <blockquote><input type="submit" value='Execute Report'/></blockquote> <% String hiddenParamName = param2; String hiddenValue = value2; %> <input type="hidden" name="<c:out value='<%=hiddenParamName%>'/>" value="<c:out value='<%=hidenValue%>'/>"/> %> </form> </body> </html>
2. Update <MyReport> to specify the input page. Navigate to the Windchill Site > Reports tab, select the edit action for <MyReport>. 3. Enter wtcore/jsp/<MyInputPagePackage>/<MyInputPage>.jsp into the Input Page text field and click OK. 4. Verify the report in Windchill. Navigate to the Home > Reports tab and Select the View Report action for the <MyReport> object.
Report Generation
27-65
When this component is populated, it would dynamically retrieve Products from Windchill and show their display names. When the user selects the display name, the internal Windchill object ID can be passed as a parameter value input to the report.
Data Source Also data source parameters can be excluded using the usual "parametersToOmit" request attribute. Note, this is a servlet request object attribute list not a parameter list. it was chosen for simplicity and ease of use.
Limitations
None.
27-66
Related Websites
http://support.cognos.com/support
Report Generation
27-67
Background
The Windchill Business Reporting (WBR) solution uses Windchill and Cognos objects. There are both Data Source and Report objects that contain text that can be localized. Localizing the text in these objects allows the text to be displayed in the client's locale.
Scope/Applicability/Assumptions
This documentation assumes that the Windchill Business Reporting (WBR) solution (i.e. Cognos) has been successfully installed and configured. The Windchill instance name is referred to as <WindchillInstanceName>. The Cognos root URL is referred to as <WBRHomeURL>. Typically, if the WBR solution is installed on <WBRHost>, then the <WBRHomeURL> would be http://<WBRHost>/cognos8/cgi-bin/cognos.cgi. It is assumed that you can login to <WBRHomeURL> and you have sufficient Cognos privileges to view Windchill Data Source objects and create reports. Assume you have access to create files in the source directory associated with <MyPackage> in <WindchillHome>. Assume you have created an Info*Engine task <MyTask> in its associated sub-directory <MyTaskPackage> in <WindchillHome>. Assume you have created the ReportTemplate, <MyReportTemplate> in the Site context of <WindchillHome>. Assume you have created a Windchill Report object, <MyReport> in the Site context. Assume you have created a Cognos Report, <MyCognosReport> in the Windchill folder.
For WBR integration, you must also have access rights to update the reporting meta model. This document describes procedures for using standard Java resource bundles to externalize text used in the WBR system. To support localized text, a language specific resource bundle must be created and the text translated to the appropriate language. It is assumed that you require support for more than one language and you have the ability to translate text to your supported languages. The text elements that are referred to in this document consist of report names, parameters, and columns. The actual data displayed in WBR reports is returned from Data Sources. Localizing this data is not covered in this document.
27-68
Intended Outcome
The end result of this solution is the use of your WBR reports in more the one language based on the client locale.
Solution
External localized text to Java resource bundles that can be translated to support a specific client locale.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following: Info*Engine User's Guide JConsole User Interface Cognos User Interface ReportManager User Interface
Solution Elements
Element
Type
Description
<MyTask> <MyTaskResource> <MyReportTemplate> Windchill ReportTemplate <MyReportTemplateResource > <MyReport> Windchill Report
Info*Engine Task Resource Bundle Info Properties File Windchill Object Resource Bundle Info Properties File Windchill Object
The Info*Engine task for retrieving and manipulating Windchill data. The resource bundle info file used to localize Info*Engine task text items. The Windchill object that specifies a query for retrieving Windchill data. The resource bundle info file used to localize ReportTemplate text items. The Windchill object that is displayed to end users in the Windchill User Interface. It acts as a proxy to a corresponding Cognos Report object. The resource bundle info file used to localize Report text items. The Cognos object for a report that contains the definition of the query and specifies the presentation formatting.
Report Generation
27-69
Element
Type
Description
<MyCognosReportResource>
The resource bundle info file used to localize Cognos Report static text.
3. Update the Cognos model to incorporate the localized text. Launch JConsole from installed Windchill shortcuts. Make connection to Tomcat JVM instance. Select reporting management bean from the MBeans tab, "Tree > com.ptc > WebAppContexts > <WindchillInstanceName> > Monitors > ReportingSystem". From the Operations tab, click "updateModel".
27-70
of <MyReportResource>.rbInfo and generate the associated java source and compiled class files. 2. Update <MyReport> to specify the resource bundle. Navigate to the Windchill "Site > Reports" tab, select the edit action for <MyReport>. Enter "<MyPackage>.<MyReportResource>" into the "Resource Bundle" text field and click "OK". 3. Verify the Report attribute "localizedName" is the translated text based on the client locale.
Report Generation
27-71
4. Create language specific versions of <MyCognosReportResource>.rbInfo and generate the associated java source and compiled class files. 5. Create the file, <WindchillHome>/loadFiles/cognosReports/custom/<MyCognosReportAttri butes>.properties. The base names from this and step 2 must match exactly (e.g. MyCognosReport.xml and MyCognosReport.properties.
type=report defaultName=<MyCognosReport> resourceBundle=<MyPackage>/<MyCognosReportResource>.rbinfo
7. Verify the report in Cognos. Refresh the "Public Folders > Windchill" folder and the <MyCognosReport> object should be listed. Use the "Run with options" action to run the report. Try setting different client locales to ensure that the static text is translated properly.
Limitations
To localize a Cognos report, the Report Studio locale must be set to "en_ZW" before authoring a report. Cognos reports reference localized data source and column names based on the Report Studio locale. Any change to these data source and column names for this locale will result in not being able to look up the translated text in another locale. The official workaround recommended by Cognos is to use non-volatile names in a special locale. This special locale is "en_ZW".
27-72
Related Websites
http://support.cognos.com/support
Report Generation
27-73
Scope/Applicability/Assumptions
The processes described in this section are applicable to the following report types: Part Part Configuration Part Instance
This section describes the process for customizing the report selection list. It does not include information on how to author a report or load a report into a third party reporting system. For any custom reports, it is assumed that they have been authored and that a JSP file exists for each custom report that needs to be hooked up to the existing report list. It is assumed that the person doing the customization has access to make the updated to <WindchillCodebase> directory.
Solution
The following section describes the process of customizing the report selection list in detail.
Solution Elements
Element service.properties
Type properties
Description Configuration point for mapping new <CustomDelegate> to ProductStructureReportListDelegate interface Run time Location: <Windchill>\codebase\service.properties
27-74
Description Implement the methods to create the Related Reports drop-down list. Used to gather some of the parameters that needs to generate a report or pass on to another report generator. Optional. Used to define the localized names for reports Runtime location: <Windchill>/codebase/com/ptc/windchill/enterprise/part/ structure
Overview
1. Implement and compile the custom delegate that defines the list of reports, including any custom reports to be displayed in the Related Reports drop down in the Product Structure Browser. 2. Author the Custom Report JSP file (and other related artifacts) corresponding to the custom report(s) into the <Windchill>/codebase. 3. Add and build the localization entries for the custom report(s) and build the localization resources. 4. Register the custom delegate by replacing the out of the box with the custom delegate. 5. Restart Windchill for your changes to take effect.
If you want to add a new custom part report at the end of the existing (out of the box) part report list. Assume that the new custom report has a JSP file netmarkets/jsp/part/custom/myCustomReport.jsp.
Report Generation
27-75
import com.ptc.windchill.enterprise.part.structure.AbstractProductStructu reReportListDelegate import com.ptc.windchill.enterprise.part.structure.partReportResource public class ProductStructureCustomPartReportListDelegate extends AbstractProductStructureReportListDelegate { public void generateReportSelection() { // Generate out of the box report list super. generateOutOfTheBoxReportList(); // Append Custom Report at the bottom // partReportResource.CUSTOM_REPORT_LABEL is resource label for the custom report // name and is defined later in the document super.generateCustomReport (partReportResource.CUSTOM_REPORT_LABEL, " netmarkets/jsp/part/custom/myCustomReport.jsp "); } }
Sample Code: Remove existing part reports from the report list
The following example shows the code to remove some of the existing part reports from the list.
import com.ptc.windchill.enterprise.part.structure.AbstractProductStructu reReportListDelegate public class ProductStructureCustomPartReportListDelegate extends AbstractProductStructureReportListDelegate { public void generateReportSelection() { // Selectively add only the reports of interest // Single-Level BOM super.generateSingleLevelBOM(); // Single-Level BOM with Notes super.generateNoteReport(); // Single-Level Consolidated BOM super.generateSingleLevelConsolidatedBom(); // Multi-Level Components List super.generateMultiLevelComponentList(); // HTML Multi-Level BOM super.generateMultilevelBOM(); // Multi-Level BOM Compare
27-76
super.generatePLMMultilevelBomCompareQuery(); // Multi-Level BOM with Replacements super.generateMultiLevelBOMWithReplacement(); // Multi-Level Where Used super.generateMultilevelWhereUsed(); }
The JSP file has the following information available as HTTP request parameters.
Parameter Name hostName sessionId oid Description Windchill installed machine IP address Windchill servlet session ID Context Object Reference of the persisted primary content item (part, or part configuration or part instance) Version Reference of the context part. Only exists if the report was invoked from part info page. Version Reference of the context part instance. Only exists if the report was invoked from part instance info page. Value String (Usually an IP address) String String Example: OR:wt.part.WTPart.:11045 String VR:wt.part.WTPart.:34023 String Example: VR:wt.part.WTProductInstance2:580 54 String Example: VR:wt.part.WTProductConfiguration :32168 true or false
part
part_instance
part_configuration
Version Reference of the context part configuration. Only exists if the report was invoked from part configuration info page. A Boolean indicating whether to apply configuration specification to the top level object criteria A Boolean indicating whether to use Latest Configuration Specification for unresolved dependents Base64 encoded configuration specification criteria.
applyCSToTop
applyDCSToUnresolved
true or false
encodedConfigSpec
String
In case your reports require the access to the encoded configuration specification, you can use ProductStructureReportSelectorHelper.decodeConfigSpec(encodedConfigSpec) to decode the configuration specification. ProductStructureReportSelectorHelper
Report Generation
27-77
27-78
<td align = "left" valign="top"><font size="-1"><%=applyCSToTop%> </font></td> </tr> <tr> <td align = "left" valign="top"><font size="1">applyDCSToUnresolved</font></td> <td align = "left" valign="top"><font size="1"><%=applyDCSToUnresolved%> </font></td> </tr> <tr> <td align = "left" valign="top"><font size="1">encodedConfigSpec</font></td> <td align = "left" valign="top"><font size="1"><%=encodedConfigSpec%> </font></td> </tr> </table> </tr> </table>
1. To have the localized name for your custom report, add a new resource entry in the <WindchillCodebase>/com/ptc/windchill/enterprise/part/structure/partReport Resource.rbInfo file. The localized report name can be used in the Related Report drop-down list, or as the title in your custom report. For more information see the Resource Info (.rbInfo) Files section on page 37-7 in the Internationalization and Localization chapter. For example:
CUSTOM_REPORT_LABEL.value=My Custom Report
Report Generation
27-79
2. Build the resource bundle by executing the following command from a windchill shell:
ResourceBuild com.ptc.windchill.enterprise.part.structure.partReportResource
Register the newly implemented custom delegate into <WindchillCodebase>/service.properties. The service delegate mechanism uses Java property files to specify the delegates that are used for each service. The main property file is service.properties and located in /Windchill/codebase/. For more information, see the Property Files section on page 2-9 in the The Windchill Development Environment chapter. For a Part report, execute the following command from within <Windchill> directory in Windchill shell:
xconfmanager -s wt.services/svc/default/com.ptc.windchill.enterprise.part.struc ture.ProductStructureReportListDelegate/reportSelector/wt.part. WTPart/0=<Qualified Path>.<CustomDelegate>/duplicate -t service.properties -p
For a Part Instance report, execute the following command from within <Windchill> directory in Windchill shell:
xconfmanager -s wt.services/svc/default/com.ptc.windchill.enterprise.part.struc ture.ProductStructureReportListDelegate/reportSelector/wt.part. WTProductInstance2/0=<Qualified Path>.<CustomDelegate>/duplicate -t service.properties -p
For a Part Configuration report, execute the following command from within <Windchill> directory in Windchill shell:
xconfmanager -s wt.services/svc/default/com.ptc.windchill.enterprise.part.struc ture.ProductStructureReportListDelegate/reportSelector/wt.part. WTProductConfiguration/0=<Qualified Path>.<CustomDelegate>/duplicate -t service.properties -p
Restart Windchill
You must restart the following for the changes to take effect: Apache Tomcat ServerManager Method Server
27-80
28
Customizing Event Audits
This chapter describes how the Windchill Auditing Framework is implemented and explains how to extend the auditing framework to allow additional events to be audited. Topic Page
Introduction .......................................................................................................28-2 Overview of the Audit Event Framework .........................................................28-3 Capturing New Events.....................................................................................28-10
28-1
Introduction
The auditing framework provides a mechanism to enable event-based logging that provides a historical record of who did what that caused changes in the Windchill database. The security auditing feature also provides a mechanism to retain historical records of security related events, such as privilege changes, team changes, and denial of access. Security audit reporting is helpful to customers in highly regulated industries that need to identify events that may have resulted in a potential security breach. The following list provides possible application uses that can be recorded: Who accessed the application? Who viewed or downloaded an object? Who changed this object? Who granted access to a specific user?
The Windchill Auditing Framework is a Windchill service that captures events generated through normal application use, using a collection of classes and configuration files that a customer modifies to indicate which specific events are to be recorded in the audit log. Out-of-the-box, the auditing framework is enabled at the global level. However, the only events that are enabled are License Usage Reporting and Organization Usage. Any other specific events that you want recorded in the audit log must be enabled on an individual basis.
28-2
28-3
ProjectAuditEvent Class
The ProjectAuditEvent class represents the basic auditing information being stored for a single event. The ProjectAuditEvent class contains the following information:
Attribute Name eventKey Description Every AuditRecord corresponds to a Windchill event (wt.events.KeyedEvent). This attribute is the Windchill event key. This is the localized value of the external label for the event represented by this AuditRecord. It is translated into the server's locale when the AuditRecord is recorded in the database Time of the event. Organization the current user belongs to at the time the event was emitted. The name of the target object of the event. A reference to the target object of the event. Name of the user that is the current principal when the event happened. Identifier of the object that is the target of the event. IP address of the client machine used when the event was emitted. Type of the object that is the target of the event. Numeric ID of the control branch of the type of the target of the event. Identifier of the object that is the target of the event. Number of the object that is the target of the event. Cage code of the object that is the target of the event. Numeric ID of the control branch of the object that is the target of the event. Numeric ID of the working copy branch of the object that is the target of the event. Version ID of the object that is the target of the event.
eventLabel
eventTime userOrgName targetName targetReference userName userID IPAddress targetType targetTypeBranchID targetID targetNumber cageCode branchID workingBranchID versionID
28-4
Attribute Name masterID orgContainerID orgContainerName appContainerID appContainerName appContainerTypeBra nchID folderPath domainPath targetIdentity lifecycleState transactionDescription
Description Identifier of the master of the object that is the target of the event. Identifier of the organization that hosts the application container that owns the object that is the target of the event. Name of the organization that hosts the application container that owns the object that is the target of the event. Identifier of the application container that owns the object that is the target of the event. Name of the application container that owns the object that is the target of the event. Numeric ID of the type of the application container that owns the object that is the target of the event. Folder path of the object that is the target of the event. Domain path of the object that is the target of the event. Identity of the object that is the target of the event. Lifecycle state of the object that is the target of the event. Transaction description associated with the transaction from which the event was emitted.
The information contained in the AuditRecord class is sufficient for most events. In certain situations, however, the Windchill Auditing Framework is required to capture additional information specific to the event generated. The event-specific information is stored in an event-specific table and is managed by an eventspecific object. For example, when a user is added to or removed from a group, it is important to note which user is involved and not just that the group membership was modified. The class ModifyGroupEventInfo holds the additional information as a reference to the user being added or removed. If multiple users were added or removed in a
28-5
single operation, all ModifyGroupEventInfo instances point to a single AuditRecord instance. This is shown in the figure below.
28-6
Audit Recorders
For each class which manages event data stored in the database, a corresponding audit recorder exists which is responsible for mapping the appropriate event information to the members of the class. The AuditRecord class, representing the base information stored for all events, is created and persisted by wt.audit.configaudit.DefaultAuditEventRecorder. Each class representing event-specific information also has a corresponding audit recorder. For example, wt.audit.configaudit.ModifyGroupEventRecorder extends the default recorder and creates the ModifyGroupEventInfo instances.
At the global level, the enabled attribute for <EventConfiguration> determines whether the Windchill Auditing Framework is loaded and initialized. If enabled="false", no auditing occurs and rest of the configuration file is not processed. To enable the Windchill Auditing Framework, set the enabled attribute to true as shown below. Any changes to this configuration file will require a method server restart in order to take effect.
28-7
The <ConfigEntry> element identifies the events to be audited for a specific class. The class attribute identifies a fully qualified class name to be audited. Within the <ConfigEntry> element there are additional elements defining the specific events being monitored for the class and which audit recorder persists the event information. Originally, these sub-elements were specific to an event type; PersistenceManagerEventEntry for PersistenceManagerEvent, AccessControlEventEntry for AccessControlEvent, etc. New in X-05, the KeyedEventEntry element allows the event class to be explicitly defined and should be used exclusively going forward. ConfigEntry dtd (part 2)
<!ELEMENT ConfigEntry (KeyedEventEntry | WIPEventEntry | WfEngineEventEntry | PersistenceManagerEventEntry | ActionItemEventEntry | ProjectServiceEventEntry | AccessControlEventEntry | ProjectManagementEventEntry | RenameEventEntry | CustomEventEntry | GroupEventEntry | ForumEventEntry | VCEventEntry)*> <!ATTLIST ConfigEntry class CDATA #REQUIRED enabled (true | false) #REQUIRED > <!ELEMENT KeyedEventEntry EMPTY> <!ATTLIST KeyedEventEntry eventKey CDATA #REQUIRED enabled (true | false) #REQUIRED handler CDATA "wt.audit.configaudit.DefaultAuditEventRecorder">
The enabled attribute for each <ConfigEntry> element determines whether a specific Windchill class, as defined by the class attribute, is to be audited. To enable auditing for a specific class, set the enabled attribute to true as shown in the example below. It is important to note that auditing is only enabled for this class if auditing is also enabled at all parent levels. Also, any changes to this configuration file will require a method server restart in order to take effect. Enabling class-level auditing
<ConfigEntry class="wt.org.WTGroup" enabled="true"> <KeyedEventEntry eventKey="*/wt.org.OrganizationServicesEvent/MEMBERSHIP_CHAN GE" enabled="true" handler="wt.audit.configaudit.ModifyGroupEventRecorder"/> </ConfigEntry>
As described above, each <KeyedEventEntry> element maps an event to an audit recorder. The eventKey identifies the fully-qualified classname for the event
28-8
being audited. The handler attribute identifies the fully-qualified classname for the audit recorder. If omitted, the default audit recorder is used. The enabled attribute for each <KeyedEventEntry> element determines whether a specific event (defined by the eventKey attribute) for a specific class (defined in the <ConfigEntry> parent element) is to be audited. To enable auditing for a specific event, set the enabled attribute to true as shown in the example below. Once again, auditing is only enabled for this event if auditing is also enabled at all parent levels and any changes to this configuration file will require a method server restart in order to take effect. Enabling event-level auditing
<KeyedEventEntry eventKey="*/wt.org.OrganizationServicesEvent/MEMBERSHIP_CHANGE" enabled="false" handler="wt.audit.configaudit.ModifyGroupEventRecorder"/>
28-9
28-10
28-11
The following examples show an implementation of persistMultiObjectEvent() and an implementation of persistEvent(). For multiple objects, notice the optimization to create a collection of event-specific event info classes and to pass the collection to the persistence layer. Example: persistMultiObjectEvent method
protected WTCollection persistMultiObjectEvent( KeyedEvent anEvent ) throws WTException { Transaction trx = new Transaction(); try { trx.start(); WTCollection auditRecordCol = super.persistMultiObjectEvent(anEvent); int numObjs = auditRecordCol.size(); WTCollection eventInfoCol = new WTArrayList(numObjs); for (Iterator i = auditRecordCol.persistableIterator(); i.hasNext(); ) { AuditRecord record = (AuditRecord)i.next(); Persistable target = record.getTargetReference().getObject(); <event_info_class> eventInfo = <event_info_class>.new<event_info_class>(); // Set event and target specific attributes here eventInfo.setAttribute1(target.getAttribute1()); eventInfo.setAttribute2(target.getAttribute2()); // These two attributes are always required eventInfo.setDomainRef(record.getDomainRef()); eventInfo.setRecord(record); eventInfoCol.add(eventInfo); } PersistentObjectManager.getPom().insert(eventInfoCol, null, null); trx.commit(); trx = null; return recordCol; } catch (WTPropertyVetoException pve) { throw new WTException (pve); } finally { if(trx != null) { trx.rollback(); }
28-12
} }
28-13
28-14
29
Customizing Communication Tools
Windchill provides tools that enable your team to communicate and collaborate effectively, such as support for meetings, subscriptions, and discussion forums. This chapter describes how to customize communication tools, where such customization is supported in Windchill. Topic Page
29-1
Customizing Meetings
Windchill PDMLink, and Windchill ProjectLink provide the ability to customize the authentication scheme used for Webex meetings. A delegate object, implementing the WebexUserInfoDelegate interface, is used to create the account name and password. To perform this type of customization, you need to write a class that implements the interface WebexUserInfoDelegate and substitute that for the default delegate provided out of the box with Windchill. 1. Write your customized WebexUserInfoDelegate. Write a class that implements the wt.meeting.WebexUserInfoDelegate interface. See your installed Javadoc for details on the WebexUserInfoDelegate API. Any class that implements this interface must conform with all Webex requirements. For example, names, email addresses, and passwords must conform to the Webex requirements listed in the Webex API documentation. If storing any information is required to make this work, that is also the responsibility of the implementor. 2. Include the compiled class in the Windchill codebase in the same way that you include other customizations. 3. To make Windchill actually use the new delegate, modify the service delegate mapping according to the procedure described in the Customizing service.properties topic in the Developing Server Logic chapter on page 35-24. In service.properties, the out of the box entry for WebexUserInfoDelegate is as follows:
wt.services/svc/default/wt.meeting.WebexUserInfoDelegate/default/java.lang.Object/0 =wt.meeting.DefaultWebexUserInfoDelegate/singleton
delegate.
29-2
Name
Exposed in UI by Default
Description
Action Plan Actual Effort Comments Contacts Contingency Cost Cost Impact Customers Date Design Cost Estimated Effort Impact Location Percent Phase Prevention
String 4000 characters Integer number of hours String 4000 characters String 4000 characters String 4000 characters Monetary real number Monetary real number String 4000 characters Date Monetary real number Integer number of hours String 4000 characters String 4000 characters % String 200 characters String 4000 characters
29-3
Name
Exposed in UI by Default
Description
String 200 characters Monetary real number Integer Integer String 4000 characters Enumerated value (same as for activities) Unavailable Very High High Medium Low Very Low
Risk Description Risk Type Schedule Impact Size Suppliers Supporting Information Time Tooling Cost
Yes Yes No No No No No No
String 4000 characters String 200 characters + or days Real number String 4000 characters String 4000 characters hh:mm Monetary real number
29-4
The following example from the attributeConfig.xml file shows that the Comments field is configured to be exposed in the user interface.
<attribute resourceKey="comments" enabled="true" order="40" required="false" resourceBundle="wt.meeting.actionitem.actionitemModelRB" displayType="textBox" internalName="Comments" type="java.lang.String"/>
29-5
29-6
IV
Services and Infrastructure Section
Chapter
Page
Windchill Services ............................................................................... 30-1 System Generation ............................................................................... 31-1 Customizing Modeled Elements .......................................................... 32-1 Enumerated Types................................................................................ 33-1 Windchill Design Patterns ................................................................... 34-1 Developing Server Logic ..................................................................... 35-1 The Enterprise Layer............................................................................ 36-1 Persistence Management...................................................................... 37-1 Advanced Query Capabilities .............................................................. 38-1 Internationalization and Localization................................................... 39-1 Customizing Archive, Purge, and Restore ........................................... 40-1 Import Export Framework ................................................................... 41-1 Evolvable Classes ................................................................................ 42-1 Creating Large Objects (LOBs) ........................................................... 43-1 Customizing Data Formats................................................................... 44-1
30
Windchill Services
This chapter describes the various Windchill services. Topic Page
30-1
Windchill Packages
Windchills functionality that is, its services and utilities is generally separated into Java packages. These packages are available in the wt and com.ptc directories within the Windchill codebase directory. You can use these packages as you build new applications and customize existing applications. Model files are provided so you can extend some of the classes in the models and then generate code for them. This section lists a subset of the packages available for use in customizations and gives an overview of their functionality. Some of the packages are described in further detail in other chapters of this guide, or in the accompanying Javadoc for the package.
access
Functionality for access control; used to define access policies (that is, define rules for what principals have access to what information). See the wt.access class entry in your installed Windchill Javadoc for more information.
admin
Functionality to create administrative domains and policies. See the wt.admin class entry in your installed Windchill Javadoc for more information.
content
Functionality for handling content data (attaching files and URLs to content holders, such as documents and change objects) and associating business information metadata (such as the author) with content. See the wt.content class entry in your installed Windchill Javadoc for more information.
content replication
Functionality for increasing the speed at which users can access data. Data is stored on more rapidly accessible external vaults known as replica vaults. Base packages cannot be extended or modified in any way. Additional information about content replication is discussed in the Windchill System Administrators Guide.
effectivity
Functionality to assert that a PDM object is effective under certain conditions. See the wt.eff and wt.effectivy class entry in your installed Windchill Javadoc for more information.
epm
The engineering service (wt.epm package) provides functionality to create and manage CAD model related objects. See the wt.epm and subpackages entry in your installed Windchill Javadoc for more information.
federation
The federation service (wt.federation package) provides functionality to create and manage proxy objects of remote systems and perform utility functions supporting the federation system. See the wt.federation class entry in your installed Windchill Javadoc for more information.
30-2
folder
Functionality to put information into folders and cabinets for navigational purposes. See the wt.folder class entry in your installed Windchill Javadoc for more information.
fv
Functionality to define and execute the vaulting algorithm for content items. See the wt.fv class entry in your installed Windchill Javadoc for more information.
identity
Functionality to display the identity of business objects; that is, their type and identifier (for example, a type of part and an identifier of part number). See the wt.identity class entry in your installed Windchill Javadoc for more information.
Import and Export
Windchill Import and Export can assist you in moving complete Windchill content and metadata to and from Windchill sites and Windchill ProjectLink portals by placing the data in Jar files. See the wt.ixb subpackages entry in your installed Windchill Javadoc for more information.
index
Functionality to index metadata and content data, controlling how information is put into search indexes. See the wt.index class entry in your installed Windchill Javadoc for more information.
lifecycle
Functionality to define and use life cycles. See the wt.lifecycle class entry in your installed Windchill Javadoc for more information.
locks
Functionality to lock and unlock objects. See the wt.locks class entry in your installed Windchill Javadoc for more information.
notify
Functionality to define rules and create subscriptions such that when certain events occur to certain objects, E-mail notification is sent. See the wt.notify class entry in your installed Windchill Javadoc for more information.
org
Organization services; functionality to create users and groups (generically called principals). See the wt.org class entry in your installed Windchill Javadoc for more information.
ownership
Functionality to define ownership of an object. See the wt.ownership class entry in your installed Windchill Javadoc for more information.
project
Functionality to create projects, associate projects to business objects, and resolve roles to principals.
Windchill Services
30-3
queue
Functionality to define and manage queues. Queues are used to persistently record deferred processes. Because queued processes are persistently stored, they are guaranteed to execute at a later time. See the wt.queue class entry in your installed Windchill Javadoc for more information.
session
Functionality to define and manage user sessions. See the wt.session class entry in your installed Windchill Javadoc for more information.
vc
Version control; functionality to handle versions of objects. Version control services described in this chapter include baselines, configuration specifications, version structuring, version viewing, and work in progress. See the wt.vc subpackages entry in your installed Windchill Javadoc for more information.
workflow
Functionality to create and manage workflow definitions, initiate and manage process instances, and distribute work items to users and groups. See the wt.workflow and subpackages entry in your installed Windchill Javadoc for more information.
30-4
EPM provides Windchill knower and doer classes that allow the engineer to express the structure of a CAD model and to load the CAD files into the Windchill database. EPM also provides background services that ensure data consistency in the database. Windchill supports the concept of a build operation, which allows a graph of dependencies in one set of objects (called target objects) to be maintained automatically as a by-product of changes to another set of objects (called source objects). EPM implements a build operation specific to creating part objects from describing CAD documents. For more information, see the appropriate Javadoc.
An EPMDocument can represent a component or an assembly, using other EPMDocuments as components. (This concept is described further in the section on Handling Model Structure later in this section.) As shown in the following model, EPMDocument implements a number of Windchill interfaces that allow it to be used in various Windchill services:
RevisionControlled
Windchill Services
30-5
BuildSource
Allows the EPMDocument to be used by the Windchill build mechanism to maintain a part structure
SupportingDataHolder
Allows the EPMDocument to have EPMSupportingData. An EPMSupportingDataHolder can hold arbitrary Java objects, each tagged with a name and an owner application name. This allows an application to store application-specific data with the EPMDocument without having to extend the Windchill schema.
EffectivityManageable
Allows the EPMDocument to have generated graphic representations that can be viewed and marked up in a view tool.
EPMDocument Model
30-6
Because the EPMDocument is RevisionControlled, a corresponding EPMDocumentMaster exists, which also implements Windchill interfaces:
UniquelyIdentified
EPMDocument is a Windchill ContentHolder (as shown in the figure above) and, thus can contain data files, URLs, or both. This allows the engineer to upload the actual Pro/ENGINEER model file (for example, the .ASM file) and maintain it in the Windchill database. An EPMDocument can contain a number of ContentItems. This allows EPM to store alternate representations of the CAD model (produced by the topology bus, for example) in the same document. Content is maintained using the normal Windchill ContentService.
Creating an EPMDocument
An EPMDocument must be created via the factory method newEPMDocument: EPMDocument doc = EPMDocument.newEPMDocument ( <number >, <name >, <EPMAuthoringAppType authoring App >, <EPMDocumentType docType>, <CADName>); The number of the document must be unique within the Windchill database. The ownerApplication is an EnumeratedType indicating the application that intends to manage changes to the document. The concept of owner application is no 2 set via a call to EPMContextHelper.setApplication (EPMApplicationType appType), where EPMApplicationType is an EnumeratedType. Set the "current application" for use by checking code. This value is cached on the client-side, but is also sent (via the EPMContextManager) to the server-side SessionContext. Once setApplication () has been called, all objects created will be tagged with the specified application. For Pro/ENGINEER authored CADDocuments, CADName needs to be specified. EPM Services ensure that CADName is unique in a Windchill database.
Windchill Services
30-7
EPM Variant Link is an Iteration to Master link that denotes that an EPM Document is a variant of another EPM Document.
30-8
Windchill Services
30-9
The EPMDependencyLink represents a relation between two EPMDocuments. EPMStructureService can be used to read the EPMDependencyLinks between EPMDocuments. A number of interfaces similar to the following are available:
public QueryResult navigateUses( EPMDocument document, QuerySpec querySpec ) throws WTException;
EPMMemberLink
The EPMMemberLink represents the use of one model by another. It includes data such as quantity and positioning, as shown in the following figure.
EPMReferenceLink
The EPMReferenceLink represents reference to an object by a model. While an EPMMemberLink can use only another EPMDocument, any Iterated object can be referred to (for example, a specification in Microsoft Word). The relationship between an EPMDocument containing a drawing and the EPMDocument containing the model is represented using an EPMReferenceLink. The direction of this link should be such that the drawing describes the model. The model never describes the drawing.
30-10
Build Model
You cannot associate an EPMBuildRule to an EPMDocument that has an effectivity assigned to it. To create an EPMBuildRule, you must first have created the WTPart and EPMDocument that you intend to relate. In addition, the WTPart, but not the EPMDocument, must be either checked out or in your personal folder. Currently, only one subtype of EPMBuildRule is implemented EPMBuildLinksRule. This rule allows for the publication of usage links to the part structure (see the following figure).
Windchill Services
30-11
Build Rule To create the rule, you must use the factory method defined on the class: EPMBuildLinksRule rule = EPMBuildLinksRule.newEPMBuildLinksRule ( <document >, <part); Once this has been done, you can use the Windchill build process to publish the document structure to the part structure. This can be done in either of two ways: By building the EPMDocument: BuildHelper.service.buildTarget (<document >,<config spec >); By building the WTPart: BuildHelper.service.buildTargetsForSource (<part >,<config spec >); If you are building a vaulted WTPart, the build process creates a new iteration of the WTPart. If the WTPart is either checked out or in your personal folder, no new iteration is created; instead, the usage links on the latest iteration are changed to reflect the results of the build.
30-12
31
System Generation
When you have finished modeling, the next step is system generation. Using Windchill extensions to Roses original functionality, Windchill generation tools generate Java code, Info files containing class metadata used by the runtime environment, and database DDL from the models you create. This chapter describes how to use the system generation tool and how the classes you model in UML (in Rose) correspond to the code that is generated. Topic Page
Overview of System Generation .......................................................................31-2 How Rose UML Maps to Java Classes .............................................................31-3 Implicit Persistable Associations Stored with Foreign ID References............31-21 Extending the EnumeratedType class .............................................................31-36 How Rose UML Maps to Info Objects ...........................................................31-39 How Rose UML Maps to Database Schema ...................................................31-41 How Rose UML Maps to Localizable Resource Info Files ............................31-47 Using the Windchill System Generation Tool ................................................31-50 Using Windchill System Generation in a Build Environment ........................31-54 Deploying Modeled Customizations ...............................................................31-60
31-1
Using the models in the Rational Rose repository, the Windchill export tool produces mData files. The system generation tools then use the mData files to produce Java code, Info files (metadata used by the runtime environment), and database schema. mData files have a non-proprietary file format so that, in the future, different modeling tools can be used without rewriting portions of the system generation tool. The following sections describe how the Rose UML is mapped to each of the types of output (Java code, Info files, and database schema). The final section of this chapter describes how to run the system generation tool.
31-2
The following sections, which describe how each of these elements are mapped to Java, also include the specifications you must set for each kind of element to ensure the correct code is generated. Within the Rose dialogs where you set these values, there are other tabs and fields. Any tabs or fields not described in this manual are either ignored by the system generation tools or have preferred default values. The figure below shows a sample specification dialog in Rose. To access this dialog, double click on an item in a diagram; or select a diagram item, then select Open Specification from the right click pop-up menu. Rose displays a specification that corresponds to the item you selected. The documentation for
System Generation
31-3
code generated items is placed in the generated source code in the format of Javadoc style comments.
Model of a Class
31-4
Copyright Statement
Rose provides for a default copyright, and also for a copyright to be specified for a particular package. This copyright statement is generated into the Java source code for each class.
Package Statement
The package statement corresponds to the Rose UML package that owns the class. For example,
// Example of a generated package statement package example;
Import Statements
Java import statements are generated based on references made to other classes through the following model elements: Class and Interfaces inherited by the class. Dependencies modeled for the class. Non-Persistable Association types. Attribute types declared by the class. Argument type s specified by the methods of the class. Return value types specified by the methods of the class. Exceptions thrown by the methods of the class.
For example,
// Examples of a generated import statements import example.MyAddress; import example.MySize; import java.lang.String; import java.sql.Date; import java.util.Vector; import wt.fc.Item; import wt.pds.PersistentRetrieveIfc; import wt.pds.PersistentStoreIfc; import wt.pom.DatastoreException; import wt.util.WTException; import wt.util.WTPropertyVetoException; //##begin user.imports preserve=yes //##end user.imports
The generated import statements depend on input from the classRegistry.properties file (discussed later in this chapter) that contains a list of classes and their associated packages.
System Generation
31-5
The user.imports section is provided as a safe place for the developer to enter additional imports to support the implementation of the class. This section is preserved during subsequent generations of the class. To better support use of Integrated Development Environments (IDEs), the generator also preserves imports found outside of the user.imports block. If the (trimmed) text of the import line doesn't begin with the word "import", it won't be preserved. Anything within a preserve=yes block is ignored. When it finds unmanaged import statements, it moves them into the user.imports preserve block and adds a comment to indicate how it got there.
//##begin user.imports preserve=yes import unmodeled.UnmodeledOne; // Preserved unmodeled dependency //##end user.imports
The negative side-effect to this change is that imports previously generated from model dependencies will not be automatically removed when the dependency is removed from the model. For instance, if a class changed from using Vector to using List, both classes would continue to be imported. Developers need to purge unused import statements as they notice them.
Class Documentation
Any documentation that is entered in Rose will be generated into the class in the form of Javadoc style comments. For example,
//##begin MyItem% [ ]34F19D1A00B3.doc preserve=no /** * An example class to demonstrate system generation * * @version 1.0 **/ //##end MyItem% [ ]34F19D1A00B3.doc
Class Declaration
A class is declared as modeled and will extend and implement all of the classes that were modeled as having a generalization relationship. If a class is modeled to extend a class that was not modeled as Extendable, via the Windchill SupportedAPI property, the generator will not allow it to be generated until that modeled generalization is removed.The class can be modeled as concrete, abstract, or as an interface. For example,
// Example of a class declaration public class MyItem extends Item implements Externalizable{ // Example of an abstract class declaration public abstract class Item extends WTObject { // Example of an interface declaration public interface Persistable extends ObjectMappable {
31-6
Class Body
Some constants are generated into the body of each class. The following are examples of generated class constants:
// Constants used by the class private static final String RESOURCE = "example.exampleResource"; private static final String CLASSNAME = MyItem.class.getName();
The RESOURCE constant identifies the resource bundle the class is to use for localizable messages. The CLASSNAME constant provides an easily accessible, programmatic reference to the name of the class. The rest of the class body contains the generated results of elements modeled as features of the class and as relationships between classes. These include operations, attributes, associations, and generalizations. The details of these will be covered in subsequent sections.
Export Control should be set to Public or Implementation. Implementation classes are visible only to other classes within the same package. Documentation specifies a description for the element. The documentation will be generated into the Java code, as Javadoc style comments. Type is ignored by the code generator.
On the Windchill tab, set the following values: Note: Some specification dialogs provide multiple property sets. Every specification provides a "default" set. The class specification also provides "EnumeratedType" and "System" sets, The EnumeratedType set contains the properties that apply to an EnumeratedType class. The System set contains the
System Generation
31-7
properties that apply to non business domain class. Property sets may provide different default values for the same property. SupportedAPI should be set to communicate to users the degree to which the class will be supported. <Default> to ignore the Supported API concept. Private if the class will not be supported at all. Public if use of the class is supported. Extendable if extension of the class is supported. Deprecated if the class is obsolete and support is being phased out. (This setting is superseded by the Deprecated property.)
Deprecated should be set when the element is obsolete. <Default> indicates the class is not deprecated, unless, for backward compatibility, SupportedAPI is set to Deprecated. deprecated if the class is obsolete and support is being phased out.
Java Properties Generate should be set to False if the system generation tools should ignore this modeled class. CodeGenerationName specifies the name of the class that will be generated. Leave it blank to have the generated name be the same as the name of the modeled class. Serializable indicates if the generated class will implement the Serializable or Externalizable interface. Default evaluates to Externalizable, if possible; otherwise, Serializable. Externalizable (basic), can be used to generate simple Externalization support that does not include support for reading old versions.For a class that will have instances serialized into BLOB columns in the database, set the property to Evolvable. (For further information, see appendix D, Evolvable Classes.) To have the class implement neither interface, set the property to None. PrimitiveType indicates which primitive value-type a class can be decomposed into. StaticInitBeforeFields indicates whether the static initializer will be placed before the field declarations. GenAttributeLabels indicates whether label constants will be generated for the modeled attributes and roles of the class. If True, they will be
31-8
generated. If Default, they will be generated for classes that implement ObjectMappable and for interfaces. ExplicitOrder (EnumeratedType set only) indicates whether the modeled EnumeratedType options will be explicitly order in the resource info (rbInfo) file. By default, a locale specific, alphabetical order will be determined at run-time.
Datastore Properties PackageName is the package name to use for the class. TableName is the database table name to use for the class. RemoveEventParticipant specifies if the persistence layer is required to dispatch Remove events for this class. Remove events include "REMOVE" and "CLEANUP_LINK". Default will be determined to be True for any Persistable class. CompositeIndexN indicates the columns for composite index on the table. CompositeUniqueN indicates the columns for composite unique index on the table. ColumnType indicates the relational storage type for the value-type. By default a mapping, based on the primitive type, is used. Specify a ColumnType of Sequence if the value of the attribute is to be set using a generated sequence number.
Oracle Properties TableSpaceName is the tablespace to use for storage option of the table. TableSize indicates if the relative size required for the objects that will be stored (the actual storage values are mapped from the size via property file settings). IndexTableSpaceName is the tablespace to use for the storage option of the indices of the table.
UI Properties StandardIcon is the file name of the standard icon for the class. OpenIcon is the file name of the open icon for the class. Localizable indicates if the class will have a localizable display name stored in the resource bundle for the package.
System Generation
31-9
Model of Operations
Operations modeled in Rose are mapped as Java methods of the generated class. For operations that are not modeled as abstract, stubs are created in the generated class where you add your own code. All documentation, keywords, parameters, and return types that are modeled in Rose are generated into Java classes. Information about operations that you can specify in Rose is detailed below. The begin and end markers that are generated into editable files denote the sections that you can edit. These sections are preserved as is during subsequent generations of the files. Some sections are marked with preserve=no. This is true for all Javadoc comment sections and some code sections, where some implementation is generated into an editable file. The "no" value for preserve indicates that the section is a generated default, which you may choose to edit. If you do edit any of these sections, you must change the preserve value from "no" to "yes"; otherwise, it will not be preserved. If MyItem were an interface, only the operation declaration would be generated into MyItem, because a Java interface can contain no implementation. To the degree possible, the implementation aspects of interface operations will be
31-10
generated into concrete subclasses. See the Implementing Interfaces section for details.
On the Detail tab, set the following values: Argument Name specifies the name of an argument in the method. Argument Type specifies the argument type. Exceptions specifies the exceptions thrown by the method. The rest of the dialog is ignored by the code generator.
On the Windchill tab, set the following values: SupportedAPI should be set to communicate to users the degree to which the operation will be supported. Private if the operation will not be supported at all. Public if use of the operation is supported. Deprecated if the operation is obsolete and support is being phased out. (This setting is superseded by the Deprecated property.)
Deprecated should be set when the element is obsolete. <Default> indicates the operation is not deprecated, unless, for backward compatibility, SupportedAPI is set to Deprecated. deprecated if the operation is obsolete and support is being phased out.
Java Properties Abstract should be set to True to make the resulting method abstract. Static should be set to True to make the resulting method static. Final should be set to True to make the resulting method final.
System Generation
31-11
Native should be set to True to make the resulting method a native method. Synchronized should be set to True to make the resulting method a synchronized method. RemoteInvocation should be set to True to make the resulting method executable only at the server. This setting is not needed for classes that implement a RemoteInterface.
Model of Attributes
31-12
Field Declarations
All attributes modeled in Rose are implemented as private fields of the Java class. For example,
// Examples of attribute declarations private String a1; private Date a2; private Xyz a3;
The accessor methods to these attributes are public or protected, depending on the export control as defined in the model. Examples of accessor methods follow.
Accessor Methods
Public and protected accessor methods are generated in the Java class. For example,
// Example of a "getter" method public String getA1() { return a1; } // Example of a "setter" method public void setA1( String theA1 ) throws WTPropertyVetoException { a1 = theA1; }
Accessor methods are code-generated from the attributes modeled on the business class in the Rose model. They need not be modeled on classes in the UML model. These accessor methods follow the Java beans naming convention. Attributes that were modeled as public get public accessor methods. Attributes that were modeled as protected get protected accessor methods. The system generation tool generates accessors that enforce attribute validation based on attribute properties specified in the model. If the constrain property (a Rose specification) is set to true for an attribute modeled in Rose, the setter method is declared to throw a wt.util.WTPropertyVetoException, which is derived from java.beans.PropertyVetoException. This exception is thrown if the setter method has determined that a value being set in the attribute is invalid. Developers can change the default accessor methods by writing code in the preserve region.
System Generation
31-13
Validation code will be generated if the attribute is modeled with a lower or upper bound, as unchangeable, or as a required attribute. Each of these properties appear, in Rose, on the Windchill tab for the attribute. Validation code will also be generated if the attribute is modeled with a constrained type. That is, the attribute is redefining an attribute, in the hierarchy, to be of a sub-type of the original definition. If a validation method is generated, the setter code will invoke it. If validation were generated for the "a1" attribute, the method would be "validateA1". If MyItem were an interface, only the accessor declarations and the label constant would be generated into MyItem, because a Java interface can contain no implementation. To the degree possible, the implementation aspects of interface attributes will be generated into concrete subclasses. See the Implementing Interfaces section for details.
On the Detail tab, set the following values: Static should be selected if the attribute is to be generated as a static field. Derived should be selected if the generated private field is not desired. Also see the DerivedFrom property below. The rest of the dialog is ignored by the code generator.
On the Windchill tab, set the following values: In addition to the default property set, attributes have two predefined sets. First, named "constant", which can be used for constant attributes. Second, named "constantEnumeratedType", which can be used for constant attributes on EnumeratedTypes. While these property sets can be used to quickly set the Windchill properties for these constant attributes, the Static property still needs to be selected on the detail tab. Abstract should be set to True if the implementation of a field for the attribute will be deferred to a subclass. Accessor methods generated for this attribute will be abstract.
31-14
DerivedFrom should be specified if this attribute is derived from another modeled element. The value will specify a traversal path to the source. For example, homeAddress.city indicates that this class has a non-first-class aggregation named homeAddress which contains an attribute named city. To specify that an attributes derivation traversal goes through an ObjectReference, a different delimiter is used. For example, homeAddress>city indicates that this class has an opposite-side role on a first-class association named homeAddress which contains an attribute named city. StringCase should be set to LowerCase to force the value to lowercase. It should be set to UpperCase to force the value to uppercase. The enforcement of this constraint will be generated into the setter method for the attribute. LowerLimit constrains the valid values for the type. For String types, it specifies the minimum length of the String. For numeric types, it specifies the minimum value of the attribute. Date and Time types are not currently supported by this property. The constraint is enforced in the validation that is generated for the setter. UpperLimit constrains the valid values for the type. For String types, it specifies the maximum length of the String. For numeric types, it specifies the maximum value of the attribute. Date and Time types are not currently supported by this property. The constraint is enforced in the validation that is generated for the setter. Required should be set to True if the database will not allow a null value in the column that persists the attributes value, and the setter validation will not allow the attributes value to be set to null. Changeable should be set to Frozen if the value cannot be changed once it has been persisted. It should be set to ViaOtherMeans if the normal setter method is not allowed to change the value once it has been persisted. (For example, ViaOtherMeans is used for those attributes that are part of the identity of the class which must be changed through the identity service.) WriteAccess should be set if the access of the setter should be different than that of the getter that will be generated. SupportedAPI should be set to communicate to users the degree to which the attribute will be supported. <Default> to ignore the Supported API concept. Private if the attribute will not be supported at all. Public if use of the attribute is supported. Deprecated if the attribute is obsolete and support is being phased out. (This setting is superseded by the Deprecated property.) Deprecated should be set when the element is obsolete.
System Generation
31-15
<Default> indicates the attribute is not deprecated, unless, for backward compatibility, SupportedAPI is set to Deprecated. deprecated if the attribute is obsolete and support is being phased out.
Java Properties Final should be set to True if the resulting field should be final. Transient should be set to True if the resulting field should be transient. Volatile should be set to True if the resulting field should be volatile. Persistent should be set to True if the field that holds the value will be persisted to the database. GenerateAccessors should be set to False if no accessors are to be generated. Constrain should be set to True if the resulting setter method should declare that it throws a WTPropertyVetoException. GetExceptions specifies exceptions that will be declared as thrown by the generated getter. SetExceptions specifies exceptions that will be declared as thrown by the generated setter. BeforeStaticInitializer should be set to True if field declaration should be placed prior to the static initializer.
Datastore Properties ColumnName is the class attribute to column name mapping. Default is the attribute name. ColumnType is used to indicate the relational storage type for the valuetype. By default a mapping, based on the attribute type, will be used. Index specifies whether an index is created for this attribute. Unique specifies whether a unique index is created for this attribute. Updatable specifies whether the column can be updated using standard persistence mechanisms.
Oracle Properties TableSpaceName is the tablespace to use for storage option of the table. TableSize indicates the relative size required for the objects that will be stored (the actual storage values are mapped from the size via property file settings).
31-16
UI Properties Localizable indicates if the attribute will have a localizable display name stored in the resource bundle for the package. Display (constantEnumeratedType set only) specifies the localizable display name for the attribute, if the attribute is a constant for an EnumeratedType. DefaultValue (constantEnumeratedType set only) should be set to True if the attribute is the default option for the EnumeratedType. Only one attribute can be set to True. The rest of the dialog is ignored by the code generator.
System Generation
31-17
The implementation of a non-persistable association is the same as the implementation of a modeled attribute. That is, it will be implemented with a private field, a constant label, and accessor methods. If classes modeled in Rose extend the class Item, these classes are automatically both ObjectMappable and Persistable. But in this example, an object called MyAddress is modeled that is a composite aggregation. This means that the instance MyAddress never exists on its own. It exists only as a part of another instance. In this case, the code generator creates a field in MyItem using the name of the composite aggregation, that is, the name of the navigable role on the association (in this example, work). Note that although modeling it as a composite aggregation communicates the ownership, the role must be navigable to accomplish the generated implementation. If the associations cardinality is greater than one, the attribute is represented as a Java Vector. For example, the class NameValue is also a composite aggregation and it contains multiple name and value strings. Because the total number that could occur is not known during system generation, the code generator creates a Vector field with the name of the composite aggregation (in this example, list). In this example, the field is a list of names and values. The generated class also contains public accessor methods for all the attributes. Note also that if the roles cardinality is optional, but the class being aggregated contains required elements, the aggregated class will be treated as required. The system generator must enforce this coordination of required attributes because of the way the PDS (Persistent Data Service) enforces required attributes. The PDS accomplishes the enforcement through the NOT NULL column feature of SQL databases. Because a column within the structure will be generated as NOT NULL, the structure as a whole cannot be nullable. If MyItem were an interface, only the accessor declarations, and the label constant would be generated into MyItem, because a Java interface can contain no implementation. To the degree possible, the implementation aspects of interface associations will be generated into concrete subclasses. See the Implementing Interfaces section for details.
31-18
An Association with No Attributes between Persistable Objects The following code is generated from this example:
public final class LinkA extends ObjectToObjectLink implements Externalizable { // role name constants public static final String MY_ITEM_ROLE = "theMyItem"; public static final String YOURS_ROLE = "theYours"; public MyItem getMyItem() { // getter return (MyItem)getRoleAObject(); } public void setMyItem( MyItem theMyItem ) // setter throws WTPropertyVetoException { setRoleAObject( theMyItem ); } // two-arg factory for link classes public static LinkA newLinkA( MyItem theMyItem, Yours theYours ) throws WTException { LinkA instance = new LinkA(); instance.initialize( theMyItem, theYours ); return instance; } }
System Generation
31-19
In this case, the code generator creates persistable Java classes that extend the ObjectToObjectLink class and are capable of maintaining a persistent association. Code-generated accessor methods return the role A and role B objects of the link. This means that the developer need not be concerned with which object is the role A object and which is the role B object. Code-generated factory methods for Link classes take at least two arguments: the role A object and the role B object. The factory methods are a result of the Link interface extending the NetFactor interface. A full explanation of factory methods is included in the section on Implementing the NetFactor Interface.
31-20
The link class is generated for LinkC, just as it was for LinkA, in the preceding example. In addition, the following code is generated in the class that plays the role opposite the role that has a cardinality of one.
public class OneMore implements Persistable, Externalizable { public static final String A1 = "myItem>a1"; public static final String MY_ITEM_REFERENCE = "myItemReference"; private ObjectReference myItemReference; public String getA1() { try { return getMyItem().getA1(); } catch (NullPointerException npe) { return null; } } public void setA1( String a_A1 ) throws WTPropertyVetoException { getMyItem().setA1( a_A1 ); } public MyItem getMyItem() { if ( myItemReference == null ) return null; return (MyItem)myItemReference.getObject(); } public ObjectReference getMyItemReference() { return myItemReference; } public void setMyItemReference( ObjectReference a_MyItemReference ) throws WTPropertyVetoException {
System Generation
31-21
In this case, since the association is persisted via a foreign id in the table for OneMore rather than in a separate link table, the OneMore class will hold a reference to myItem and will get myItemReference accessors generated. In addition to the getter and setter that are generated for the reference, a convenience getter is generated for the myItem object. Although these additional accessors are created for developer convenience, the LinkC class that is generated for the association can be operated on in the same manner as a link class that is stored in a separate link table. This provides a common API for manipulating links, regardless of how the database storage is implemented. The example also had a derived attribute modeled for the OneMore class. The DerivedFrom property for the attribute was defined as myItem>a1, which caused the A1 label constant and accessors to be generated for the a1derived attribute. (If this were a non-persistable association, the syntax for the derived attribute source would be myItem.a1.) Care should be taken in using this feature with persistable associations since allowing the generation and use of a derived setter will cause a state change in a different persistable object (myItem) which may not be obvious to the developer who is using your class (OneMore). The generation of the setter can be turned off while retaining the generation of the getter by setting the attributes WriteAccess property to Private.
31-22
If an association has attributes associated with it, the code generator creates a Java class that has all of the attributes for the association and the accessor. The name of the generated Java class is the name of the attributing class. The generated Java class extends the ObjectToObjectLink class if the attributing class does not extend another class in the model. If the attributing class extends another class in the model, the Java class extends that class. (The class being extended must be a subclass of Link.)
On the Detail tab, set the following value: Derived should be set to True to indicate that the implementation of the association will be derived, as determined by the developer. The rest of the dialog is ignored by the code generator.
On the Windchill tab, set the following values: Java Properties Generate should be set to False if the system generation tools should not generate a Java class for this modeled association.
System Generation
31-23
SuperClass is the name of the link class that the class generated for the association should extend. SuperClass should be defined when a class that contains a ForeignKey association is a sub-class and the sub-class's ForeignKey class referential integrity properties (i.e. Owner, Cascade) should be inherited from the parent's ForeignKey class.
SupportedAPI should be set to communicate to users the degree to which the association class will be supported. Private if the association class will not be supported at all. Public if use of the class is supported. Extendable if extension of the class is supported. Deprecated if the class is obsolete and support is being phased out. (This setting is superceded by the Deprecated property.)
Deprecated should be set when the element is obsolete. <Default> indicates the class is not deprecated, unless, for backward compatibility, SupportedAPI is set to Deprecated. -deprecated if the class is obsolete and support is being phased out.
Datastore Properties PackageName is the package name to use. TableName is the database table name to use. Storage indicates if the association will be stored in a link table or as a foreign ID reference in the table for one of the role classes. Default evaluates to ForeignKey if there is a role with single cardinality and the class opposite that role resides in the same package as the association; otherwise, evaluates to LinkTable. RemoveEventParticipant specifies if the persistence layer is required to dispatch Remove events for this implicit Link class. Remove events include "REMOVE" and "CLEANUP_LINK". Default will be determined to be True for any Persistable class.
Oracle Properties TableSpaceName is the tablespace to use for storage option of the table. TableSize indicates if the relative size required for the objects that will be stored (the actual storage values are mapped from the size via property file settings). IndexTableSpaceName is the tablespace to use for the storage option of the indices of the table.
31-24
On the Role <A/B> General tab, set the following values: Role specifies the name of the role. (See Role A (or B) description for General tab above.) Export control should be set to Public, Protected, or Implementation. If you want private attributes, declare them in your source code. Documentation specifies a description for the element. The documentation will be generated into the Java code, as Javadoc style comments.
On the Role <A/B> Detail tab, set the following values: Role specifies the name of the role. (See Role A (or B) description for General tab above.) Cardinality specifies the cardinality of the role. The popup menu for associations provides an alternative means for specifying cardinality. Navigable should be selected if the role B (or role A) object should get a method for accessing the role A (or role B) object. The popup menu for associations provides an alternative means for specifying navigability. Navigable is ignored for Persistable associations. Aggregate should be selected if the association is an aggregate. The popup menu for associations provides an alternative means for specifying aggregation. By value should be selected if the aggregate is a composite aggregation. The popup menu for associations provides an alternative means for specifying composite aggregation. The rest of the dialog is ignored by the code generator.
On the Windchill<A/B> tab, set the following values (ignored for Persistable associations): Abstract should be set to True if the implementation of a field for the role will be deferred to a subclass. Access methods generated for this role will be abstract. StringCase should be set to LowerCase to force the value to lowercase. It should be set to UpperCase to force the value to uppercase. The enforcement of this constraint will be generated into the setter method for the attribute. LowerLimit constrains the valid values for the type. For String types, it specifies the minimum length of the String. For numeric types, it specifies the minimum value of the role. Date and Time types are not currently supported by this property. The constraint is enforced in the validation that is generated for the setter. UpperLimit constrains the valid values for the type. For String types, it specifies the maximum length of the String. For numeric types, it specifies the maximum value of the role. Date and Time types are not currently supported
System Generation
31-25
by this property. The constraint is enforced in the validation that is generated for the setter. Changeable should be set to Frozen if the value cannot be changed once it has been persisted. It should be set to ViaOtherMeans if the normal setter method is not allowed to change the value once it has been persisted. WriteAccess should be set if the access of the setter should be different than that of the getter that will be generated. Dependency should be set to True if the opposite-side role class is dependent on this role. SupportedAPI should be set to communicate to users the degree to which the role will be supported. Private if the role will not be supported at all. Public if use of the role is supported. Deprecated if the role is obsolete and support is being phased out. (This setting is superceded by the Deprecated property.)
Deprecated should be set when the element is obsolete. <Default> indicates the role is not deprecated, unless, for backward compatibility, SupportedAPI is set to Deprecated. deprecated if the role is obsolete and support is being phased out.
Java Properties Final should be set to True if the resulting field should be final. Transient should be set to True if the resulting field should be transient. Volatile should be set to True if the resulting field should be volatile. Constrain should be set to True if the resulting setter method should declare that it throws a WTPropertyVetoException. ReferenceType specifies the class of ObjectReference that will be used for first-class associations that are stored as with a ForeignKey and thereby make use of a held ObjectReference. By default, the generic ObjectReference will be used. AutoNavigate should be set to True if the object playing this role should be automatically retrieved (instantiated) from the database whenever the object on the other side is retrieved. Update operations are not impacted by this property. This feature is dependent on the association being implemented as a ForeignKeyLink. Persistent should be set to True if the field that holds the value will be persisted to the database.
31-26
GetExceptions specifies exceptions that will be declared as thrown by the generated getter. SetExceptions specifies exceptions that will be declared as thrown by the generated setter. ContainerClass specifies that class of container to use for roles of unbounded multiplicity (cardinality). Default container is Vector. InitialValue specifies the value to which the field will be initialized upon declaration. DelegatedInterface specifies that the object playing the role is a delegate that supplies an implementation for the specified interface. All the methods necessary to fulfill (implement) the interface will be generated as methods that forward to the role object. BeforeStaticInitializer should be set to True if field declaration should be placed prior to the static initializer.
Datastore Properties ColumnName is the class attribute to column name mapping. Default is the attribute name. ColumnType is used to indicate the relational storage type for the valuetype. By default a mapping, based on the attribute type, will be used. Index specifies whether an index is created for this attribute. Unique specifies whether a unique index is created for this attribute. Updatable specifies whether the column can be updated using standard persistence mechanisms. Owner specifies if this role is an owner of the association. Owner means when the is role is deleted, the association will be deleted also. Both roles can be an owner. Default will be determined to be True for any role. Cascade specifies if association deletion should cascade to the role object. Default will be determined to be False for any role.
Oracle Properties TableSpaceName is the tablespace to use for storage option of the table. TableSize indicates if the relative size required for the objects that will be stored (the actual storage values are mapped from the size via property file settings).
System Generation
31-27
UI Properties Localizable indicates if the role will have a localizable display name stored in the resource bundle for the package.
Implementing Interfaces
In Rose, an interface is modeled as a class that has the stereotype <<Interface>>.
In this example, MyItem, which is concrete, is said to implement the interface named Timelineable, which aggregates Timeline. The following code is generated for this example.
public class MyItem extends Item implements Timelineable, Externalizable { private Timeline timeline; public Timeline getTimeline() { return timeline; } public void setTimeline( Timeline a_Timeline ) throws WTPropertyVetoException { timelineValidate( a_Timeline ); // may throw exception if not valid timeline = a_Timeline; } private void timelineValidate( Timeline a_Timeline ) throws WTPropertyVetoException { if ( a_Timeline == null ) { // required attribute check Object[] args = { new wt.introspection.PropertyDisplayName( CLASSNAME, "timeline" ) }; throw new WTPropertyVetoException( "wt.fc.fcResource", wt.fc.fcResource.REQUIRED_ATTRIBUTE, args,
31-28
new java.beans.PropertyChangeEvent( this, "timeline", timeline, a_Timeline ) ); } } // The constant label is generated into the // Timelineable interface }
In general, system generation causes the following actions: Classes in the model that extend an interface cause an implements clause to be created on the class declaration of the generated class. Stubs for the operations of the interface are created in the generated class if the inheriting class is concrete. This is where you insert your implementation code. (This applies even for protected methods modeled on an interface, which will not appear on the generated interface since an interface can have only public features.) Non-constant attributes modeled on the interface cause private fields to be created on the generated classes that implement the interface, along with generated accessor methods. Associations with non-persistable classes are handled similar to modeled attributes, where the API is generated on the interface and the implementation is generated into the concrete subclasses.
Factory operations
To give flexibility to the system architecture, Windchill uses a factory design pattern for the construction of Java objects. A constructor signature is one where the operation name matches the name of the class and has no return type. Object constructors are modeled in Rose but are not generated directly in Java code. Instead of constructors, Windchill generates factory operations that are used to construct objects. Using factory operations instead of constructors provides the opportunity to vary the class of the returned object. When constructors are used to create an object, the class of the returned object must match exactly the class requested. However, when factories are used, the class of the returned object will be polymorphically compatible with the requested class but need not match the requested class exactly. This allows the return of objects whose class may vary depending on the context.
System Generation
31-29
When a constructor is specified in a Rose model, two operations are generated in the Java code: a public factory operation and a protected initialization operation. The factory operation is called directly by the application to create a Java instance. The factory method calls the initialize operation to put the instance into an initial state. Note that for optimization reasons, an initialize method is generated only when one having the same signature is not provided by a superclass. You can manually supply an override initialize method if you wish. If the modeled class (directly or indirectly) inherits from NetFactor, this is a cue to the code generator to generate factory and initialize methods in the Java class. The following modeled class has a constructor that takes an argument of a string.
A factory method instantiates and initializes business objects. It invokes the constructor of the implementation class and then invokes an initialize method with the same parameters as the factory method. The code generator also generates the correct method stubs so you can implement the initialize method. This method is responsible for setting the initial state of a new object. Factory methods have the form: public static <class> new <class> (args)
31-30
throws WTException The factory method has the same name as the class in the Rose model plus the prefix "new" (for example, newMyItem). If no constructor is modeled for a class, the generator assumes a default, no-arg constructor. For link classes, the default factory method includes a reference to the two objects being related by the link. For details on link class generation, see the Persistable Associations section.
This method returns the fully-qualified conceptual class name of the object. Because the instantiated object may really be an instance of some other implementation class, getConceptualClassname is a useful method to find the business class in an object. You should not use object.getClass().getName() to determine the class name for software objects in the Windchill system because it may not return the name of the conceptual class.
This method returns the ClassInfo instance that contains the metadata from the installed model.
System Generation
31-31
classes, such as Address, to read (or write) the state for the persistent attributes that those classes declared with the readObject and writeObject methods. Because the class defers the reading of some of the fields from the database to its superclass, the types of structured attributes are hard-coded into the super class. The exception to this rule of hard-coded types is for ObjectReferences that are generated for roles of Persistable associations. The Persistent Data Service (PDS) does a runtime look-up in the introspection information to see if the ReferenceType for the role was redefined at a lower level in the class hierarchy. If so, the PDS uses that type. But even if the type is redefined, its persistent structure must be compatible with the type that was used by the super class, because the column definitions defined by a super class cannot be changed by a subclass. The PersistentRetrieveIfc argument for readExternal contains the state for the object being read. The PersistentStoreIfc argument for writeExternal receives the state of the object being written. Examples of the readExternal and writeExternal methods follow:
// Example of a database writeExternal method public void writeExternal( PersistentStoreIfc output ) throws SQLException, DatastoreException { super.writeExternal( output ); output.setString( "a1", a1 ); output.setDate( "a2", a2 ); output.setObject( "a3", a3 ); output.writeObject( "work", work, wt.tools.generation.example.MyAddress.class, true ); output.setObject( "list", list ); output.setString( "size", size == null - null : size.toString() ); output.writeObject( "timeline", timeline, wt.tools.generation.example.Timeline.class, true ); } // Example of a database readExternal method public void readExternal( PersistentRetrieveIfc input ) throws SQLException, DatastoreException { super.readExternal( input ); a1 = a2 = a3 = work input.getString( "a1" ); input.getDate( "a2" ); (Xyz)input.getObject( "a3" ); = (wt.tools.generation.example.MyAddress)input.readObject( "work", work, wt.tools.generation.example.MyAddress.class, true ); list = (Vector)input.getObject( "list" ); size = MySize.toMySize( input.getString( "size" ) ); timeline = (wt.tools.generation.example.Timeline) input.readObject("timeline", timeline, wt.tools.generation.example.Timeline.class, true ); }
31-32
A property in Rose allows you to override the default determination. This property, named Serializable, is in the Java Properties on the Windchill tab for the class. With this property, you can force the class to Serializable, Externalizable, or neither.
System Generation
31-33
The Evolvable option has been added to this property to better manage which classes can be serialized into BLOB columns in the database. This option was added in conjunction with a change to the generated Externalization stream format. Because of this change to the stream format, much externalization code is generated to maintain backward compatibility. In a future release, only the readExternal and writeExternal methods will be generated for classes that implement Externalizable but not Evolvable. Until the backward compatibility is removed, new classes can be forced to generate simplified externalization code by selecting the "Externalizable (basic)" option. The evolvable aspects of externalization will not be shown below. For details on when to use Evolvable and how to manage Evolvable classes, see Evolvable Classes on page 42-1.
Externalization methods
In the generated externalization methods, all non-transient, non-static fields that were modeled will be handled. The externalization is generated in a manner that provides hooks for reading in previous versions of the class, unless "basic" externalization is generated. Code generation detects when the externalizable signature of a class changes, and changes its internal version UID accordingly. You have the ability to take control of the externalization code, but it is not recommended because it requires careful management of the externalizable signature of the class. Examples of the externalization methods follow:
// Example of a writeExternal method public void writeExternal( ObjectOutput output ) throws IOException { //##begin writeExternal%writeExternal.body preserve=no output.writeLong( EXTERNALIZATION_VERSION_UID ); super.writeExternal( output ); output.writeObject( output.writeObject( output.writeObject( output.writeObject( a1 ); a2 ); a3 ); list );
31-34
output.writeObject( (size == null ? null : size.getStringValue()) ); output.writeObject( theOneMoreReference ); output.writeObject( timeline ); output.writeObject( work ); //##end writeExternal%writeExternal.body }
// Example of a readExternal method public void readExternal( ObjectInput input ) throws IOException, ClassNotFoundException { //##begin readExternal%readExternal.body preserve=no long readSerialVersionUID = input.readLong(); consume UID //
if ( readSerialVersionUID == EXTERNALIZATION_VERSION_UID ) { // if current version UID super.readExternal( input ); handle super class //
a1 = (String)input.readObject(); a2 = (Date)input.readObject(); a3 = (Xyz)input.readObject(); list = (Vector)input.readObject(); String size_string_value = (String)input.readObject(); try { size = (MySize)wt.fc.EnumeratedTypeUtil.toEnumeratedType( size_string_value ); } catch( wt.util.WTInvalidParameterException e ) { // old format size = MySize.toMySize( size_string_value ); } theOneMoreReference = (ObjectReference)input.readObject(); timeline = (Timeline)input.readObject(); work = (MyAddress)input.readObject(); } else throw new java.io.InvalidClassException( CLASSNAME, "Local class not compatible:" + " stream classdesc externalizationVersionUID=" + readSerialVersionUID + " local class externalizationVersionUID=" + EXTERNALIZATION_VERSION_UID ); //##end readExternal%readExternal.body }
System Generation
31-35
Extending EnumeratedTypes
There should be no need for a developer to change any of the implementation of a generated enumerated type, but they are generated with preserve markers to allow for developer enhancements, if the need should arise. Note that the Windchill tab on Rose specification dialogs for classes and attributes provides property set sheets specific to EnumeratedType usage. These properties are detailed in the model elements sections above. For more information on working with enumerated types, see the Enumerated Types chapter on page 33-1.
31-36
System Generation
31-37
Services contain the complete business logic and are expected to run only on the method server, but forwarders go back and forth between the server and the client. From the client, they invoke the business service methods running on the server. At runtime, the forwarder binds to a service which is determined by the registration of services that is done in the wt.properties file. The forwarder classes are completely generated and provide no preserve markers for developer editing.
31-38
Links (When you have a link, you can also create a link between objects that are subtypes of the role A and role B objects. Therefore, you need to know which are valid and how many there can be.) Role A and role B names Valid role A and role B classes Role A and role B cardinality
Attributes of classes Standard JavaBeans PropertyDescriptor with extended information Derived flag Persistent flag Updateable flag Query name (name of its column descriptor) StringCase (if a String type is forced to either uppercase or lowercase) Required flag Upper limit Method that returns set of valid values
System Generation
31-39
ConstrainedType (if type overridden in subclass) DefinedAs (class and attribute name as originally modeled) ModeledPersistentType (modeled column type)
For a complete description of the introspection information that is provided, see the wt.introspection package entry in your installed Windchill Javadoc. Windchill provides a utility to print the content of a serialized Info object. You can run the utility as follows: InfoReport <fully.qualified.classname> The resulting report is in a file named <qualified.classname >.out, which is located in the directory specified by the wt.temp property in wt.properties. To print the info contents for each class of an entire package, you can run the utility as follows: InfoReport <fully.qualified.*> Windchill also provides a utility that will verify the environment as it relates to introspection information. That is, it will verify the existence and ability to load all classes and serialized info objects that are referenced in the registry files. The utility simply writes its output to the console, with reported problems being preceded by three asterisks (***). To verify the entire registry (the complete environment), enter the following command: executeTool wt.introspection.VerifyEnvironment registry To verify a single package, enter the following command: executeTool wt.introspection.VerifyEnvironment <fully.qualified.*>
31-40
System Generation
31-41
Table 8-1: Possible Rose Types and the associated JDBC specification standard SQL types and datastore SQL types
Rose Type JDBC Type Oracle Type SQL Server Type
NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER NUMBER(1) CHAR(3) VARCHAR(length) where length is the UpperLimit value (default=200). The length value may also be multiplied by the wt.db.maxBytesPerChar value for multi-byte configurations NUMBER DATE BLOB VARCHAR (4000) VARCHAR (4000) BLOB Two columns are generated. The encoded object is stored in the VARCHAR column if it fits, otherwise the BLOB column is used.
INT BIGINT SMALLINT TINYINT FLOAT(24) FLOAT(35) TINYINT NCHAR(1) NVARCHAR(length) where length is the UpperLimit value (default=200).
DECIMAL(28) DATETIME IMAGE VARCHAR (4000) VARCHAR (4000) IMAGE Two columns are generated. The encoded object is stored in the VARCHAR column if it fits, otherwise the IMAGE column is used. BIGINT
SEQUENCE
WTTypes.NUMERIC
NUMBER
31-42
INLINEBLOB
SMALLBLOB
All other types BLOB Types.BLOB
INLINEBLOB
System Generation
31-43
MyItem is persistable because it extends Item, which extends WTObject, which implements the Persistable interface. Therefore, a table is created in the database for the objects in MyItem. The first element shown in the table, Attributes of superclasses, represents the persistent attributes (from persistInfo) that MyItem inherits from its superclasses. Each of the attributes would be mapped to a separate column in the actual table. One of those columns would be the object identifier. Attribute a1 is a String, so column A1 is a VARCHAR (NVCHAR for SQLServer). Attribute a2 is a Date (actually a java.sql.Date), so column A2 is a DATE (DATETIME for SQLServer). Attribute a3 has no SQL mapping support but is serializable so the value for a3 is stored in column A3 as a BLOB (IMAGE for SQL Server).
31-44
MyItem has a one-to-one composite aggregation relationship with Address, so the attributes of the Address class are mapped to the MyItem table. Windchill uses a naming algorithm to map attributes of an embedded structured attribute to table column names. To list the mapping, use the InfoReport utility mentioned in the section on how Rose UML maps to Info objects, earlier in this chapter. MyItem has a one-to-many composite aggregation relationship with NameValue, so NameValue is stored as a BLOB. By default, the class name is mapped to the table name. You can specify a different name with the Rose specification table name property. Caution: Each class must be mapped to its own unique table name. If the table name of a customized class conflicts with that of an out-of-the-box class or another customized class, then it must be changed using the Rose specification table name property. Similarly, you should change the table name to avoid matching a datastore reserved word used in your database (such as VIEW). Some additional properties can be specified to influence storage options. The storage for tables, indexes, and blob data is referred to as a tablespace in Oracle and a filegroup in SQLServer. The Windchill datastore term for both of these is tablespace. By default, all Windchill tables and indexes are created in the Windchill users default tablespace. Data for the table can be stored elsewhere by specifying a TableSpaceName. If an IndexTableSpaceName is specified, it is used to store the indexes for the table. The TableSize (TINY, SMALL, MEDIUM, LARGE, or HUGE) is used together with the associated properties in the tools properties1 to specify storage parameters for tablespace. The default storage mechanism for BLOB attributes is to store them in their own tablespace. The name of the tablespace is a configurable property in the tools properties. The default name is BLOBS. For further information, see the section on creating large objects in the Creating Large Objects (LOBs) chapter on page 43-1. By default, generated SQL files explicitly reference two different tablespaces, blobs and indx. All blob data storage is allocated in the blobs tablespace and all index storage is allocated in the indx tablespace. The storage for all other schema objects (e.g., tables) is not specified, so their storage is allocated in the default tablespace configured in the datastore. The default values for all of these tablespaces can be overridden in user.properties using the properties, wt.generation.sql.BLOBTablespaceName, wt.generation.sql.indexTablespaceName, wt.generation.sql.defaultTablespaceName, and wt.generation.sql.auditTablespaceName.In addition, the table and index tablespaces for a given table can be overridden using the Class Specification, Windchill tab, tablespace fields.
1.
See the tools.properties file and user.properties file descriptions in the The Windchill Development Environment chapter on page 2-13.
System Generation
31-45
Each attribute of the table also has properties which can be specified for the DDL generation, such as whether to allow NULLS or whether to index the attribute. If more complex indexing is required, then the Rose Class specification Windchill index properties should be used. There are several index entries available for specifying composite indices. Composite unique indices are also supported. See the Rose Windchill Help documentation for more information. Typically indices are generated into the associated table creation script. However, a utility, IndexGenerator, is also available that generates scripts containing only indices. For complex DDL statements associated with a class that cannot be handled by the SQL generation support, the user additions script feature is available. It is recommended that this feature only be used if absolutely necessary. When the Rose modeling DDL generation features are used, this information can also be used by the upgrade tools to ensure that the DDL is migrated properly. Every generated sql script contains a line at the end to execute the statements in an associated sql file. If the <tablename>_UserAdditions script is located in the same directory as the table script, then this line is not commented out of the script that creates the table. For a many-to-one aggregation implemented via a foreign key, the autoNavigate property can be used. When the autoNavigate property is set to true, the runtime query APIs treat the columns on the base table along with the columns of the aggregated table in much the same was as a database view. The two tables are implicitly joined via the foreign key. There are two types of modeled sequence data types. For attribute-based sequences, you can make the attribute type Long and select SEQUENCE from the WT_Oracle tab for the column type. This causes the DDL generation to create a sequence (if it does not already exist) with a name that consists of the attributeName and the suffix "_seq". When an object that uses an attribute-based sequence is created and persisted in the datastore, the sequence value is incremented and used for that attribute's value. Sequences can also be created as standalone datastore elements. A sequence will be generated for any class that extends wt.fc.DatastoreSequence. The datastore schema name, initial seed value, and increment value can all be set from the Rose model. You can use PersistenceManager.getNextSequence() to obtain the next available sequence number. This method returns a String, so you would either use the value as a String or convert it to whatever you need. All the database scripts necessary for a given java package are generated to an associated subdirectory of the database generation directory. In addition, "make" scripts are generated for the entire package. The "Make_<package name>" script calls all the scripts for creating the datastore schema objects. The "make" scripts will also call the associated make scripts in any nested packages.
31-46
The Localizable property for Attributes and Roles is also an enumerated type, and thus has possible values: <Default>, True and False. The default value is <Default>. These elements will be considered Localizable by the localizable display generator only under the following circumstance: The element's Localizable property is explicitly set to True
If the resource info file contains an entry for a particular model element, the generator will not overwrite it, but it can remove it if the modeled element no longer exists, or if it is no longer considered localizable. The removal of elements is controlled by the wt.generation.cleanupDisplayNames property in the tools properties. For more information on creating localizations, see the Internationalization and Localization chapter on page 39-1. The generated resource info files should only be edited by the owner of the package. The resource info tool set provides a means of customization, where the customers of the package can define customizations in a separate file. For more information on customizing localizable resource entries, see Defining Localizable Text for the UI in the Generic UI Customizations chapter on page 9-1. The name of the file is "ModelRB.rbInfo", with the simple package name prepended, for example, partModelRB.rbInfo. The following sections describe the generated resource info files.
System Generation
31-47
The first entry is the display name for the WTPart class, and the second is the display name for partType attribute of the WTPart class. These values will only be generated once, so that the package owner can override the default values, if desired. For example, the value for the partType attribute could be changed as follows:
WTPart.partType.value=Type
In addition, any of the keys described in the Resource Entry Format on page 39-9, could be added for an element. For example, the following information could be added for the partType attribute.
WTPart.partType.fullDisplay=Part Type WTPart.partType.longDescription=Classification of parts according to predefined types.
Note: Follow the practices described in the Managing Customizations chapter on page 5-1 when customizing rbInfo files.
To build the runtime resource into the codebase for all the resource info files for a particular directory, use the following command: ResourceBuild <directory_relative_to_src> For example:
ResourceBuild wt/part
31-48
The resulting resource file is named <name>RB.ser, which is a serialized instance of SerializedResourceBundle. For example, src/wt/part/partModelRB.rbInfo will build to codebase/wt/part/partModelRB.RB.ser. To print the contents of the serialized resource bundle, you can run the following utility:
windchill wt.util.resource.ResourceBundleUtil <fully_qualified_name> [<locale>]
For example:
windchill wt.util.resource.ResourceBundleUtil wt.part.partModelRB en_GB
System Generation
31-49
As mentioned in the overview at the beginning of this chapter, the system generator creates mData files which, in turn, are used to create Java code, Info files, SQL files and Resource Info files. The system generator also updates the classRegistry, descendentRegistry and associationRegistry, properties files.
Registry Files
The classRegistry, descendentRegistry, and associationRegistry files are located in the directory specified by the wt.generation.bin.dir entry in the tools properties. The classRegistry file contains all the information the code generator needs to create import statements for the generated Java classes. When classRegistry is
31-50
initialized, it goes through all the directories in your CLASSPATH variable and makes an entry for every class it finds. The classRegistry must be deleted and regenerated if you change your CLASSPATH to include new packages that contain classes for which the code generator will need to generate imports. As the number of CLASSPATH packages increases, the potential for conflicts increases. These conflicts are best resolved by explicitly modeling package level dependencies in Rose. The generator will then use this information to resolve any ambiguities that occur due to having multiple classRegistry entries for a particular class name. The descendentRegistry file contains genealogy information about which classes extend the classes above them. It is required to support subclass queries. The associationRegistry contains information about Persistable associations. Classes that are renamed or removed from a package will be automatically removed from the registries upon a regeneration of that package. A complete package can be removed from the registries (uninstalled), by using the modelUnInstall script.
System Generation
31-51
31-52
If you have classes and tables, it is useful to create a single SQLPLUS script that can execute each @create script. (The create_ddl_wt.sql script is an example.) For SQLServer, a java command line application is provided in Windchill codebase. In addition, a bat file has also been created in $wt.home/db/sqlServer. Use the following command: execute_sql_script create_ <your table name >
System Generation
31-53
Process
Input(s)
Outputs
Rose model (.mdl and/or .cat) mData files for all dependent packages
tools properties wt.classRegistry.search.path tools properties wt.classRegistry.search.pattern classRegistry.properties modelRegistry.properties registered mData files mData file for target package modelRegistry.properties registered mData files mData file for target package .ClassInfo.ser files for target package and dependents .mData file for target package .rbInfo files for target package
.ClassInfo.ser files . modelRegistry.properties descendentRegistry.propertiesN associationRegistry.properties .sql files .rbInfo files .RB.ser files
1. Accumulated during generation, but used to define the modeled relationships for the installed runtime application.
31-54
checking in and checking out the two files in tandem, and ensuring that the generated mData reflects the saved version of the cat file.
Build Sequence
The following table describes the steps and commands used in a build sequence.
Step
Description
Command
Create classRegistry, based on search path and pattern defined in tools properties.1 Register all models that will be integrated Generate Java source code, info objects, SQL and resource bundle files scripts for target packages.2 Build the resource bundles for target directory. Compile Java source code.
2 3
4 5
1. The system generation tool will create a classRegistry if one does not exist. 2. Remember to update database table structures after generating SQL scripts that have structural changes.
Access point to Ant targets that implement most of the utilities listed below. Executing this script with no arguments will list the targets that are available and explain how to get configuration options help for each target.
tools class_registry
Creates a class registry from scratch, searching for *.class & *.java files in the specified classpath. To specify the classpath, use one of these properties: class_registry.use_env - if true, will use the environment's classpath class_registry.classpath - can define any specific classpath
ModelInstall
Updates the model registries with all the modeled packages specified by Arg1. Arg1 can be either of the following: "<package>.*"
System Generation
31-55
Registers the single package specified. "<package>.**" Registers the package for each mData found recursively under the <package> directory.
ModelUnInstall
Removes the modeled packages specified by Arg1 from the model registries. Arg1 can be either of the following: "<package>.*" Removes the single package specified. "<package>.**" Removes the package for each mData found recursively under the <package> directory.
JavaGen
Generates the outputs specified by the arguments for the classes/packages specified by Arg1. Arg1 can be any of the following: <package>.<Class> Generates outputs for the single class specified. <package>.* Generates outputs for the single package specified. <package>.** Generates outputs for each mData found recursively under the <package> directory. registry Generates outputs for all registered packages. The following additional arguments can be specified: Arg2 Specifies if Java Source will be generated. Arg3 Specifies if Introspector Info Objects will be generated. When using this argument, it is recommended to comment out the following line in the moduleRegistry.properties file:
Module1=WNC/Windchill
Therefore, you should generate Info Objects separately from any other generations you are performing. For example, when generating info objects for all registered packages, do the following:
31-56
1. Comment the moduleRegistry entry indicated above. 2. Execute JavaGen registry f true f f f 3. Uncomment the moduleRegistry entry. Any other generations should be performed with Arg3 set to f. Arg4 Specifies if SQL scripts will be generated. Arg5 Specifies if Model Check will be performed. Values for arguments not passed will be obtained from the tools properties. Arg6 Specifies if Display Names will be generated into resource info files.
ResourceBuild
Builds the runtime resource bundles for the packages/directories specified by Arg1. Arg1 can be any of the following: <package>.<resource> Builds resource bundle for the single resource info. "<absolute_dir\sub>" Builds resource bundles for each resource info found under in the directory. ( <absolute dir\sub>is an absolute directory.) The following additional arguments can be specified: Arg2 Specifies if locale specific files will be built. (wt.locale.set in wt.properties define valid locales)
InfoReport
Reports the contents of info objects to a text file for classes/packages specified by Arg1. Arg1 can be any of the options below. Note: To display characters entered using something other than the default encoding, set the wt.locale.encoding property to the encoding appropriate to your locale before running this utility. <package>.<Class> Reports for the single class specified. <package>.*
System Generation
31-57
Reports for the single package specified. registry Reports for all registered packages.
VerifyEnvironment
Verifies the existence and ability to load all classes and serialized info objects that are referenced in the registry files. One caveat is that classes that have static initialization that requires a running method server environment will fail to load. Arg1 can be any of the following: executeTool wt.introspection.VerifyEnvironment "<package>.<Class>" Verifies the single class specified. executeTool wt.introspection.VerifyEnvironment "<package>.*" Verifies the single package specified. executeTool wt.introspection.VerifyEnvironment registry Verifies all registered packages.
31-58
IndexGenerator Generates index creation (and drop) DDL to a standalone SQL script. The utility supports both a single package and all indices for all modeled packages. executeApp wt.tools.generation.sql.OracleIndexGenerator "*" "create file name" "drop file name" Generates index creation DDL for all modeled packages to the specified files. Files names must be absolute. The "*" parameter must be specified in quotes. executeApp wt.tools.generation.sql.OracleIndexGenerator <package>.*" "create file name" " drop file name" Generates index creation DDL for the package to the specified files. If a file path is not absolute, then it is treated as path relative to the wt.generation.sql.dir directory.
System Generation
31-59
Background
It is recommended that you develop Windchill customizations on a development system that is separate from your deployment system. If you create modeled customizations (that is, using Windchill InfoModeler), follow this best practice to deploy your generated artifacts, rather than regenerating them on the deployment system. For example, your deployment system may run on an operating system (such as HP-UX) that does not support Windchill InfoModeler. To create modeled customizations, you could use a Windows server as your development system and run Windchill InfoModeler on that system. You would then follow this best practice to copy the necessary generated artifacts to your deployment system.
Scope/Applicability/Assumptions
Assume you have created new modeled customization packages on your development system. Assume that, prior to your new customization, your development environment included all the packages the production environment has. This best practice does not apply if, for example: Your production environment is an aggregation of multiple development environments; You have installed anything (such as an upgrade or module) into production that is not also in your development environment.
Intended Outcome
Your deployment environment will again mirror your development environment, including your new customizations.
Solution
Copy the relevant files from your development system to your deployment system.
Prerequisite knowledge
To achieve this objective, you need to have an understanding of the following:
31-60
Some method for transferring files from your development system to your deployment system. Executing SQL scripts on your database server.
Solution Elements
Element
Type
Description
Customized packages
Any folder corresponding to a customized package, containing compiled Java classes and related artifacts for the modeled and generated customization. This includes .class files, .RB.ser files, and .ClassInfo.ser files. Located under <Windchill>/codebase.
Registry files
Property files
Located in <Windchill>/codebase. SQL files SQL files These contain generated SQL scripts for creating the necessary database tables for your customized objects. Located in <Windchill>/db/sql.
System Generation
31-61
31-62
32
Customizing Modeled Elements
This chapter describes how to customize modeled elements. Topic Page
32-1
b. Inspect the value of the WTIntrospector.UPPER_LIMIT property (the value being customized) of the name PropertyDescriptor:
getValue( WTIntrospector.UPPER_LIMIT ) : 60
d. Based on this information, use the following values: The customization property file is <Windchill>\wtCustom\wt\doc\ docModel.properties.
1.
See the tools.properties file and user.properties file descriptions in The Windchill Development Environment chapter on page 2-13.
32-2
2. Add the customization property entry to the appropriate customizations property file. In this example, add the following entry to <Windchill>\ wtCustom\wt\doc\docModel.properties (create this file if it does not exist):
WTDocumentMaster.name.UpperLimit=350 # ignore multi-byte database character sets when setting value
3. Generate the class info objects and the SQL scripts: a. Update the serialized info object and the SQL script for the customized class by entering the following command (on one line):
ant -f <Windchill>\bin\tools.xml custom_column -Dgen.input=wt.doc.*
c. If the customized class has descendants that are concrete, their tables must also be adjusted with the following commands (one line each):
ant -f <Windchill>\bin\tools.xml custom_column Dgen.input=wt.build.buildtest.SourceMaster ant -f <Windchill>\bin\tools.xml custom_column -Dgen.input=wt.federation.ProxyDocumentMaster
4. Verify the customization: a. Obtain an info report for the class and inspect the UPPER_LIMIT value as described in the preceding steps. The value should reflect the customization. b. If the info report value is unchanged, perform the following steps: i. Verify that the generate step actually updated the following serialized info file:
<Windchill>\codebase\wt\doc\WTDocumentMaster.ClassInfo.ser
ii. Verify that a class or interface in WTPartMasters hierarchy does not also define the name attribute. This is done most easily by viewing the Attributes tab of the Class Specification dialog in Rose, with Show inherited selected. If the name attribute is defined in the hierarchy, the name attribute that was modeled originally must be customized.
32-3
5. Create the database tables, if they dont already exist, by executing the relevant SQL scripts generated above. If the tables already exist, adjust the length of the customized column by taking the following steps: a. Execute the Upgrade Manager to run the Compare Schema step only. See "Comparing a Database Schema with Persistence Model" in the Windchill Upgrade Guide. b. Inspect the generated output to find the SQL script(s) related to this customization. Caution: Review the output carefully to ensure the results are what you expect. You should never execute any SQL that you do not understand, or that does not seem related to your intended customizations c. Execute the relevant SQL scripts. Because, in this example, WTDocumentMaster.name is also the source for the derived attribute WTDocument.name, the derived attribute must also be customized in this manner. This customization is necessary because the derived attribute, WTDocument.name, does not get its UpperLimit from the source attribute, WTDocumentMaster.name. The derived attribute also explicitly set the UpperLimit property in the model. Therefore, the customization must be defined explicitly for the derived attribute WTDocument.name. Following the preceding steps would determine that a WTDocument.name.UpperLimit entry would be set in the customization property file <Windchill>\wtCustom\wt\doc\ docModel.properties. This additional step applies specifically to the way derived attributes work and is not necessary for normal attributes.
32-4
33
Enumerated Types
This chapter describes enumerated types. Topic Page
The EnumeratedType Class...............................................................................33-2 Creating an EnumeratedType Subclass.............................................................33-3 Editing the Resource Info for an Enumerated Type..........................................33-7 Localizing an Enumerated Type........................................................................33-9 Extending an Enumerated Type ......................................................................33-10 The Enumerated Type Customization Utility .................................................33-11 GUI Usage of an Enumerated Type ................................................................33-12
33-1
value
Specifies the value that is the default value for the type.
selectable
Specifies if the value should be allowed to be selected. The constructors for EnumeratedTypes are protected so that instances can only be constructed internally. The data needed for construction is obtained from a resource and used to construct the instances in the static initializer. getValueSet() returns the set of possible values for the class, where the possible values are instances of the class. toString() returns the internal value, which will be persisted. This follows the pattern of primitive wrappers provided by Sun. This means toString() is not available for generic use by GUI components; they must use getDisplay().
33-2
Select the EnumeratedType property set on the Windchill tab of the Class Specification. This property set provides just the properties that apply to EnumeratedType classes, and changes the default values of certain properties, such as PrimitiveType to String. If the values are to be ordered explicitly, set the ExplicitOrder property to True. Otherwise, the values will be ordered alphabetically at runtime, using the locale-specific display.
Enumerated Types
33-3
The Localizable property under the UI Properties section refers to the name of the class being localizable, not the display values.
2. Generating the EnumeratedType also generates its companion resource info file. For MySize, it will be named MySizeRB.rbInfo. If the wt.resource.updateLocales property of the tools properties1 is set to true, any locale-specific versions of the rbInfo file will also be updated, indicating which entries need to be translated.
1.
See the tools.properties file and user.properties file descriptions in the The Windchill Development Environment chapter on page 2-13.
33-4
Modeled constants are Static and Final. A value definition for each modeled constant will be generated in the resource info file.
Enumerated Types
33-5
Select the constantEnumeratedType property set on the Windchill tab of the Attribute Specification. This property set provides just the properties that apply to EnumeratedType constants, and changes the default values of certain properties, such as BeforeStaticInitializer to False. If the constant represents the default value for the EnumeratedType, set the DefaultValue property to True. To explicitly define the display name to generate into the resource info file, set the Display property. Otherwise, the generated display name will be based on the initial value of the constant.
33-6
The first line classifies the resource info and should never be changed. The values of the second two lines can be changed by the owner of the package, if the file should not be customized and if the file is deprecated.
These default values are generated only once, so that the package owner can override the default values, if desired. If the classs ExplicitOrder property is set to True, the orders are controlled by the generator, and should not be edited directly in the resource info file. If one of the constants has DefaultValue set to True, it is controlled by the generator. For example, the value for the "sm" value could be changed as follows:
sm.value=Small sm.shortDescription=Small Comment sm.order=10 sm.defaultValue=true
Enumerated Types
33-7
To build the runtime resource into the codebase for all the resource info files for a particular directory, use the following command: ResourceBuild <directory_relative_to_src> For example:
ResourceBuild wt/example
The resulting resource file is named <name>.RB.ser, which is a serialized instance of SerializedResourceBundle. For example, src/wt/example/MySizeRB.rbInfo will build to codebase/wt/example/MySizeRB.RB.ser. To verify the values stored in a resource bundle, a verification utility is provided by the EnumeratedType base class. A batch file, enumVerify.bat, can be used to invoke this verification, as follows: enumVerify <fully_qualified_EnumClassname>[<language>][<country>] [<variant>] The following are examples of usage:
enumVerify wt.lifecycle.State enumVerify wt.lifecycle.State fr enumVerify wt.lifecycle.State fr CA
For information on locales, and codes for languages and countries, see the java.util.Locale class entry in your installed Windchill Javadoc.
33-8
Enumerated Types
33-9
The one caveat with using extended EnumeratedType instances is that, if concrete types are used in the model, they are the only types that can be read back from the database. Using the example in the preceding figure, this means that other subclasses of MySize can be assigned to the size attribute of MyItem, and they can be stored in the database, but they can be read out only as instances of the types that are modeled. This limitation would not apply if MySize were an abstract class. When an abstract class is modeled, the runtime type information is stored in the database along with the instance information. Therefore, the exact type and instance can be reconstructed when reading it back from the database.
33-10
The remainder of this section describes how to start the utility. For specific instructions on its usage, see the online help available when you start the utility.
Enumerated Types
33-11
To see the changes you have made after using the utility, perform the following steps: 1. Restart the method server. 2. Rebuild all of the client jar files (see Managing Client JAR Files in the Managing Customizations chapter on page 5-14) so clients can access the new values. 3. Restart any Java clients. (HTML clients access the new values as soon as their pages are refreshed from the server.)
33-12
34
Windchill Design Patterns
This section describes design patterns that represent Windchills current best practices regarding development of server logic, most notably the design pattern on how to develop business services. These patterns have emerged during the development of the Windchill services and should be used as standards and guidelines when developing new server logic.
Topic
Page
The Object Reference Design Pattern ...............................................................34-2 The Business Service Design Pattern................................................................34-3 The Master-iteration Design Pattern .................................................................34-7
34-1
Object Reference Pattern This pattern essentially encapsulates details concerning persistable objects and their unique database query key. The pattern asserts that an object is a derived attribute aggregated by reference and is not persisted. The objects unique database query key is aggregated by value, is persisted, and is write-protected against the attempt of any other package class to set its value. In cases where database performance and storage are issues, object references persist only their object identifiers, and can be used in place of actual objects and acted upon via their identifiers. However, when the actual object is required, it can be gotten from the object reference which may or may not be currently holding the object. If the object reference does not hold the object and the object is asked for, the object is refreshed via its query key from the database.
34-2
34-3
This pattern has the following major kinds of abstractions: Type Cookie Helper Service ServiceEvent ServiceException
The Type abstraction provides an interface for means to type an object as being of a particular kind. This interface is what the service expects to deal with in terms of input and output, other than additional information. An object that does not specify it is of a certain type cannot statically be used by the service and thus is rejected at compile-time. In general, a Type is a kind of persistable object. The Cookie abstraction provides a class that is used to specify the information to be associated with and stored as a part of the typed object. When an object asserts itself as being a Type, the Cookie and its attributes, including all nested attributes, are code generated into the object along with applicable accessors. If a Cookies cardinality is 0..1, the Cookie and all its nested attributes can be stored as null if none of the Cookies attributes are required. If any of the simple, or structured, attributes of the Cookie are constrained to be non-null in the database, the Cookie is forced to be non-null. The Helper abstraction provides a class representing the services external interface from which all visible functionality can be invoked. The helper is intended to specify only static methods and attributes which any other class can access without having to create any instances. The static methods are typically Cookie accessors. The static attribute is a remote reference to the services server-
34-4
side functionality by means of initializing the "service" attribute as shown in the following example.
Notice the property in bold type named "InitialValue" and its value, "new ServiceFwd()." This property setting directs the code generator to make an initializer for the "service" instance to what is specified as the value. The service name appended with "Fwd" is the name of the class generated for a class stereotype as being a "RemoteInterface." The Service abstraction provides an interface that specifies the main functionality of the service itself, which may or may not be invoked remotely if the interface is stereotyped as a "RemoteInterface." Otherwise, the services interface will be available only locally in the server. This interface must be adhered to and implemented for the service to function properly. Additionally, a standard implementation of the services methods exists. This standard implementation is a singleton executing on the server and is the default for all Windchill services. The ServiceEvent abstraction provides a common definition of an event that can be emitted from the service and cause another service to be notified of the event. This event specifies one or more kinds of occurrences that are used to generate keys for listeners. Because these specific kinds of occurrences are extremely simple in nature, only one event per service that defines all occurrences is specified.
34-5
The ServiceException abstraction provides a common definition of an exceptional condition that may occur as a result of abnormal behavior in the service. This exception, along with the services resource bundle, can be used exclusively to throw any and all kinds of errors. However, it may be appropriate, but not necessary, to specialize this exception for more explicit and applicable errors.
34-6
Master-Iteration Pattern
This pattern typically establishes two objects that work in concert with one another. Without one, the other should not exist and is certainly invalid. At the root are the basic abstractions: Mastered Iterated
The Mastered interface provides an abstraction of a plug-and-play component in conjunction with the Iterated interface. The intent is that, in a business model, an object would assert that it is a master by inheriting the Mastered interface. With this assertion, the business object can then be mastered through the version control services API. The business object must assert itself as being a kind of mastered object in order for its instance to be iterated. The Iterated interface provides an abstraction of a plug-and-play component in conjunction with the Mastered interface. The intent is that, in a business model, an object would assert that it is an iteration (instance) by inheriting the Iterated interface. With this assertion, the business object can then be incrementally
34-7
superseded, rolled back, and rolled up through the version control services API, provided it has a master. The business object must assert itself as being a kind of Iterated object in order for it to be incrementally changed. The next level of master-iteration pairs defines abstract entities that start pulling together (that is, assert) all applicable capabilities from a general [virtual] enterprise perspective. The level below starts becoming more concrete where the EnterpriseItemMaster is concrete but the EnterpriseItem is not. It is at this level where the association between master and iteration is overridden with the exact named roles. However, it should be noted that cardinality of the iterations within a master can be specialized to be further constrained. Also, this association again specifies itself as a foreign key and the master can be auto-navigated from the iteration. Thus, when an iteration is fetched from the database, its master is fetched as well in one SQL statement via a database view. Note that the iteration at this level need not be concrete for an association of this kind with the foreign key, and auto-navigation on the concrete class can have the other side as an abstract class. At the very bottom, all of the concrete specializations of the EnterpriseItem exist. All of these specializations inherit the foreign key, auto-navigate association from EnterpriseItem. And thus, each is generated with a specific database view such that three database views are generated for EnterpriseItem1, EnterpriseItem2, and EnterpriseItem3.
34-8
35
Developing Server Logic
This chapter describes how to develop server logic. Topic Page
Overview ...........................................................................................................35-2 Service Management .........................................................................................35-2 Service Event Management...............................................................................35-4 Implementing Business Data Types ..................................................................35-8 Lightweight Services.......................................................................................35-18 Customizing service.properties .......................................................................35-24 Windchill Multi-object Operations .................................................................35-26
35-1
Overview
Developing server logic is primarily a task of designing and implementing business data types and services. To develop these kinds of abstractions, you must understand applicable Windchill design patterns, service and event management in general, and guidelines used in detailed design and implementation. A business data type can be characterized as an important piece of information known in the business domain. This information consists of data and/or state once it exists and is recognized in the system. A business service can be characterized as a set of one or more functions that carry out business-specific processing. The purpose of these kinds of abstractions is to separate the entity objects from control objects. Once they are separated, developmental impacts and risks, typically caused by evolving requirements and behavior, are reduced. That is, data and behavior changes are less likely to directly affect each other given sound abstraction and encapsulation. In addition to the information presented here, see the Windchill Design Patterns chapter on page 34-1. That chapter describes design patterns that represent Windchills current best practices regarding development of server logic. See the Windchill Services chapter on page 30-1 for a description of standard, reusable Windchill services.
Service Management
The development of the standard, reusable Windchill services caused the need for a general mechanism to manage the behavior of and interaction between these services. This service management mechanism specifies a protocol for startup, shutdown, and communication between Windchill services.
35-2
35-3
Service Management
ManagerService is a manager which is used to startup and provide access to a predefined list of managers. This list includes different managers for services mentioned in the Windchill Services chapter on page 30-1. In addition to managing managers, the ManagerService provides a synchronous event dispatch service. This service can dispatch a vetoable or non-vetoable event to all listeners for the event key. Each listener may or may not object to the event. The service performs a synchronous "in thread/transaction" notification of each event listener for the event branch identified by the event key. It calls the notifyEvent operation on each subscriber.
35-4
VersionServiceEvent.class.getName(), VersionServiceEvent.POST_SUPERSEDED ); manager.addEventBranch( VersionServiceEvent.generateEventKey( VersionServiceEvent.PRE_ROLLBACK ), VersionServiceEvent.class.getName(), VersionServiceEvent.PRE_ROLLBACK ); manager.addEventBranch( VersionServiceEvent.generateEventKey( VersionServiceEvent. POST_ROLLBACK), VersionServiceEvent.class.getName(), VersionServiceEvent. POST_ROLLBACK); manager.addEventBranch( VersionServiceEvent.generateEventKey( VersionServiceEvent. PRE_ROLLUP), VersionServiceEvent.class.getName(), VersionServiceEvent. PRE_ROLLUP); manager.addEventBranch( VersionServiceEvent.generateEventKey( VersionServiceEvent. POST_ROLLUP), VersionServiceEvent.class.getName(), VersionServiceEvent. POST_ROLLUP); }
Note: A more implicit means of registering events is by not doing so in the registerEvents method, but by allowing the event to be registered when it is first emitted. Once this occurs, all listeners subscribing to this event will be notified.
35-5
protected void performStartupProcess() throws ManagerException { // // // // At a request prior to a modification, if the target is a lockable object then validate if a modify on the object would be accepted. If not then veto it.
getManagerService().addEventListener( new ServiceEventListenerAdapter( this.getConceptualClassname() ) { public void notifyVetoableEvent( Object event ) throws WTException PersistenceManagerEvent pmEvent = (PersistenceManagerEvent)event; Persistable target = pmEvent.getTarget(); if (target instanceof Lockable) validateLock( (Lockable)target); } }, PersistenceManagerEvent.generateEventKey( PersistenceManagerEvent.PREPARE_FOR_MODIFICATION )); } protected void validateLock( Lockable object ) throws WTException, LockException { if (object.getLock() != null) { if (object.getLock().isSeized()) { if (!object.getLock().getLocker().getObjectId().equals( (Object) PersistenceHelper.getObjectIdentifier( SessionHelper.manager.getPrincipal() ))) throw new LockException( RESOURCE, "5", null ); } } }
35-6
35-7
events are used to notify listeners that an event has finished. They are most useful when a service needs to perform some kind of post-processing as a result of the event. Not all events have to be either pre- or post-events. A singular definition of an event can be used to indicate some special occurrence, which may or may not have happened.
35-8
customized message. The following example shows the property for constraining an attribute, and a getter and setter for an attribute named "note".
Constraining an Attribute
public String getNote() { //##begin getNote% [ ]348C64E401C5g.body preserve=no return note; //##end getNote% [ ]348C64E401C5g.body } protected void setNote( String a_Note ) throws WTPropertyVetoException { //##begin setNote% [ ]348C64E401C5s.body preserve=no noteValidate( a_Note ); // throws exception if not valid note = a_Note; //##end setNote% [ ]348C64E401C5s.body }
Note that the body of the methods are flagged as "preserve=no." This instructs the code generator to overwrite the code within a method. Getters and setters can be preserved by setting this flag to "yes", but in general this is not recommended. On the other hand, the code generator can be instructed to not generate a getter and setter for an attribute with the "GenerateAccessors" property on the Windchill tab set to "False."
35-9
Attribute validation (as shown in the example) Lazy attribute initialization Computed attribute access
35-10
following examples illustrate the use of these two properties and the validation code that is generated automatically:
Validation Example
private void noteValidate( String a_Note ) throws WTPropertyVetoException { if ( a_Note != null && a_Note.length() > MAX ) { // upper limit check Object[] args = { "note", "MAX_LENGTH" }; throw new WTPropertyVetoException( "wt.fc.fcResource", wt.fc.fcResource.UPPER_LIMIT, args, new java.beans.PropertyChangeEvent( this, "note", note, a_Note ) ); } if ( a_Note != null && a_Note.length() < MIN ) { // lower limit check Object[] args = { "note", "MIN_LENGTH" }; throw new WTPropertyVetoException( "wt.fc.fcResource", wt.fc.fcResource.LOWER_LIMIT, args, new java.beans.PropertyChangeEvent( this, "note", note, a_Note ) ); } }
The other more general level of validating one or more attributes is to override and implement the "checkAttributes" method inherited from wt.fc.WTObject. This method is invoked before the object is stored in the database initially and every time it is modified. In this case the exception thrown is wt.fc.InvalidAttributeException, not wt.util.WTPropertyVetoException.
35-11
35-12
Persistent Attribute
Otherwise, it is treated as an in-memory attribute only and is not mapped to a column in the database table.
35-13
35-14
throw new ManagerException (this, "Failed to initialize service."); } finally { SessionContext.setContext(previous); // restore initial SessionContext } }
35-15
if (!object.getLock().isSeized()) { if (AccessControlHelper.manager.hasAccess( locker.getPrincipal(), object, WTPermission.MODIFY )) { dispatchVetoableEvent( LockServiceEvent.PRE_LOCK, object ); object.getLock().seize( locker, note );
35-16
// // // // //
Now update the object without changing the objects modify date. The modify date is left as is since all that is being updated is the cookie information, not the object.
try { trx.start(); PersistenceServerHelper.manager.update( (Persistable) object, LEAVE_MODIFY_DATE ); trx.commit(); trx = null; } finally { if (trx != null) trx.rollback(); } dispatchVetoableEvent( LockServiceEvent.POST_LOCK, object ); } } return object; //##end lock% [ ]342A8DDB0271.body }
Enforcement of problem domain integrity is somewhat different than access control. Maintaining correct problem domain behavior within the business service should always be a goal, but in particular there may be some special requirements that must be satisfied. As in version control, for example, when an object is checked in, it is then once again available to be checked out. However, if the object is already checked out, it can not be checked out again unless some sharing and merging rules are in place.
35-17
Lightweight Services
Lightweight services reside in the application layer between the client and the business service layer. Lightweight services are light because they do not start automatically and dispatch events. Consequently, lightweight services are not specified in the wt.properties file with wt.services entries. Lightweight service methods should be designed to do the following: Reduce the number of round trips between the client and the server. Provide task-specific and higher-level functionality than business service methods. Ensure client transactional integrity.
Lightweight services can dispatch events but should not listen for them. If a service is not started automatically, it will not be able to hear events that it is supposed to listen for until it is started. Lightweight services are an effective means to ensure client transactional integrity. Several client-server operations can be grouped into a single, lightweight service method call that will carry out these operations on the server in a single transaction. Lightweight services can be implemented in the following two ways: Through a modeled class that extends wt.services.StandardManager Through a non-modeled, inner class that implements wt.method.RemoteAccess
35-18
The following is an example of a lightweight service named CommentLogger. This model can be found in WTDesigner.mdl in the wt.services.test package.
In this example, the CommentLogger interface defines a lightweight service that will log a message to the server log file. This service could be useful for applet clients that want to include a message in the server log. Without such a service, all System.out.println calls will send their output to the browsers Java console window instead of the server log file. StandardCommentLogger implements this service by extending wt.services.StandardManager and the CommentLogger interface. Note that the name must be StandardCommentLogger in order for the ManagerService to find the implementation class for the CommentLogger service. Since CommentLogger has a stereotype of RemoteInterface, a Forwarder class named CommentLoggerFwd is automatically generated. It is this class that is used to invoke the CommentLogger service methods:
CommentLoggerFwd logger = new CommentLoggerFwd(); logger.log("a message");
35-19
import wt.util.WTContext; import wt.method.RemoteMethodServer; import wt.method.RemoteAccess; import import import import import import import wt.fc.QueryResult; wt.fc.PersistenceHelper; wt.fc.PersistenceManager; wt.part.WTPart; wt.part.WTPartMaster; wt.query.QuerySpec; wt.query.SearchCondition;
public class AppLightFwd extends Applet { // Class name of our inner class that runs in the server private static final String SERVER_CLASS = AppLightFwd.class.getName() + "$Server"; private private private private private private private Button action; RunnerEventListener rel; Label partNames; TextField text; Label queryCount; TextField countVal; TextArea feedback;
public void init() { WTContext.init(this); action = new Button ("Get Parts"); this.add(action); rel = new RunnerEventListener(); action.addActionListener(rel); partNames = new Label( " with names like ... " ); this.add(partNames); text = new TextField("", 25); this.add(text); queryCount = new Label( "Number of parts to return" ); this.add(queryCount); countVal = new TextField( "5", 4); this.add(countVal); feedback = new TextArea("",10, 40); this.add(feedback); } public void start() { WTContext.getContext(this).start(this); super.start(); }
35-20
public void stop() { WTContext.getContext(this).stop(this); super.stop(); } public void destroy() { WTContext.getContext(this).destroy(this); super.destroy(); } // Applet event listener class RunnerEventListener implements ActionListener { public void actionPerformed (ActionEvent event) { Object o = event.getSource(); if (o == action) { String name = text.getText(); String count = countVal.getText(); if (!name.equals("")) doSomeWork(name,count); else text.setText("must enter a part name search key" ); } } } // // // // Food for thought: here we should disable appropriate GUI components and spin off a separate thread to do the actual work so we dont hang the AWT-Thread ( the GUI thread )
public void doSomeWork(String name, String count) { Vector results = null; String like = "% [ ]"+name.toUpperCase()+"% [ ]"; feedback.setText(""); try { Integer cnt = null; try { cnt = new Integer(count); } catch (Exception e) { // some parse exception, just get default count try { cnt = new Integer(5); // this will work } catch (Exception e2){} } // construct arguments for call Class [] argTypes = { String.class, Integer.TYPE }; Object [] args = { like, cnt }; // Run to server and do some work there. // Build Server inner class name as a string so we dont // load the class here. results = (Vector) RemoteMethodServer.getDefault().invoke( "doSomeWork", SERVER_CLASS, null, argTypes, args);
35-21
// display results in text area for (int i=0;i results.size(); i++) { PartMasterInfo pmi = (PartMasterInfo)results.elementAt(i); feedback.append("> "+pmi.getName()+" # "+pmi.getNumber()+\n); } } catch (RemoteException e) { // // Put localized Exceptions // into a Dialog popup // feedback.append(e.toString()); } catch (InvocationTargetException e) { // Localize in a dialog feedback.append(e.toString()); } } // "Public" static inner class. // Yes 2 public classes in the same file, this is the // only exception public static class Server implements RemoteAccess { public static Vector doSomeWork (String name, int count) { int i=0; Vector parts = new Vector(count); WTPartMaster wtpm; try { // // Use feedback mechanism to send progress updates // to the user // and of course be sure to Localize it // QuerySpec queryspec = new QuerySpec(WTPartMaster.class); queryspec.appendSearchCondition( new SearchCondition(WTPartMaster.class, WTPartMaster.NAME, SearchCondition.LIKE, name) ); QueryResult queryresult = PersistenceHelper.manager.find(queryspec); // create a vector of PartMasterInfo object to return // to the client while (queryresult.hasMoreElements()) { wtpm = (WTPartMaster)queryresult.nextElement(); parts.addElement(new PartMasterInfo(wtpm.getName(), wtpm.getNumber())); if (++i >= count) break; }
35-22
} catch (Exception e) { // Localize parts.addElement(new PartMasterInfo(e.toString(),"-1")); e.printStackTrace(); } return parts; } } // simple support (inner) class which contains // the information we are interested in returning to the // client for display purposes public static class PartMasterInfo implements Serializable { String name; String partNumber; public PartMasterInfo( String name, String number ) { this.name = name; partNumber = number; } public String getName() { return name; } public String getNumber() { return partNumber; } } }
35-23
Customizing service.properties
The service delegate mechanism uses Java property files to specify the delegates that are used for each service for a given set of criteria. The main property file is named service.properties and is located in /Windchill/codebase/. For further information, see the section on property files in the The Windchill Development Environment chapter on page 2-1) Instead of adding new entries to the service.properties file, or overriding existing entries in it, use a separate file. This file must have entries with the same format as those in service.properties. To use the new property file, add the files full path (relative to the system classpath) to a comma-separated list of files in the following property located in wt.properties:
wt.services.applicationcontext.WTServiceProviderFromProperties. customPropertyFiles
Consider the example of creating a new wt.identity.DisplayIdentification delegate. The DisplayIdentification service is an interface that defines methods for creating strings that identify an object for user interface display purposes. In service.properties, several entries exist for the DisplayIdentification service, as follows:1
# The wt.identity.DisplayIdentification service. # # Delegate definitions for all objects ################################################# wt.services/svc/default/wt.identity.DisplayIdentification/null/ java.lang.Object/0= wt.identity.DisplayIdentificationObjectDelegate/ duplicate wt.services/svc/default/wt.identity.DisplayIdentification/null/ wt.fc.Persistable/1= wt.identity.DisplayIdentificationPersistableDelegate/ duplicate wt.services/svc/default/wt.identity.DisplayIdentification/null/ wt.folder.Folder/2= wt.folder.DisplayIdentificationFolderDelegate/ duplicate wt.services/svc/default/wt.identity.DisplayIdentification/null/ wt.folder.Shortcut/2= wt.folder.DisplayIdentificationShortcutDelegate/ duplicate wt.services/svc/default/wt.identity.DisplayIdentification/null/ wt.doc.WTDocumentMaster/2= wt.identity.DisplayIdentificationWTDocumentMasterDelegate/ duplicate wt.services/svc/default/wt.identity.DisplayIdentification/null/ wt.enterprise.RevisionControlled/2= wt.identity.DisplayIdentificationRevisionControlledDelegate/
1.
Indentation in this example indicates a continuation of the preceding line, necessary for presentation in the manual. The entry for each property in a property file can be on only one line.
35-24
Each entry maps a class or interface, such as wt.part.WTPart, to a class that implements the interface wt.identity.DisplayIdentification, such as wt.identity.DisplayIdentificationWTPartDelegate. If a customization includes a subclass of WTPart named AcmePart, and that part has different display identification needs than WTPart, a new delegate must be implemented. After the delegate class is implemented, it is used only when the correct entry has been added to a service delegate property file. To do so, perform the following steps: 1. Create a new property file named acme_part_services.properties to contain all entries for service delegates that apply to the AcmePart class. 2. Put this property file in a directory where it will not be deleted if your Windchill installation is reinstalled or upgraded, for example: <Windchill>/src/com/acme/part. Place a copy in <Windchill>/codebase/com/acme/part. 3. Add the name of the new property file to the list of files specified in the wt.properties file property named wt.services.applicationcontext.WTServiceProviderFrom Properties.customPropertyFiles, using the following procedure: Create a new declarative xconf file, for example, <Windchill>/src/com/acme/part/acme_part_services.xconf that looks like the following:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE Configuration SYSTEM "xconf.dtd"> <Configuration targetFile="codebase/wt.properties"> <!-- Ensure that the file com/acme/part/acme_part_services.properties is appended to the list of custom property files. --> <Property default="com/acme/part/acme_part_service.properties" name="wt.services.applicationcontext.WTServiceProviderFromProperties.customProperty Files"/> </Configuration>
Modify the customPropertyFiles property in <Windchill>/codebase/wt.properties and generate the acme_part_services.properties file by executing the new xconf file from a windchill shell as follows:
xconfmanager -i src/com/acme/part/acme_part_services.xconf -p
4. Restart the method server in order for the change to take effect.
35-25
Windchill-specific collections utilize the Java Collections framework to provide sets, lists, and maps optimized for Windchill persistent objects. These collections seamlessly handle Persistables represented as QueryKeys, WTReferences, and fully-inflated Persistables. The collections also provide numerous APIs for doing things such as refreshing and inflating, getting sub-collections based on class, and testing membership. See the wt.fc.collections package in the Javadoc for more information. Multi-object event dispatch and notification allows any event (such as PRE_STORE) to be dispatched and notified as either single- or multi-object. The event mechanism automatically handles the case where the dispatcher and notifier (that is, the listener) are inconsistent by converting the multi-object event into single-object events and looping over the listener and, vice-versa, by converting the single-object event into a multi-object event and notifying the multi-object listener. Multi-object events will have collections-based event targets.
2. "CRUD" refers to Create (store/insert), Read (find/query/navigate/expand), Update (modify/update), and Delete (delete/remove) operations.
35-26
Multi-object delegation makes it possible to request the delegates for a collection of objects. The multi-object delegate APIs will then map the appropriate delegates to sub-collections of the collection that would use them. It is then possible to execute multi-object APIs on the delegate, passing these subcollections to the delegate's multi-object APIs. For example, when requesting the "x.y.Z" delegate for a collection of parts and documents, the result may be that delegate1 matches the parts and delegate2 the documents; delegate1's multi-object API can then be called, passing the parts sub-collection. See the Javadoc entry for wt.services.ac.DefaultServices for more information. Multi-object exceptions are thrown by multi-object APIs and listeners. These exceptions provide extended information about the nature of the problem(s) associated with some of the objects in the passed-in collection. For example, if a change identity against ten objects failed because three of the objects were assigned non-unique identities, the resultant exception will indicate the three individual failures. This is made possible by the addition of "additionalMessages" to wt.util.WTException. Multi-object CRUD persistence manager APIs interact with the database using batch operations, reducing the total number of database interactions for a CRUD operation to as little as one (more practically, as little as one per table). A "store" operation passing a collection of 100 parts can employ a single bulk insert to the database, rather than 100 individual insert operations. See the wt.fc Javadoc entry for more information. Batch ("UPDATE WHERE" and "DELETE FROM") statement capabilities produce Windchill statements that, in the database, are translated as UPDATE WHERE and DELETE FROM statements. This makes it possible, for example, to delete all of the associations for a collection of objects in one database hit without even requiring the links to be pre-queried (in practice, these operations are still subject to events, so the OIDs may be returned and, if the listeners require full persistables, inflated). See wt.fc.batch for more information. Transaction context and listeners provide fine-grained mechanisms for adding information to the nested and global transactions (in a manner similar to the MethodContext) and for being notified when a transaction is about to commit, has committed, or rolls back. See the Javadoc entries for Transaction, TransactionListener, and TransactionCommitListener in the wt.pom package. Referential integrity association validation during object delete employs a declarative mechanism to specify how associations should behave during deletion. Each role can indicate that, when the role object is being deleted, the association should be deleted or the deletion vetoed.
35-27
35-28
36
The Enterprise Layer
This chapter describes the classes and interfaces available in four packages: wt.enterprise wt.doc wt.part wt.change2
The classes provided in these packages were designed and intended for you to extend as you customize Windchill for your own use. Topic Page
Enterprise Abstractions .....................................................................................36-2 Document Abstractions ...................................................................................36-10 Part Abstractions .............................................................................................36-13 Change Abstractions........................................................................................36-21
36-1
Enterprise Abstractions
The wt.enterprise package provides the basic business objects used in the Windchill system. Most business classes you construct will be extended from the enterprise classes or their subclasses.
Business classes should be extended from one of the abstract classes included in the wt.enterprise package to take advantage of the capabilities and services they offer. This diagram shows convenience classes designed to consolidate a basic set of features that various business classes might require. Most of the business classes in your model are expected to extend one of these classes and simplify your implementations.
36-2
folders, they tend to be more administrative in nature (that is, created by administrators but referenced by end users).
36-3
36-4
36-5
Represents the version independent idea of a business concept. It contains the information that identifies the business objects. Typically this is information such as a name and number that remains constant for all versions (or, more accurately, is the same for all versions).
36-6
Revision controlled
Represents the successive changes to the business objects as it is developed over time. A RevisionControlled object represents an official version (for example, revision A or B) but also provides access to previous iterations of that version. The previous iterations are considered a history of work-inprogress activity (checkouts and checkins) for the object.
36-7
36-8
36-9
Document Abstractions
The wt.doc package provides a standard implementation of managed documents. A simplification of the document model is shown below. This simplification shows some of the core interfaces that make up WTDocument and WTDocumentMaster. These objects actually implement a number of interfaces to acquire their behavior. To see the full scope of interfaces that are implemented by these two objects go to the Javadoc for wt.doc.WTDocument and wt.doc.WTDocumentMaster. A more complete diagram can also be viewed using Rose.
Doc Package
36-10
The document classes are implemented based on the pattern established for revision controlled objects in the wt.enterprise package. These classes, WTDocumentMaster and WTDocument, provide concrete classes exhibiting the management characteristics established in wt.enterprise and add specifics for documents. The properties of a document are specified on the WTDocument class. Then, for normalization purposes, the sum of the properties are stored on the WTDocumentMaster. More specifically, WTDocument implements Format ContentHolder to give it a primary content item and multiple secondary content items. WTDocument can create two types of relationships to other documents. The first, WTDocumentUsageLink, is similar to the WTPartUsageLink in that it also subclasses IteratedUsageLink. It does not have a quantity. WTDocumentUsageLink is used to create uses relationships between documents or document structure. Documents should use this if a document is made up of sub-documents and the sub-documents can be reused by other documents, or need to be controlled separately. Similar to the part implementation, the WTDocumentService has convenience methods for navigating this relationship and there is a WTDocument ConfigSpec to filter results. The second, WTDocumentDependencyLink implements IteratedDescribeLink which is also implemented by WTPartDescribeLink. This is a version-specific relationship between two documents. This relationship is shown in the client as references. A reference between two documents can be created to show a dependency on another document. A document may reference some information in another document, so during a create or update, a reference to that document is added. The references relationship has a comment attribute that can be used to explain why the reference exists or what the dependency is. WTDocument Service also has convenience methods for navigating the WTDocumentDependencyLink. The doc package is an example of implementing a Revision Controlled Business subclass. The concrete document business classes inherit from the Revision Controlled Business model (Master and RevisionControlled) template in the enterprise model. Document inherits most of its functionality from the enterprise object RevisionControlled. RevisionControlled pulls together many plug and play functionality interfaces. To see the full list of interfaces go to wt.enterprise.Revisioncontrolled in the javadoc. In particular, it includes interfaces from the content package. This means that a WTDocument is a content holder; that is, it can have files or URLs included in it. Attributes are on either WTDocumentMaster or WTDocument. Attributes on WTDocumentMaster have the same value for all versions and iterations. If an attribute on the master changes after several versions and iterations have been created, the change is reflected in all the versions and iterations. Attributes on WTDocument can generally have different values for each iteration, so changes impact only one iteration. This is why content holder is implemented on DocumentIteration.
36-11
To add new document types that can have different administrative controls, the WTDocument class must be extended. Subclassing of WTDocument also is preferable if there are specific associations in which only some documents can participate. These kinds of rules are difficult to specify without subclassing WTDocument. Use the following rules when extending WTDocument: For every new child of WTDocument, you must make a corresponding entry in the DocumentType resource bundle. This ensures that the WTDocumentMaster object for each WTDocument child knows the type for its document version. When adding new classes of documents, it is not necessary to extend the WTDocumentMaster class, only the WTDocument class. All children classes of WTDocument can share the same WTDocumentMaster class. Follow the constructor pattern established in WTDocument. Override the appropriate initialize methods from WTDocument, invoking super.initialize() and then performing your class specific logic. Specifically, invoke the method initialize(number, name, type) where type is substituted for a value that has been added to DocumentTypeRB.java.
Department is implemented as an enumerated type attribute or a valid value list. The valid values are defined in the wt.doc.DepartmentListRB.java file. The values in DepartmentListRB.java can be changed, the file compiled, and replaced in the codebase. For further information, see the section on Extending the EnumeratedType class in the System Generation chapter on page 31-36 and the Enumerated Types chapter on page 33-1.
36-12
Part Abstractions
The wt.part package provides a standard implementation of parts. A part is an item that can be produced or consumed, such as, an engine, a bolt, or paint. Parts can be assembled to produce other parts; for example, the drive train of an automobile can be thought of as a part composed of an engine, transmission, shaft, differential, and so on.
Design Overview
The following figure illustrates the basic concepts encapsulated by the Windchill part reference implementation.
The part classes are implemented based on the pattern established for revision controlled objects in the wt.enterprise package. These classes, WTPartMaster and WTPart, provide concrete classes exhibiting the management characteristics established in wt.enterprise and add specifics for parts. The properties of a part are specified on the WTpart class. Then, for normalization purposes, the sum of the properties are stored on the WTPartMaster. The part package is an example of implementing a Revision Controlled Business subclass. The concrete part business classes inherit from the Revision Controlled Business model (Master and RevisionControlled) template in the enterprise model. Part inherits most of its functionality from the enterprise object RevisionControlled. RevisionControlled pulls together the following plug and play functionality: Foldered, Indexable, Notifiable, DomainAdministered, AccessControlled, BusinessInformation, LifeCycleManaged, Version, Workable, and Changeable.
36-13
Attributes are on either WTPartMaster or WTPart. The WTPartMaster, as a Mastered object, represents the parts identity. As such, "number" and "name" have been placed on it. The parts number is the stamp the enterprise recognizes and uses for tracking purposes. The name is the human-readable component. These properties of the part are assigned carefully and rarely changed. Attributes on WTPartMaster have the same value for all versions and iterations. If an attribute on the master changes after several versions and iterations have been created, the change is reflected in all the versions and iterations. The WTPart, as a Versioned and Workable object, undergoes change that is recorded in its versions and iterations as a result of a check-out and check-in process. Attributes on WTPart can generally have different values for each iteration, so changes impact only one iteration. An iteration occurs every time a part is checked out and in. It can be viewed as a working copy of the part. Iterations are assumed to happen many times between versions. Versions, however, represent a business increment; that is, an approved, major change to a part. A typical scenario is that version A of a part is approved and put into production. Then a change is determined to be necessary. The part goes through many iterations while the change is being investigated and tested. Finally, version B is approved. Also, being ViewManageable, WTPart can be assigned to views, allowing it to progress through stages of development, such as engineering and manufacturing stages. It resides in folders, is subject to access control, progresses through life cycles, and is part of the change process as a consequence of being RevisionControlled. It can also be assigned to baselines to preserve a specific implementation and its versions can be made effective to indicate to a manufacturing process what to build. Although shown in the preceding figure, WTPart is no longer a ContentHolder by default. The capability to hold files and URLs still exists, but it is no longer exposed to the user. The WTPart also contains as aggregated properties a source and a type (as shown in the following figure).
WTPart Properties
36-14
The source can be used to indicate how the part is procured, for example by being made or bought. The type specifies how it can be decomposed, for example by being separable (is assembled from components that can be taken apart to be serviced), inseparable (is assembled, but can not be disassembled), or component (is not assembled). The values of these properties can be altered by editing their resource bundles. Also, note that number and name are modeled as derived and are implemented to set and get the real values from its WTPartMaster. The DerivedFrom property in the Windchill tab of the attribute specification has been used to indicate that it has been derived from the masters attributes by specifying the database derivation; also, the getters and setters have been overridden in a manner similar to the following:
((WTPartMaster) getMaster()).get/set...(...)
WTParts can use other parts to build assemblies using the WTPartUsageLink as shown in the following figure.
The WTPartUsageLink is a type of IteratedUsageLink, an association defined to be used to build structures. The WTPartUsageLinks aggregated Quantity can be used to indicate the amount of the component that is being consumed. The QuantityUnits values can be altered by editing its resource bundle. The WTPartUsageLink can be navigated using the PersistenceManagers navigate APIs, or even the StructServices navigateUses and navigateUsedBy APIs. Be aware that navigating the usedBy role results in the returning of all part iterations; StructServices navigateUsedBy API returns only versions. However, the StructServices APIs navigate using the IteratedUsageLink as its target; the
36-15
WTPartUsageLink might not be the only IteratedUsageLink in a customization. We recommend using the APIs in the following figure.
getUsesWTParts navigates to the WTPartMaster and resolves WTParts from the masters using a WTPartConfigSpec, returning a QueryResult of Persistable[]s in which the WTPartUsageLink is in the 0th position and the WTPart/WTPartMaster in the 1st. getUsesWTPartMasters simply navigates the WTPartUsageLink and returns a QueryResult of WTPartUsageLinks. Finally, getUsedByWTParts returns a QueryResult of WTParts (the versions, not simply all iterations) representing the implementations that call out the part. WTParts can also reference documents (see the following figure).
Parts generally reference documents for one of two reasons: The part is not the logical owner of a document. An example of such a document is a standards document. A standards document is independent of a part, but may be used to verify conformance to the document. A document (file) is conceptually owned by the part, but must be separately life cycle managed, checked in and out independently of the file, and so on. Note that the WTPartReferenceLink may not be appropriate if the documents versions are not necessarily interchangeable from the perspective of the WTPart. If a specific version of a document should be linked to a specific version of a part, use the DescribedBy link (as described later in this section) instead.
36-16
A WTPart can also be linked to a document that describes it on a version-specific level using WTPartDescribedByLink. An example of such a document is a CAD drawing that shows exactly how a specific version of a part is designed and should be built. If a change is made to the part and a new version created, the revised version of the CAD drawing, that reflects that change, should be linked to the new part using the DescribedBy functionality. To summarize, a reference should be considered supplemental information that is useful but not required. It is likely to have its own life cycle and change independently of the part referencing it. A document linked to a part by a DescribedBy link contains information you may need specifically for that version of the part. A specific version of the document is linked to a specific version of the part. The WTPartConfigSpec was alluded to by the getUsesWTParts API. It is used by the Product Structure Explorer during its navigations. It consists of three ConfigSpecs: the WTPartStandardConfigSpec, the WTPartEffectivityConfigSpec, and the WTPartBaselineConfigSpec (as shown in the following figure).
WTPartConfigSpec
A concept of zones has been added to the WTPartConfigSpec to determine which ConfigSpec is active at any given time. The WTPartConfigSpec is stored, one per principal, using the WTPartServices APIs listed in the following figure.
36-17
WTPartStandardConfigSpec
When active, WTParts are filtered based on their state and their view membership. workingIncluded can be used to allow users to toggle between their working copies and their checked-out versions.
WTPartEffectivityConfigSpec
When active, allows the user to see structures based on effectivity and view. Only WTParts designated as effective are shown (see the wt.effectivity package for additional information).
WTPartBaselineConfigSpec
When active, displays only those WTParts assigned to the specified baseline (see the wt.vc.baseline package for additional information).
36-18
Parts can often be replaced by other parts, either globally or in the context of an assembly. This interchangeability is used to indicate that one part is equivalent to another in a given situation. The WTPartAlternateLink (shown in the following figure) is used to indicate global interchangeably, while the WTPartSubstituteLink indicates interchangeability within the context of an assembly. Note that the WTPartSubstituteLink is copied whenever the WTPartUsageLink is copied.
Both of these links can be navigated using the Persistence Managers navigate APIs. In addition, the WTPartService offers getAlternatesWTPartMasters and getAlternateForWTPartMasters methods for navigation of WTPartAlternateLinks and getSubstitutesWTPartMasters and getSubstituteForWTPartUsageLinks methods for navigation of WTPartSubstituteLinks. Both WTPartAlternateLinks and WTPartSubstituteLinks are access controlled, so permission to perform operations such as creation and deletion of links is defined using the access control service.
36-19
The Part, PartMaster, and PartIteration classes modeled in the wt.part package (see the following figure) are placeholders for future functionality.
Placeholders
36-20
Change Abstractions
The change2 package includes the basic service methods and change item classes necessary to support change management. The change management module provides the means by which users can identify, plan, and track changes to the product information managed by the Windchill product data management system. Note: The change2 package replaces the change package available in releases prior to Release 4.0. The following figure shows the five conceptual steps in the change management process.
To understand the Windchill change management object model, it is important to understand these conceptual steps, as described below. Although the order of these steps is not fixed, they are presented here in a logical sequence.
Describe symptoms
The symptoms of a perceived problem are recorded. The person experiencing the symptoms could be an internal employee, a customer, or any other end user or person. This person records the symptoms.
Pursue formal change
At some point, the group of symptoms is evaluated. A formal decision is made to investigate the symptoms.
Identify problem pause
By investigating the symptoms and performing analysis, the root cause of the problem is determined. As part of this work, the person investigating the problem may identify relevant parts or documents.
Propose solution
A course of action to fix the problem is proposed. As part of this work, the person preparing a solution may identify relevant parts or documents.
36-21
Implement solution
A solution is chosen and implemented. As part of the implementation work, the users of the change process identify part or document revisions, both old revisions (that is, those that require a change) and new revisions (that is, those that have been changed). This step includes the incorporation of the solution into production, if appropriate.
36-22
<<Abstract>> ChangeIssue 0..n FormalizedBy 0..1 <<Abstract>> ChangeRequest2 1 ResearchedBy 0..n <<Abstract>> ChangeAnalysis 1 <<Abstract>> ChangeInvestigation DetailedBy For the Windchill out of the box change process, there can be only one ChangeInvestigation per ChangeRequest. 0..n <<Abstract>> AnalysisActivity For the Windchill out of the box change process the UI does not expose this relationship <<Abstract>> ChangeProposal 0..1 AcceptedStrategy 1 0..n <<Abstract>> ChangeOrder2 Address edBy2 0..1 1 0.. n <<Abstrac t>> ChangeActivity2
IncludedIn2
36-23
The following figure shows the relationship between the change item classes and the change management process shown earlier.
A change issue holds information about the problems symptoms. A change issue can be thought of as a suggestion box.
Change request
A change request is the object that organizes the other change objects. It represents a formal, traceable change. This object can be associated with product data versions (for example: parts, products, product instances, documents, or CAD documents).
Change investigation
A change investigation organizes the information pertaining to the root cause of the problem. It is used when the root cause is not trivial or obvious. If the research to determine the root cause is very detailed or complicated, analysis activities are used to organize the effort into logical work breakdowns.
Change proposal
A change proposal organizes the information pertaining to a solution for the problem. It is used when the problem solution is not trivial or obvious. If the research to determine the solution is very detailed or complicated, analysis activities are used to organize the effort into logical work breakdowns.
Analysis activity
An analysis activity is used in conjunction with either a change investigation or a change proposal. When the cause of the problem is complex, an analysis activity helps to further organize a change investigation. When the solution to a problem is complex, an analysis activity helps to further organize a change proposal. This object can be associated with product data versions that are relevant to the analysis work.
36-24
Change order
A change activity serves as the work breakdown for a change order. This object can be associated with product data versions for two distinct reasons: the product data is defective or otherwise must be changed, or the product data version is a result of a change. This allows users of the system to track the reason for change to product data.
36-25
<<Interface>> Changeable2
Product Master that is the_subject of_ the change request
W TProductInstance2
(from part)
WTPart
(from part)
WTDocument
(from doc)
EPMDocument
(from epm)
WTProduct
(from part)
Changeable Objects
36-26
The change management model defines four distinct relationships between change objects and changeables. Any number of changeables can be associated with each of the relationships. In the following figure, one part and one document is associated to the change object in each case. Also shown is a relationship between a change request and a product master, which is not changeable.
Subject Product
Product Master
Relationships to Product Information The following are the four relationships between change objects and changeables and the relationship between a change request and a product master.
Relevant request data
The relevant request data association identifies changeables that are relevant the change request for any reason.
Relevant analysis data
The relevant analysis data association identifies changeables that are relevant to the analysis for a change investigation or change proposal.
Affected activity data
The affected activity data association identifies changeables that must be changed to satisfy a change activity.
Change record
The change record association identifies changeables that have been changed as a result of a change activity
Subject product
The subject product association identifies product masters that are the subject of the change request. Product masters are not changeables and may not be directly affected by the change request.
36-27
To summarize, relevant request data and relevant analysis activity data identify versions that might change, affected activity data identifies old (or defective) revisions which have been superseded, and change record identifies new (or improved) revisions. Also, subject product identifies product masters that are the subject of a change request, but are not necessarily affected themselves. The following figure shows a UML class diagram representing these associations:
This relationship identifies Changeable2 revisions which were relevant for a given Analysis Activity.
This relationship identifies Changeable2 revisions which must be changed to satisfy a Change Activity.
RelevantAnalysisData
AffectedActivityData
0..n 0..n
<<Abstract>> ChangeActivity2
WTProductMaster
(from part)
RelevantRequestData2
ChangeRecord2
SubjectProduct This relationship identifies Changeable2 revsions which were relevant for a given Change Request. This relationship identifies Changeable2 revisions which were created to satisfy a Change Activity. These revisions are either entirely new, or new revisions of existing objects.
36-28
Interface layer
The interface classes simply implement the Persistable interface to indicate that the change management classes are objects stored by Windchill.
Abstract classes
The abstract classes implement various Windchill plug and play interfaces and enterprise package classes to obtain standard Windchill functionality. Each abstract class implements ContentHolder (see the content package in the Windchill Services chapter on page 30-1), which provides the ability to attach files. In addition, each abstract class extends either Managed or CabinetManaged (see the enterprise package, earlier in this chapter for an explanation of these classes). The abstract classes also contain modeled associations among change objects, and between change objects and product information objects.
Concrete classes
36-29
Change issue
The following figure shows the model for change issues:
<<Abstract>> Managed
(from enterprise)
<<Interface>> ChangeIssueIfc
<<Interface>> ContentHolder
(f ro m co ntent )
<<Interface>> ChangeItem
<<Interface>> ElectronicallySignable
(from electronicIdentity)
WTChangeIssue number : String name : String description : String requester : String WTChangeIssue() WTChangeIssue() checkAttributes() WTChangeIs sueIdentity number : String name : String WTChangeIssueIdentity() assignToObject() setToObject() getIdentity()
<<Interface>> Typed
(from type)
0..1 IssuePriority HIGH : IssuePriorit y = toIssuePriority ("HIGH") ME DIUM : IssuePriority = t oIssuePriorit y(" MEDIUM" ) LOW : IssuePriority = t oIss uePriorit y(" LOW ") EMERGENCY : IssuePriority = t oIssuePriorit y(" EMERGENCY" ) 0..1 Category SAFETY_ISSUE : Category = toCategory("SAFETY_ISSUE") COST_REDUCTION : Category = toCategory("COST_REDUCTION") DESIGN_ISSUE : Category = toCategory("DESIGN_ISSUE") QUALITY_IMPROVEMENT : Category = toCategory("QUALITY_IMPROVEMENT") OTHER : Category = toCategory("OTHER")
36-30
Change Request
The following figure shows the model for change requests:
<<Abstract>> Managed
(f rom e nte rp ris ) e
<<Interface>> ChangeRequestIfc
<<Interface>> ContentHolder
(from content)
<<Interface>> ChangeItem
<<Interface>> ElectronicallySignable
(f ro m el ectroni cI den ti ty)
<<Interface>> Identified
(from fc)
<<Abstract>> ChangeRequest2
<<Interface>> Typed
(from type)
WTChangeRequest2 number : String name : String description : S tring needDate : Timestamp WTChangeRequest2() WTChangeRequest2() checkA ttributes()
0..1
Category SAFETY_ISSUE : Category = toCategory("SAFETY_ISSUE") COST_REDUCTION : Category = toCategory("COST_REDUCTION") DESIGN_ISSUE : Category = toCategory("DESIGN_ISSUE") QUALITY_IMPROVEMENT : Category = toCategory("QUALITY_IMPROVEMENT") OTHER : Category = toCategory("OTHER") RequestPriority HIGH : RequestPriority = toRequestPriority("HIGH") MEDIUM : RequestPriority = toRequestPriority("MEDIUM") LOW : RequestPriority = toRequestPriority("LOW") EMERGENCY : RequestPriority = toRequestPriority("EMERGENCY") Complexity
0..1
0..1
<<Abstract>> IdentificationObject
(from fc)
WTChangeRequest2Identity number : String name : String WTChangeRequest2Identity() assignToObject() setToObject () getIdent it y()
36-31
Change Investigation
The following figure shows the model for change investigations:
<<Interface>> ChangeAnalysisIfc
<<Interface>> ChangeItem
<<Interface>> ElectronicallySignable
(from electron icIdentity)
<<Interface>> ChangeInvestigationIfc
WTChangeInvestigation number : String name : String description : String needDate : Timestamp results : String WTChangeInvestigation() WTChangeInvestigation() checkAttributes()
<<Interface>> Typed
(from type)
36-32
Change Proposal
The following figure shows the model for change proposals:
<<Interface>> ChangeAnalysisIfc
<<Abstract>> CabinetManaged
(f rom en terprise)
<<Interface>> ContentHolder
(f rom c ontent)
<<Interface>> ChangeItem
<<Interface>> ElectronicallySignable
(f rom el ectroni cI denti ty)
<<Interface>> ChangeProposalIfc
<<Abstract>> ChangeAnalysis
<<Abstract>> ChangeProposal
<<Abstract>> IdentificationObject
(from fc)
<<Interface>> Ty ped
(from type)
WTChangeProposal number : String name : String description : String WTChangeProposal() WTChangeProposal() checkAttributes()
36-33
Analysis Activity
The following figure shows the model for analysis activities:
<<Interface>> AnalysisActivityIfc
<<Abstract>> CabinetManaged
(from enterprise)
<<Interface>> ContentHolder
(from content)
<<Interface>> ChangeItem
<<Interface>> Identified
(f rom f c)
<<Abstract>> IdentificationObject
(f rom f c)
number : String name : String des cription : String needDate : Timest amp results : String W TAnalys isAct ivit y() W TAnalys isAct ivit y() checkAtt ributes ()
WTAnalysisActivityIdentity name : String number : St ring W TAnaly sisAct ivit yIdentity() assignToObject () s etToObject() getIdentit y()
36-34
Change Order
The following figure shows the model for change orders:
<<Abstract>> Managed
(f rom enterprise)
<<Interface>> ChangeOrderIfc
<<Interface>> ContentHolder
(from content)
<<Interface>> ChangeIt em
<<Interface>> ElectronicallySignable
(from electronicIdentity)
<<Abstract>> ChangeOrder2
<<Abstract>> IdentificationObjec t
(f ro m f c)
WTChangeOrder2 number : String name : String description : String needDate : Timestamp WTChangeOrder2() WTChangeOrder2() checkAttributes()
36-35
Change Activity
The following figure shows the model for change activities:
<<Abstract>> CabinetManaged
(f ro m e nterp ri se )
<<Interface>> ChangeActivityIfc
<<Interface>> ContentHolder
(from con tent)
<<Interface>> ChangeItem
<<Interface>> ElectronicallySignable
(from electronicIdentity)
<<Interface>> Identified
(from fc)
W TChangeAct ivity2 number : String name : String description : String needDate : Timestamp WTChangeActivity2() checkAttributes() WTChangeActivity2()
WTChangeActivity2Identity number : St ring name : String W TChangeAct ivity2Ident it y() ass ignToObject() setToObject() getIdentit y()
36-36
The category to which the change object belongs. The category identifies the general reason for the suggested change (for example, a cost reduction, quality improvement, or safety issue).
complexity
The summary of the change object. This attribute is displayed on the user interface as "summary."
needDate
The target date by which the change object should be resolved and closed.
number
36-37
36-38
37
Persistence Management
This chapter describes persistence management. Topic Page
Overview ...........................................................................................................37-2 Persistence Manager..........................................................................................37-2 Query .................................................................................................................37-4 Transaction ........................................................................................................37-8 Paging................................................................................................................37-9 Referential Integrity ..........................................................................................37-9 Multi-object CRUD Persistence Manager APIs..............................................37-12 Batch (update where/delete from) Statement Capabilities ..............................37-13 Transaction Context and Listeners ..................................................................37-14 Referential Integrity Association Validation During Object Delete ...............37-15 Persistence Datastore Sequence Customization ..............................................37-16
37-1
Overview
The PersistenceManager is an interface for database access. To use the PersistenceManager, a class must implement the wt.fc.Persistable interface. By implementing Persistable, the classes have the necessary code generated to read and write data to and from the database and display its identity. Applications should access the PersistenceManager through a convenience class named PersistenceHelper. The PersistenceManager operations support events associated with the operation. Application code can listen for these events and perform some related action in the same transaction. Operations that fetch objects from the database perform access control checks on each object returned in the result set. These query operations use wt.query.QuerySpec to define the classes of objects to select from the database. QuerySpec uses the wt.query.SearchCondition class to define search criteria. That is, in the SELECT statement that is generated, the QuerySpec defines which columns to select and which tables to select from, and SearchCondition defines the WHERE clause. The fetch operations return wt.fc.QueryResult. The operations that delete, modify, and store a Persistable object all perform access control checks before continuing with the operation. These operations return the Persistable object with updated persistence information. Support for large result sets and long running queries is provided via the paging mechanism. Much like a web search, paging allows the user to execute a query and view results in pages via fetch requests. Result pages are defined in terms of an offset and range. A paging session corresponding to a specify query is available for paging fetch requests for a limited amount of time. This is due to the limited system resources that must be used to implement the paging session. Therefore, the user must be prepared to handle exceptions caused by a paging session timeout.
Persistence Manager
The PersistenceManager is the base business manager that other managers use to handle persistence. For programming convenience, a helper class has been implemented to facilitate client (and server) usage of the PersistenceManager methods. The name of the class is PersistenceHelper. The wt.fc package Javadoc
37-2
Persistence Manager
Persistence Management
37-3
Query
The wt.query package contains the following classes for creating queries which retrieve objects from the database. When used with the find operation, QuerySpec can perform both single and multiple class queries. The following sections discuss how to perform single class queries using QuerySpec, SearchCondition, and QueryResult. The last section describes how all three are used in multiple class queries. The information in this section is sufficient for most database queries. If you require more advanced SQL queries, see the Advanced Query Capabilities chapter on page 36-1.
QuerySpec
QuerySpec is used as an argument on the find and navigate operations to define the classes of objects to retrieve. The SearchCondition object (described later in this section) defines the criteria on those classes.
Since this is usually not the desired result, search conditions are used to limit the number of objects returned. For example, to add a search condition to the QuerySpec, use the following form:
QuerySpec.appendWhere(WhereExpression where, int[] classIndices)
The classIndices parameter is used to apply the search condition to the appropriate classes in the QuerySpec. The classes referenced from the SearchCondition must match the QuerySpec classes at the specified index.
The targetClass is the class of the "other side role" in the navigate. SearchConditions can be appended based on either the target or the link.
37-4
Example:
QuerySpec qs = new QuerySpec( wt.part.WTPartMaster.class, wt.part.WTPartUsageLink.class); CompositeWhereExpression where = new CompositeWhereExpression(LogicalOperator.AND); where.append(new SearchCondition(wt.part.WTPartMaster.class, wt.part.WTPartMaster.NAME,SearchCondition.EQUAL,"XYZ")); where.append(new SearchCondition(wt.part.WTPartUsageLink.class, WTAttributeNameIfc.CREATE_STAMP_NAME,true, new AttributeRange(beginTime,endTime))); qs.appendWhere(where, new int[] {0, 1});
SearchCondition
The number of objects retrieved by a QuerySpec is limited by criteria defined with SearchCondition. The most common format of a SearchCondition constructor is as follows: SearchCondition(Class targetClass, String attributeName, String operation, Object value) The targetClass can be a concrete class, abstract class, or interface. When appended to a QuerySpec, the SearchCondition is responsible for creating a WHERE clause on the query. The attributeName can be any attribute of the target class that maps to a column in the table being queried. In the case of a target class that has AutoNavigate associations to other classes, any attributes that map to columns in the base class or associated class can be used. Not all attribute types can be used in a search condition, for example, attributes stored in BLOB columns. To verify which attributes can be used, inspect the InfoReport for the target class, looking at the attributes PropertyDescriptor to ensure that its QUERY_NAME property is not null.
QueryResult
The QueryResult object is the standard container returned from all Persistence queries and navigations. QueryResult implements the standard java.util.Enumeration plus the added abilities to determine the number of objects in the QueryResult and reset the QueryResult to process it again. Example: (using the QuerySpec created in the previous section):
QueryResult qr = PersistenceHelper.manager.navigate(thePart, wt.part.WTPartUsageLink.USES_ROLE,qs,false);
Persistence Management
37-5
The QueryResult in this example will contain WTPartUsageLinks with both the WTPartMaster and WTPart roles populated because onlyOtherSide is false. If onlyOtherSide had been true, QueryResult would contain WTPartMaster objects. The SearchConditions narrow the search to only those WTPartMasters with the name of "XYZ" who had usage links created between a specified beginTime and endTime.
The difference between the two is that appendClassList() always adds a new class to the QuerySpec. If the method addClassList() is used and the specified class is already in the QuerySpec, the index of the existing class is returned. The index returned when adding (or appending) a class is used when appending a search condition for that class. When using multiple class queries, all of the classes usually should be joined to avoid redundant results. Use the following constructor for SearchCondition to join two classes:
SearchCondition(Class targetClass, String targetAttribute, Class linkClass, String linkAttribute)
When appending this type of SearchCondition to a QuerySpec, both class indexes must specify classes in the QuerySpec. When multiple classes are in the QuerySpec, the elements in the QueryResult will no longer be Persistable objects. If the full object is selected (via the isSelectable argument, then the QueryResult elements will be an array of wt.fc.Persistable objects (that is, Persistable[]). The array is needed because more than one class can be returned. The exact type of the element will be Persistable[]. If any attributes of the class are selected, then the QueryResult elements will be an array of java.lang.Object objects (that is Object[]). When adding (or appending) a class, the boolean parameter isSelectable specifies whether objects of that class will be returned in the QueryResult. The QueryResult Persistable array will have the same order as the classes in the QuerySpec. However, classes that are not Selectable will not appear in the QueryResult. For example, if the QuerySpec contains the classes W, X, Y, and Z with X and Z selectable, the QueryResult Persistable array will contain X and Z. All of the classes in a multiple class query are subject to Access Control regardless of whether objects of that class are returned in the QueryResult.
37-6
Example:
QuerySpec qs = new QuerySpec(); // Append the classes int partIndex = qs.appendClassList(wt.part.WTPart.class, true); int viewIndex = qs.appendClassList(wt.vc.views.View.class, true); // Join the WTPart class to the View class via the View object ID and // the WTPart Foreign Key SearchCondition sc = new SearchCondition( wt.part.WTPart.class, wt.part.WTPart.VIEW + "." + wt.vc.views.ViewReference.KEY + "." + wt.fc.ObjectIdentifier.ID, wt.vc.views.View.class, WTAttributeNameIfc.ID_NAME); qs.appendWhere(sc, new int[] { partIndex, viewIndex }); QueryResult result = PersistenceHelper.manager.find(qs); while(result.hasMoreElements()) { Persistable[] persistableArray = (Persistable[]) result.nextElement(); wt.part.WTPart part = (wt.part.WTPart) persistableArray[partIndex]; wt.vc.views.View view = (wt.vc.views.View) persistableArray[viewIndex]; }
Persistence Management
37-7
Transaction
Transaction objects provide a mechanism that supports the standard concept of a database transaction. It has the following methods:
start
After a transaction is started, all subsequent database inserts, deletes, and updates are part of that transaction.
commit
Discards the pending database operations. The pattern for a method that can throw WTException is as follows:
Transaction trx=new Transaction(); try { trx.start(); <your code here> trx.commit(); trx=null; } finally { if (trx!=null) trx.rollback(); }
If you create a transaction in which to perform some activities but never reach your commit statement, be sure you mark the current transaction for rollback. Someone else may accidentally ground out an exception and later try to commit your partially completed work. The rollback call in a finally block, marks any enclosing transaction so partial results cannot be accidentally committed later. If code following notices a problem and calls rollback, the database is safe but, if your code is the deepest transaction, it is your responsibility to call rollback if you do not get to your commit call. Because you may not know for certain if your code is the deepest transaction at the time an exception is thrown, you should always do it.
37-8
Paging
The basic idea behind paging is the concept of a "snapshot" query. When a paging session is opened, a "snapshot" is taken of the results. These results can then be fetched in pages over multiple calls. When all desired fetches are complete, the paging session should be closed. This cleans up any data associated with the paging session to free system resources. These system resources are significant so a timeout property exists. If the timeout limit is reached, then the paging session is automatically closed. Any further fetch requests would result in an exception. Another configurable property is the paging limit (there is a system wide value and this value can also be overridden when opening a paging session). Because of the system resource required, a limit can be set such that if the result set size of the "snapshot" query is less than this value, then all of the results are returned immediately and no paging session is established. Note also that the results of the initial "snapshot" query are access controlled. Only data that the user can access (i.e. data that the user has read permission for) will be stored for subsequent page requests. In addition, the total count of the size of the result set will also be returned when the paging session is opened. This "snapshot" behavior is important to understand in terms of how the underlying query results can change. Consider a paging session that is established and a total paging size of 50 is available for fetch requests. The first 25 objects are returned and displayed to the user. The set of data can be modified by other user operations. For example, another user could delete an object in the second set of 25 objects. Now when a fetch request is made for objects 25 through 50, the object that was deleted will not be available. The paging results will still contain 25 elements. However, for the object that was deleted, a null value would be returned in the paging results. Another situation can occur for updates. Consider a paging session that is established for a query that returns data where a numeric attribute of an object is less than some value. Between the time that the paging session was opened and a subsequent fetch request, an object from the results could have been modified and the numeric attribute changed such that it no longer meets the original querys criteria. Yet, it would still be part of the paging session results because it did meet the criteria at the time that the paging session was established. This is another reason for the timeout limit on paging sessions. The definition of the "snapshot" query uses the same query constructs as normal queries. Both QuerySpec and CompoundQuerySpec objects can be specified. The classes or column expressions that are selected will be returned in the fetch requests. Criteria and sorting will be applied when executing the "snapshot" query. The sorting (if any is specified) will be maintained on fetch requests. When specifying a sort on a QuerySpec that will be paged, each ColumnExpression must have a unique column alias. This should be specified using the ColumnExpression.setColumnAlias() method. The actual fetch requests return a PagingQueryResult, which is a sub-class of QueryResult. The PagingQueryResult has additional paging attributes such as the paging session ID (used for subsequent fetch requests) and the total paging size.
Persistence Management
37-9
The Paging APIs are specified as static methods in the wt.fc.PagingSessionHelper class (see the wt.fc.PagingSessionHelper class entry in your installed Windchill Javadoc for more information). There are several types of APIs that are available for opening a paging session, fetching from a paging session, and closing a paging session. The following example shows how these methods can be used to perform an interactive paging session for an arbitrary query passed to the method as an argument. The method consists of a while loop that prompts the user for an offset and range for a fetch request (or to end the paging session). The first time through the loop the paging results are null so the paging session is opened. The paging session ID and total paging count values are then stored in local variables. The paging session ID will be used to execute fetch requests and eventually close the paging session. If the paging session has already been opened, then a fetch is made using the offset and range. The paging results are then displayed along with the offset, range, and total count. The last piece of code in the loop checks the paging session ID to ensure that a paging session has been established. If the query returned no results or the paging limit was not reached, then no paging session would exist. This entire loop is enclosed in a try/finally block to ensure that the paging session is always closed (if one has been established).
public void executePaging(QuerySpec a_querySpec) throws WTException, WTPropertyVetoException { long pagingSessionId = 0; try { PagingQueryResult pagingResults = null; int offset = 0; int range = 0; int totalCount = 0; boolean done = false; while(true) { // Prompt user for offset and range offset = ..; range = ..; done = ..; if(done) { break; } if(pagingResults == null) { // Open Paging Session pagingResults = PagingSessionHelper.openPagingSession( offset, range, a_querySpec); pagingSessionId = pagingResults.getSessionId(); totalCount = pagingResults.getTotalSize(); else { pagingResults = PagingSessionHelper.fetchPagingSession(
37-10
offset, range, pagingSessionId); } // Display QueryResult items System.out.println("Displaying " + offset + " to " + (offset + range) + " of " + totalCount); if(pagingSessionId <= 0) { // No paging session was established break; } } } finally { if(pagingSessionId > 0) { PagingSessionHelper.closePagingSession(pagingSessionId); } } }
Persistence Management
37-11
Referential Integrity
The persistence layer supports associations between two Persistable objects via classes extending wt.fc.BinaryLink. For these associations, the persistence layer also supports enforcing referential integrity as specified in the associations modeled properties. The Rose Information Modeler supports Association Specification model properties, "Owner" and "Cascade", on the "Windchill A" and "Windchill B" tabs for the corresponding role . Both properties will be boolean options. The persistence layer will uses these properties when an object is removed. If the "Owner" property is true, then the persistence layer will remove the link object associated with the removed object. If the "Owner" property is false, then the persistence layer does not implicitly remove the link object when the object is removed, but it will verify that this association does not exist before the transaction is allowed to commit. The "Cascade" property is used only when an association link object is removed. If the "Cascade" property is true, then the persistence layer will cascade the remove operation to the associated role object. This occurs when the link is removed via a direct call or via the "Owner" processing. The default value for all roles is "Owner=true" and "Cascade=false". The role A and role B settings are independent of each other, and any combination is valid. When extending an association, the sub-class will inherit these role attributes from the parent, but the values can still be explicitly overridden in the sub-class.
37-12
When to use
The batch update/delete operations represent the most performant option for affecting change in the database because they minimize both the data needed to perform the operation and the data needed to affect the change neither requires that the objects to be changed first be retrieved from the database and only the columns to change need to be sent (as opposed to full persistables) in the case of an update.These APIs should be considered when: There is no need to bring the object back into the VM, either to perform tests or to dispatch events None of the objects involved in the batch operation exist in memory prior to the batch operation
In most cases, it is sufficient to say that their use should be limited only to cases where there is never a need to bring the object or its reference back to memory and should never be used on objects already in memory. The above guidelines are based on the fact that the performance benefits drop when the data is actually needed and by the fact that the changes won't be reflected in any of the in-memory objects. However, a gray area for batch update is in cases where the references are needed for event dispatch, the dispatched event indicates that the change has occurred, and the listeners need not inflate.
Persistence Management
37-13
37-14
// Set up to receive service events getManagerService().addEventListener(myListener, PersistenceManagerEvent.generateEventKey (PersistenceManagerEvent.POST_DELETE)) } public static MyCache getMyCache() { if (myCache == null) { try { return new MyCache(); } catch (RemoteExcepiton re) { // do something } } return myCache; } } // class which implements the actual cache public class MyCache extends CacheManager { public MyCache() { super(); } }
Persistence Management
37-15
Background
Windchill uses datastore schema objects to implement a sequence. In Oracle, this is implemented directly as a sequence schema object. In SQLServer, this is implemented as a table and access stored procedure.
Scope/Applicability/Assumptions
This documentation assumes that the Windchill Information Modeler (i.e. Rose) has been successfully installed and configured. Assume you have access to the Windchill datastore directory, <WindchillHome>/db, and access rights to execute DDL scripts in the target datastore.
Intended Outcome
The end result of this solution is the creation of a datastore sequence.
Solution
Model a sequence class using Information Modeler.
Solution Elements
Element
Type
Description
<MySequence>
Java class
37-16
2. Specify the sequence properties. Open the Class Specification dialog for the class, select the "Windchill" tab, and choose the "Sequence" value from the "Set" drop down list. Specify the initial seed and increment values if the defaults are not sufficient.
Persistence Management
37-17
3. Generate the model elements. 4. Execute the sequence DDL. From a Windchill shell, execute:
<WindchillHome>/db/execute_sql_script.bat <MyPackage>/create_<MySequence>_sequence.sql
Limitations
None.
Packaged Samples
None.
37-18
38
Advanced Query Capabilities
This chapter describes advanced query capabilities supported in the wt.query package. These capabilities support advanced SQL queries and you are assumed to be familiar with the functionality and behavior of advanced SQL statements. Note: See your installed Windchill Javadoc entries for the wt.query package for further information, including database-specific support for SQL functions and keywords. Topic Page
38-1
QuerySpec
The QuerySpec contains the following attributes and APIs for building complex query expressions.
ClassAttribute
This class represents a class attribute that can be used in a SQL statement. Introspection information is used to determine the associated table and column.
38-2
Column Expression
Description
SQLFunction
0 or more. This number is based on the sum of the required from indices of all arguments. 0 0
ConstantExpression KeywordExpression
This class represents a constant in a SQL statement. This class represents an expression that evaluates to a SQL keyword that can be used in a SQL statement. This class represents a table column that can be used in a SQL statement. The exact table and column name specified are used directly in the SQL statement.
TableColumn
Note that when the WTPart class is appended to the query, the selectable parameter is false. The full object is not returned; only the number column is returned. Results are still returned in the QueryResult object. Each element of the QueryResult corresponds to a row and is an Object array (that is, Object[]). In this example, the number column is at index 0 for each element. The actual Java type for each result is based on the table column and the JDBC SQL-to-Java type mapping. The behavior of queries for parent classes (that is, classes that have one or more persistable, concrete subclasses) is to execute SQL for each table. When only ColumnExpressions are included in the SELECT clause, all of these SQL statements are implicitly executed as a single UNION statement instead of multiple separate database queries. Queries that include only column expressions still have Access Control applied. Internally, columns are added to the query to retrieve information needed for Access Control. When queries containing only columns are used as sub-selects as part of an ObjectReference query (described later in this section), then the Access Control columns are not added. This behavior is important to understand when using aggregate SQL functions. When these are used, the SELECT clause must contain only expressions with aggregate SQL functions (or the expression must be included in the GROUP BY clause. If Access Control is applied to such a statement, then it will result in invalid SQL.
38-3
ClassViewExpression
SubSelectExpression
ExternalTableExpression
The following example builds a query against a non-modeled table named dual:
QuerySpec qs = new QuerySpec(); int fromIndex = qs.appendFrom(new ExternalTableExpression("dual")); TableColumn dummyColumn = new TableColumn("dual", "dummy"); SQLFunction currentDate = SQLFunction.new SQLFunction(SQLFunction.SYSDATE); qs.appendSelect(dummyColumn, new int[] { fromIndex }, false); qs.appendSelect(currentDate, null, false);
38-4
appendWhere(WhereExpression a_expression, TableExpression[] a_tableExpressions, String[] a_aliases) The following are concrete WhereExpression implementations: SearchCondition This class represents a search condition on a query. When appended to a QuerySpec, the values will be used in the SQL WHERE clause. This class represents an EXISTS expression in a WHERE clause. A StatementSpec instance is used for the subselect. This class represents a number of WHERE expressions connected using a logical operator (i.e. AND/OR). This class represents a negation of an expression in a WHERE clause. This class contains an aggregated WhereExpression that is preceded with a NOT when this expression is evaluated.
ExistsExpression
CompositeWhereExpression
NegatedExpression
The fromIndices parameter is used to associate the WHERE expression operands with tables in the FROM clause. Similar to the appendSelect() method, the fromIndices array is based on the types of WhereExpression and ColumnExpressions used in those WhereExpressions. For example, a SearchCondition with a ClassAttribute and a ConstantExpression would require a single from index. A CompositeWhereExpression containing three SearchConditions would require fromIndices array with size equal to the sum of the size needed for each SearchCondition. The following example demonstrates the proper usage of the fromIndices. This code queries for parts and their associated alternate parts. A composite where expression is used with several criteria: the second through fourth characters of the associated part numbers are equivalent, the part name begins with "E", or the alternate part name begins with "E". This first section of code sets up the classes in the query, the select items, and the joins between the classes.
QuerySpec qs = new QuerySpec(); int partIndex = qs.appendClassList(wt.part.WTPartMaster.class, false); int alternatePartIndex = qs.appendClassList(wt.part.WTPartMaster.class, false); int linkIndex = qs.appendClassList(wt.part.WTPartAlternateLink.class, false); // Define the attributes in the query ClassAttribute partName = new ClassAttribute(wt.part.WTPartMaster.class, wt.part.WTPartMaster.NAME);
38-5
ClassAttribute alternatePartName = new ClassAttribute(wt.part.WTPartMaster.class, wt.part.WTPartMaster.NAME); ClassAttribute partNumber = new ClassAttribute(wt.part.WTPartMaster.class, wt.part.WTPartMaster.NUMBER); ClassAttribute alternatePartNumber = new ClassAttribute(wt.part.WTPartMaster.class, wt.part.WTPartMaster.NUMBER);
// Define constants used in the criteria ConstantExpression subStringStart = new ConstantExpression(new Long(2)); ConstantExpression subStringEnd = new ConstantExpression(new Long(4)); ConstantExpression wildcardExpression = new ConstantExpression("E% [ ]"); // Add items to the select and join the classes qs.appendSelect(partName, new int[] { 0 }, false); qs.appendSelect(alternatePartName, new int[] { 1 }, false); qs.appendJoin(linkIndex, wt.part.WTPartAlternateLink.ALTERNATES_ROLE, partIndex); qs.appendJoin(linkIndex, wt.part.WTPartAlternateLink.ALTERNATE_FOR_ROLE, alternatePartIndex);
In this next section, the criteria are constructed and appended to the query. Note that the first SearchCondition uses two ClassAttribute instances. The corresponding indices must be added to the fromIndices array that is used in the appendWhere. Likewise, the second SearchCondition references the part class and the third SearchCondition references the alternate part class. Therefore, four fromIndices are required and each array element must correspond to the appropriate SearchCondition.
CompositeWhereExpression orExpression = new CompositeWhereExpression(LogicalOperator.OR); orExpression.append(new SearchCondition( SQLFunction.newSQLFunction(SQLFunction.SUB_STRING, partNumber, subStringStart, subStringEnd), SearchCondition.EQUAL, SQLFunction.newSQLFunction(SQLFunction.SUB_STRING, alternatePartNumber, subStringStart, subStringEnd))); orExpression.append(new SearchCondition( partName, SearchCondition.LIKE, wildcardExpression)); orExpression.append(new SearchCondition( alternatePartName, SearchCondition.LIKE, wildcardExpression)); qs.appendWhere(orExpression, new int[] { partIndex, alternatePartIndex, partIndex, alternatePartIndex });
The last API explicitly specifies table expressions and aliases for the WHERE expression operands. This API is used for correlated subselects. When using subselects, it is common to use correlated columns (that is, a join between a column in the outer select and a column in the subselect). This is supported using the appendWhere() API in which TableExpressions and aliases are passed explicitly. For WhereExpressions that do not involve a subselect, the TableExpressions and aliases are derived implicitly using the QuerySpec FROM clause and the specified indices. The following example builds a query using an EXISTS clause and a correlated subselect. The query will return all PartMasters for which an alternate PartMaster
38-6
does not exist. An alternate is represented by the WTPartAlternateLink class, which is a many-to-many association between PartMasters. The role A of the WTPartAlternateLink class specifies the current PartMaster and the role B specifies the alternate PartMaster. Following is the SQL for this query:
SELECT A0.* FROM WTPartMaster A0 WHERE NOT (EXISTS (SELECT B0.ida2a2 FROM WTPartAlternateLink B0 WHERE (A0.ida2a2 = B0.ida3a5)))
The following code constructs the query specification. The outer select will return PartMaster objects.
QuerySpec select = new QuerySpec(); int partIndex = select.appendClassList(wt.part.WTPartMaster.class, true);
The following code constructs the subselect. The alias prefix is changed to avoid conflicts with the outer select.
QuerySpec subSelect = new QuerySpec(); subSelect.getFromClause().setAliasPrefix("B"); int altIndex = subSelect.appendClassList(wt.part.WTPartAlternateLink.class, false); subSelect.appendSelect(new ClassAttribute( wt.part.WTPartAlternateLink.class, WTAttributeNameIfc.ID_NAME), new int[] { altIndex }, true);
The following code explicitly sets up the TableExpressions and aliases, which are passed as arrays. The join will be from the outer select to the subselect so the outer select values are placed in the arrays at index 0 and the subselect values are placed in the array at index 1. The arrays are then used to append the SearchCondition.
TableExpression[] tables = new TableExpression[2]; String[] aliases = new String[2]; tables[0] = select.getFromClause().getTableExpressionAt(partIndex); aliases[0] = select.getFromClause().getAliasAt(partIndex); tables[1] = subSelect.getFromClause().getTableExpressionAt(altIndex); aliases[1] = subSelect.getFromClause().getAliasAt(altIndex); SearchCondition correlatedJoin = new SearchCondition( wt.part.WTPartMaster.class, WTAttributeNameIfc.ID_NAME, wt.part.WTPartAlternateLink.class,WTAttributeNameIfc.ROLEA_OBJECT_ID); subSelect.appendWhere(correlatedJoin, tables, aliases);
38-7
Bind Parameters
Bind parameters are a database/JDBC feature to take advantage of database statement preparsing and optimization. Bind parameters are a mechanism for replacing constants in a SQL statement with replacement parameters at execution time. For example, the following WHERE clause expression uses the constant Engine: WTPartMaster.name = Engine This expression can be replaced with the following in the static SQL: WTPartMaster.name = ? and the value Engine can be bound to the parameter ? at execution time. On a subsequent execution, a new value, such as Cylinder, can be bound to that same parameter. If these two statements had used the constant value directly in the static SQL, each statement would have been parsed, optimized, and precompiled separately. When bind parameters are used, a single static SQL statement can be reused multiple times. This bind parameter feature is implicitly supported when using the QuerySpec, SearchCondition, and other query classes. However, the bind parameters can also be explicitly accessed using the following APIs: getBindParameterCount() getBindParameterAt(int a_index) setBindParameterAt(Object a_value, int a_index)
Query Limit
A QuerySpec attribute, "queryLimit", can be used to limit the results returned from a query. As the database results are processed, a count is kept for each item in the result set. This count includes items filtered out due to Access Control. If the limit is reached, then a PartialResultException will be thrown. This exception will contain a QueryResult with the items that have been processed. This could be used in a situation where a client may choose to display these results after issuing a message that a query limit was reached.
38-8
SearchCondition
A SearchCondition represents a SQL WHERE clause expression of the following form: <left side operand> <operator> <right side operand> The following are examples:
MyTable.Column1 = 5 MyTable.Column2 LIKE "E%" MyTable.Column3 = JoinTable.Column1
Operands can also be more complex, such as SQL functions or subselects. SearchCondition can use arbitrary RelationalExpression operands. The operands can be specified using the SearchCondition constructor or setter methods. The following are concrete ColumnExpression implementations: ClassAttribute This class represents a class attribute that can be used in a SQL statement. Introspection information is used to determine the associated table and column. This class represents a SQL function within a SQL statement. This class represents a subselect that can be used in a SQL statement. The subselect is specified via a StatementSpec attribute. This class represents a constant in a SQL statement. This class represents an expression that evaluates to a SQL keyword that can be used in a SQL statement. This class represents a range in a SQL WHERE clause. This class represents a date constant in a SQL statement. This subclass of ConstantExpression is necessary to provide the special handling for date values. This class represents an array of constants in a SQL IN clause. This class represents a table column that can be used in a SQL statement. The exact table and column name specified are used directly in the SQL statement.
SQLFunction SubSelectExpression
ConstantExpression KeywordExpression
RangeExpression DateExpression
ArrayExpression TableColumn
38-9
The following example builds a complex query to determine the WTPartMaster object with the oldest modify timestamp after a specified date cutoff. Following is the SQL for this query:
SELECT A0.* FROM WTPartMaster A0 WHERE (A0.modifyStampA2 IN (SELECT MIN(B0.modifyStampA2) FROM WTPartMaster B0 WHERE B0.modifyStampA2 > cutoff) )
QuerySpec select = new QuerySpec(); int index = select.appendClassList(targetClass, true); select.appendWhere(new SearchCondition(modifyStamp,SearchCondition.IN, new SubSelectExpression(subSelect)), new int[] { index });
Compound Query
A compound query is a SQL statement that combines more than one component query into a single SQL statement via a set operator. Set operators include UNION, UNION ALL, INTERSECT, and MINUS. A compound query is composed by specifying a set operator and adding component queries. The component queries are StatementSpec objects so nesting of compound queries is also supported. Note: The current version of the Oracle JDBC driver contains a bug that prohibits using parentheses around component statements in a nested compound query. The setting of the wt.pom.allowCompoundParentheses property in the db.properties file controls whether parentheses are used. By default, this setting is false to avoid the Oracle JDBC driver bug. This workaround could lead to unexpected results if the set operator precedence is significant. The following example builds a compound query to return a specific PartMaster number and the numbers of all of its alternates. Note that only numbers are selected, not full objects. This is necessary because, if all subclasses are considered, the compound query statement must include all subclass tables. These subclass tables may contain additional columns that would make the select list for
38-10
each statement incompatible with other component statements. SQL requires that each component query in a compound statement must have the same number and corresponding type in the select list. Following is the SQL for this query:
SELECT A0.number FROM WTPartMaster A0 WHERE (A0.name = ENGINE') UNION SELECT A2.number FROM WTPartMaster A0,WTPartAlternateLink A1,WTPartMaster A2 WHERE (A0.name = ENGINE') AND (A0.idA2A2 = A1.idA3A5) AND (A2.idA2A2 = A1.idA3B5)
The following code constructs the query specification. The first select constructed is for PartMasters with the name ENGINE.
QuerySpec partSelect = new QuerySpec(); int partIndex = partSelect.appendClassList(wt.part.WTPartMaster.class, false); partSelect.appendWhere(new SearchCondition(wt.part.WTPartMaster.class, WTPartMaster.NAME, SearchCondition.EQUAL, "ENGINE"), new int[] { partIndex });
The next select is constructed for returning PartMaster alternates. An alternate is represented by the WTPartAlternateLink class, which is a many-to-many association between PartMasters. A join must be specified across this association from the original part to its alternates.
QuerySpec altSelect = new QuerySpec(); partIndex = altSelect.appendClassList(wt.part.WTPartMaster.class, false); int altIndex = altSelect.appendClassList(W wt.part.WTPartAlternateLink.class, false); int altPartIndex = altSelect.appendClassList(wt.part.WTPartMaster.class, false); altSelect.appendSelect(new ClassAttribute( wt.part.WTPartMaster.class, wt.part.WTPartMaster.NUMBER), new int[] { altPartIndex }, false); altSelect.appendWhere(new SearchCondition(wt.part.WTPartMaster.class, WTPartMaster.NAME, SearchCondition.EQUAL, "ENGINE"), new int[] { partIndex }); altSelect.appendJoin(altIndex, wt.part.WTPartAlternateLink.ALTERNATES_ROLE, partIndex); altSelect.appendJoin(altIndex, wt.part.WTPartAlternateLink.ALTERNATE_FOR_ROLE, altPartIndex);
Finally, the compound statement is constructed using the two previous queries and the UNION set operator.
38-11
This is done to ensure that Access Control is not bypassed unknowingly. In some cases, the use of these advanced SQL features that bypass Access Control is legitimate. For these cases, the advanced checking can be disabled at runtime. Query specification classes support an "advancedQueryEnabled" attribute that can only be set from server side code. If applicable, the attribute should be set to true on the query instance that is passed to the PersistenceManager query/find API to allow these queries to be executed without throwing an exception. // Use advanced APIs to build query. // Disable checking of advance features statement.setAdvancedQueryEnabled(true); // Execute query with access control PersistenceHelper.manager.find(statement); The find() method executes the statement with access control. Therefore, Access Control related columns may be implicitly added to the select. For some advanced features, such as aggregate functions, INTERSECT, and MINUS, the addition of these columns can affect the expected results or cause a SQL exception. In these cases, to successfully execute the query, the server side, nonaccess controlled query() method should be used.
38-12
PersistenceServerHelper.manager.query(statement);
Sorting
Queries can be used to sort the result data at the database level. However, in general, database sorting should only be applied to paging queries and queries that involve only ColumnExpressions. Other types of queries may be implemented as several separate SQL statements so the sorting is only applied to the individual statements and not the complete query. Any ColumnExpression can be used as a sort column. The OrderBy item is used to pass the ColumnExpression to the StatementSpec. The OrderBy also indicates the sort order (ascending or descending) and optionally a Locale. If a Locale is specified, then any character based attributes are sorted with respect to that Locale using the database language support. For Oracle, this is the National Language Support (NLS) (see Oracle documentation for more information). Java Locale values are mapped to Oracle NLS linguistic sort names via dbservice.properties entries. Sorting is supported for standard and compound queries via QuerySpec and CompoundQuerySpec methods.
QuerySpec.appendOrderBy(OrderBy a_orderBy, int[] a_fromIndicies) CompoundQuerySpec.appendOrderBy(OrderBy a_orderBy)
The QuerySpec method validates the ColumnExpression contained in the OrderBy against the QuerySpecs FROM clause. The CompoundQuerySpec method does not validate. Note that neither method handles appending the ColumnExpression to the SELECT clause of the statement. This still must be done via the appendSelect() method. In both cases, it is recommended that a column alias be set for each ColumnExpression that is contained in an OrderBy. Depending on the type of query and the number of subclasses involved, the actual SQL statements may not be valid if a column alias is not used. Note that the column alias must not be a SQL reserved word (e.g., "number"). The following example builds a compound query using sorting. The names of parts and documents are returned sorted by name. Following is the SQL for this query:
SELECT A0.bname sortName FROM WTPart A0 UNION SELECT A0.bname sortName FROM WTDocument A0 ORDER BY sortName DESC
The following code constructs the query specification. The first component query is for Parts. Note the setting of the column alias.
String sortName = "sortName"; QuerySpec partQuery = new QuerySpec(); int classIndex = partQuery.appendClassList(wt.part.WTPart.class, false); ClassAttribute partName = new ClassAttribute(wt.part.WTPart.class,
38-13
This next section constructs the Document portion of the query. The same column alias is used.
QuerySpec docQuery = new QuerySpec(); classIndex = docQuery.appendClassList(wt.doc.WTDocument.class, false); ClassAttribute docName = new ClassAttribute(wt.doc.WTDocument.class, wt.doc.WTDocument.NAME); docName.setColumnAlias(sortName); docQuery.appendSelect(docName, new int[] { classIndex }, false);
Finally, the compound query is constructed using these two component queries. The OrderBy is appended to the overall query. The default locale is used to sort the names with respect to the users language.
CompoundQuerySpec query = new CompoundQuerySpec(); query.setSetOperator(SetOperator.UNION); query.addComponent(partQuery); query.addComponent(docQuery); query.appendOrderBy(new OrderBy(partName, true ));
Join Support
Query joins are used for associating data contained in separate tables. Joins can be accomplished by using the PersistenceManager navigate methods or through adhoc WhereExpressions. The QuerySpec class also provides explicit support for appending a join to a query using link classes and roles defined in the Rose model. This offers the flexibility of the QuerySpec along with the simplicity of specifying query joins using model information. The following QuerySpec methods can be used.
appendJoin(int a_linkIndex, String a_role, Persistable a_source) appendJoin(int a_linkIndex, String a_role, int a_targetIndex)
The following example builds a query that joins together the SubFolder and Part classes via the FolderMembership link. The query returns all folders and all of the associated parts that are contained in the folder. The following code constructs the query specification. The first section adds the classes and the attributes that should be returned. The final two lines of code join together the classes using the modeled roles for the FolderMembership link class.
QuerySpec query = new QuerySpec(); int folderIndex = query.appendClassList(wt.folder.SubFolder.class, false); int linkIndex = query.appendClassList(wt.folder.FolderMembership.class, false); int partIndex = query.appendClassList(wt.part.WTPart.class, false);
38-14
query.appendSelect(new ClassAttribute(wt.folder.SubFolder.class, wt.folder.SubFolder.NAME), new int[] { folderIndex } , false); query.appendSelect(new ClassAttribute(wt.part.WTPart.class, wt.part.WTPart.NAME), new int[] { partIndex }, false); query.appendJoin(linkIndex, wt.folder.FolderMembership.FOLDER_ROLE, folderIndex); query.appendJoin(linkIndex, wt.folder.FolderMembership.MEMBER_ROLE, partIndex);
38-15
38-16
39
Internationalization and Localization
Internationalization is the process of designing and developing an application that can be easily adapted to the cultural and language differences of locales other than the one in which the application was developed. Localization is the process of adapting an application to fit the culture and language of a specific locale. All Windchill applications are fully internationalized and ready to be localized. Windchill applications are delivered with a default locale of US English (en_US). This chapter describes how to localize text visible to the user by using resource bundles. Topic Page
Background .......................................................................................................39-2 The Windchill Approach ...................................................................................39-3 Localizing Text Visible to the User ..................................................................39-5 Resource Info (.rbInfo) Files .............................................................................39-8
39-1
Background
Changing an application for use in another country or culture is often thought of as merely translating the language that appears in the user interface. There are many other aspects, however, that you should consider when developing a global application. How will you identify the preferred language and geographic location of the userYou may want to design into the application (or underlying product architecture) the ability to determine the locale and present the appropriate version from a collection of different localized versions. What data used within your application is sensitive to localeConsider the use of decimals within numbers, currency symbols, date formats, address styles, and system of measurement. How should data be formattedConsider the order in which text and numbers are read by different audiences. Languages that display numbers from left to right and text from right to left affect the layout of menu bars and text entry fields. The grammar of a language may dictate different placement of variables in error messages. Collation of sortable lists Consider how different alphabets affect the collation sequence and how collation of typical list elements is done in the locales of potential users of your application. Non-Roman alphabets Your application must be able to accommodate different fonts and different sizes of fonts. This again can affect the layout of menu bars and text entry fields. What are the cultural sensitivities toward graphics and use of colorWhen designing icons or other graphics, and deciding on background and other colors, consider whether they may be objectionable in another culture Both client and server developers need to be aware of these factors. You must be able to localize not only the GUI, but also feedback messages and exceptions that might be displayed to the user.
39-2
39-3
Handling local customs The java.text package provides classes that convert dates and numbers to a format that conforms to the local conventions. This package also handles sorting of strings. java.text.NumberFormat. formats numbers, monetary amounts, and percentages. java.text.DateFormat contains the names of the months in the language of the locale and formats the data according to the local convention. This class is used with the TimeZone and Calendar classes of the java.util package. TimeZone tells DateFormat the time zone in which the date should be interpreted and Calendar separates the date into days, weeks, months, and years. All Windchill dates are stored by the server in the database based on a conversion to Greenwich Mean Time. To display Timestamps in the correct Timezone, the application programmer should use wt.util.WTContext to set the Timezone in the DateFormat as follows:
DateFormat df = DateFormat.getDateTimeInstance( DateFormat.SHORT, DateFormat.SHORT,WTContext.getContext().getLocale() ); df.setTimeZone(WTContext.getContext().getTimeZone()); System.out.println("The current time is: " + df.format(new Timestamp(current_time_millis)));
39-4
associates the label defined internally as lblUser with the string found in the resource bundle that corresponds to the lblUser key; that is,
{"lblUser","User"},
39-5
public void addNotify() { //Localize localize(); } //{{DECLARE_CONTROLS //}} //{{DECLARE_MENUS //}} } private void localize() { RB=ResourceBundle.getBundle("wt.clients.administrator.LabelsRB" ,getLocale()); lblUser.setText(RB.getString("lblUser") + ":"); btnSearch.setLabel(RB.getString("btnSearch")); btnCreate.setLabel(RB.getString("btnCreate")); btnUpdate.setLabel(RB.getString("btnUpdate")); btnAddUsertoGroup.setLabel(RB.getString "btnAddUsertoGroup")); btnView.setLabel(RB.getString("btnView")); btnDelete.setLabel(RB.getString("btnDelete")); btnClose.setLabel(RB.getString("btnClose")); try { //MultiList column headings java.lang.String[] tempString = new java.lang. String[4]; tempString[0] = RB.getString("Full Name"); tempString[1] = RB.getString("UserID"); tempString[2] = RB.getString("Web Server ID"); tempString[3] = RB.getString("E-Mail"); lstUsers.setHeadings(tempString); } catch (PropertyVetoException e) {} }
39-6
{"lblEmail","E-Mail"}, {"lblFullName","Full Name"}, {"lblGroup","Group"}, {"lblGroupName","Group Name"}, {"lblID","*ID"}, {"lblLocale","Locale"}, {"lblModify","Modify"}, {"lblName","Name"}, {"lblRead","Read"}, {"lblState","State"}, {"lblStreet1","Street1"}, {"lblStreet2","Street2"}, {"lblTitle","Title"}, {"lblUse","Use"}, {"lblUser","User"}, {"lblUserName","User Name"}, {"lblZip","Zip"}, //Button Labels {"btnAdd","Add>>"}, {"btnAddAll","Add All>>"}, {"btnAddRemove","Add/Remove Members"}, {"btnAddUsertoGroup","Add User to Group"}, {"btnApply","Apply"}, {"btnCancel","Cancel"}, {"btnClear","Clear"}, {"btnClose","Close"}, {"btnCreate","Create"}, {"btnDelete","Delete"}, {"btnGenerate","Generate Now"}, {"btnNewGroup","New Group..."}, {"btnNewUser","New User..."}, {"btnOK","OK"}, {"btnRefresh","Refresh"}, {"btnRegenerate","Regenerate"}, {"btnRemove","< {"btnRemove","<
To create a different localization for this resource bundle, for example, French, you would create a new class in the wt.clients.administrator package called LabelsRB_fr. This class would contain the same label keys, such as "lblAdministrative" but its value would be "administratif" rather than "Administrative". All the other values would likewise be changed to their French counterparts. You would compile the new class; then the Java runtime would be able to find a French resource bundle for the Administrator client.
39-7
RbInfo files are converted to compiled Java class files in the integration process, so that the same naming convention rules apply to rbInfos as resource bundles. (Localized versions are kept in separate files; there is one resource file per language, the name of the locale is appended to the name of the localized files.) The format of the rbInfo files is PTC-specific. It was designed primarily for Windchill, but can be used in other Java-based products as well. The migration from resource bundles to rbInfo files is seamless; there is no need to change the source code. Old resource bundles can be converted to rbInfo format using a relatively straightforward process. To find out more about the migration, refer to the Windchill Upgrade and Migration Guide.
Message Text
*RB.rbInfo *Resource.rbInfo
*RB.class *Resource.class
39-8
<package>ModelRB.rbInfo <EnumType>RB.rbInfo
<package>ModelRB.RB.ser <EnumType>RB.RB.ser
<key>.value <key>.constant
The localizable text that will be displayed. A string that will be used to generate a constant field into the runtime resource bundle, which can be used by code that does resource lookups. A comment describing the entry. A comment for each substitution argument of the value string. Indicates whether the resource entry is customizable. Indicates (to the developer) whether the resource entry is deprecated. Reserved for future use. Reserved for future use.
Required Message text: Optional Metadata: Unused EnumeratedType: Unused Optional Optional Optional Optional Unused Unused
39-9
Key
Description
Usage
Reserved for future use. Reserved for future use. Explicit sort order for the value, unused for alpha ordering.
<key>.defaultValue
Specifies the value is the default value for the Enumerated Type.
<key>.selectable
Each resource info file must contain the following lines that define certain file level information.
ResourceInfo.class=wt.tools.resource.StringResourceInfo ResourceInfo.customizable=false ResourceInfo.deprecated=false
The first line classifies the resource info and should never be changed. The values of the second and third lines can be changed by the owner of the package, if the file can be customized, and/or the file is deprecated.
39-10
39-11
39-12
40
Customizing Archive, Purge, and Restore
Archive and Purge allow you to remove data from your Windchill system while preserving a reasonable working set of data for end users. You have the ability to couple archive functionality with purge so that while data is removed from the production system, an archive of that data still exists to be retrieved as required. Note: In order to access the archive functionality, you must install Windchill Archive. Topic Page
Archiving Related Classes.................................................................................40-2 Enabling Archive/Purge/Restore for Custom Classes.......................................40-4 Customizing Archive Upgrade..........................................................................40-8
40-1
This enables Windchill to recreate the object with enough contextual information to use it meaningfully after restore, even if all such information has been deleted from active use from the Windchill instance at the point of restore. Out of the box, Windchill takes a "safety first" approach and collects all the supported contextual objects (barring exceptions) for the Versions and Iterations category of related items. The list of supported objects is as follows:
wt.epm.structure.EPMMemberLink wt.epm.structure.EPMVariantLink wt.epm.structure.EPMReferenceLink wt.epm.build.EPMBuildHistory wt.epm.structure.EPMContainedIn wt.part.WTPartUsageLink wt.part.WTPartReferenceLink wt.part.WTPartDescribeLink wt.epm.build.EPMBuildLinksRule
For your business objectives, a subset of the above list may make more sense and/or you may need to add customized links to the list. The following information describes the way related objects are collected by Windchill; this needs to be understood to customize this behavior: Windchill uses wt.dataops.objectcol.RelationshipMapDef objects and wt.dataops.objectcol.RelationshipMap objects to control the collection of related objects. Windchill loads one wt.dataops.objectcol.RelationshipMapDef object, that holds the traversal map for related objects based on <Windchill>/loadFiles/content/RelationshipMap.xml file, as part of the base data loading. Windchill loads four wt.dataops.objectcol.RelationshipMap objects that use the above loaded wt.dataops.objectcol.RelationshipMapDef object and
40-2
correspond to each of the four options offered by Windchill (given the combination of two options with two choices each as described above), as part of the base data loading. To change/extend the related object collection behavior, you need to delete and recreate the five objects above. This can only be done before any one of them has been used in active Windchill use, that is, by creating a archive. Follow the steps below for this customization: 1. Delete the five objects referred to above, making sure they have not been used earlier (and thus ensuring referential integrity is not violated). For example, use the PersistenceManager API to delete the objects (see the Persistence Management chapter on page 37-1). 2. Make a copy of <Windchill>/loadFiles/content/RelationshipMap.xml and suitably alter the related object definition in it. The DTD is located in <Windchill>/codebase/registry/objectcol/dtds/Criterion-def.dtd. 3. Make a copy of <Windchill>/loadFiles/BaseCriterionDefs.xml, removing all sections except for those that relate to the creation of RelationshipMapDef and RelationshipMap objects. Change the reference of the XML to refer to the new, altered copy of RelationshipMap.xml from the previous step. 4. Reload the objects deleted in step 1 by loading the new BaseCriterionDefs.xml copy from the step above, using the LoadFromFile mechanism. For example,
windchill wt.load.LoadFromFile -d <Windchill>/loadFile/BaseCriterionDefs.xml
For more information on data loading, see: Windchill Installation and Configuration Guide - Windchill Windchill Data Loading Reference and Best Practices Guide
40-3
Note: All objects that need to be archived must implement the wt.fc.archive.Archiveable interface.
Writing Handlers
You will need to create IX handlers for all your custom classes including your link classes. Refer to the How to Write Exp/Imp Handlers section in the Import Export Framework chapter on page 41-17. In addition you can refer to the implementation of handlers for WTPart and WTDocument. Alternatively you can derive your handlers from existing handlers and reuse the code. Apart from importing normal attributes, you need to export and import certain additional attributes. To do this use the wt.ixb.archive.ArchiveHndHelper class. This class provides helper methods that IX handlers need to support Archive and Restore functionality. In your IX handler you should check to see whether archive/restore is being done. In this case you must also perform certain operations on the archive-specific attribute. To export/import Archive-related attributes use the ExpImpForFlexibleVersioningAttr, ExpImpForArchiveAttr, ExpImpForMarkUpAttr classes. You can refer to the IX Handler for WTPart for details. The following examples show sample code that is added to various methods to enable archive/restore. protected void exportAttributes (Object object, IxbDocument fileXML, Exporter exporter)
40-4
The above code will ensure that Archive and Flexible Versioning attribute information is also stored in the archive. public void checkConflicts (IxbElement fileXML, Importer importer)
If you are implementing this method you should also include the code below.
if (ArchiveHelper.isArchiveRestoreContext(importer)) { IxbHndHelper.checkConflictForAttribute(ExpImpForFlexibleVersioningAttr.class, existingOb, fileXML, importer); IxbHndHelper.checkConflictForAttribute(ExpImpForArchiveAttr.class, existingOb, fileXML, importer); }
if (ArchiveHelper.isArchiveRestoreContext(importer)) { ob = IxbHndHelper.importAttribute(ExpImpForFlexibleVersioningAttr.class, ob, fileXML, importer); ob = IxbHndHelper.importAttribute(ExpImpForArchiveAttr.class, ob, fileXML, importer); } public Object importObjectAttributesAfterStore(Object object,IxbElement fileXML, Importer importer) if (ArchiveHelper.isArchiveRestoreContext(importer)) { ob = (WTPart)IxbHndHelper.importAttribute(ExpImpForMarkUpAttr.class, ob, fileXML, importer); }
If your handler classes do not extend from existing handler and your classes are not derived from an out-of-the-box class you will also need to override the storeObject method to ensure that your objects are created with the same OIDs they had before archive/purge.
For example,
ObjectIdentifier oid = ((Persistable) object).getPersistInfo().getObjectIdentifier(); ArchiveHndHelper.addOidForReuse(Transaction.getCurrentTransaction(), oid); PersistenceHelper.manager.save(object) ;
40-5
<!-- CustomOtoOLink --> <related> <by-relationship collect-related-by='true' collect-other-end='true' other-end-dependant='true'> <output-types> <output-type classname='auto.Custom.CustomDoc' allow-subtypes='true'/> </output-types> <relationship> <seeds> <seed classname="auto.Custom.CustomPart" allow-subtypes="true"/> </seeds> <link classname="auto.Custom.CustomOtoOLink"/> <role> <name> <derived> <derive classname="auto.Custom.CustomOtoOLink" field="CUSTOM_DOC_ROLE" /> </derived> </name> </role> <recurse> <input type="string" name="recurse-part-reference" required="false" default-value="false"> <match> <pattern resource="true value">true</pattern> <pattern resource="false value">false</pattern> </match> </input> </recurse> </relationship> </by-relationship> </related>
Recreate the schema for the Dataops module and load the XML file into the database using the LoadFromFile mechanism. For example,
windchill wt.load.LoadFromFile
40-6
-d <Windchill>/loadFile/BaseCriterionDefs.xml
Limitations
For archive information to be stored objects need to implement at least the Iterated and Ownable interfaces. For storing Archive attribute information your classes need to be Iterated and Ownable. For storing Flexible attribute information your classes need to be Iterated and Federatable. If your classes are not Iterated and Ownable you will not be able to store Archive information, however you can import/export your custom attributes, and restore the OIDs as this only requires your classes to be Persistable.
40-7
The dtd of objects have changed in the current version. The kinds of changes that may occur are listed in the Schema Changes section. All the facilities listed above can be used by customizes as well. Developers making these changes should not change any out-of-the-box artifacts. This may cause failures during Upgrade. To start customizing Archive Upgrade the customizer must decide on a location to store the Customized Archive Upgrade Artifacts. This will be referred to as the customization_dir. The com.ptc.windchill.ixupgrade.customization_dir property must be added to site.xconf and propagated to ixupgrade.properties. The artifacts to be created and the syntax is exactly the same as the out-of-the-box procedure. Please refer to the other sections for details. The most important difference is the location for the customized artifacts. Create all the required artifacts as described in the document. Run the IXUpgrade utility. The rules and XSLs will be generated under the customization_dir directory.
40-8
CAPTION
Refer to common uses cases and how to write upgrades from them in the Common Use Cases section.
40-9
Testing Restore
The generated artifacts should be tested on a test system by restoring old archives containing customized objects prior to deploying on a production system.
40-10
41
Import Export Framework
This chapter describes the Import Export (IX) Framework and explains how to customize and use it for various solutions. Topic Page
Overview ...........................................................................................................41-2 How to Write an IX Application .......................................................................41-3 How to Write Exp/Imp Handlers.....................................................................41-17 Navigating Through an Objects Structure with ObjectSet Application.........41-26 Product Design eXchange (PDX) Support for Export ....................................41-46
41-1
Overview
The basic unit of job for the framework is importing or exporting a single object. The framework understands the transactional nature of import and encapsulates a session of individual imports into one database transaction.
41-2
Create an Application Export Handler 'appHandler'. This is an instance of a class either implementing ApplicationExportHandler interface or extending the abstract class ApplicationExportHandlerTemplate. In the export application in StandardIXBService, the appHandler extends ApplicationExportHandlerForJar, a subclass of ApplicationExportHandlerTemplate
The job of the 'appHandler' is: To create a file to store exported objects (e.g. a JAR file). To store logs to be sent back to the client (optional). To clean up temporary files and do other clean-up jobs (advised, but optional).
To create, the following methods must be implemented in 'appHandler': storeLogMessage(...) methods are used to send logs back to clients. It is up to the developer how to implement the mechanism to send the logs back. If you do not want to send any log messages, make your Export Handler extend ApplicationExportHandlerTemplate. This class has the default storeLogMessage() (empty method). It is optional to have clean up and other concluding tasks here, and these jobs must be called explicitly after exporter.finalizeExport().
The Application Export Handler may also contain methods to perform tasks of transforming the output if the application needs to modify the exported XML. For example, PDXExportHandler has methods for XSL transformation to PDX format. These methods must be called explicitly after exporter.finalizeExport(). The existing implementations of the Application Export Handler are:
41-3
WCXMLExportHandler extends ApplicationExportHandlerTemplate. This is a public class designed for creating export jar file on server. (It is mostly a copy of the inner class ExportHandler in StandardIXBService.). This handler will be removed in 7.0, since now we have ApplicationExportHandlerForJar. PDXExportHandler extends ApplicationExportHandlerTemplate. This class performs specific tasks connected with export to PDX format. This includes creating additional XML attributes/elements and XSL transformation to PDX format.
Create an instance of the Exporter class, and use it to export objects by calling exporter.doExport(obj), where obj runs through all WT objects collected for export. After this, call exporter.finalizeExport(), perform any additional tasks (for example, transformation to another format), call methods of appHandler to clean up after the export process, send log messages to client. The methods doExport(), doExportImpl() and the inner class ExportHandler in StandardIXBService are examples of one export application. Please see the details in the section, "Example of an Export Application" later in this chapter. Prerequisite In order to create the export jar at a client specific location, the following prerequisite needs to be satisfied before calling the doExport api of StandardIXBService: The context key IXBStreamer.CLIENT_SAVE_AS_FILE needs to be set with the complete client side file path:
WTContext.getContext().put(IXBStreamer.CLIENT_SAVE_AS_FILE,CLIE NT_JAR);
Where CLIENT_JAR is the complete client side file path, e.g. c:\\ mydocuments\\impex.jar
Exporter Class
The details of the exporter class are as follows: Definition:
public class Exporter extends ExpImporter{};
Constructor:
Exporter (ApplicationExportHandler _applicationExportHandler, String targetDTD, IxbElement localMappingRules, File policyRuleFile) throws WTException { super ("export", localMappingRules);
41-4
// -- init expActionTuner -applicationExportHandler = _applicationExportHandler; dtd = targetDTD; // -- init expActionTuner -expActionTuner = new ExportActionTuner (policyRuleFile); }
An explanation of the arguments follows: _applicationExportHandler - an instance of any class that either implements the interface ApplicationExportHandler,extends the abstract class ApplicationExportHandlerTemplate or extends the abstract class ApplicationExportHandlerForJar. The class ApplicationExportHandlerForJar extends the class ApplicationExportHandlerTemplate. The class ApplicationExportHandlerForJar provides methods for storing XML and content files in export jar file. It handles both ApplicationData content and content residing in local file system. _applicationExportHandler has a job of creating a Jar file (or any other way of storing) of the resulting collection of XML pieces (exported objects). It must implement two methods: storeContent storeDocument (ApplicationDataob); (IxbElement elem);
targetDTD: string that specifies what DTD must be used for export process. The IX framework will find appropriate handlers for objects and Document Type Definition for objects based on this DTD string. The DTD string used in Windchill 9.0 is standardX10.dtd. Generally the intent was to be able to export objects in any DTD. As you will see below the class export handlers are resolved using the DTD identifier. The string targetDTD is also written to the XML file of exported objects, so the import process could know what DTD should be used to import objects. localMapppingRules: XML file or XSL file that is used to override, change or exclude certain attributes objects when the export process takes place. The following XML rule file overrides the Team Template attribute, and no matter what team an object belonged to when it was exported, its team template attribute will be Change Team in the /System domain.
<?xml version="1.0" encoding="UTF-8"?> <userSettings> <mappingRules> <COPY_AS>
41-5
The XSL rule file tests if the exported object has the name of part_c, it will override the Team Template attribute and version information, and tests if the exported object has the name of PART_B, it will override the Team Template attribute. If you dont want to override anything, just pass null for the argument localMapppingRules. policyRuleFile: XSL file that is used to override, change or exclude certain attributes objects when the export process takes place.
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="@* | node()" priority="-9"> </xsl:template> <xsl:template match="WTPart"> <xsl:choose> <xsl:when test="name='part_c'"> <newInfo> <teamIdentity>Default (/System)</teamIdentity> <folderPath>/Design</folderPath> <versionInfo> <versionId>B</versionId> <iterationId>2</iterationId> <versionLevel>1</versionLevel> </versionInfo> </newInfo> </xsl:when> <xsl:when test="number='PART_B'"> <newInfo> <teamIdentity>Default (/System)</teamIdentity> <folderPath>/Design</folderPath> </newInfo> </xsl:when> <xsl:otherwise> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
For example the policy rule file specifies that check out exported WTPart objects in the database after exporting them. If an exported WTDocument object has the number of TESTDOC-1, check it out after exporting it. With all other exported WTDocuments, lock them in the database after exporting them.
41-6
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:output method="xml" indent="no" encoding="UTF-8"/> <!-The syntax of Export Policy is standard XSL syntax. The output of XSLT using the XSL policy file must only have at most one element of the form: <actionInfo> <action>...</action> </actionInfo> --> <!-The following is a sample of a well-formed xsl. In the cases, where there are no specific actions to be performed, nothing needs to be done, which is the default action that would transpire as shown in the uncommented section below. --> <!-<xsl:template match="@* | node()" priority="-9"> </xsl:template> <xsl:template match='WTPart'> <actionInfo> <action>Checkout</action> </actionInfo> </xsl:template> <xsl:template match='WTDocument'> <actionInfo> <xsl:choose> <xsl:when test="number='TESTDOC-1'"> <action>Checkout</action> </xsl:when> <xsl:otherwise> <action>Lock</action> </xsl:otherwise> </xsl:choose> </actionInfo> </xsl:template> --> <!-- Do nothing by default --> <xsl:template match="@* | node()" priority="-9"> </xsl:template> </xsl:stylesheet>
41-7
If you dont want to override anything, just pass null for the argument policyRuleFile. An instance of the Exporter must be created via the factory method newExporter() of the class IxbHelper. For example:
Exporter exporter = IxbHelper.newExporter ( appHandler, IxbHelper.STANDARD_DTD, localMappingRules, policyRuleFile);
After you export all objects, you must call exporter.finalizeExport(); You can call clean-up methods of appHandler (if there are any). Now the export is finished. Note: A sample file with comments is distributed along with installation information.
41-8
5. Create an instance of the class Importer (importer). 6. Get the list of XML files in the jar file. 7. Create IxbDocuments from those XML files. 8. With each IxbDocument, do the following: If there is an action name passed to the application and the policyFile is null, apply the action name into the IxbDocument. If the policyFile is not null, apply action name and action information in the policyFile into the IxbDocument. Feed them to the importer one by one by calling the import process: importer.doImport(IxbDocument Doc); importer.finalizeImport();
9. Clean up (if needed). 10. Send log messages to client. The methods doImport(...), doImportImpl(...) and the inner class ImportHandler in the StandardIXBService are an example of one import application. Please see the details in the part Example of an Import Application.
41-9
Versioned objects can be imported in any of 10 different manners decided by action name and action information that are written to the IxbDocument fileXML of each importing object. Developers who write import applications must know about action names and their meanings to apply them correctly, but object handlers dont have to worry about the Actor classes. A list of all available action names can be found in the file Windchill\src\wt\ixb\registry\ixb\handlers\ actor.xml. All of the actions are different from each other in 3 crucial methods: previewObject, createObject and storeObject. In the class ExpImpForVersionedObject, based on action name and action information that are passed into the IxbDocument fileXML, appropriate actor will be created and this actors methods will be called to serve the purpose of previewing, creating and storing versioned objects. Here is the list by actor names for information. 1. PickExistingObject: Find if an object with the same ufid or same (name, number, version, iteration) with the object in XML file exists in database. If such an object exists, do nothing. Otherwise, import the object in XML file. 2. NewIteration: Import object in XML file as the next available iteration in the database. For example: If there is no version/iteration in the database for the object which is in the XML file, the imported object will get the version / iteration specified in the XML file. If the latest version / iteration of the object in the database is B.2, the imported object will be B.3.
3. NewVersion:Import objects from the XML file as the next available version in the database. For example: If there is no version / iteration in the database for the object which is in the XML file, the imported object will get the version / iteration specified in the XML file. If the latest version / iteration of the object in the database is B.2, the imported object will be C.1.
4. CheckOut: Find any version/iteration of the object in the XML file (Check the existence of the master object in the database). If there is no version of the object in the XML file, throw an error. Otherwise, find an instance of the object in the database that has the same version (iteration can be different) as the object in the XML file. If such an object exists, check out the latest iteration of the object in the database, update it with information from the XML file. I agree Otherwise, throw an error. No, we dont check it in 5. ImportNonVersionedAttr: Find an object with the same ufid or same (name, number, version, iteration) with the object in the XML file. If such an object exists, update it with information from the XML file. Otherwise, throw an error. 6. UpdateInPlace: Find an object with the same ufid or same (name, number, version, iteration) with the object in XML file exists in database. If
41-10
such an object exists AND it is checked out, update it with information from the XML file. Otherwise, throw an error. 7. UnlockAndIterate: Find an object in the database with the same ufid or same (name, number, version, iteration) as the object in the XML file. If such an object exists AND it is locked, unlock and iterate it, then update it with information from the XML file. Otherwise, throw an error. 8. CreateNewObject: Create a brand new object with new name, new number, new version, new iteration provided in Import Policy file. Other information will be extracted from the XML file. This functionality cannot be used alone, Note: This option cannot work without a policy file to specify the new object identities. The format of new information that must be provided in ImportPolicy file is:
<?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <!-The syntax of Import Policy is standard XSL syntax. The output of XSLT using the XSL policy file must only have at most one element of the form: <actionInfo> <action>...</action> </actionInfo> The following is a sample of a well-formed xsl. In the cases, where there are no specific actions to be performed, nothing needs to be done, which is achieved by the following: <xsl:template match="@* | node()" priority="-9"> </xsl:template> --> <xsl:template match="@* | node()" priority="-9"> </xsl:template> <xsl:template match='WTPart'> <actionInfo> <action>PickExistingObject</action> </actionInfo> </xsl:template> <xsl:template match='WTDocument'> <actionInfo> <action>PickExistingObject</action> </actionInfo> </xsl:template> <xsl:template match='EPMDocument'>
41-11
Note: <actionInfo> must always exist. Criteria can be any valid attribute of the object in XML file. Between <xsl:choose>, there can be many <xsl: when test ....> with different criteria and different action names. Only CreateNewObject and SubstituteObject can have action params, and there are only four action params <newName>, <newNumber>, <newVersion>, <newIteration>, all of them must be provided.
SubstituteObject: Substitute the object in the XML file for an object in
the database that has the name, number, version, and iteration provided in the ImportPolicy file. If such an object doesn't exist, throw an exception. Format of tag and params for this case is exactly the same with CreateNewObject, but the <action> is SubstituteObject. Ignore: Do not import the object in the XML file. This action doesn't require any actor.
Importer class
Definition: public class Importer extends ExpImporter Constructor: Importer (ApplicationImportHandler _applicationImportHandler,
String String Boolean Boolean ) throws WTException _dtd, _ruleFileName, _overrideConflicts, _validate
Parameters explanation: applicationImportHandler: an instance of a class that either implements the interface ApplicationImportHandler or extends the abstract class ApplicationImportHandlerTemplate applicationImportHandler has a job of extracting from the Jar file that stores XML, and its class must implement 2 methods:
41-12
getContentAsInputStream (String contentId); getContentAsApplicationData (String contentId); The later method may always return null to indicate that the file does not exist in Windchill DB. Note: Please see the inner class ImportHandler of the class StandardIXBService for an example of implementation of an application import handler. targetDTD: string that specifies what DTD must be used for import process. The IX framework will find appropriate handlers for objects and Document Type Definition for objects based on this DTD string if the imported file does not specify any. The DTD string used in Windchill 9.0 is standardX10.dtd. ruleFileName: Mapping rule file can be XML file (like in previous versions) or XSL file, so this parameter is String. The constructor that uses IxbElement _localMappingRules is deprecated. In the case you do not have mapping rule file and want to put it to null, please do not put the null value directly in the constructor, because it will cause one ambiguous reference error. Instead of doing that, you should use a string, assign null value to it, and pass it as ruleFileName. Mapping rule file is used to change, override or exclude certain attributes objects when the import process takes place.
For example, the rule file overrides the Team Template attribute, and no matter what team an object belonged to when it was exported, its team template attribute is replaced by Change in the /System Domain on import.
<?xml version="1.0" encoding="UTF-8"?> <userSettings> <mappingRules> <COPY_AS> <tag>teamIdentity</tag> <value>*</value> <newValue>Change Team (/System)</newValue> </COPY_AS> </mappingRules> </userSettings>
41-13
<versionLevel>1</versionLevel> </versionInfo> </newInfo> </xsl:when> <xsl:when test="number='PART_B'"> <newInfo> <teamIdentity>Default (/System)</teamIdentity> <folderPath>/Design</folderPath> </newInfo> </xsl:when> <xsl:otherwise> </xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
This XSL file says that whenever the import process meet a WTPart named part_c, then change its team identity template to Default (/System), change its folder part to /Design, and change its version to B.2, whenever the import process meet a WTPart with the number PART_B, then change its team identity template to Default (/System), change its folder part to /Design If you dont want to override anything, just pass null for the argument localMapppingRules.
_overrideConflicts: boolean value specifies whether the import process
validate the XML file of the imported object against the DTD. An instance of the class Importer must be created via the method
newImporter() of the class IxbHelper. For example:
Importer importer = IxbHelper.newImporter( handler, IxbHelper.STANDARD_DTD, ruleFileName, overrideConflicts, null);
41-14
doImport (doc) This method doesnt really import the object, but inserts the XML document that represents the object in to a list to be imported later. After all XML documents representing all the imported objects are inserted in the import list, the real import process starts with the call to finalizeImport().
finalizeImport(): The import process is actually performed in this
In the method importElement() the import handler for a particular type of the object is created by calling getImportHandler(tag, dtdFromXML). The method getImportHandler() finds the appropriate handler for the imported object as follows. 1. Try to get an import handler by using the DTD string in the <dtd> tag of the XML file of the imported object. 2. If the handler is null, try again using current DTD in the importer. This current DTD is calculated using version of the current Windchill. For Windchill R9.0 it is standardX10.dtd. After getting the handler for the element, the importElement() calls the following methods:
handler.importElement() to do the import task. handler.outputLog() to send log to user.
All handlers for non-versioned objects (for example links, ReportTemplate ... ) extend the class ClassExporterImporterTemplate, and all handlers for versioned objects (for example Parts, Documents, EPMDocuments ...) extend the class ExpImpForVersionedObject. Note: Handlers for non-versioned objects act like the previous versions. If the real handler doesnt implement the method importElement(), then the call invokes the default method importElement() of the class ClassExporterImporterTemplate. In this class, the importElement() method calls to findAmongExistingObjects (fileXML, importer); If it finds that the object in the XML file currently exists in the database, it will not import the object. Otherwise, it will call the following methods:
41-15
createObject (fileXML, importer); importObjectAttributes (ob, fileXML, importer); storeObject (ob, fileXML, importer); importObjectAttributesAfterStore (ob, fileXML, importer);
Some of these methods should be implemented in the handler, and it is how and when the real handler comes to do its job. Note: Handlers for versioned objects act different. If the real handler doesnt implement the method importElement(), then the call invokes the default method importElement() of the class ExpImpForVersionedObject. In this class, despite the object in the XML file exists in the database or not, the importElement() method always calls to:
createObject (fileXML, importer); importObjectAttributes (ob, fileXML, importer); storeObject (ob, fileXML, importer); importObjectAttributesAfterStore (ob, fileXML, importer);
Then, the Import Application can do a clean-up, and send messages to the client. The import process is finished.
41-16
For example:
<classExporter> <class>wt.part.WTPart</class> <dtd>standardX10.dtd</dtd> <targetTag>default</targetTag> <handler>wt.ixb.handlers.forclasses.ExpImpForWTPart</handler> </classExporter>
41-17
All handlers with the <dtd> tag standardX10.dtd are handlers for export object in R9.0. For example, for R9.0 we have tags:
<classExporter> <class>wt.part.WTPart</class> <dtd>standardX10.dtd</dtd> <targetTag>default</targetTag> <handler>wt.ixb.handlers.forclasses.ExpImpForWTPart</handler> </classExporter>
So we know that the class wt.ixb.handlers.forclasses.ExpImpForWTPart is a handler for exporting the class wt.part.WTPart in R9.0 format. The class IxbHandlersManager contains all necessary methods to manipulate handlers.
DTD Files
In the folder Windchill\src\wt\ixb\registry\ixb\dtds\standardX10.dtd there is a file named coreobjects.dtd that is the DTD file for all objects that will be exported/imported.
41-18
3. Override getRootTag() method, which returns the desired root tag for the object type to be exported. The following is an example of this method for the object of "MyClass":
protected String getRootTag() { return "MyClass"; }
4. Add an entry in the handlers XML file (<WC_home>\registry\ixb\ handlers\coreX10.xml) that specifies the class being exported (com.mycompany.MyObject), the XML DTD for core Windchill objects (standardX10.dtd), and the handler for the class (wt.ixb.handlers.forclasses.ExpImpForMyObject). An example entry follows:
<classExporter> <class>com.mycompany.MyObject</class> <dtd>standardX10.dtd</dtd> <targetTag>default</targetTag> <handler>wt.ixb.handlers.forclasses.ExpImpForMyObject</handler> </classExporter>
41-19
After adding this, the export handler for class may call this method to have the part attribute exported.
For example:
<elementImporter> <tag>WTPart</tag> <dtd>standardX10.dtd</dtd> <handler>wt.ixb.handlers.forclasses.ExpImpForWTPart</handler> </elementImporter>
All handlers with the <dtd> tag standardX10.dtd are handlers for import object in R9.0.
For R9.0 format we have tags:
41-20
the class wt.part.WTPart in R9.0. The class IxbHandlersManager contains all methods to manipulate handlers.
1. Create a Java class that extends ClassExporterImporterTemplate 2. Implement method: 3. public Object createObject (IxbElement fileXML, Importer importer) 4. Override the following methods if necessary:
public Object importObjectAttributes (Object ob, IxbElement fileXML, Importer importer); public Object storeObject (Object object, IxbElement fileXML, Importer importer); public Object importObjectAttributesAfterStore(Object object, IxbElement fileXML, Importer importer); public Object findAmongExistingObjects (IxbElement fileXML, Importer importer);
Import handlers for non-versioned objects are quite straightforward, and any of the following classes can be referred as example:
ExpImpForWTPartDescribeLink ExpImpForWTPartReferenceLink ExpImpForWTPartUsageLink
41-21
imported after the object is stored. 5. Add an entry to the handlers registry file (<WC_home>\registry\ixb\ handlers\coreX10.xml). The entry specifies the class being imported (MyObject), XML DTD for core Windchill objects (standardX10.dtd), and the handler for the class com.ptc.mypackage.ExpImpForMyObject. An example entry follows:
<elementImporter> <tag>MyObject</tag> <dtd>standardX10.dtd</dtd> <handler>com.ptc.mypackage.ExpImpForMyObject</handler> </ elementImporter >
1. Create a Java class that extends ExpImpForVersionedObject 2. Implement the following methods:
public Mastered getMaster (IxbElement fileXML):
returns the Object Master if there is any version of the importing object in the database, otherwise returns null.
public Versioned createNewObject (IxbElement fileXML,Importer importer): create a new object with
information from the XML file. 3. Override the following methods if necessary:
public Object importObjectAttributes (Object ob, IxbElement fileXML, Importer importer);
public Object importObjectAttributesAfterStore(Object object, IxbElement fileXML, Importer importer); public Object findAmongExistingObjects (IxbElement fileXML,
41-22
Importer importer);
Actor classes, depends on the actor name in the XML file (The actor name is writen into the XML file by import application). Particular object handlers dont have to worry about createObject() and Actor.
importObjectAttributes(): import all attributes of the object that can be imported before the object is stored. storeObject(): This method is implemented in the class ExpImpForVersionedObject. The store of objects will be delegated to Actor
classes, depends on the actor name in the XML file (The actor name is writen into the XML file by import application). Particular object handlers dont have to worry about storeObject() and Actor.
importObjectAttributesAfterStore():import all attributes of the object
examples of import handlers for versioned objects. 4. Add an entry to the handlers registry file (<WC_home>\registry\ixb\ handlers\coreX10.xml). The entry specifies the class being imported (MyObject), XML DTD for core Windchill objects (standardX10.dtd), and the handler for the class com.ptc.mypackage.ExpImpForMyObject. An example entry follows:
<elementImporter> <tag>MyObject</tag> <dtd>standardX10.dtd</dtd> <handler>com.ptc.mypackage.ExpImpForMyObject</handler> </ elementImporter >
41-23
checking. It is likely never be implemented by a particular handler. checkConflictForAttribute(Object existingOb, IxbElement fileXML, Importer importer) : This method does the conflict checking for particular attribute, so if the imported attribute can potentially have conflicts with an attribute that exists in the database, this method must be overridden.
importAttribute (Object object, IxbElement fileXML,
Importer importer):
Retrieves the attribute data from the XML DOM Document and set it to the imported object. This method must be overridden to suit particular attribute.
41-24
Here is an example for importAttribute() for the attribute MyAttr to the object MyObject:
public Object importAttribute (Object object, IxbElement fileXML, Importer importer) throws WTException{ String myAttr; try{ myAttr = fileXML.getValue(IxbHndHelper.XML_ATTR_MYATTR); // XML_ATTR_MYATTR tag must be defined in IxbHndHelper } catch (Exception exc){ // The paragraph bellows allows the import process continue, // even when the import of MyAttr fails. If the programmer // wants the import process to stop when the import of // MyAttr fails, please assign ob=null and throw exception System.out.println( "Exception when getting MyAttr in importAttribute"); System.out.println("MyAttr attribute is not imported"); return object; } MyObject ob = (MyObject) object; try { MyObjectHelper.service.setMyAttr(ob, myAttr); } catch (Exception e) { if (! importer. attributeExporterImporterManager. overrideConflicts) { ob = null; throw e; } else{ // override the conflict by doing something here } } finally{ return ob; }
41-25
Example:
<loadCondition> <className>wt.ixb.objectset.ObjectSetHelper</className> <methodName>isPDMLinkInstalled</methodName> </loadCondition>
Object Collection
When an object is given to the export process, the ObjectSet application does the job of navigating through the object's structure and collecting all of its related objects. The definition of the navigation is taken from a set of XML files known as navigation?rule files. Additionally, the ObjectSet application uses Java classes known as generators and filters to collect a set of objects that will be exported when simple navigation is not enough and some programming logic needs to be applied. The navigation rule files reside in the folder Windchill\codebase\ registry\ixb\object_set_handlers.
Navigating Rules
There are two types of navigating rules: Generator and Filter.
41-26
Generators are rules that are used by the application to traverse through the objects structure and get all of its objects to be exported, such as uses, described by, reference, etc. Filters are rules that are applied to objects to be exported to exclude certain objects from the export process. For example, with Filter By Time, we can choose to export objects that were modified during a specified period. This is the only out-of-the-box filter currently available.
Available GeneratorIds are defined in XML files in the folder Windchill\ codebase\registry\ixb\object_set_handlers with the tag <setGenerator>. A list of these Generator Ids can be obtained by calling to IXBHelper.service.getAllAvaiableGenerators(). The call returns all available Generators in the system.
IXBHelper.service.getGeneratorList() returns a list of Generators that
will be displayed to the GUI for end-user selection. This helps to hide Generators that you dont want the end-user to see. To hide these Generators, the XML files for these Generators, should have the <display> tag set to false.
41-27
For example: a paragraph of XML file for WTPart: (From <Windchill>\codebase\registry\ixb\object_set_handlers\ product_struct.xml)
<setGenerator> <id>productStructureNavigator</id> <handler> wt.ixb.objectset.handlers.navigator.ProductStructureNavigator </handler> <dialogClassName> wt.clients.ixb.exp.NavigatorSearchDialog </dialogClassName> <localizedName> <localizedString> <class>wt.ixb.objectset.objectSetResource</class> <key>PRODUCT_STRUCTURE_NAME</key> </localizedString> </localizedName>
Tags
<id>: Generator Id <handler>: Navigator Java class that helps navigating through the object structure. In the example, to navigate through WTPart structure. <dialogClassName> : Java class of the dialog that must be called from the GUI to search the top-level object of this class in database (in this example, to search WTPart). <localizedName> and its sub tags are for internationalization purpose. The
string resource for displaying the Generator to the GUI will be defined in the
.rbInfo file specified by localizedName/localizedString/class and its key in the .rbInfo file is localizedName/localizedString/key.
If you dont want this GeneratorId to be displayed to the GUI, but only to be used programmatically in your application, add the tag <display> like this:
<setGenerator> <id>productStructureNavigator</id> <display>false</display> <handler> wt.ixb.objectset.handlers.navigator.ProductStructureNavigator </handler> <dialogClassName> wt.clients.ixb.exp.NavigatorSearchDialog </dialogClassName> <localizedName> <localizedString> <class>wt.ixb.objectset.objectSetResource</class> <key>PRODUCT_STRUCTURE_NAME</key> </localizedString> </localizedName>
41-28
Available Filter Id-s are defined in XML files in the folder Windchill\ codebase\registry\ixb\object_set_handlers with the tag <setFilter>. A list of these Filter Ids can be obtained by calling to IXBHelper.service.getAllAvaiableFilters(). It returns all available Filters in the system. IXBHelper.service.getFilterList() returns a list of Filters that will be displayed to the GUI for user selection. This function help to hide filters which you dont want the end user to see. To hide such Filters, set the value of the <display> tag to false in the XML files of these Filters. Note: If the tag <display> is not specified, or set to true, the Generator will be included in the result of the method ObjectSetHelper.getListOfObjectSetGenerators() and it will be displayed in the GUI. If the tag <display> is false, the Generator will not be included in the result of the method ObjectSetHelper.getListOfObjectSetGenerators(), and it will not be displayed to the GUI. To get all Generators in the system, use the method ObjectSetHelper.getAllAvaiableGenerators(). All the methods getGenerators and getFilters return Vectors that contain an element list of the type IXBHandlerDescription. Use getId() of those elements to get lists of Generators or Filters that are passed as arguments generatorIds and filterIds for the method doExport() in the StandardIXBService.
Object Navigation
The mechanism is an XML-rule-driven navigator of Windchill objects. Given a seed (top level) object the mechanism uses specified rules to navigate from object to object. The navigation can be performed through a DB link, a foreign key, or a specified method. Here is an example of rule definition of WTPart. The seed is a Folder object. (From <Windchill>\codebase\registry\ixb\object_set_handlers\ product_struct.xml)
<handler> wt.ixb.objectset.handlers.navigator.ProductStructureNavigator </handler> <schema> <rule> <for>wt.part.WTPart</for> <go> <byMethod> <method>navigateFromWTPartToDescribeByDoc</method> </byMethod> </go> </rule>
41-29
<rule> <for>wt.part.WTPartDescribeLink</for> <go> <fromForeignKey> <targetClass>wt.doc.WTDocument</targetClass> <getMethodName>getDescribedBy</getMethodName> </fromForeignKey> </go> </rule> </schema>
The example above shows both possible types of navigation: From WTPart it navigates to wt.part.WTPartDescribeLink by a navigate method and from there using the method getDescribedBy to get the WTDocument that the WTPart is described by. Then, non-trivial semantic steps can be made. After collecting, the objects can be filtered out by a set of defined filters. The filter definition is stored in the same object set registry. The following is an example of a date/time filter:
(File: <Windchill>\codebase\registry\ixb\object_set_handlers\ filter_by_time.xml) <setFilter> <id>filterByTime</id> <handler>wt.ixb.objectset.handlers.FilterByTime</handler> <dialogClassName> wt.clients.ixb.exp.FilterByTimeDialog </dialogClassName> <localizedName> <localizedString> <class>wt.ixb.objectset.objectSetResource</class> <key>FILTER_BY_TIME_NAME</key> </localizedString> </localizedName> <parameters> </parameters> </setFilter>
The filtering mechanism, as well as the object collection are coupled with the export application at the level of StandardIXBService. They can be separated.
41-30
This appendix provides help for the GUI developer who will be using the IX Object Collection mechanism by calling: ObjectSetHelper.computeObjectSetForGivenGeneratorsAndFilters(generatorIds, generatorParams, filterIds, filterParams);
41-31
Examples
Part With all Children
genId[0] = productStructureNavigator; genParams[ 0] = wt.part.WTPart:6789; WTHashSet objects = (WTHashSet) ObjectSetHelper. computeObjectSetForGivenGeneratorsAndFilters(genIds, genParams, new String [0 ], new String [0 ]);
Note: Warning, if there are no filters, you can pass new String[0] for filterIds and filterParams (Dont pass null, an exception is thrown) To get String constants for GUI, see Windchill\codebase\wt\ixb\ objectset\ObjectSetResource.rbInfo.
41-32
Generators list
String id Description Localized name En (for GUI) Parameters as String
folderContent
Collects all objects in a given Cabinet/Folder (including subfolders) Collects all children of a given Part (e.g. Parts, which it uses and Documents which describe it)
productStructureNavi gator
<class name: oid>, like: wt.part.WTPart:1234 for the top-level object. This object must be instance of WTPart <class name: oid>, like: wt.epm.EPMDocument:12 34 for the top-level object. This object must be instance of EPMDocument <class name:oid>, like: wt.part.WTPart:1234 for the top-level object. This object must be instance of WTPart
productStructureNavi gatorEPM
productStructureNavi gatorWithEPM
Product Structure with CAD documents (built with active Config Spec)
singleDocument
Document
Filters list
String id Description Localized name En (for GUI) Parameters as String
filterByTime
Filters out objects with modification time before/after the given interval
41-33
The current Windchill Export out-of-the-box GUI and the StandardIXBService is an Export Application. The out-of-the-box Windchill Export GUI is Export Application (client) that calls export process in StandardIXBService (Export Application (server)) via IXBHelper. There are two ways to use it: With GUI:
IXBExpImpStatus status = IXBHelper.service.doExport( boolean previewOnly, String[ ] generatorIds, String[ ] generatorParams, String[ ] filterIds, String[ ] filterParams, IXBStreamer ruleFile, String guiId, boolean detailedLog);
Without GUI:
IXBExpImpStatus status = IXBHelper.service.doExport( boolean previewOnly, String[ ] generatorIds, String[ ] generatorParams, String[ ] filterIds, String[ ] filterParams, IXBStreamer ruleFile, boolean detailedLog, String stDtd);
exported. From the current Exp GUI, those objects will be chosen by using
NavigatorSearchDialog. After the selection is done, this dialog will return a list of IXBSelectedNavInfo with Navigator Id and Generator Id, and seed object as an objectId. Given an object obj, we can get the Object Id by using IXBHelper.service.getObjectId(obj).
41-34
filterIds - see definition above filterParams is an array of objects attributes to set the objects to be excluded from export process, or to be included in export process, depends on the type of filters. ruleFile is the rule file for export process. This file is provided to Exporter to
STRING_DTD will be calculated based on the current Windchill. When the method IXBHelper.service.doExport() is called, it will call to the method doExportImpl() in the StandardIXBService. This method: Creates a general export handler ExportHandler handler. This is an inner class of StandardIXBService. Gets a list of objects that will be exported by calling:
ObjectSetHelper.computeObjectSetForGivenGeneratorsAndFilters ( generatorIds, generatorParams, filterIds, filterParams);
Creates an instance of Exporter, the class that does the export. Depending on isPreview (true/false) the exporter will do a preview or real export by calling methods of Exporter class mention in the section Exporter class of this document. Calls clean-up methods of the ExportHandler handler.
Import Application
The current Windchill Import GUI and StandardIXBService are the Import Application. The current Windchill Import out-of-the-box GUI is Import Application client that calls import process in StandardIXBService (Import Application server) via IXBHelper.
41-35
Without GUI:
IXBExpImpStatus status = IXBHelper.service.doImport( IXBStreamer ruleFile, IXBStreamer dataFile, boolean overrideConflicts, boolean isPreview, boolean detailedLog, String creatorName, String stDtd);
overridden or not.
isPreview specifies whether the process should do real import, or check
41-36
creatorName specifies how top-level imported objects (for example EPMDocument, WTDocument, WTPart) are created. stDtd specifies which version of Exp/Imp handlers will be used. This is used to support backward compatible. If stDtd is null or empty (), the STRING_DTD
will be calculated based on version of current Windchill system. When the method IXBHelper.service.doImport() is called, it will call to the method doImportImpl() in StandardIXBService. This method: Puts creator name in WTContext to be used by import handler. Creates a general import handler ImportHandler handler. Gets a list of XML files from the Jar file to be imported by calling
jar.getFileNamesByExtension ("xml");
Creates an instance of Importer, the class that does the import job. Depending on isPreview (true/false), the method doImportImpl() calls the appropriate methods of Importer to do a preview or the real import: importer.doImport(stream); importer.doPreview(stream);
The others (importer.doImport(fn, tag) and importer.doPreview(fn,tag)) are for optimization, and they depend on how XML files are named. This feature is just for a particular Exp/Imp Application (wt.clients.ixb and StandardIXBService). Sends log messages back to client.
41-37
import java.util.HashSet; import java.util.Set; import java.util.Iterator; import import import import wt.pom.Transaction; wt.content.ApplicationData; wt.content.ContentItem; wt.content.Streamed;
import wt.ixb.publicforapps.ApplicationExportHandlerTemplate; import wt.ixb.publicforhandlers.IxbElement; import wt.ixb.publicforapps.Exporter; import wt.ixb.publicforapps.IxbHelper; import wt.ixb.objectset.ObjectSetHelper; import wt.util.WTException; import wt.util.WTMessage; import wt.ixb.clientAccess.IXBJarWriter; import wt.fc.Persistable;
public class SimpleApplicationExportHandler extends ApplicationExportHandlerTemplate{ private File targetDir = null; private PrintStream log = null; private IXBJarWriter jw = null; private File resJar = null; private int fileNum = 0; //counter for exported content files private HashSet contentFileNames = new HashSet(); //to handle content files with the same name public static final String NAME_IS_TAG = "TAG"; public final static String CONTENT_SUBDIR = "CONTENTS";
public SimpleApplicationExportHandler(File tmp_storeDir, PrintStream a_log) throws WTException{ if (!tmp_storeDir.exists()){ tmp_storeDir.mkdirs(); } targetDir = tmp_storeDir;
41-38
log = a_log; } public String storeContent (Object ob) throws WTException { String storeName = null; if(ob instanceof ApplicationData) { ApplicationData obj = (ApplicationData)ob; String fileName = obj.getFileName(); try { storeName = this.computeUniqueFileName(fileName); Streamed sd = (Streamed)obj.getStreamData().getObject(); InputStream is = sd.retrieveStream(); jw.addEntry(is, storeName); } catch (IOException ioe) { throw new WTException(ioe); } } return storeName; }
public String storeDocument(IxbElement elem, String dtd)throws WTException { try { String tag = elem.getTag(); String fn = NAME_IS_TAG+"-"+tag+"-"+(fileNum++)+".xml"; File file = new File(targetDir,fn); FileOutputStream stream= new FileOutputStream (file); elem.store(stream, dtd); stream.close(); jw.addEntry(file); file.delete(); } catch (IOException ioe){ throw new WTException(ioe); } } public void storeLogMessage(String resourceBundle, String messageKey, Object[] textInserts) throws WTException{ WTMessage m = new WTMessage(resourceBundle, messageKey, textInserts); String s = m.getLocalizedMessage(); log.println(s); } public void storeLogMessage(String resourceBundle, String messageKey, Object[] textInserts, int importanceLevel) throws WTException{ storeLogMessage (resourceBundle, messageKey, textInserts);
41-39
} public void exportObjectContent (Object obj, Exporter exporter, ContentItem item, String exportFileName) throws WTException { if (item instanceof ApplicationData) { ApplicationData ad = (ApplicationData) item; Streamed streamedIntfc = (Streamed) ad.getStreamData().getObject(); try{ InputStream is = streamedIntfc.retrieveStream(); jw.addEntry(is, exportFileName); } catch (IOException ioe){ throw new WTException(ioe); } } } private String computeUniqueFileName (String fn) throws IOException { //compute file name in jar (should be unique) if (contentFileNames.contains(fn)) { // if simple content's name already has been used then look for // name in form name-123.ext // As a result will have names like: design.doc, design-23.doc, design57.doc, ... int i = fn.lastIndexOf('.'); String fn_n = ( i>0 ? fn.substring(0, i) : fn); String fn_t = ( i>0 ? fn.substring(i+1) : "" ); while (true) { fn = (i>0 ? fn_n + '-' + (fileNum++) + '.' + fn_t : fn_n + '-' + (fileNum++) ); if (!contentFileNames.contains(fn)) break; } } contentFileNames.add(fn); String fnInJar = CONTENT_SUBDIR + "/" + fn; return fnInJar; } public File doExport( WTContainerRef container, String[] generatorIds, String[] generatorParams, String[] filterIds, String[] filterParams, File ruleFile, File policyFile, String actionName, String stDtd, File resultingJar) throws WTException{ //init jar file resJar = resultingJar; try{ jw = new IXBJarWriter(resultingJar); }
41-40
//adopt incoming rule file IxbElement clientSettingsElement = null; if (ruleFile!=null) { try{ InputStream clientSettingsStream = new FileInputStream(ruleFile); clientSettingsElement = IxbHelper.newIxbDocument(clientSettingsStream, false); } catch(IOException ioe){ throw new WTException(ioe); } } //create exporter Exporter exporter = null; if ( policyFile==null ) { // policy rule is null; export action is expected ... exporter = IxbHelper.newExporter(this, container, IxbHelper.STANDARD_DTD, clientSettingsElement, null, actionName); } else{ exporter = IxbHelper.newExporter (this, container, IxbHelper.STANDARD_DTD, clientSettingsElement, policyFile, null ); } //gen set of items to export Set res = ObjectSetHelper.computeObjectSetForGivenGeneratorsAndFilters (generatorIds, generatorParams, filterIds, filterParams); Iterator iter = res.iterator(); Transaction trx = new Transaction(); try { if ( !(actionName != null && actionName.equals(wt.ixb.tuner.ExportActionHelper.NO_ACTION_CMD) )){ trx.start(); } while (iter.hasNext()) { Persistable ob = (Persistable)iter.next(); exporter.doExport(ob); } exporter.finalizeExport(); if ( !(actionName != null && actionName.equals(wt.ixb.tuner.ExportActionHelper.NO_ACTION_CMD) )){ trx.commit(); } trx = null; } finally { if (trx != null) {
41-41
if ( !(actionName != null && actionName.equals(wt.ixb.tuner.ExportActionHelper.NO_ACTION_CMD) )){ trx.rollback(); } trx = null; } } try{ jw.finalizeJar(); } catch(IOException ioe){ throw new WTException (ioe); } return resJar; } }
41-42
import wt.content.ApplicationData; import wt.content.ContentItem; import wt.content.Streamed; import wt.ixb.publicforapps.ApplicationImportHandlerTemplate; import import import import import wt.ixb.publicforhandlers.IxbElement; wt.ixb.publicforhandlers.IxbHndHelper; wt.ixb.publicforapps.IxbDocument; wt.ixb.publicforapps.Importer; wt.ixb.publicforapps.IxbHelper;
import wt.ixb.objectset.ObjectSetHelper; import wt.ixb.actor.actions.IxbActionsHelper; import wt.util.WTException; import wt.util.WTMessage; import wt.ixb.clientAccess.IXBJarReader; import wt.fc.Persistable; import javax.xml.transform.stream.StreamSource;
public class SimpleApplicationImportHandler extends ApplicationImportHandlerTemplate{ private IXBJarReader jr = null; private PrintStream log = null; public SimpleApplicationImportHandler(PrintStream a_log){ log = a_log; } public InputStream getContentAsInputStream (String contentId) throws WTException { try{ return jr.getStreamByName (contentId);
41-43
} catch(IOException ioe){ throw new WTException(ioe); } } public void storeLogMessage(String resourceBundle, String messageKey, Object[] textInserts) throws WTException{ WTMessage m = new WTMessage(resourceBundle, messageKey, textInserts); log.println(m.getLocalizedMessage()); } public void doImport(WTContainerRef container, File ruleFile, File dataFile, boolean _overrideConflicts, String actorName, File policyFile, File containerMappingFile) throws WTException{ try{ jr = new IXBJarReader(dataFile); } catch(IOException ioe){ throw new WTException (ioe); } //prepare rule file String ruleFileName = (ruleFile!=null)? ruleFile.getAbsolutePath(): null; //prepare container mapping file String containerMappingFileName = (containerMappingFile!=null)?containerMappingFile.getAbsolutePath(): null; //prepare policy file String policyFileName = (policyFile!=null)?policyFile.getAbsolutePath(): null; StreamSource xslPolicyFile = null; if (policyFile!=null) { xslPolicyFile = new StreamSource(policyFile.getAbsolutePath()); } Boolean overrideConflicts = new Boolean (_overrideConflicts); Importer importer = IxbHelper.newImporter(this, container, IxbHelper.STANDARD_DTD, ruleFileName, policyFileName, containerMappingFileName, actorName, overrideConflicts, null /*validate*/); String [] fns = jr.getNonContentFileNamesByExtension ("xml"); boolean validate = IxbHndHelper.getIxbProperty("import.parser.validate", false);
41-44
for (int i=0; i<fns.length; i++) { String fn = fns[i]; InputStream stream = null; try{ stream = jr.getStreamByName (fns[i]); } catch (IOException ioe){ throw new WTException (ioe); } IxbDocument doc = IxbHelper.newIxbDocument(stream,
validate);
//if policyFile == null, apply actorName to XML Document before pass it to importer if (policyFile == null){ IxbElement rootElem = doc.getRootElement(); //XML_ACTION_KEY = "actionInfo/action" IxbElement actionElement = doc.getElement(IxbActionsHelper.XML_ACTION_KEY); if (actionElement == null){ rootElem.addValue(IxbActionsHelper.XML_ACTION_KEY, actorName); } else { rootElem.removeChildElement( actionElement); rootElem.addValue(IxbActionsHelper.XML_ACTION_KEY, actorName); } } else { //apply policy file doc = IxbActionsHelper.writeActionAndParametersToFileXML(doc,xslPolicyFile); } //set elem ready for import importer.doImport(doc); } //perform actual import importer.finalizeImport(); }
41-45
41-46
Customization Points
Required artifacts Class files: wt.ixb.pdx.* XSL path used for transformation : <WT_HOME>codebase\registry\ixb\pdx DTD path: <WT_HOME>codebase\registry\ixb\pdx\dtds
Default behavior By default it would be Agile compatible. By default: Agile_07.dtd and wcxml2pdx_agile.xsl would be the respective dtd and xsl corresponding to Agile format. IPC_2571.dtd and wcxml2pdx.xsl would be the respective dtd and xsl corresponding to PDX format.
Overridable properties for wt.properties pdx.export.dtdFilePath=$(wt.home)$(dir.sep)codebase$(dir.sep)registry$(dir.sep )ixb$(dir.sep)pdx$(dir.sep)dtds$(dir.sep) Agile_07.dtd pdx.export.xslFilePath=$(wt.home)$(dir.sep)codebase$(dir.sep)registry$(dir.sep )ixb$(dir.sep)pdx$(dir.sep) wcxml2pdx_agile.xsl pdx.AgileCompatible=true pdx.debug.enable=false
The xsl may also be modified as per requirement or to support PDX export of other exportable windchill objects.
Supported APIs
ExportPackage exportPackage = ExportPackageForPDX.createExportPackageForPDX() PDXExportHelper.doExportToPDX()
createExportPackageForPDX
There are four static public APIs (createExportPackageForPDX) in ExportPackageForPDX to support this functionality.
public static wt.ixb.objectset.ExportPackage createExportPackageForPDX( java.lang.String name, java.lang.String exporter, java.lang.String[] generParams, java.lang.String[] filterParams) java.lang.String description, java.lang.String[] generIds, java.lang.String[] filterIds, throws wt.util.WTException
41-47
Purpose: Creates ExportPackage holding all information necessary for export in PDX format. The objects are collected using standard ixb collection mechanism (generators and filters). Parameters: name Name of the export package description - Description of the export package exporter - Name of the user who makes export generIds - Array of String id for object set generator types, e.g. {"singleDocument", "productStructureNavigatorWithEPM"} generParams - Array of local id for the corresponding seed objects filterIds - Array of String id for object set filters filterParams - Array of Strings representing parameters for filtering
Throws: wt.util.WTException
public static wt.ixb.objectset.ExportPackage createExportPackageForPDX( wt.inf.container.WTContainerRef container, java.lang.String description, java.lang.String[] generIds, java.lang.String[] filterIds, throws wt.util.WTException java.lang.String name, java.lang.String exporter, java.lang.String[] generParams, java.lang.String[] filterParams)
Purpose: Creates ExportPackage holding all information necessary for export in PDX format. The objects are collected within a container using standard ixb collection mechanism (generators and filters). Parameters: container - Object reference of container holding objects to export name Name of the export package description - Description of the export package exporter - Name of the user who makes export generIds - Array of String id for object set generator types, e.g. {"singleDocument", "productStructureNavigatorWithEPM"} generParams - Array of local id for the corresponding seed objects filterIds - Array of String id for object set filters filterParams - Array of Strings representing parameters for filtering
41-48
Throws: wt.util.WTException
public static wt.ixb.objectset.ExportPackage createExportPackageForPDX( java.lang.String name, java.lang.String exporter, java.lang.String[] generParams) java.lang.String description, java.lang.String[] generIds, throws wt.util.WTException
Purpose: Convenience method for the common case when objects are collected without filtering Parameters: name Name of the export package description - Description of the export package exporter - Name of the user who makes export generIds - Array of String id for object set generator types, e.g. {"singleDocument", "productStructureNavigatorWithEPM"} generParams - Array of local id for the corresponding seed objects
Throws: wt.util.WTException
public static wt.ixb.objectset.ExportPackage createExportPackageForPDX( wt.inf.container.WTContainerRef container, java.lang.String description, java.lang.String[] generIds, throws wt.util.WTException java.lang.String name, java.lang.String exporter, java.lang.String[] generParams)
Purpose: Convenience method for the common case when objects are collected within a container without filtering Parameters: container - Object reference of container name Name of the export package description - Description of the export package exporter - Name of the user who makes export generIds - Array of String id for object set generator types, e.g. {"singleDocument", "productStructureNavigatorWithEPM"}
41-49
Throws: wt.util.WTException
doExportToPDX
public static void doExportToPDX( ExportPackageForPDX expPackage, File dirToSave, throws wt.util.WTException String attachmentOption, String zipName)
Purpose: Creates pdx file on server. Parameters: container - Source container expPackage - Export package attachmentOption - Attachments option. Possible values are: PDXExportHandler.XML_VALUE_ATTACHMENTS - content files are included into pdx package (default option) PDXExportHandler.XML_VALUE_NO_ATTACHMENTS - content files are ignored (not mentioned in pdx.xml) PDXExportHandler.XML_VALUE_ATTACHMENTS_AS_FILE_NAME S - content files are mentioned in pdx.xml but are not included into zip
dirToSave - directory on server where the resulting pdx file will be stored zipName - name for the resulting pdx file (pass name without extension since extension '.pdx' is added)
Throws: wt.util.WTException
41-50
public static void doExportToPDX( ExportPackageForPDX expPackage, java.io.File dirToSave, throws wt.util.WTException java.lang.String attachmentOption, java.lang.String zipName)
Purpose: Creates pdx file on server. Parameters: expPackage - Export package attachmentOption - Attachments option. Possible values are: PDXExportHandler.XML_VALUE_ATTACHMENTS - content files are included into pdx package (default option) PDXExportHandler.XML_VALUE_NO_ATTACHMENTS - content files are ignored (not mentioned in pdx.xml) PDXExportHandler.XML_VALUE_ATTACHMENTS_AS_FILE_NAME S - content files are mentioned in pdx.xml but are not included into zip
dirToSave - directory on server where the resulting pdx file will be stored zipName - name for the resulting pdx file (pass name without extension since extension '.pdx' is added)
Throws: wt.util.WTException
41-51
41-52
42
Evolvable Classes
This chapter describes evolvable classes. Topic Page
Background Information ...................................................................................42-3 General Externalization Guidelines...................................................................42-4 Hand-coded Externalization Guidelines............................................................42-4 Migration Guidelines for Classes with Hand-coded Externalization................42-5 Examples of Generated Externalization Code for Evolvable Classes...............42-6
42-1
Externalizable classes that implement the Evolvable interface are the Windchill classes that can be serialized into BLOB columns in the database. As the persistent structure of these classes changes, action may be required to maintain compatibility with previous versions that have been serialized into the database. During the migration period (that is, at Windchill Release 4.0), all Externalizable classes have the methods necessary to manage class compatibility but, in the future, only Evolvable classes will have these features. Any modeled class that is intended to support being serialized into a BLOB database column must implement the Evolvable interface. Once Evolvable is implemented, the owner of the class must manage its compatibility from version to version. The Persistent Data Service (PDS) will report any classes being serialized into the database that implement the NetFactor interface and not the Evolvable interface. This allows third party classes, such as Vectors, Hashtables, and so on, to be serialized into the database. This also allows modeled classes that do not implement NetFactor to be serialized into the database; however, we do not recommend this practice because it leaves the class exposed to serious data migration problems. The best way to specify that a modeled class will implement the Evolvable interface is to set the Serializable property for the class to Evolvable. This property is on the Windchill tab of the class specification in Rose.
42-2
Background Information
As of Release 4.0, the generated externalization code reads and writes a data stream according to the following order, with field values for each class ordered alphabetically: 1. BottomClass.ID 2. MiddleClass.ID 3. TopClass.ID 4. TopClass field value1 5. TopClass field value2 6. TopClass field value...N 7. MiddleClass field value1 8. MiddleClass field value2 9. MiddleClass field value...N 10. BottomClass field value1 11. BottomClass field value2 12. BottomClass field value...N To maintain externalization compatibility of a class from version to version, it is most important to understand the resulting stream layout for each version of a class. When the persistent signature of a class is being changed significantly, it may be helpful to map out the stream format for each version, in order to understand clearly what is necessary to read a previous version of the stream. Beyond the fundamental understanding of the stream format, points in the following sections provide guidance concerning when and what kind of manual intervention is necessary to maintain compatibility.
Evolvable Classes
42-3
Changing the persistent signature of a class requires implementation of readOldVersion pre-Release 9.0 versions. Adding or removing fields. Changing the name or type of a field.
For Windchill Release 9.0 and beyond, the virtually all changes are handled automatically. See explanations in examples sections below for details on how the automated readVersion<EXTERNALIZATION_VERSION_UID> methods are generated.
Do not model a serialVersionUID attribute with a value other than 1 as this disallows the ability to read old versions of the class.
42-4
Evolvable Classes
42-5
42-6
Evolvable Classes
42-7
manage. The first is when an attribute (field) is removed from a release. This case is easy, since the old externalization methods will no longer compile, since they reference non-existent fields. The developer will need to modify the code to not set field, but the old field must still be read off the stream, or it will throw a runtime exception. For example, if the title field is removed from the class, the previous readVersion<EXTERNALIZATION_VERSION_UID> methods will need to change the line that reads the title, as follows.
/*title = (String)*/input.readObject(); // field to assign no longer exists
The second scenario is when attributes (fields) are added. In this case, there will be no compile error and the code will deserialize without problem, but the object could possibly be left in an invalid state. The developer should be aware of this possibility and ensure that the object will be initialized to a valid state.
private boolean readVersion6676079877272797361L( ObjectInput input, long readSerialVersionUID, boolean superDone ) throws IOException, ClassNotFoundException { //##begin readVersion6676079877272797361L%readVersion6676079877272797361L.body preserve=maybe if ( !superDone ) super.readExternal( input ); a1 = (String)input.readObject(); a2 = (Date)input.readObject(); a3 = (Xyz)input.readObject(); list = (Vector)input.readObject(); String size_string_value = (String)input.readObject(); try { size = (MySize)wt.fc.EnumeratedTypeUtil.toEnumeratedType( size_string_value ); } catch( wt.util.WTInvalidParameterException e ) { // old format size = MySize.toMySize( size_string_value ); } theOneMoreReference = (ObjectReference)input.readObject(); timeline = (Timeline)input.readObject(); work = (MyAddress)input.readObject(); return true; //##end readVersion6676079877272797361L%readVersion6676079877272797361L.body } // if not doing backward compatibility // handle super class
42-8
Evolvable Classes
42-9
" + readSerialVersionUID + " local class externalizationVersionUID= " + EXTERNALIZATION_VERSION_UID ); return success; //##end readOldVersion%readOldVersion.body }
42-10
43
Creating Large Objects (LOBs)
This chapter describes how to create large objects (LOBs). Topic Page
43-1
DDL Generation
The DDL generated by Windchill defines the BLOB columns to be stored in their own tablespace. This can be controlled for each attribute by changing the tablespace property under the Windchill tab while modeling. The tablespace must be defined before the DDL is executed. The name of the default tablespace to contain BLOBs can be modified using a property in the user.properties file. See the properties.html file for details on the specific property. Note: Both Oracle and SQLServer support this tablespace feature. SQLServer terminolgy refers to this concept as FileGroups.
43-2
1. Make the class Externalizable, which aids performance as well. 2. Specify a fixed serialVersionUID value. 3. Put an internal version number on the object stream and handle version changes in code. See the code-generated Externalizable business classes for an example of this technique. The disadvantage is that all subclasses are now Externalizable and require readExternal and writeExternal methods. You can use the same type of technique with Serializable (fix serialVersionUID and implement read/writeObject) if independence from the class hierarchy is important.
Small BLOBs
SMALLBLOBs are encoded into Strings before being stored and are mapped to VARCHAR2(4000) rather than BLOB. Because of the size limitation of 4,000 characters, this option is inflexible and should be used with caution. Your code should be prepared to handle the possible exception that is thrown if the size of the attribute grows beyond what can be encoded into 4,000 characters.
Inline BLOBs
INLINEBLOBs combine the features of SMALLBLOB and BLOB to provide better performance when data is small, but still allow for large data storage capability. An attribute that is stored as an INLINEBLOB uses two columns: A VARCHAR2(4000) column A BLOB column
Each object is examined at runtime and, when the data is small enough, it is stored in the VARCHAR(4000) column; otherwise, it is stored in the BLOB column. When the data is stored in the VARCHAR(4000) column, no additional datastore calls are required to read the BLOB data. Using an INLINEBLOB introduces a fixed cost in terms of storage (two columns are used instead of one) and additional processing at runtime. However, when the majority of data is stored inline with the table, this cost is negligible in comparison to the performance benefits. If most of the data exceeds the 4000-byte limit, BLOB storage is probably more appropriate. However, if it is known that all data will never exceed the 4000-byte limit, SMALLBLOB should be used.
43-3
Example
An example follows, which uses the classes shown in the following figure.
/* * * Lobber is an example of storing BLOBs. BlobClass has three BLOBs: * imablob which is LobLocator, and imasmallblob, and imanothersmallblob * which are * */
public class Lobber { private static final int size = 1000; private static BlobClass atr = null; private static Enumeration lob_files; public static void goLobs( String lob_dir ) { try { // create a BlobClass object lob_files = getLobFiles( lob_dir ); // loop thru the files in this directory if ( lob_files != null ) { if ( lob_files.hasMoreElements() ) { try { String lobIt = (String)lob_files.nextElement(); File lobFile = new File(lobIt); long len = lobFile.length(); System.out.println( "file length "+len ); InputStream aIs = new FileInputStream(lobFile);
43-4
System.out.println( "bytes available on this InputStream "+aIs.available()); atr = createBlobClassRec(lobIt); Transaction trx = new Transaction(); trx.start(); // save the class containing the LOB atr = (BlobClass) PersistenceHelper.manager.save(atr); // // // // Save a LOB of unknown length. Note that PersistenceServerHelper is used rather than PersistenceHelper. This is server side only code.
long theLength = (long)PersistenceServerHelper.manager.updateLob( (Persistable)atr, atr.getImablob(), aIs, false ); // save a LOB of known length len = lobFile.length(); System.out.println( "file length "+len ); aIs = new FileInputStream(lobFile); System.out.println( "bytes available on this InputStream "+aIs.available()); PersistenceServerHelper.manager.updateLob( (Persistable)atr, atr.getImablob(), aIs, len, false ); trx.commit(); trx = null; aIs.close(); } catch ( FileNotFoundException fnf ) { fnf.printStackTrace();} catch ( IOException ioe ) {ioe.printStackTrace();} finally { if ( trx != null ) { trx.rollback(); throw new RuntimeException("Error processing lobs"); } } } } } catch (WTException WTe) { WTe.printStackTrace();
43-5
} } private static Enumeration getLobFiles( String ldir ) { String[] s_files = null; Vector aVec = new Vector(); File lob_dir = new File( ldir ); if ( !lob_dir.isDirectory() ) return null; s_files = lob_dir.list(); for ( int i=0; i for ( int i=0; i
43-6
44
Customizing Data Formats
This chapter explains how to customize data formats. Topic Page
44-1
You can use a command-line utility, provided by Solution Name, to maintain data format objects.
You are then prompted to provide values for the following attributes:
Attribute Description
Displays this name (for example, Microsoft Word) in the client to identify the file format. The value specified must be unique. The MIME type (for example, application/msword) to be used in downloading a file of this type. You must specify a space-separated list of valid extensions for the MIME type (for example, .txt, .text, or .t). This is the way in which the format of these objects will be set when a file is uploaded. Describes this data format object. Indicates whether or not this data format type can be indexed. Most MIME types supported are defined in the system when it is installed. However, any simple text format is indexable.
44-2
Attribute
Description
Icon (required)
Defines the path to a subdirectory of the codebase that contains the icon for this format type. When you add a data format type, you have the option to reference an icon other than one of those found in the Solution Name codebase. However, you must ensure that the pixel size for your icon is 16 x 16 to avoid an error when viewing icons. Defines the extensions that are associated with this particular mime type (for example, .doc or .rtf for Microsoft Word).
Extensions (required)
After adding a new format for a MIME type using DataFormatUtil, you must add a new line for that format to the wt\content\FormatNameRB.rbinfo file and then run the ResourceBuild utility to generate resource classes from FormatNameRB.rbinfo file. Enter the new line using the following format:
<Mime_Type>.value=<Display_Value>
For example, if the MIME type is Java Archive and display value desired is Java Archive File, then new entry is as follows:
Java Archive.value=Java Archive File
For details on using the ResourceBuild utility, see the System Generation chapter on page 31-1.
The tool prompts you for the format name of an existing data format object. After you have identified the data format, you can update its attributes. If you make a change to the MIME type name or display value, you must also update the corresponding line in the wt\content\FormatNameRB.rbinfo file. Note: If you change the MIME type of a data format object, you must stop and restart the method server to implement the change.
44-3
The tool prompts for the format name of an existing data format object. After the data format is identified, the tool will prompt for a new name for the data format.
The tool prompts for the format name of an existing data format object. After the data format is identified, it gets deleted. If any object currently refers to this data format, then data format is not deleted and error is shown.
44-4
V
Customization Appendices Section
Chapter
Page
Extendable Classes in the Windchill Supported API............................ A-1 Multi-Object Conversion Guidelines .................................................... B-1 Creating Non-Modeled Services for Listening ..................................... C-1 Windchill Profiler ................................................................................. D-1 Additional Topics - Client Customization .............................................E-1
A
Extendable Classes in the Windchill Supported API
This appendix lists many of the extendable classes and implementable interfaces in the Windchill supported API. It serves as a roadmap to help guide developers when initiating modeling activities. Further information about these classes can be found throughout this manual, and in the Windchill Javadoc. Many Windchill objects and features can be tailored without programmatic customization. For more information on these options, see the Customization Overview on page 1-1. Additional information can also be found in the Windchill System Administrator's Guide, and the Windchill Business Administrator's Guide. Topic Page
PDM Business Information Classes ...................................................................A-2 Enterprise Business Information Classes ...........................................................A-2 Windchill Services .............................................................................................A-2 Foundation Classes.............................................................................................A-3 PDM Auxiliary Business Information Classes...................................................A-3 Business Logic Classes ......................................................................................A-3 Server Development Classes ..............................................................................A-4 Client Development Classes...............................................................................A-5
A-1
Windchill Services
The following extendable classes represent the Windchill plug-and-play interfaces. For more information, see the Windchill Services chapter on page 30-1.
wt.change2.Changeable2 wt.content.ContentHolder wt.content.FormatContentHolder wt.folder.Foldered wt.folder.IteratedFoldered wt.index.Indexable wt.locks.Lockable wt.ownership.Ownable wt.vc.baseline.Baselineable wt.vc.Iterated wt.vc.Mastered wt.vc.Versioned wt.vc.views.ViewManageable wt.vc.wip.Workable
A-2
Foundation Classes
For an overview, see the Modeling Business Objects chapter on page 4-1, specifically the Windchill Foundation Abstractions section on page 4-8.
wt.fc.BinaryLink wt.fc.IdentificationObject wt.fc.Identified wt.fc.Item wt.fc.Link wt.fc.NetFactor wt.fc.ObjectMappable wt.fc.ObjectReference wt.fc.ObjectToObjectLink wt.fc.Persistable wt.fc.QueryKey wt.fc.SemanticKey wt.fc.UniquelyIdentified wt.fc.WTObject wt.fc.WTReference
A-3
wt.part.HtmlPreformattedPartsListVisitor wt.series.HarvardSeries wt.series.IntegerSeries wt.series.MulticharacterSeries wt.series.MultilevelSeries wt.series.Series wt.vc.baseline.Baseline wt.vc.baseline.BaselineVisitor wt.vc.baseline.ManagedBaseline wt.vc.config.ConfigSpec wt.visitor.BasicNodeExpander wt.visitor.CompositeVisitor wt.visitor.ConfigSpecNodeExpander wt.visitor.Expander wt.visitor.NodeExpander wt.visitor.NodeExpandInfo wt.visitor.RoleExpandInfo wt.visitor.TextOutputVisitor wt.visitor.Visitor wt.visitor.VisitorAdapter wt.visitor.Walker
A-4
A-5
A-6
B
Multi-Object Conversion Guidelines
Topic
Page
Conversion Overview......................................................................................... B-2 API Guidelines ................................................................................................... B-3 Collections Guidelines ....................................................................................... B-7 Event Dispatch Guidelines ................................................................................. B-9 Multi-Object Delegation Guidelines ................................................................ B-10 Multi-Object Exceptions Guidelines ................................................................ B-11 Multi-Object CRUD API Guidelines ............................................................... B-13 Batch Update/Delete Guidelines ...................................................................... B-13 Transaction Context/Listener Guidelines......................................................... B-14 Neat Tips and Tricks ........................................................................................ B-15
B-1
Conversion Overview
Objectives
Windchill performance is largely a function of database access: how often you go to the database, what you send it, what you ask it to do, and what you ask it to send back to you.The primary goal of converting single-object APIs to multiobject is to replace the CRUD operations driven by single objects with multiobject CRUD operations. A single-object operation that does a query and then updates, individually, the objects returned by that query will execute n queries and as many updates as the number of objects those queries produce. Ideally, the multi-object conversion of that operation will execute one query and one update. While what is being sent to the database, asked of the database, and sent back from the database is about the same, the number of trips has been significantly reduced. Since the connection cost is significant (and, furthermore, since the CRUD operations take advantage of more performant batch SQL operations), the multi-object will significantly outperform the looped-over single-object operation. This is true even before the VM cost of the looping is factored in.
Considerations
The following factors weigh in to increase the complexity of multi-object operations over their single-object counterparts: What should the multi-object operation's signature look like? Exceptions? Related data changing? Data coming at you for different reasons? Complex query building?
B-2
API Guidelines
Multi-Object vs. Multi-Multi-Object APIs
The changeFolder example is a good, illustrative example of how far to go when converting to multi-object. The single object changeFolder API is defined as follows:
public Foldered changeFolder(Foldered member,Folder newFolder)throws WTException
The first API requires that all of the objects in the set go to the new folder and represents a simple multi-object API that would require the caller to call the API multiple times if changes to multiple folders are required. The second API simply maps the foldered object to the new folder to change to; it (the multi-multi-object API) is more complex there's a lot more to manage in the API and the caller is required to build the map even if all of the objects are going to a single location. If the second implementation requires an internal breakup by folder, it'll likely not be appreciably more performant than the former. Then again, if it doesn't need to break up the data and can dispatch a single event for all the moved objects, it will likely be more performant, although the added complexity will then be passed onto the multi-object listeners. If performance is the only measurement, the multi-multi-object API wins. However, there are other factors to consider: When weighing the performance benefits, is it really the case that in the API (and in any of the listeners for the events the API might dispatch) the code won't simply end up breaking up the work in such a way that it's really looping over the work as though it were multi-object and not multi-multiobject? Is there a real need to provide that flexibility? Is the additional flexibility worth the additional complexity? If more than a map is needed, multiple, ordered arguments grouped by index is probably the only way to pass the data, but this is somewhat ugly. For example, checkout takes a Workable to check out, a folder to check out to, and a note representing the check out comment; making all three arguments multi-object most likely implies two lists and an array, or three lists.
Note: The changeFolder APIs in the Folder Service are not intended to be used when moving Foldered objects between containers; the moveAllVersions API in the Container Move Service should be used instead.
B-3
B-4
WTList is ordered, which may be needed by some multi-multi-object operations. WTSets provide the most efficient lookup (good for when contains(...) is needed), WTLists have smaller and more efficient memory footprints It is easy to convert between container types.
So, what arguments should your operation take? Firstly (and to reiterate), it should take the interfaces (WTCollection, WTList, WTSet) rather than the concrete classes (WTArrayList, WTHashSet) because the synchronized and unmodifiable variants of these collections do not descend from WTArrayList/WTHashMap. Beyond that, an operations should take what it contractually requires (which may require internal conversions for implementation efficiency): Take a WTList if order matters because other arguments to the operation must be paired with collection (also consider WTKeyMap and WTValuedMap, covered later). Take a WTSet if duplicates should not exist. Take a WTList if both order and duplicates matter (the operation should then internally validate uniqueness). Take a WTCollection if neither duplicates nor order matters.
And, similarly, what should an operation return? Most operations should return WTCollection, providing them the ability to change the underlying implementation without impacting callers In cases where the returned collection is the same object as an argumentpassed collection, return the same type as that argument
Empty collections
Windchill does not have a prescribed standard for the validation of arguments to a method. Some methods exhaustively validate each argument, others leave invalid arguments to fail later in the method (via NullPointerExceptions and the like). The issue of argument validation comes up in collections not because they might be null, but because transformation operations (sub-collections, conditional copying of collection elements, etc.) may result in a collection being empty. That empty collection, then, may be passed to another multi-object API. What would it mean to call store with an empty collection? What should the store method do? There are a few options relative to this: The method checks if the collection argument is empty; if it is empty, it throws an IllegalArgumentException
B-5
The method checks if the collection argument is empty; if it is empty, it returns (which may necessitate the creation of a potentially ambiguous return value) The method follows the predominant practice for other arguments today; that is, it assumes arguments are passed correctly and attempts to go about its business, potentially failing in odd ways somewhere along the line.
This document recommends the last option. It is the caller's responsibility to recognize when its collections' manipulations may result in empty collections and the caller should not call other multi-object operations with an empty collection. The behavior, unless explicitly documented otherwise, of any multi-object operation is considered to be undefined when empty collections are passed. The justifications for this approach are as follows: There is no established precedent that suggests arguments should be exhaustively validated in Windchill methods, public or not, supported or not. The prevailing practice is that arguments are not checked at all. Operations that manipulate collections in such a way that empty collections may result are presumably a minority, while there can be lots of multi-object operations; it makes sense to localize the handling of empty collections by making it the responsibility of the method that could produce them to handle the end-case. Experience with methods that can produce empty collections has shown that the methods themselves will generally fail even if the multi-object methods they call do not, so it's generally necessary for these methods to be aware of and handle the empty collections they may produce.
Memory considerations
A multi-object operation has a much higher footprint than the corresponding single object operation. This is true in both the VM, where multi-object operations take significantly more memory, and in the database, where transaction sizes increase dramatically. There are some things that can be done to the reduce memory footprint, such as querying only what is needed to make decisions. Both the VM and Oracle can be tuned to handle the expected increased footprints.
B-6
Collections Guidelines
Inflating
The WTCollection interface transparently masks the fact that a persistable can be represented as a QueryKey, WTReference, or full-blown Persistable. It also has iterator APIs (queryKeyIterator(), referenceIterator(), and persistableIterator()) to get the objects based on the representation desired. The persistableIterator() will inflate the query keys and references if they are ot already inflated, but it is important to note that referenceIterator will not. This means that one should be extremely careful using the following code:
for (Iterator i =col.referenceIterator();i.hasNext();){ ... Persistable p =((WTReference)i.next()).getObject(); ... }
The problem with the above code is that the getObject() may result in sequential inflates. Unless you're absolutely sure the collection has bee inflated, this is a bad idea. Even if you are, it's a bad idea. Instead, use the persistableIterator()API.
Using connect()
WTCollection's inflate and refresh implementation does not replace persistables in-place. This means that two collections with the same data may become out-ofsync when an inflate or refresh is done on one of the collections. When creating new collections from the objects in existing collections, use the connect() APIs to ensure that the changes made to objects in one collection affect all the collections which contain the same objects.
WTKeyedMap vs.WTValuedMap
The WTKeyedMap is a map in which the keySet is essentially a WTCollection, providing all of the benefits of the WTCollection to the keys. The values, however, are just a regular collection. Many APIs will wish to map Persistables as keys to Persistables as values, which is exactly what the WTValuedMap provides; the WTValuedMap's values are a WTCollection. Where both the keys and the values are Persistables, the WTValuedMap should be used.
B-7
differently cannot be connected, because the toIdArray() API will return different IDs for the same objects (one will return OIDs and the other branch Ids), and the get/contains(QueryKey/WTReference) APIs will return false if the reference/key is different than the one in the collection even if the persistable is logically equivalent. Multi-object operations acting on Iterated data, presumably, would need to handle collections keyed either as OBJECT_IDENTIFIER or as VERSION_FOREIGN_KEY. This can get quite complicated, even if the operation simply throws in the towel, inflates the collection, and creates a new collection that is keyed properly . Rather than force all operations to deal with this, the guideline should be that all multi-object operations will assume the collection passed in is keyed as OBJECT_IDENTIFIER unless specifically documented otherwise. This is for the following reasons: The added complexity of handling multiple keyings could, and most likely would, dwarf the true logic on the method. Collections keyed differently cannot be connected. The collection must be inflated to convert their contents to another collection that is keyed differently.
Callers should not call multi-object APIs with collections keyed as VERSION_FOREIGN_KEY unless the APIs are explicitly documented to take them. The APIs being called are not required to verify the passed-in collections' key type, and will most likely fail in odd ways if invalid collections are passed.
Modifying collections
Generally, the contents of collections passed to an operation as argument should not be altered (by removing or adding members); doing so alters the caller's collection. Be especially careful using collections' APIs that produced backedcollections, such as the subCollection(...) APIs, as modifying the contents of a backed collection also change the contents of the source collection.
B-8
In general, little should be done to the single-object events save superficial clean up (such as removing the service). An exception to this is when the changes to the event to make it multi-object necessitate a re-evaluation of the single-object event.
Use of collections
The multi-object events, like other multi-object operations, should pass collections of objects. These collections should be unmodifiable to ensure that listeners and the APIs they call do not alter the contents of the collection.This deviates slightly from the relaxed stance taken above, however there is never justification for a listener to alter an event's contents, so it should be ensured that this does not happen.
B-9
KeyedEvent's getEventTarget()API
The single-object events all upheld an unspoken, implicit contract when implementing getEventTarget(). The API always returned the target Persistable of the event. This made it possible for listeners to listen generically to multiple events, casting the result of getEventTarget() to a Persistable. The notification functionality, for example, relies on the ability to generically listen to arbitrary events. Multi-object variants of the single-object events must adhere to this policy by ensuring that the result of calling getEventTarget() on a multi-object event is a WTCollection of some form. This will allow generic listeners to cast getEventTarget() to a collection without requiring further knowledge of the event. Note that this does not preclude using the eventTarget field to store more complicated data, such as WTValuedMaps in the WorkInProgressServiceEvent, so long as getEventTarget() is overridden in the event to return an appropriate collection.
B-10
Pre-flight checks
The single-object APIs all fail fast -- once an error condition is discovered, processing stops and an exception is thrown. For example, if it is determined that the object a user wants to check out is already checked out, the code doesn't continue determining if the user does or does not have modify access; it bails out and throws an exception. Many single-object APIs, and by extension their multi-object counterparts, perform what are called pre-flight checks . These are the validations that occur before the real work is done to the object(s). The single-object APIs bail when the first validation fails. With multi-object operations, however, it is possible to take the another approach. Upon encountering an error, they may continue to collect additional problems so as to later report a more informative exception message. Thus, the multi-object check out operation could check access (provided it uses the non-exception throwing hasAccess ), validate that the objects aren't already checked out, and do a number of other things, recording the problems along the way, and eventually throw a single exception with messages for each of the failures. The motivation to do this is the belief that it will aid the users, as they will get as much information
B-11
up front as opposed to needling them incrementally (assuming they can and actually do fix the problems reported to them). This document recommends against this approach in favor of the continued practice of failing fast for the following reasons: Exceptions are expected to be infrequent; you should not put significant work into them. This approach requires the use of non-exception-throwing APIs; the exception-throwing variants would prematurely terminate the pre-flight checks. These exception-throwing variants throw their own exceptions, which may be strongly-typed exceptions (such as NotAuthorizedException),and provide their own messages. Calling the non-exception-throwing variants drops the strong typing and makes the message building the caller's responsibility. The additional information gathered is not necessarily correct nor complete. You may either mask errors or produce unreliable ones by either dropping/retaining the objects in the collection that logically failed a preflight check. Similarly, addressing all the issues uncovered during the preflight checks does not guarantee success; there will always be at least some needling.
B-12
In most cases, it is sufficient to say that their use should be limited only to cases where there is never a need to bring the object (or its reference) back to memory and should never be used on objects already in memory. The above guidelines are based on the fact that the performance benefits drop when the data is actually needed and by the fact that the changes will not be reflected in any of the inmemory objects. However, a gray area for batch update is in cases where the references are needed for event dispatch, the dispatched event indicates that the change has occurred, and the listeners need not inflate.
B-13
Single-object contexts
Existing single-object code that puts objects on the method context for downstream processing will need to be evaluated. Both the code that puts the object on the context and the code that processes it will likely need to change. In fact, only when the downstream consumer of the context data is guaranteed to still be flat-lined (from the point that the flat-lined code added the context) will the single-object context be OK. The issue, especially in the case of contexts added by listeners, is that the downstream code may be dealing with the entire collection while only a single object is on the context. Keep in mind that the dispatch order is multi0-ab, single0-a, single0-b, multi1ab, single1-a, single1-b, NOT multi0-ab, multi1-ab, single0-a, single1-a, single0-b, single1-b, so if one listener, in single-object mode, adds an object to the context for another listener to consume, the other listener will always only get the last object in the collection on the context because event dispatch will loop over the first listener (single0-a, single0-b) before getting to the second one (single1).
B-14
The classic use case for deferred validation is when changes to related objects in the same transaction impact the logic of the listener and its APIs. Because of flat-lining and the splitting of collections, if the listener/API cannot handle any of the following, it should move its work into a transaction listener: A related object having already undergone change prior to this object's/collection's changes that are being handled now. The changes occurring to related objects in the same collection. A related object changing after this listener/API processes it.
Remember that the other objects that are changing will likely have their own events associated with them, returning to the same listener/API. You should consider, based on the above points, what happens when related data changes and is processed by the same code both before and after this collection is processed and what it means for data in the same collection to be changing.
The master references in the parts will automatically reflect the persisted changes of the partMasterCollection (most notably, the OIDs will now be in the references.
B-15
B-16
C
Creating Non-Modeled Services for Listening
Topic
Page
Overview ............................................................................................................ C-2 Create a Service Interface................................................................................... C-2 Create a Standard Service Class......................................................................... C-3 Compile .............................................................................................................. C-5 Register the New Service ................................................................................... C-6 Restart the Method Server.................................................................................. C-6
C-1
Overview
Customers that do not have Windchill InfoModeler may create services for listening to events generated by other services (customers that have Windchill InfoModeler should create listeners by following the instructions in the Creating a Listener Service section of this Guide). Here are the steps necessary to create a non-modeled service for listening: 1. Create a service interface 2. Create a standard service class to implement your service interface and extend the StandardManager class 3. Compile your interface and class into your Windchill codebase 4. Register your new service in the codebase with xconfmanager Below is an example to create a service that listens for pre- and post-checkin events. When it "hears" one of these events, it prints a simple message to standard output. The example assumes the service is in a package called com.acme.listen, and that the service is called the "Listen" service. If you copy this example, be sure to change these names to something more appropriate. The example assumes that you are familiar with the information in the Developing Server Logic chapter on page 35-1.That chapter explains how to write code to register listeners for particular events.
C-2
The example below has comments that indicate "standard" pieces of code that should not be changed as they are necessary to interact with the standard service manager and other services. There are other comments that indicate pieces of code that should be changed, for example, to reflect your choice of package and class names and to listen to the particular events you are interested in. Here is the source code:
/* Change to your package name */ package com.acme.listen; /* javac -classpath z:/Windchill/codebase -d z:/Windchill/codebase *.java */ /* xconfmanager -t codebase/wt.properties -s wt.services.service.4160=com.acme.listen.ListenService/com.acme.listen.StandardList enService -p */ /* Change to import you Service Interface */ import com.acme.listen.ListenService; import java.lang.String; /* Standard imports for services */ import wt.services.ManagerException; import wt.services.ServiceEventListenerAdapter; import wt.services.StandardManager; import wt.session.SessionContext; import wt.session.SessionHelper; import wt.session.SessionServerHelper; import wt.session.SessionMgr; import wt.util.DebugFlag; import wt.util.DebugProperties; import wt.util.DebugType; import wt.util.DebugWriter; import wt.util.WTException; /* Changes required here: * Imports necessary for listening to particular events, in this case * check-in and check-out events */ import wt.vc.wip.Workable; import wt.vc.wip.WorkInProgressServiceEvent; /** * Listens for pre/post checkin events. When an event is * "heard", prints messages to the MethodServer log and console. * <p> * Use the <code>newStandardListenService</code> static factory method(s), * not the <code>StandardListenService</code> constructor, to construct * instances of this class. Instances must be constructed using the static * factory(s), in order to ensure proper initialization of the instance. * <p> *
C-3
**/ /* Change to your class name */ public final class StandardListenService extends StandardManager implements ListenService { /* Standard class identification string */ private static final String CLASSNAME = StandardListenService.class.getName(); /* Standard debug variables for services */ private static final boolean DEBUG = DebugProperties.isDebugOn(CLASSNAME); private static final DebugWriter LOG = (DEBUG ? DebugProperties.getWriter(CLASSNAME) : null); /* Standard getter for class name */ public String getConceptualClassname() { return CLASSNAME; } /* * Standard default factory for the class. * */ public static StandardListenService newStandardListenService() throws WTException { StandardListenService instance = new StandardListenService(); instance.initialize(); return instance; } /* * Initializations of event listeners */ /* Override inherited method */ protected void performStartupProcess() throws ManagerException { /* Standard debug output */ if (DEBUG && DebugProperties.isTrace(this)) LOG.enter(CLASSNAME,"performStartupProcess"); /* Standard way to become admin */ SessionContext prev = SessionContext.newContext(); try { SessionHelper.manager.setAdministrator(); } catch (WTException wte) { System.err.println("StandardListenService: failed to set Administrator (ok if installation)"); return; } finally { SessionContext.setContext(prev); }
C-4
/* Change: Add event listeners here */ getManagerService().addEventListener( new ServiceEventListenerAdapter( this.getConceptualClassname() ) { public void notifyVetoableEvent( Object event ) throws WTException { final Workable target = ((WorkInProgressServiceEvent)event).getOriginalCopy(); System.out.println("Listen hears PRE_CHECKIN: "); System.out.print(" target:"); System.out.println(target.toString()); } }, WorkInProgressServiceEvent.generateEventKey( WorkInProgressServiceEvent.PRE_CHECKIN )); getManagerService().addEventListener( new ServiceEventListenerAdapter( this.getConceptualClassname() ) { public void notifyVetoableEvent( Object event ) throws WTException { final Workable target = ((WorkInProgressServiceEvent)event).getOriginalCopy(); System.out.println("Listen hears POST_CHECKIN: "); System.out.print(" target:"); System.out.println(target.toString()); } }, WorkInProgressServiceEvent.generateEventKey( WorkInProgressServiceEvent.POST_CHECKIN )); /* Standard debug output */ if (DEBUG && DebugProperties.isTrace(this)) LOG.exit(CLASSNAME,"performStartupProcess"); } }
Compile
Compile your classes into:
<Windchill>/codebase/com/acme/listen
C-5
Note that xconfmanager will add the entry to site.xconf and then propagate the changes to wt.properties.
C-6
D
Windchill Profiler
The Windchill Profiler can be used to help diagnose performance bottlenecks after you have customized code. It enables you to capture an elapsed time profile while executing application logic in the method server. The profile shows call stacks, call counts, and context data (for example, SQL, bind parameters, JNDI strings, son on). PTC recommends profiling in a test environment; however, profiling is possible in a production environment without interrupting system operation. Topic Page
D-1
Overview
The Windchill Profiler enables you to instrument server side application logic. A user interface is provided to control the profiler, which is embedded within the method server. Note: Support for the profiler is limited and the profiler is subject to change without notice.
Profiler Features
The Windchill Profiler supports the collection of performance profiles in the following Windchill subsystems: JDBC execution CacheManager get/put/update WTAdapter JNDI Task RMI Object Serialization
The profiler allows you to filter call stacks by thread; sort call stacks by count or by cost (for example, elapsed time). The call stacks, call counts, and elapsed times are displayed in a JTree format. The output can include additional data such as SQL bind parameters or cache keys. Profiles can be saved to disk and reloaded, or they can be exchanged using e-mail. HTML summaries can also be generated.
Profiler Operation
To launch the profiler, open a command shell on the Windchill server. From the windchill shell, invoke the profiler as follows:
windchill wt.tools.profiler.WindchillProfiler
Note: A long running profile session might need a larger heap. In that case, use the following command to start the profiler:
windchill --javaargs=-Xmx512m wt.tools.profiler.WindchillProfiler
You are prompted to authenticate. Log in as the administrative user. If the authentication is successful, the profiler opens. From the Operations drop-down menu, select the area that you want to profile. For example to profile all JDBC executed by the Method Server, select SQL + Execution Time + Bind Parameters. To start collecting the SQL profile, click the blue start button. To stop collecting profile data, click the red button.
D-2
In the following example, an RMI-based client executed a number of method calls. Notice that the profile frame is divided into two panes: The left pane allows you to select call stacks sorted by count or by cost. The right pane shows the call stacks for all threads captured by the profile.
Call stacks appearing in the right pane need to be expanded until the leaf node for a given call stack is displayed. The leaf node of a call stack contains an SQL string.
Windchill Profiler
D-3
The call count field for SQL profiles may be a little confusing to interpret at first. To illustrate, look at the following example
O-count=157:wt.pds.BasicResultCursor.next(BasicResultCursor.java:487):cost=16 O-count=155:wt.pds.BasicResultCursor.advance(BasicResultCursor.java:626):cost=16 | O-count=155:wt.util.TraceTimingHelper.addEndEntry(TraceTimingHelper.java:159): cost=16 | O-count=155:wt.util.TraceTimingHelper.addEndEntry(TraceTimingHelper.java: 134):cost=16 | O-count=155:wt.util.TraceTimingThreadedLogger.addEndEntry( TraceTimingThreadedLogger.java:208):cost=16 | '-count=155:DB FETCH: SELECT 'wt.epm.workspaces.EPMWorkspace',... FROM EPMWorkspace A0 WHERE ((A0.idA3M5 = ?)) AND (A0.markForDeleteA2 = ?):cost=16 count=2:wt.pds.BasicResultCursor.advance(BasicResultCursor.java:633):cost=0 O-count=1:wt.pds.BasicResultCursor.getNextResultSet(BasicResultCursor.java: 683):cost=0 | O-count=1:wt.pds.BasicStatementBuilder.getStatement(BasicStatementBuilder. java:236):cost=0 | O-count=1:wt.pom.WTConnection.prepareStatement(WTConnection.java:433): cost=0 | O-count=1:wt.util.TraceTimingHelper.addEndEntry(TraceTimingHelper.java: 159):cost=0 | O-count=1:wt.util.TraceTimingHelper.addEndEntry(TraceTimingHelper.java: 134):cost=0 | O-count=1:wt.util.TraceTimingThreadedLogger.addEndEntry (TraceTimingThreadedLogger.java:208):cost=0 | '-count=1:DB PREPARE:cost=0 O-count=1:wt.pds.BasicResultCursor.getNextResultSet(BasicResultCursor.java: 705):cost=0 O-count=1:wt.util.TraceTimingHelper.addEndEntry(TraceTimingHelper.java: 159):cost=0 O-count=1:wt.util.TraceTimingHelper.addEndEntry(TraceTimingHelper.java: 134):cost=0 O-count=1:wt.util.TraceTimingThreadedLogger.addEndEntry (TraceTimingThreadedLogger.java:208):cost=0 '-count=1:SELECT 'wt.epm.workspaces.EPMWorkspace', FROM EPMWorkspace A0 WHERE ((A0.idA3M5 = ?)) AND (A0.markForDeleteA2 = ?):cost=0
Every new query comprises three phases: 1. DB PREPARE 2. EXECUTE 3. FETCH The sample above shows a count of 157 that is comprised of 1 Prepare, 1 Execute and 155 rows fetched. The cost field is milliseconds it took 16 ms to execute this query.
D-4
E
Additional Topics - Client Customization
This appendix provides additional procedures for performing client customizations. These procedures are not expected to be commonplace, but may be useful in advanced customization scenarios. Topic Page
Launching a DCA Wizard From a JSP Page...................................................... E-2 Embedding a DCA Page in a JSP to Use as a Main Page .................................. E-3 Defining Non-JSP Actions to be Executed From a JSP Page ........................... E-3 URLFactory in the JSP Environment................................................................. E-7 Using File-Handling Applets in Non-JSP Clients............................................ E-15
E-1
E-2
When your custom tab is selected, the DCA page will be presented in a frame under the tab.
E-3
<objecttype name="site" class="com.ptc.netmarkets.site"> <action name="view" checkaccess="true" enabledwhensuspended="true"> <command windowType="page"/> </action> <action name="listOrgs" checkaccess="true" enabledwhensuspended="true"> <command windowType="page"/> </action> <action name="listFiles" checkaccess="true" enabledwhensuspended="true"> <command windowType="page"/> </action> <action name="listAdmin" enabledwhensuspended="true"> <command windowType="page"/> </action> <action name="listTypes" enabledwhensuspended="true"> <command windowType="page"/> </action> <action name="listTemplates" enabledwhensuspended="true"> <command windowType="page"/> </action> <action name="listUtilities" enabledwhensuspended="true"> <command windowType="page"/> </action> <action name="site_audit_Reports" enabledwhensuspended="true"> <command windowType="page"/> </action> </objecttype>
where <type> and <action> are, respectively, the names of the objecttype and action specified in actions.xml. For example, above is an action with name="view" defined under an objecttype with name="site". Since a renderType attribute is not specified in the action element, the URL
http://<hostname>/<webapp>/netmarkets/jsp/site/view.jsp
If you want to override this default you can specify a value of GENERAL, GENERAL_WITH _CONTEXT, or PDM for the renderType on the action.
E-4
with
<Windchill>/codebase/wtcore/jsp/customizedAction.jsp
as the corresponding JSP file. You can use renderType="GENERAL_WITH_CONTEXT" in the same fashion; the difference is that the dynamically-generated URL will include the context object OID.
The URLActionDelegate (CreateDocumentURLActionDelegate) that produces the PDMLink URL to the Create Document wizard is identified in the properties file <Windchill>/codebase/com/ptc/windchill/pdmlink/doc/doc.properties in the following manner:
wt.services/svc/default/wt.enterprise.URLActionDelegate/CREATEDOCUMENT1 /java.lang.Object/0=com.ptc.windchill.pdmlink.doc.server.processors .CreateDocumentURLActionDelegate/duplicate
The selector for this action, CREATEDOCUMENT1, corresponds to the method attribute of the command element in the actions XML definition. This should be identical to the name of the action. In the above example, the type is specified in the property entry as java.lang.Object. This means you do not need to specify a class attribute on the command element -- the default is java.lang.Object.
E-5
In some cases, you may need to specify the class to find the appropriate URLActionDelegate. Suppose you wanted to use a URLActionDelegate whose property entry is defined as follows:
wt.services/svc/default/wt.enterprise.URLActionDelegate/list2 /wt.pdmlink.PDMLinkProduct/0=com.ptc.windchill.pdmlink.templateutil.server .processors.DefaultProjectLinkURLActionDelegate/duplicate
If you didnt specify the class in the command element of the action, there is no guarantee that this property entry will be determined as the best match. This is because the list2 action is provided when the user has not yet viewed a Product, so they dont have a context set. Therefore, Windchill cant dynamically determine the class to use for the lookup. By specifying the class in the command element of the action, Windchill can match it to the appropriate property entry.
actions.xml Elements
Listed in the following table are the valid elements and their attributes that can be used to register an action.
Value (Default if not specified)
Element objecttype
Attribute
Required
Description
name class
Yes No
NA NA
A unique name for the alias to use for the object type. The fully qualified path to the actual class representing this type A unique name for the given objecttype to identify the action Indicates to execute the checkAvailable() method on the class specified for the objecttype Indicates if this action is valid only within the Wildfire Embedded Browser. Indicates what mechanism is used to determine the URL.
action
name checkaccess
Yes No
NA true/false
cad
No
true/false
renderType
No
<novalue>/GENERAL/P DM
E-6
command
windowType
No
page/popup/ no_content/normal NA
Indicates if the action will open a new window or replace the page in the current window Indicates the command class to use for this action if the action is a PJL action or the class to use in the lookup of the appropriate URL action delegate if the action renderType is PDM. The method to call on the command class if the action is a PJL action or the selector to use in the lookup of the appropriate URL action delegate if the action renderType is PDM. Indicates what level of access of the user should have to be able to execute this action.
class
No
method
No
NA
access
name
No
read/update/full
Creating an URLFactory
All Windchill Java client Server Pages or Servlets should set the context by using the WTContextBean using the code below:
<% [ ] /*** The WTContextBean is a JavaBean for use in Java Server Pages or Servlets that wish to use Windchill Java client or server APIs ***/ % [ ]> <jsp:useBean id="wtcontext" class="wt.httpgw.WTContextBean" scope="request"
E-7
Next, an URLFactory instance may be created for the current codebase by using the useBean JSP command and setting the scope of the URLFactory (in this case for the request, which supports JSP include commands).
<% [ ] /*** The URLFactory is a JavaBean for use in the generation of HREFs used in Windchill HTML clients ***/ % [ ]> <jsp:useBean id="url_factory" class="wt.httpgw.URLFactory" scope="request" />
If a remote codebase needs to be accessed (note the request from the server) an URLFactory object can be instantiated by first creating the bean as above, and then recreating the URLFactory pointing it to the new codebase. (NOTE: The codebase ends with a / marking it as a directory.)
<% [ ] /*** The URLFactory is a JavaBean for use in the generation of HREFs used in Windchill HTML clients ***/ % [ ]> <jsp:useBean id="url_factory" class="wt.httpgw.URLFactory" scope="request" > <% [ ] url_factory = new wt.httpgw.URLFactory ( SomeURLToRemoteWindchill ); % [ ]> </jsp:useBean>
Setting a BaseTag
This configuration has the advantage of allowing a user to reload a page after it has been persisted (say to a local file system) and still have all the links work properly. If the base is to be the Windchill Codebase then a call to setRequestURItoBase() will suffice.
<BASE HREF="<% [ ]= url_factory.setRequestURItoBase() % [ ]>">
E-8
However in many situations, you may wish to set the base tag relative to some point in the Windchill codebase. An example is you want to generate a search page and have all the links be relative to some starting position. In this case, a little more is involved. If you can obtain the current request context (i.e., you are developing either a jsp or servlet page) then first you should set the request information using the setRequestURL() method described above.
Setting the BaseTag Within JSP pages and Servlets
<% [ ] // First set the request URI to be relative to the request (thus maintaining // the protocol, port and host information. url_factory.setRequestURL(request.getScheme(), request.getHeader("HOST"), request.getRequestURI() ); // Next set the request URI to be null (ie. to the Windchill codebase) url_factory.setRequestURI(null); // Now set the request URI to be relative to the resource you desire. url_factory.setRequestURI("wt/clients/login/ Login.html"); // Now the Base tag can be set to this resource % [ ]> <BASE HREF="<% [ ]=url_factory.getFullyQualifiedRequestURI ()% [ ]>">
Setting the BaseTag Within a Non-JSP Page or Servlet (i.e, Java code)
We will not have access to the request object in Java code that is not a servlet. Therefore we have to set the RequestURI to be relative to initially the Windchill codebase based on the configured host, protocol and port information and then set the requestURI to desired resource.
... // Set the request URI to the Windchill codebase. url_factory.setRequestURItoBase(); // Now set the request URI to the desired resource. url_factory.setRequestURI("wt/clients/login/Login.html"); // Now we can obtain the string for the Base Tag String baseTag = url_factory.getFullyQualifiedRequestURI();
E-9
1. Standard resources located under the codebase. 2. Access to a Windchill Servlet via a Gateway (for example Authenticated Gateway) 3. Access to an external source 4. Forcing a fully qualified link with a URLFactory that has a non-null request URI 5. Creating a link from the request.getRequestURI() String
Depending on the Request Context setup above, the correct HREF String will be returned and inserted into the output page at compile time.
E-10
Forcing a Fully Qualified Link With a URLFactory that has a Non-null Request URI
If you want to create a link that opens a file in a new window (such as through the Javascript.open( ) method) the string must be fully qualified. However, the rest of the links on the page may be relative. Most getHREF() methods have a form which accepts a boolean. By using this form, it is possible to request a fully-qualified URL from a URLFactory which is otherwise configured to generate relative URLs.
<A HREF="<% [ ]= url_factory.getHREF( "wt/clients/login/Login.html" , true ) % [ ]>">Fully Qualified Link</A>
This only applies to servlets and JSP Pages. The request object has a method getRequestURI( ) which returns the path to the web resource (usually starting after the hostname/port onward). This String includes a leading / which by definition in the URLFactory would redefine the resource and not create a relative link. However, there is a chance to create a relative link if the getRequestURI( ) path and the Windchill codebase are common. This is where usage of the determineResource( ) method may be used.
<A HREF="<% [ ]= url_factory.getHREF( url_factory.determineResource(request.getRequestURI()))% [ ]>" > Resource Link</A>
2. Set the response content type. This will set the encoding of the HTML page returned to the client. It should be set near the start of the JSP page (after Bean declarations). In order to do this the following needs to be added:
<% [ ] response.setContentType( "text/html; charset=UTF-8" ); % [ ]>
E-11
Note: The response content type method must be called before any call to request.getParameter() is made.
Note: See the EncodingConverter class entry in your installed Windchill Javadoc for more information. The EncodingConverter class (in the wt.httpgw package) contains a series of decode() methods that may be used to efficiently decode text that has been encoded in UTF-8 format. This must be called on ALL text that is read from parameters that were submitted from a FORM element. There are two ways to decode text: The first method is to use the decode() methods of wt.httpgw.EncodingConverter to efficiently decode text that has been encoded in UTF-8 format. This must be called for every text entry that was submitted from a FORM element, or any parameters that contain encoded text. This methodology supports both request query strings and FORM data. For example:
// Create an instance of the encoding converter for the page // EncodingConverter encoder = new EncodingConverter (); // Using the EncodingConverter with the default encoding (UTF-8 ) // String tag = encoder.decode( request.getParameter ("tag") ); // Using the EncodingConverter with a specific encoding // String tag = encoder.decode( request.getParameter ("tag"), "UTF-8");
The second method that can be to used is the parseQueryString() method of the URLFactory() class. Usage of the parseQueryString() method takes an encoded query string and decodes it. The result is placed into a HashMap. The HashMap values may then be queried using the HashMap get method. This method will only work with Request Parameters and not form elements. For example:
// Use the URLFactory to parse the Query String // java.util.HashMap query_map = url_factory.parseQueryString(
E-12
request.getQueryString() ); // Retrieve the (already decoded) string from the hash map // String tag = query_map.get("tag");
Deprecation of WTURLEncoder
As of Windchill release 6.0 WTURLEncoder SHOULD NOT be used for text encoding or decoding. This class may be removed post-R 6.0.
Encoding of Forms
By default POST submitted forms are submitted using the encoding application/xwww-form-urlencoded. The methods provided above for decoding the text will allow these forms data to be written properly. All HREFs and URLs should be generated using the URLFactory class. The URLFactory provides methods to automatically encode any non-ASCII characters in the query string, if a HashMap containing the parameters is provided to the URLFactory. If a string is being passed in for a query string that has been created within your code, you must encode it first, with a call to EncodingConverter.encode() Note: See the URLFactory class entry in your installed Windchill Javadoc for more information.
E-13
request.getHeader("Accept-Language") ); % [ ]> </HEAD> <BODY> <h1>Sample Form</H1> <% [ ] String text = request.getParameter("sample_text"); if ( text != null ) { % [ ]> Here was the text that was submitted: <i> <% [ ]= url_factory.decode(text) % [ ]> </I> <BR><% [ ]= new String(text.getBytes("ISO8859_1"),"UTF-8")% [ ]> <% [ ] } % [ ]> <P> <FORM METHOD="POST" ACTION="<% [ ]=url_factory.getHREF("sample.jsp",request. getQueryString () ) % [ ]>" > <% [ ] if ( request.getParameter("sample_text") != null ) { % [ ]> <INPUT TYPE="text" NAME="sample_text" VALUE="<% [ ]= url_factory.decode( text) % [ ]>"> <% [ ] } else { % [ ]> <INPUT TYPE="text" NAME="sample_text" > <% [ ] } % [ ]> <INPUT TYPE="submit" NAME="button" VALUE="click here"> </FORM> </BODY> </HTML>
E-14
<Windchill>/codebase/wt/clients/util/FileChooserDropApplet (combined file drop target and file browser launch button or "hyperlink" which launches single-select or multi-select JFileChooser)
Content upload applet
<Windchill>/codebase/wt/clients/util/http/UploadApplet.java
Content download applet
<Windchill>/codebase/wt/clients/util/http/DownloadApplet.java
E-15
which enables the RMI tunneling necessary for the applet to communicate with the server 3. Java class archive - they require the one-time download of a Java class archive, which creates a noticeable loading delay the first time an applet is accessed from a given client machine. Subsequent visits to the same page are much faster because the class archive is cached locally by the Java plug-in.
There are two looks for the applet button that launches a Java file browser. The "button" look is typically used in a single-select situation where the selected file will be written to an adjacent HTML textfield, in order to look and act like an HTML file input (only smarter!).
Button look:
<param name="buttonLook" value="true">
The "hyperlink with icon" look is typically used in a multi-select situation where each selected file will result in another row added to a table.
E-16
Hyperlink-with-icon look:
<param name="buttonLook" value="false"> <param name="imageFilename" value="wtcore/images/attach_add.gif"> <param name="multiSelect" value="true">
Drag-and-Drop targets
The presence/absence of a file drop target next to the file browse launcher is determined by the following parameter (true means drop target, false means no drop target):
<param name="acceptFileDrop" value="true">
When using a drop target, you will need to provide a pair of images to use for the drop target's normal state and active (dragged-over) state. The following images are provided by Windchill for this purpose:
Normal:
<Windchill>/codebase/wtcore/images/droptarget.gif
E-17
Active:
<Windchill>/codebase/wtcore/images/droptarget_active.gif
E-18
E-19
FileChooserDropApplet Parameters
Parameter Name java_codebase type java_code cache_archive Sample Value http://machinename.ptcnet.ptc.com/Windchill/ application/x-java-applet;version=1.4 wt/clients/util/FileChooserDropApplet "contentCust.jar, contentDSU.jar, contentFCS.jar, lib/HTTPClient.jar, content3rdParty.jar, content.jar" wt/security/security.jar wt/security/security.cab Plugin true true en_US 15066585 Description Provided by taglib generator Provided by taglib generator Applet location in codebase never changes Java archives containing the classfiles used by this applet typically never changes Never changes Never changes Never changes Never changes Never changes Locale of users browser Decimal version of desired background color (i.e. what is seen around the button), typically matches the background color of the page or table cell where the applet is located (Optional) Decimal version of desired background color (i.e. what is seen around the button) when button is active. Defaults to same as bgcolor. (Optional) Decimal version of desired button color. Defaults to same as bgcolor. (Optional) Decimal version of desired button color when button is active. Defaults to same as bgcolor. (Optional) Name of Javascript method to be invoked from applet with the selected filepath value(s). Defaults to "setPath". Label for button or "hyperlink" seen in HTML page
bgcoloractive
15066585
buttoncolor
13421772
buttoncoloractive
15066585
jsSetMethod
setPathFromMultiSelectApplet
buttonLabel
E-20
Normally true, change to false if you dont want a drop target Image displayed when drop target is idle
Image displayed when drop target is dragged-over Normally true for single-select usage, normally false for multiselect usage (Optional) Icon shown above "hyperlink" if buttonLook is false (Optional) Label for window and action button on file browser dialog (Optional) Normally retrieved from workspacePath user preference setting, determines where file browse dialog initially launches. (Optional) Defaults to false for single-select, change to true for multi-select. (Optional) Delimiter string used to separate filepaths if multiSelect is true (Optional) Defaults to false, change to true for Java Console output during processing
multiSelect
true, false
delim
;;;zzz
debug
true, false
E-21
<param name="acceptFileDrop" value="true"> <param name="MAYSCRIPT" value="true"> <param name="buttonLook" value="true"> <param name="cabinets" value="wt/security/security.cab"> <param name="dropImageFilename" value="wtcore/images/droptarget.gif"> <param name="cache_option" value="Plugin"> <param name="wt.context.locale" value="en_US"> <param name="bgcolor" value="15066585"> <COMMENT> <EMBED type="application/x-java-applet;version=1.4" name="formApplet" width="200" height="40" MAYSCRIPT=true pluginspage="http://java.sun.com/getjava/download.html" java_code="wt/clients/util/FileChooserDropApplet" java_codebase="http://mecasey03d.ptcnet.ptc.com/Windchill/" java_archive="wt/security/security.jar" SCRIPTABLE="true" actionLabel="Open" debug="false" cache_archive="contentCust.jar, contentDSU.jar, contentFCS.jar, lib/HTTPClient.jar, content3rdParty.jar, content.jar" dropImageFilenameActive="wtcore/images/droptarget_active.gif" buttonLabel="Browse..." acceptFileDrop="true" buttonLook="true" cabinets="wt/security/security.cab" dropImageFilename="wtcore/images/droptarget.gif" cache_option="Plugin" wt.context.locale="en_US" bgcolor="15066585" ><NOEMBED> </COMMENT> </NOEMBED></EMBED> </OBJECT>
E-22
<param name="dropImageFilename" value="wtcore/images/droptarget.gif"> <param name="cache_option" value="Plugin"> <param name="wt.context.locale" value="en_US"> <param name="bgcolor" value="15066585"> <COMMENT> <EMBED type="application/x-java-applet;version=1.4" name="formApplet" width="300" height="50" MAYSCRIPT=true pluginspage="http://java.sun.com/getjava/download.html" java_code="wt/clients/util/FileChooserDropApplet" java_codebase="http://mecasey03d.ptcnet.ptc.com/Windchill/" java_archive="wt/security/security.jar" SCRIPTABLE="true" actionLabel="Open" debug="false" delim=";;;zzz" multiSelect="true" cache_archive="contentCust.jar, contentDSU.jar, contentFCS.jar, lib/HTTPClient.jar, content3rdParty.jar, content.jar" dropImageFilenameActive="wtcore/images/droptarget_active.gif" acceptFileDrop="true" buttonLabel="Add+Attachment" imageFilename="wtcore/images/attach_add.gif" cabinets="wt/security/security.cab" dropImageFilename="wtcore/images/droptarget.gif" cache_option="Plugin" wt.context.locale="en_US" bgcolor="15066585" ><NOEMBED> </COMMENT> </NOEMBED></EMBED> </OBJECT>
E-23
E-24
When uploading to a single location, the selected primary content filepath is validated, preference values are checked and the user is prompted if necessary to decide what to do should the selected filepath be invalid. If the file is valid or the preferences and/or user prompt authorize skipping the upload, then the upload is considered successful, and the applet will forward to the "completionUrl" and/or "completionJSMethod" upon completion (if both are provided, completionUrl will be passed into completionJSMethod as an argument value). In Windchill Foundation & PDM, this typically submits to post-processing code followed by the properties page for the document. In Windchill PDMLink, this typically submits to post-processing code followed by closing the wizard window. In the absence of both completionUrl and completionJSMethod parameter values, completionJSMethod will default to "displayInvalidPaths". Note: The "uploadFeedback" argument provided to the completionJSMethod will be a value from the class wt.clients.util.http.UploadConstants indicating whether some kind of non-upload completion was reached (NO_UPLOAD, FILE_NOT_FOUND, FILE_UNCHANGED, DECLINED_UPLOAD). This can be used for customizing a feedback status message for a non-error outcome. If the file is invalid and the preferences and/or user prompt do not authorize skipping the upload, or if the file is valid but the upload is unsuccessful, or if the user cancels, then the applet will forward to the "failureUrl" and/or "failureJSMethod" (if both are provided, failureUrl will be passed into failureJSMethod as an argument value). This typically displays some sort of error feedback message (unless cancelled) and returns to the form where the primary filepath was originally selected. When performing a multiple-file upload, such as multiple primary files or attachments, individual feedback is not provided on each file. Instead, all valid files are uploaded and a list of all invalid filepaths is compiled. When the upload is complete, this list of invalid filepaths is sent as an argument to a designated Javascript method, along with the appropriate URL. When uploading multiple primary files, this will always be the Javascript method and URL specified in the applet parameters for the completion case. When uploading secondary files, the method and URL may be from either the completion or failure cases, depending on the outcome of the selected primary content file upload.
E-25
var invalidPathMessage = "The following files were not uploaded due to invalid filepaths:"; var uploadFailureMessage = "A problem occurred while uploading content to server. Please notify administrator if this problem continues."; function uploadCompleted( invalidPaths, nextURL, newChecksum, uploadFeedback ) { document.<form name>.<checksum form field name>.value = newChecksum; if ( uploadFeedback != null && uploadFeedback.length > 0 ) { \document.<form name>.<uploadFeedback form field name>.value = uploadFeedback; } if ( invalidPaths != null && invalidPaths.length > 0 ) { alert( invalidPathMessage + invalidPaths ); } if ( nextURL != null && nextURL.length > 0 && nextURL != "null" ) { submitForm( nextURL ); } else { submitForm( propertiesPageURL ); // generated value } } function uploadFailed( invalidPaths, nextURL, cancelled ) { if ( invalidPaths != null && invalidPaths.length > 0 ) { alert( invalidPathMessage + invalidPaths ); } if ( !cancelled ) { alert( uploadFailureMessage ); } if ( nextURL != null && nextURL.length > 0 && nextURL != "null" ) { submitForm( nextURL ); } else { submitForm( previousPageURL ); // generated value } } function displayInvalidPaths( invalidPaths, nextURL ) { alert( invalidPathMessage + invalidPaths ); location = nextURL; } </SCRIPT>
E-26
Here are the essential steps for persisting the checksum (in reality, there may also be some error handling). The context object has to be a FormatContentHolder, such as a WTDocument.
Properties props = getQueryData(); String uploaded = (String)props.get("uploaded"); if ( uploaded != null && uploaded.equalsIgnoreCase("true") ) { long checksum = 0; checksum = Long.parseLong((String)props.get("checksum")); FormatContentHolder holder = (FormatContentHolder)getContextObj(); holder = (FormatContentHolder)ContentHelper.service.getContents(holder); ContentItem item = ContentHelper.getPrimary( holder ); if ( item instanceof ApplicationData ) { ApplicationData app = (ApplicationData)item; app.setChecksum( checksum ); ContentHelper.service.updateAppData( holder, app ); } }
E-27
E-28
true C:/Temp/MyFolder/Sample.jpg FILE, URL, NONE http://mecasey03d.ptcnet.ptc.com/Windchil l/servlet/WindchillAuthGW/wt.content.Con tentHttp/saveContent?wt.doc.WTDocument %3A656270 create, update
docOperation
callingAction
create, updateReplace
E-29
oidString attachments
wt.content.ApplicationData:656261 FILE;;;qqqnewfile;;;qqqC:\TEMP\ DgadReq.doc;;;qqqADD;;;zzzURL;;;qqqne wURL;;;qqqwww.amazon.com;;;qqq;;;qqq ADD;;;zzzFILE;;;qqqwt.content.Applicatio nData:656293;;;qqqC:\TEMP\ MyDoc.doc;;;qqqREPLACE;;;zzzURL;;;qq qwt.content.URLData:656295;;;qqqhttp://w ww.askjeeves.com;;;qqqAsk Jeeves website;;;qqqREPLACE;;;zzzFILE;;;qqqwt. content.ApplicationData:656902;;;qqq;;;qq qREMOVE;;;zzzURL;;;qqqwt.content.URL Data:656904;;;qqq;;;qqqREMOVE 3 ;;;qqq
On updateReplace, the OID of the persisted primary content item Type, content item OID (if any), filepath/URL, description (if any) and action for any attachments to be added, removed or replaced. Attachments are separated by contentRecordDelim value, individual fields for each attachment are separated by contentDelim value
multipleQuantity contentDelim
(Optional) Number of different primary files/destinations (Optional) Delimiter within attachments entries and between multiple-upload targets/uploadURLs, defaults to ;;;qqq (Optional) Delimiter used between separate attachments entries, defaults to ;;;zzz (Optional) Methodname of Javascript method to be called if upload doesnt error out (Optional) URL to follow if upload doesnt error out
contentRecordDelim
;;;zzz
completionJSMethod
uploadCompleted
completionUrl
failureJSMethod
(Optional) Methodname of Javascript method to be called if upload errors out (Optional) URL to follow if upload errors out
failureUrl
E-30
checksum
3774325531
(Optional on updateReplace) The checksum from previous upload of persisted primary content item (Optional on updateReplace) The filename of the persisted primary content item (Optional on updateReplace) The filepath from previous upload of persisted primary content item (Optional on updateReplace) Determines whether to automatically skip the upload and keep current primary content if the selected file cannot be found, normally retrieved from user preference setting (Optional on updateReplace) Determines whether to automatically skip the upload and keep current primary content if the selected file has not changed since the previous upload, normally retrieved from user preference setting (Optional on updateReplace) determines whether to automatically upload the file if it has changed since the previous upload, normally retrieved from user preference setting (Optional) Normally retrieved from user preference setting (Optional) Normally false, change to true if you want to permit 0-size files to be considered valid Windchill content (Optional) Defaults to rmi, change to http only for unsupported uses of this applet. (Optional) Defaults to false, change to true for Java Console output during processing
fileName
MyDoc.doc
uploadedFromPath
C:/temp/MyDoc.doc
continueIfFileNotFo und
true, false
continueIfFileUncha nged
true, false
uploadIfFileChanged
true, false
workspacePath validEmptyFile
uploadImpl
rmi, http
debug
true, false
E-31
E-32
<param name="target" value="c:\temp\MyDoc.doc"> <COMMENT> <EMBED type="application/x-java-applet;version=1.4" name="formApplet" width="2" height="2" MAYSCRIPT=true pluginspage="http://java.sun.com/getjava/download.html" java_code="wt/clients/util/http/UploadApplet" java_codebase="http://mecasey03d.ptcnet.ptc.com/Windchill/" java_archive="wt/security/security.jar" bgcolor="16777215" validEmptyFile="false" oid="" SCRIPTABLE="true" callingAction="create" cache_option="Plugin" checksum="" contentRecordDelim=";;;zzz" continueIfFileNotFound="false" cache_archive="contentCust.jar, contentDSU.jar, contentFCS.jar, lib/HTTPClient.jar, content3rdParty.jar, content.jar" uploadedFromPath="" completionUrl="http://mecasey03d.ptcnet.ptc.com/Windchill/servlet/WindchillAuthGW/w t.enterprise.URLProcessor/invokeAction?action=CreateDocCloseWindow&class=wt.doc.WTD ocument&OID=VR%3Awt.doc.WTDocument%3A288876&refresh=true&formName=CreateDocumentWiz ard" workspacePath="" docOperation="create" debug="false" failureUrl="http://mecasey03d.ptcnet.ptc.com/Windchill/servlet/WindchillAuthGW/wt.e nterprise.URLProcessor/invokeAction?nextAction=CreateDocument2&action=CreateDocumen tUploadFailure&class=wt.doc.WTDocument&OID=VR%3Awt.doc.WTDocument%3A288876&uploaded =false&formName=CreateDocumentWizard" uploadIfFileChanged="true" targetType="" cabinets="wt/security/security.cab" continueIfFileUnchanged="true" oidString="" contentDelim=";;;qqq" wt.context.locale="en_US" delim=";;;qqq" uploadURL="http://mecasey03d.ptcnet.ptc.com/Windchill/servlet/WindchillAuthGW/wt.co ntent.ContentHttp/saveContent?wt.doc.WTDocument%3A288877" removable="true" attachments="FILE;;;qqqnewFile;;;qqqC:\TEMP\MyFolder\New Microsoft Excel Worksheet.xls;;;qqqADD;;;zzzFILE;;;qqqnewFile;;;qqqC:\TEMP\MyFolder\New Microsoft PowerPoint Presentation.ppt;;;qqqADD;;;zzzFILE;;;qqqnewFile;;;qqqC:\TEMP\MyFolder\ New Microsoft Word Document.doc;;;qqqADD;;;zzzFILE;;;qqqnewFile;;;qqqC:\TEMP\ MyFolder\New Text Document.txt;;;qqqADD;;;zzzFILE;;;qqqnewFile;;;qqqC:\TEMP\ MyFolder\New WinZip File.zip;;;qqqADD" fileName="" target="c:\temp\MyDoc.doc" ><NOEMBED> </COMMENT> </NOEMBED></EMBED> </OBJECT>
E-33
E-34
checksum="" contentRecordDelim=";;;zzz" continueIfFileNotFound="false" cache_archive="contentCust.jar, contentDSU.jar, contentFCS.jar, lib/HTTPClient.jar, content3rdParty.jar, content.jar" completionJSMethod="uploadCompleted" uploadedFromPath="" completionUrl="" workspacePath="" docOperation="create" failureJSMethod="uploadFailed" debug="false" failureUrl="" uploadIfFileChanged="true" targetType="URL" cabinets="wt/security/security.cab" continueIfFileUnchanged="true" oidString="" contentDelim=";;;qqq" wt.context.locale="en_US" delim=";;;qqq" uploadURL="http://mecasey03d.ptcnet.ptc.com/Windchill/servlet/WindchillAuthGW/wt.co ntent.ContentHttp/saveContent?wt.doc.WTDocument%3A656270" removable="true" fileName="" attachments="URL;;;qqqnewURL;;;qqqwww.google.com;;;qqqGoogle search engine;;;qqqADD;;;zzzURL;;;qqqnewURL;;;qqqwww.cnn.com;;;qqq;;;qqqADD" target="www.ptc.com" ><NOEMBED> </COMMENT> </NOEMBED></EMBED> </OBJECT>
E-35
<param name="workspacePath" value=""> <param name="failureJSMethod" value="failure"> <param name="debug" value="true"> <param name="java_archive" value="wt/security/security.jar"> <param name="uploadIfFileChanged" value="true"> <param name="targetType" value=""> <param name="cabinets" value="wt/security/security.cab"> <param name="continueIfFileUnchanged" value="true"> <param name="java_code" value="wt/clients/util/http/UploadApplet"> <param name="contentDelim" value=";;;qqq"> <param name="wt.context.locale" value="en_US"> <param name="delim" value=";;;qqq"> <param name="uploadURL" value="http://lqkohpsh.ptcnet.ptc.com:2801/PDMLink700/servlet/WindchillAuthGW/wt.co ntent.ContentHttp/saveContent?wt.doc.WTDocument%3A20350;;;qqqhttp://lqkohpsh.ptcnet .ptc.com:2801/PDMLink700/servlet/WindchillAuthGW/wt.content.ContentHttp/saveContent ?wt.doc.WTDocument%3A20335;;;qqqhttp://lqkohpsh.ptcnet.ptc.com:2801/PDMLink700/serv let/WindchillAuthGW/wt.content.ContentHttp/saveContent?wt.doc.WTDocument%3A20365"> <param name="removable" value="true"> <param name="attachments" value=""> <param name="target" value="c:\temp\myfolder\New Text Document.txt;;;qqqc:\temp\ myfolder\New Bitmap Image.bmp;;;qqqc:\temp\myfolder\New WinZip File.zip"> <COMMENT> <EMBED type="application/x-java-applet;version=1.4" width="2" height="2" MAYSCRIPT=true pluginspage="http://java.sun.com/getjava/download.html" java_code="wt/clients/util/http/UploadApplet.class" java_codebase="http://lqkohpsh.ptcnet.ptc.com:2801/PDMLink700" java_archive="wt/security/security.jar" bgcolor="16777215" oid="" SCRIPTABLE="true" multipleQuantity="3" callingAction="create" cache_option="Plugin" type="application/x-java-applet" contentRecordDelim=";;;zzz" continueIfFileNotFound="false" cache_archive="lib/HTTPClient.jar, contentCust.jar, contentDSU.jar, contentFCS.jar, content3rdParty.jar, content.jar" jreversion="1.4" completionJSMethod="completion" uploadedFromPath="" workspacePath="" failureJSMethod="failure" debug="true" java_archive="wt/security/security.jar" uploadIfFileChanged="true" targetType="" cabinets="wt/security/security.cab" continueIfFileUnchanged="true" java_code="wt/clients/util/http/UploadApplet" contentDelim=";;;qqq" wt.context.locale="en_US" delim=";;;qqq"
E-36
uploadURL="http://lqkohpsh.ptcnet.ptc.com:2801/PDMLink700/servlet/WindchillAuthGW/w t.content.ContentHttp/saveContent?wt.doc.WTDocument%3A20350;;;qqqhttp://lqkohpsh.pt cnet.ptc.com:2801/PDMLink700/servlet/WindchillAuthGW/wt.content.ContentHttp/saveCon tent?wt.doc.WTDocument%3A20335;;;qqqhttp://lqkohpsh.ptcnet.ptc.com:2801/PDMLink700/ servlet/WindchillAuthGW/wt.content.ContentHttp/saveContent?wt.doc.WTDocument%3A2036 5" removable="true" attachments="" target="c:\temp\myfolder\New Text Document.txt;;;qqqc:\temp\myfolder\New Bitmap Image.bmp;;;qqqc:\temp\myfolder\New WinZip File.zip" ><NOEMBED> </COMMENT> </NOEMBED></EMBED> </OBJECT>
E-37
<param name="attachments" value=""> <param name="target" value="C:/TEMP/MyFolder/Sample.jpg"> <COMMENT> <EMBED type="application/x-java-applet;version=1.4" name="formApplet" width="2" height="2" MAYSCRIPT=true pluginspage="http://java.sun.com/getjava/download.html" java_code="wt/clients/util/http/UploadApplet" java_codebase="http://mecasey03d.ptcnet.ptc.com/Windchill/" java_archive="wt/security/security.jar" bgcolor="16777215" validEmptyFile="false" oid="VR:wt.doc.WTDocument:656218" SCRIPTABLE="true" callingAction="updateReplace" cache_option="Plugin" checksum="3774325531" contentRecordDelim=";;;zzz" continueIfFileNotFound="false" cache_archive="contentCust.jar, contentDSU.jar, contentFCS.jar, lib/HTTPClient.jar, content3rdParty.jar, content.jar" completionJSMethod="uploadCompleted" uploadedFromPath="c:/temp/MyDoc.doc" completionUrl="" workspacePath="" docOperation="update" failureJSMethod="uploadFailed" debug="false" failureUrl="" uploadIfFileChanged="true" targetType="FILE" cabinets="wt/security/security.cab" continueIfFileUnchanged="true" oidString="wt.content.ApplicationData:656261" contentDelim=";;;qqq" wt.context.locale="en_US" delim=";;;qqq" uploadURL="http://mecasey03d.ptcnet.ptc.com/Windchill/servlet/WindchillAuthGW/wt.co ntent.ContentHttp/saveContent?wt.doc.WTDocument%3A656220" removable="true" fileName="MyDoc.doc" attachments="" target="C:/TEMP/MyFolder/Sample.jpg" ><NOEMBED> </COMMENT> </NOEMBED></EMBED> </OBJECT>
E-38
<param name="oid" value="VR:wt.doc.WTDocument:656218"> <param name="SCRIPTABLE" value="true"> <param name="callingAction" value="updateReplace"> <param name="cache_option" value="Plugin"> <param name="MAYSCRIPT" value="true"> <param name="checksum" value="3774325531"> <param name="contentRecordDelim" value=";;;zzz"> <param name="continueIfFileNotFound" value="false"> <param name="cache_archive" value="contentCust.jar, contentDSU.jar, contentFCS.jar, lib/HTTPClient.jar, content3rdParty.jar, content.jar"> <param name="completionJSMethod" value="uploadCompleted"> <param name="uploadedFromPath" value="c:/temp/MyDoc.doc"> <param name="completionUrl" value=""> <param name="workspacePath" value=""> <param name="docOperation" value="update"> <param name="failureJSMethod" value="uploadFailed"> <param name="debug" value="false"> <param name="failureUrl" value=""> <param name="uploadIfFileChanged" value="true"> <param name="targetType" value="NONE"> <param name="cabinets" value="wt/security/security.cab"> <param name="continueIfFileUnchanged" value="true"> <param name="oidString" value="wt.content.ApplicationData:656261"> <param name="contentDelim" value=";;;qqq"> <param name="wt.context.locale" value="en_US"> <param name="delim" value=";;;qqq"> <param name="uploadURL" value="http://mecasey03d.ptcnet.ptc.com/Windchill/servlet/WindchillAuthGW/wt.conten t.ContentHttp/saveContent?wt.doc.WTDocument%3A656220"> <param name="removable" value="true"> <param name="fileName" value="MyDoc.doc"> <param name="attachments" value=""> <param name="target" value=""> <COMMENT> <EMBED type="application/x-java-applet;version=1.4" name="formApplet" width="2" height="2" MAYSCRIPT=true pluginspage="http://java.sun.com/getjava/download.html" java_code="wt/clients/util/http/UploadApplet" java_codebase="http://mecasey03d.ptcnet.ptc.com/Windchill/" java_archive="wt/security/security.jar" bgcolor="16777215" validEmptyFile="false" oid="VR:wt.doc.WTDocument:656218" SCRIPTABLE="true" callingAction="updateReplace" cache_option="Plugin" checksum="3774325531" contentRecordDelim=";;;zzz" continueIfFileNotFound="false" cache_archive="contentCust.jar, contentDSU.jar, contentFCS.jar, lib/HTTPClient.jar, content3rdParty.jar, content.jar" completionJSMethod="uploadCompleted" uploadedFromPath="c:/temp/MyDoc.doc" completionUrl="" workspacePath="" docOperation="update" failureJSMethod="uploadFailed" debug="false"
E-39
failureUrl="" uploadIfFileChanged="true" targetType="NONE" cabinets="wt/security/security.cab" continueIfFileUnchanged="true" oidString="wt.content.ApplicationData:656261" contentDelim=";;;qqq" wt.context.locale="en_US" delim=";;;qqq" uploadURL="http://mecasey03d.ptcnet.ptc.com/Windchill/servlet/WindchillAuthGW/wt.co ntent.ContentHttp/saveContent?wt.doc.WTDocument%3A656220" removable="true" fileName="MyDoc.doc" attachments="" target="" ><NOEMBED> </COMMENT> </NOEMBED></EMBED> </OBJECT>
E-40
<param name="uploadURL" value="http://mecasey03d.ptcnet.ptc.com/Windchill/servlet/WindchillAuthGW/wt.conten t.ContentHttp/saveContent?wt.doc.WTDocument%3A656270"> <param name="removable" value="true"> <param name="fileName" value=""> <param name="attachments" value="FILE;;;qqqnewfile;;;qqqC:\TEMP\ DGadReq.doc;;;qqqADD;;;zzzURL;;;qqqnewURL;;;qqqwww.amazon.com;;;qqq;;;qqqADD;;;zzzF ILE;;;qqqwt.content.ApplicationData:656293;;;qqqC:\TEMP\ MyDoc.doc;;;qqqREPLACE;;;zzzURL;;;qqqwt.content.URLData:656295;;;qqqhttp://www.askj eeves.com;;;qqqAsk Jeeves website;;;qqqREPLACE;;;zzzFILE;;;qqqwt.content.ApplicationData:656902;;;qqq;;;qqqRE MOVE;;;zzzURL;;;qqqwt.content.URLData:656904;;;qqq;;;qqqREMOVE"> <param name="target" value=""> <COMMENT> <EMBED type="application/x-java-applet;version=1.4" name="formApplet" width="2" height="2" MAYSCRIPT=true pluginspage="http://java.sun.com/getjava/download.html" java_code="wt/clients/util/http/UploadApplet" java_codebase="http://mecasey03d.ptcnet.ptc.com/Windchill/" java_archive="wt/security/security.jar" bgcolor="16777215" validEmptyFile="false" oid="VR:wt.doc.WTDocument:656269" SCRIPTABLE="true" callingAction="create" cache_option="Plugin" checksum="" contentRecordDelim=";;;zzz" continueIfFileNotFound="false" cache_archive="contentCust.jar, contentDSU.jar, contentFCS.jar, lib/HTTPClient.jar, content3rdParty.jar, content.jar" completionJSMethod="uploadCompleted" uploadedFromPath="" completionUrl="" workspacePath="" docOperation="update" failureJSMethod="uploadFailed" debug="false" failureUrl="" uploadIfFileChanged="true" targetType="NONE" cabinets="wt/security/security.cab" continueIfFileUnchanged="true" oidString="" contentDelim=";;;qqq" wt.context.locale="en_US" delim=";;;qqq" uploadURL="http://mecasey03d.ptcnet.ptc.com/Windchill/servlet/WindchillAuthGW/wt.co ntent.ContentHttp/saveContent?wt.doc.WTDocument%3A656270" removable="true" fileName=""
E-41
attachments="FILE;;;qqqnewfile;;;qqqC:\TEMP\ DGadReq.doc;;;qqqADD;;;zzzURL;;;qqqnewURL;;;qqqwww.amazon.com;;;qqq;;;qqqADD;;;zzzF ILE;;;qqqwt.content.ApplicationData:656293;;;qqqC:\TEMP\ MyDoc.doc;;;qqqREPLACE;;;zzzURL;;;qqqwt.content.URLData:656295;;;qqqhttp://www.askj eeves.com;;;qqqAsk Jeeves website;;;qqqREPLACE;;;zzzFILE;;;qqqwt.content.ApplicationData:656902;;;qqq;;;qqqRE MOVE;;;zzzURL;;;qqqwt.content.URLData:656904;;;qqq;;;qqqREMOVE" target="" ><NOEMBED> </COMMENT> </NOEMBED></EMBED> </OBJECT>
E-42
choice. The default is to prompt. For downloads of multiple files, this decision only applies to the first file downloaded (all other files will be saved to disk, in the same location). The Default Local Directory preference (node=/wt/content key= workspacePath) determines where the file will be downloaded upon open-in-application, or where the file chooser will open to upon save-to-disk. Users who have a particular directory where they like to keep all their Windchill files might like to set this preference to that directory. If no value is specified, or if the specified path does not exist on the local machine, then a default directory will be used as specified by the environment variables of the local machine's operating system.
E-43
Never changes Never changes Never changes Locale of users browser Decimal version of desired background color, typically matches the background color of the page or table cell where the applet is located URL that content will be downloaded from
downloadURL
http://mecasey03d.ptcnet.ptc.co m/Windchill/servlet/WindchillA uthGW/wt.fv.master.RedirectDo wnload/redirectDownload/1026 508screenshot.doc?u8&HttpOpe rationItem=wt.content.Applicati onData%3A294016&ContentHo lder=wt.doc.WTDocument%3A 294014" MyDoc.doc http://mecasey03d.ptcnet.ptc.co m/Windchill/servlet/WindchillA uthGW/wt.enterprise.URLProce ssor/invokeAction?action=Chec kOutDocCloseWindow&OID= VR%3Awt.doc.WTDocument% 3A294013&formName=CheckO utDocumentWizard 3
filename url
Filename of file to be downloaded, used in prompt dialogs, can be changed during download. URL to follow after processing is complete
downloadQua ntity
(Optional) Number of different files and download sources, if downloading more than one file
E-44
(Optional) Delimiter string used to separate filepaths if downloading more than one file (Optional) Normally retrieved from user preference setting, determines whether user is prompted to open-in-app vs. save-to-disk (Optional) Normally retrieved from workspacePath user preference setting, determines where file is downloaded for open-in-app or where file browser is launched for save-to-disk (Optional) Defaults to false, change to true for Java Console output during processing (Optional) Defaults to false, change to true to have main file's checksum and local download path appended to the URL query string for persistence by the post-processing code.
debug remember
E-45
java_codebase="http://mecasey03d.ptcnet.ptc.com/Windchill/" java_archive="wt/security/security.jar" filename="1026508screenshot.doc" url="http://mecasey03d.ptcnet.ptc.com/Windchill/servlet/WindchillAuthGW/wt.enterpri se.URLProcessor/invokeAction?action=CheckOutDocCloseWindow&OID=VR%3Awt.doc.WTDocume nt%3A294013&formName=CheckOutDocumentWizard" debug="FALSE" delim=";;;qqq" cache_archive="contentCust.jar, contentDSU.jar, contentFCS.jar, lib/HTTPClient.jar, content3rdParty.jar, content.jar" cabinets="wt/security/security.cab" downloadOpType="ALWAYS_ASK" cache_option="Plugin" wt.context.locale="en_US" downloadQuantity="1" defaultPath="" downloadURL="http://mecasey03d.ptcnet.ptc.com/Windchill/servlet/WindchillAuthGW/wt. fv.master.RedirectDownload/redirectDownload/1026508screenshot.doc?u8&HttpOperationI tem=wt.content.ApplicationData%3A294016&ContentHolder=wt.doc.WTDocument%3A294014" recordDelim=";;;zzz" ><NOEMBED> </COMMENT> </NOEMBED></EMBED> </OBJECT>
E-46
Download/redirectDownload/Memo_Template.doc?u8&HttpOperationItem=wt.content.Applica tionData%3A294363&ContentHolder=wt.doc.WTDocument%3A294353;;;qqqhttp://mecasey03d.p tcnet.ptc.com/Windchill/servlet/WindchillAuthGW/wt.fv.master.RedirectDownload/redir ectDownload/Minutes_Template.doc?u8&HttpOperationItem=wt.content.ApplicationData%3A 294381&ContentHolder=wt.doc.WTDocument%3A294371;;;qqqhttp://mecasey03d.ptcnet.ptc.c om/Windchill/servlet/WindchillAuthGW/wt.fv.master.RedirectDownload/redirectDownload /MS_Project_Plan_Template.mpp?u8&HttpOperationItem=wt.content.ApplicationData%3A294 399&ContentHolder=wt.doc.WTDocument%3A294389;;;qqqhttp://mecasey03d.ptcnet.ptc.com/ Windchill/servlet/WindchillAuthGW/wt.fv.master.RedirectDownload/redirectDownload/Pr esentation_Template.ppt?u8&HttpOperationItem=wt.content.ApplicationData%3A295917&Co ntentHolder=wt.doc.WTDocument%3A295907;;;qqq"> <param name="recordDelim" value=";;;zzz"> <COMMENT> <EMBED type="application/x-java-applet;version=1.4" name="formApplet" width="2" height="2" pluginspage="http://java.sun.com/getjava/download.html" java_code="wt/clients/util/http/DownloadApplet" java_codebase="http://mecasey03d.ptcnet.ptc.com/Windchill/" java_archive="wt/security/security.jar" filename=";;;qqqRequirements_Template.doc;;;qqqAgenda_Template.doc;;;qqqMemo_Templa te.doc;;;qqqMinutes_Template.doc;;;qqqMS_Project_Plan_Template.mpp;;;qqqPresentatio n_Template.ppt;;;qqq" url="javascript:close()" debug="FALSE" delim=";;;qqq" cache_archive="contentCust.jar, contentDSU.jar, contentFCS.jar, lib/HTTPClient.jar, content3rdParty.jar, content.jar" cabinets="wt/security/security.cab" downloadOpType="ALWAYS_ASK" cache_option="Plugin" wt.context.locale="en_GB" downloadQuantity="6" defaultPath="" downloadURL=";;;qqqhttp://mecasey03d.ptcnet.ptc.com/Windchill/servlet/WindchillAuth GW/wt.fv.master.RedirectDownload/redirectDownload/Requirements_Template.doc?u8&Http OperationItem=wt.content.ApplicationData%3A295941&ContentHolder=wt.doc.WTDocument%3 A295939;;;qqqhttp://mecasey03d.ptcnet.ptc.com/Windchill/servlet/WindchillAuthGW/wt. fv.master.RedirectDownload/redirectDownload/Agenda_Template.doc?u8&HttpOperationIte m=wt.content.ApplicationData%3A294345&ContentHolder=wt.doc.WTDocument%3A294335;;;qq qhttp://mecasey03d.ptcnet.ptc.com/Windchill/servlet/WindchillAuthGW/wt.fv.master.Re directDownload/redirectDownload/Memo_Template.doc?u8&HttpOperationItem=wt.content.A pplicationData%3A294363&ContentHolder=wt.doc.WTDocument%3A294353;;;qqqhttp://mecase y03d.ptcnet.ptc.com/Windchill/servlet/WindchillAuthGW/wt.fv.master.RedirectDownload /redirectDownload/Minutes_Template.doc?u8&HttpOperationItem=wt.content.ApplicationD ata%3A294381&ContentHolder=wt.doc.WTDocument%3A294371;;;qqqhttp://mecasey03d.ptcnet .ptc.com/Windchill/servlet/WindchillAuthGW/wt.fv.master.RedirectDownload/redirectDo wnload/MS_Project_Plan_Template.mpp?u8&HttpOperationItem=wt.content.ApplicationData %3A294399&ContentHolder=wt.doc.WTDocument%3A294389;;;qqqhttp://mecasey03d.ptcnet.pt c.com/Windchill/servlet/WindchillAuthGW/wt.fv.master.RedirectDownload/redirectDownl oad/Presentation_Template.ppt?u8&HttpOperationItem=wt.content.ApplicationData%3A295 917&ContentHolder=wt.doc.WTDocument%3A295907;;;qqq" recordDelim=";;;zzz" ><NOEMBED> </COMMENT> </NOEMBED></EMBED> </OBJECT>
E-47
E-48
Index
A
Access control Property, 2-12 Access control package, 30-5 Accessor methods Overriding, 35-9 Adding content holder data formats, 44-2 allSearch Types Search User Interface, 20-11 API report generation, 27-31 Applet Advantages, E-15 Content Download Applet, E-15 Content Upload Applet, E-15 Default Local Directory, E-19 Disadvantages, E-15 Download Applet, E-42 Download Applet Parameters, E-44 File Selection Applet, E-15 File Selection files for upload, E-16 FileChooserDropAppletParameters, E-20 FileChooserDropAppletsample HTML, E-21 Multi-Select Javascript sample, E-19 Processing File Selection Output, E-18 Sample Javascript for Feedback and Navigation, E-25 Single-Select Javascript sample, E-18 Upload Applet Parameters, E-29 Upload Behavior-System Properties, E-27 Upload Behavior-User Preferences, E-28 UploadApplet, E-23 Audit Event configaudit.xml file, 28-7 Handler Classes, 28-7 ProjectAuditEvent, 28-4 Audit Recorders, 28-7 auditing events configuration file, 28-3 Windchill Auditing Framework, 28-2
B
Batch scripts, 2-2 Best practices modifying files, 5-9 new files, 5-26 Bill of Materials Customizing, 21-19 Hierarchy Visitor, 21-20 product structure, 21-19 report, 21-19 bin directory, 2-2 BOM see Bill of Materials Business Classes, 21-2 Business classes Revision controlled business class, 36-6 Business data types Implementing, 35-8 Business objects Modeling, 4-1 Business services Implementing, 35-14
C
cat files, 2-7 For sharing code, 2-8 Change Management Delegates, 22-2 ChooseFolderDelegate, 22-2 ChooseLifeCycleDelegate, 22-2 ConcreteAssociationDelegate, 22-3 DisplayIdentificationDelegate, 22-4 Change Management Workflow Process Templates Change Issue Process, 24-6 Code Impacted, 24-12 Custom Workflow Process Templates, 24-12 customizing, 24-6 Existing Installations, 24-11 Installation and Upgrade, 24-11 New Installations, 24-11 Synch on Change Request Submit, 24-8 Synch on Multiple Object State Change, 24-10 synchronization robots, 24-6
Index-1
checkAttribute method, 35-12 ChooseFolderDelegate, 22-2 ChooseLifeCycleDelegate, 22-2 Class files, 2-5 Class path environment variable, 2-9 Classes Document, 36-10 Folder resident business class, 36-4 Foundation classes, 4-10 Item, 4-10 Link, 4-11 Managed business class, 36-5 Part, 36-13 Simple business class, 36-2 WTObject, 4-10 ClassInfo.ser files Location, 2-6, 2-13 CLASSPATH environment variable, 2-9 Client JAR files, 5-7, 5-11, 5-14 Code Sharing, 2-8 Code generation Files, 2-7 See system generation tools.properties file, 2-13 Code Impacted Change Management Workflow Process Templates, 24-12 codebase directory Details, 2-5 Location, 2-3 codebase files, 5-13 Column Length change for modeled attribute, 32-2 customizing, 32-2 default location, 32-2 comment EnumeratedType, 33-2 CompositeUnique property, 21-13 ConcreteAssociationDelegate, 22-3 constantEnumeratedType, 33-6 Content Download Applet, E-15 Content holders data formats, 44-2 Content Upload Applet, E-15 Control units, 2-8 cookie abstraction Design Pattern, 34-4 createSafeArea target, 5-6 Creating new packages, 5-26 CSS Customization, 27-17 csvReport Template, 27-11
elements, 27-11 Custom Reports, 1-6 custom_getFieldData overriding, 20-22 Customized files, 5-2 Customizing, 27-16 Customizing Modeled Business Objects Windchill Customization Points, 1-8 Customizing workflows key points, 24-14 lock/unlock promotion targets, 24-14 owner role, 24-16 review promotion request activity, 24-15
D
Data Model Customizations, 1-5 Database Access set by properties, 2-14 db.properties.file, 2-14 Default table size, 2-13 Properties file, 2-3 Property file See db.properties file Database indexes, 21-12 db directory, 2-3 db.properties file Database access properties, 2-14 General description, 2-10 wt.pom.dbPassword property, 2-14 wt.pom.dbUser property, 2-14 wt.pom.serviceName property, 2-14 DCA Update configurations, 20-14 DCA patterns Search Page, 20-10 Debug tracing, 2-12 debug.properties file General description, 2-10 Default Local Directory, E-19 defaultValue EnumeratedType, 33-2 Design Pattern Business Service, 34-3 cookie abstraction, 34-4 helper abstraction, 34-4 service abstraction, 34-5 ServiceEvent abstraction, 34-5 ServiceException abstraction, 34-6 type abstraction, 34-4 Iterated interface, 34-7 Master Iteration, 34-7
Index-2
Mastered interface, 34-7 Object Reference, 34-2 Development environment Directory structure, 2-2 Environment variables, 2-9 Files, 2-3, 2-7 Property files, 2-10 Source code control, 2-8 Directory Ant, 2-2 apacheConf, 2-2 bin, 2-2 cgi-bin, 2-2 codebase Details, 2-5 Location, 2-3 codebase/wt, 2-6 db, 2-3 installer, 2-3 lib, 2-3 loadFiles, 2-3 loadXMLFiles, 2-3 logs, 2-3 Module, 2-3 RoseExtensions, 2-9 src Details, 2-7 Location, 2-3 src/wt, 2-7 srclib, 2-3 Structure after installation, 2-2 upgrade, 2-4 display EnumeratedType, 33-2 DisplayIdentificationDelegate, 22-4 Doc package, 36-10 Document class, 36-10 Document package, 36-10 Download Applet, E-42 Download Behavior-User Preferences, E-42 Downloading a file, E-42 Downloading multiple files, E-42 Sample HTML, E-45 Download Applet Parameters, E-44 Drag and Drop Targets, E-17 drop, E-17
Customization Utility, 33-11 editing resource info, 33-7 entry contents, 33-7 entry format, 33-7 Extending, 33-10 GUI Usage, 33-12 localizing, 33-9 RBrbInfo, 33-7 resource bundle, 33-9 resource info header, 33-7 runtime resources, 33-8 start utility, 33-12 Enumerated Types creating subclass, 33-3 EnumeratedType class, 33-2 comment, 33-2 defaultValue, 33-2 display, 33-2 order, 33-2 selectable, 33-2 value, 33-2 enumVerify tool, 33-8 Environment variables Class path, 2-9 Rational Rose virtual path map, 2-9 SQL path, 2-9 Events Managing, 35-4 Examples Development process, 3-1 Executable class files, 2-5 ExportReport Template, 27-13 optional parameters, 27-13
F
feedback, E-24 File Browse Launchers launch Java file, E-16 File Selection Applet, E-15 File Browse Launchers, E-16 Processing Output, E-18 upload files, E-16 User Preferences, E-19 FileChooserDropApplet Parameters, E-20 Files new, 5-26 site-modified, 5-2, 5-5 Folder resident business class, 36-4 Foundation classes Definitions, 4-10
E
Enterprise package, 36-2 enumCustomize tool, 5-10, 33-11 Enumerated Type
Index-3
G
Generate Form URL, 27-33
J
java.rmi.server.hostname property, 2-12 java.util.Date, 27-29 Javascript method File Selection Applet, E-18
H
helper abstraction Design Pattern, 34-4 HTML files Location of, 2-6 HTML templates, 5-12
L
Link class, 4-11 listSiteChanges target, 5-6, 5-8 listSiteChangesIgnored target, 5-6 listSiteModExclusions target, 5-6 loadFiles directory, 2-3 Loading Initial data, 2-3 LoadReport Template, 27-11 standalone mode options, 27-13 Localization, 39-1 Location of required files, 2-6 Localizing Text, 39-5 Logging Default location for trace logs, 2-3 Enable/disable logging, 2-12 Trace messages From method server, 2-12 From server manager, 2-12 LogicalAttributes.xml file, 5-12 logs directory, 2-3
I
IdentificationObject, 21-6, 21-8 implements identified, 21-8 implements UniquelyIdentified, 21-10 Identified, 21-7 Identity Attributes flowchart, 21-5 IdentityService, 21-5 modify, 21-2 RevisionControlled Identity, 21-4 SemanticKeys, 21-11 System Assigned, 21-2 UniquelyIdentified, 21-11 User-Assigned, 21-2 Identity attributes, 21-2 IdentityService How to use, 21-6 Implementation of Visitors, 21-22 quantity units, 21-22 Indexed-Search webject customized search application, 20-15 IndexObject method reference, 20-23 IndexSearch indexed text, 20-19 Info*Engine, 1-6 Info*Engine tasks, 5-13 INI files, 5-13 Installation and Upgrade Change Management Workflow Process Templates, 24-11 installSiteChanges target, 5-6, 5-8 Internationalization, 39-1 Item class, 4-10 Iteration and Version Identifiers Customizing, 21-17 multicharacter series, 21-18 Iteration Identifiers integer series, 21-17
M
Macros customizing, 27-35 report parameter, 27-9 make_jar.config_jars target, 5-7 Managed business class, 36-5 Managing client JAR files, 5-14 mData files, 2-7 Location, 2-13 mdl files, 2-7 Meetings, 29-2 Method server Logging trace messages, 2-12 Model files, 2-7 Modeled PSE Support, 19-5 Modeling Business objects, 4-1 Modifying files, 5-9 Multicharacter Series, 21-18
Index-4
MyDerivedItem enumerated type, 33-10 MyDerivedSize enumerated type, 33-10 MySize enumerated type, 33-10
O
Object Identity System Managed, 21-4 User Managed, 21-4 Object Initialization Rules, 1-3 Object Selection Actions, 20-9 Oracle password property, 2-14 Oracle service name property, 2-14 Oracle user name property, 2-14 order EnumeratedType, 33-2 Organization and Container Templates, 1-4
customizing, 24-13 Properties, 1-2 Properties and Preferences, 1-2 Property files, 5-11 db.properties file, 2-10 debug.properties file, 2-10 Editing, 2-11 service.properties file, 2-10 System Configurator, 2-11 wt.properties file, 2-10 PSE Modeled and Soft Type Support, 19-5 ptcCurrent directory, 5-3, 5-4 ptcOrig directory, 5-3, 5-5
Q
QueryBuilder, 27-28 QueryBuilder Types Report Generation, 27-37 QueryResult, 37-5 QuerySpec, 37-4
P
Packages Access control, 30-5 Control units, 2-8 Doc, 36-10 Document, 36-10 Enterprise, 36-2 Location, 2-6 Overview, 30-2 Part, 36-13 Query, 37-4 Packages, new, 5-26 Parameters Input to the webject, 20-15 report generation, 27-7 Part class, 36-13 Part package, 36-13 PATH environment variable, 2-9 Path environment variable, 2-9 Persistence Management, 37-1 Manager, 37-2 Query, 37-4 Preferences, 1-2 Product Structure Explorer See PSE ProjectAuditEvent class, 28-4 Promotion Request Approval Process, 24-13 Promotion Request Review Process, 24-14 Promotion Request Workflow Processes
R
Rational Rose, 4-2 Virtual path map, 2-9 Windchill extensions, 2-9 WT_EXTENSIONS entry, 2-9 WT_STD_PACKAGES entry, 2-9 WT_WORK entry, 2-9, 2-13 Rational Rose Modeler Edition, 5-27 RB.java files Location, 2-6 RB.rbInfo enumerated type, 33-7 RBINFO files, 5-9, 5-10 Rebuilding client JAR files, 5-7, 5-11 Report Generation API, 27-31 basic example, 27-2 client, 27-30 csvReport Template, 27-11 customization details, 27-15 CSS Customization, 27-17 new formats, 27-26 query, 27-15 report format, 27-16 stylesheets, 27-18 XML Resource Bundles, 27-25 XML Result Format, 27-27 XSLT Customization, 27-17
Index-5
customizing macros, 27-35 ExportReport Template, 27-13 Generate Form URL, 27-33 initial query steps, 27-2 LoadReport Template, 27-11 macro generation form steps, 27-10 macros, 27-9 new client, 27-33 parameters, 27-7 QueryBuilder Types, 27-37 Report Templates, 27-11 URL customizing, 27-33 XSLT API, 27-32 XSLT standard, 27-26 XSLT Stylesheets as Report Formats, 27-30 Report Generation Form, 27-31 Report Generation Output, 27-32 Resource bundles Localizing, 39-5 Location, 2-6 Revision control, 36-6 Revision controlled business class, 36-6 RevisionControlled Identity, 21-4 Rose model components, 2-7 RoseExtensions directory, 2-9 Runtime environment Files, 2-3, 2-5 Runtime Resources building, 33-8
S
Safe area, 5-2, 5-3 Search Adding Actions to Search Table, 20-9 Adding Attributes, 20-7 Adding Search Component, 20-2 Adding Table Actions, 20-9 allSearch Types, 20-11 attributes within criteria pulldown, 20-7 componentId, 20-2 DCA patterns, 20-10 Defining a search component, 20-2 Formats, 20-14 Indexed-Search, 20-15 Indexing Behavior, 20-19 IndexObject reference, 20-23 IndexSearch, 20-19 Input Parameters, 20-15 Layout of page, 20-10 modify picker, 20-4 componentId parameter, 20-4
containerRef parameter, 20-4 containerType parameter, 20-4 frameTitleLabel parameter, 20-5 objectType parameter, 20-4 selectorType parameter, 20-4 Object Selection Actions, 20-9 overriding custom_getFieldData(), 20-22 Query Layer, 20-8 Row Level Actions, 20-9 Search component definition Key, 20-3 Windchill Solution, 20-2 Search User Interface, 20-11 SearchableAttributes.properties, 20-8 Soft Attributes, 20-6 Soft Types, 20-6 Style Sheet, 20-14 Update DCA Configurations, 20-14 Using a Component, 20-4 SearchCondition, 37-5 selectable EnumeratedType, 33-2 SemanticKey, 21-11 Server logic Overview of developing, 35-1 Server manager Logging trace messages, 2-12 service abstraction Design Pattern, 34-5 Service Customizations, 1-5 Service provider property file, 5-27 service.properties file General description, 2-10 ServiceEvent abstraction Design Pattern, 34-5 ServiceException abstraction Design Pattern, 34-6 Services Access control, 30-5 Event management, 35-4 Managing, 35-2 Overview, 30-1 Query, 37-4 Servlet Helper GatewayServletHelper, 21-30 URLFactory Functionality, 21-30 Sharing code, 2-8 Simple business class, 36-2 site.xconf file, 5-11 siteMod directory, 5-3, 5-4 Soft Attributes Search, 20-6
Index-6
Soft Types Searches, 20-6 Soft Typing, 1-4 Source code management, 2-8 Source files, 2-3, 2-7 SQL path environment variable, 2-9 SQL scripts, 2-3 Location, 2-13 SQLPATH environment variable, 2-9 src directory, 2-3 Details, 2-7 Style Sheet create new, 20-14 Stylesheets, 27-18 Supported API, 1-8 class, 1-8 method, 1-9 swmaint.xml script, 5-5 Synchronization robots, 24-6 System, 21-2 System generation Overview, 31-1 Using, 31-50 System-Managed Identity, 21-15
Updating client JAR files, 5-11, 5-14 content holder data formats, 44-3 Upload Applet, E-23 Checksum, E-27 feedback, E-24 multiple files initial upload, E-24 Persisting Information, E-25, E-26 Primary/Secondary initial upload, E-24 Sample HTML, E-32 Update/Replace/Remove, E-24 Upload Applet Parameters, E-29 uploadImpl parameter System Properties, E-27 URL parameters report generation table, 27-33 URLFactory implementation example, 21-31 User Interface Customizations, 1-6 User Preferences customizing, 21-24
V
validEmptyFile parameter System Properties, E-27 value EnumeratedType, 33-2 Version Identifiers harvard series, 21-17 Virtual path map Rational Rose Purpose, 2-9 WT_EXTENSIONS entry, 2-9 WT_STD_PACKAGES entry, 2-9 WT_WORK entry, 2-9, 2-13
T
Template files, 5-12 Text tailoring, 5-2, 5-9, 5-10 tools.properties file Use by code generator, 2-13 wt.classRegistry.search.path property, 2-13 wt.classRegistry.search.pattern property, 2-13 wt.generation.bin.dir property, 2-13 wt.generation.source.dir property, 2-13 wt.generation.sql.dir property, 2-13 wt.generation.sql.xxxTablesSize property, 2-13 ToolsSetup.bat, 2-2 Trace logs Default location, 2-3 Trace messages Logging From method server, 2-12 From server manager, 2-12 Transactions, 37-8 type abstraction Design Pattern, 34-4
W
Webex meetings customizing authentication scheme, 29-2 Windchill Auditing Framework configuration, 28-7 Windchill Customization Points, 1-8 Windchill directory structure, 2-2 Windchill Info*Engine tasks, 5-13 Workflow customizing, 24-2 Workflow HTML template customization steps, 24-3 Workflow HTML Templates customizing, 24-2
U
Unique database indexes, 21-12 UniquelyIdentified, 21-11
Index-7
Workflow Templates, 1-3 wt directory See also Packages wt.access.enforce property, 2-12 wt.change2 package change management delegates, 22-2 wt.change2.WTChangeRequest2 identified instructions, 21-7 wt.classRegistry.search.path property, 2-13 wt.classRegistry.search.pattern property, 2-13 wt.generation.bin.dir property, 2-13 wt.generation.source.dir property, 2-13 wt.generation.sql.dir property, 2-13 wt.generation.sql.xxxtablesSize property, 2-13 wt.home property, 2-11 wt.logs.enabled property, 2-12 wt.manager.verboseClient property, 2-12 wt.manager.verboseServer property, 2-12 wt.method.verboseClient property, 2-12 wt.method.verboseServer property, 2-12 wt.pom.dbPassword property, 2-14 wt.pom.dbUser property, 2-14 wt.pom.properties property, 2-14 wt.pom.serviceName property, 2-14 wt.properties file Double back slashes in path names, 2-11 Format of path names, 2-11 General description, 2-10 java.rmi.server.hostname property, 2-12 wt.access.enforce property, 2-12 wt.home property, 2-11 wt.logs.enabled property, 2-12 wt.manager.verboseClient entry, 2-12 wt.manager.verboseServer entry, 2-12 wt.method.verboseClient entry, 2-12 wt.method.verboseServer entry, 2-12 wt.pom.properties property, 2-14 wt.server.codebase entry, 2-11 wt.server.codebase property, 2-11 WT_EXTENSIONS entry, 2-9 WT_STD_PACKAGES entry, 2-9 WT_WORK entry, 2-9, 2-13 wtCustom directory, 5-2, 5-9 WTObject class, 4-10 wtSafeArea directory, 5-2, 5-3
XML Resource Bundles, 27-25 XML Result Format, 27-27 XSLT API report generation, 27-32 XSLT Customization, 27-17 XSLT standard, 27-26 XSLT Stylesheets Report Formats, 27-30 XSLT stylesheets XML resource bundles, 27-25
X
XCONF files, 5-11, 5-12, 5-28 xconfmanager, 6-2 XML Query results top level elements, 27-29
Index-8