WCApp Dev Gdsuide
WCApp Dev Gdsuide
Windchill 7.0
December 2003
AutoDesk Inventor are registered trademarks of Autodesk, Inc. Baan is a registered trademark of Baan
Company. CADAM and CATIA are registered trademarks of Dassault Systemes. COACH is a trademark of
CADTRAIN, Inc. DOORS is a registered trademark of Telelogic AB. FLEXlm is a registered trademark of
GLOBEtrotter Software, Inc. Geomagic is a registered trademark of Raindrop Geomagic, Inc. EVERSYNC,
GROOVE, GROOVEFEST, GROOVE.NET, GROOVE NETWORKS, iGROOVE, PEERWARE, and the
interlocking circles logo are trademarks of Groove Networks, Inc. Helix is a trademark of Microcadam, Inc.
HOOPS is a trademark of Tech Soft America, Inc. HP-UX is a registered trademark and Tru64 is a trademark of
the Hewlett-Packard Company. I-DEAS, Metaphase, Parasolid, SHERPA, Solid Edge, and Unigraphics are
trademarks or registered trademarks of Electronic Data Systems Corporation (EDS). InstallShield is a registered
trademark and service mark of InstallShield Software Corporation in the United States and/or other countries.
Intel is a registered trademark of Intel Corporation. IRIX is a registered trademark of Silicon Graphics, Inc.
MatrixOne is a trademark of MatrixOne, Inc. Mentor Graphics and Board Station are registered trademarks and
3D Design, AMPLE, and Design Manager are trademarks of Mentor Graphics Corporation. MEDUSA and
STHENO are trademarks of CAD Schroer GmbH. Microsoft, Microsoft Project, Windows, the Windows logo,
Windows NT, Visual Basic, and the Visual Basic logo are registered trademarks of Microsoft Corporation in the
United States and/or other countries. Netscape and the Netscape N and Ship's Wheel logos are registered
trademarks of Netscape Communications Corporation in the U.S. and other countries. Oracle is a registered
trademark of Oracle Corporation. OrbixWeb is a registered trademark of IONA Technologies PLC. PDGS is a
registered trademark of Ford Motor Company. RAND is a trademark of RAND Worldwide. Rational Rose is a
registered trademark of Rational Software Corporation. RetrievalWare is a registered trademark of Convera
Corporation. RosettaNet is a trademark and Partner Interface Process and PIP are registered trademarks of
"RosettaNet," a nonprofit organization. SAP and R/3 are registered trademarks of SAP AG Germany.
SolidWorks is a registered trademark of SolidWorks Corporation. All SPARC trademarks are used under license
and are trademarks or registered trademarks of SPARC International, Inc. in the United States and in other
countries. Products bearing SPARC trademarks are based upon an architecture developed by Sun Microsystems,
Inc. Sun, Sun Microsystems, the Sun logo, Solaris, UltraSPARC, Java and all Java based marks, and "The
Network is the Computer" are trademarks or registered trademarks of Sun Microsystems, Inc. in the United
States and in other countries. VisTools is a trademark of Visual Kinematics, Inc. (VKI). VisualCaf is a
trademark of WebGain, Inc. WebEx is a trademark of WebEx Communications, Inc.
Licensed Third-Party Technology Information
Certain PTC software products contain licensed third-party technology: Rational Rose 2000E is copyrighted
software of Rational Software Corporation. RetrievalWare is copyrighted software of Convera Corporation.
VisualCaf is copyrighted software of WebGain, Inc. VisTools library is copyrighted software of Visual
Kinematics, Inc. (VKI) containing confidential trade secret information belonging to VKI. HOOPS graphics
system is a proprietary software product of, and is copyrighted by, Tech Soft America, Inc. G-POST is
copyrighted software and a registered trademark of Intercim. VERICUT is copyrighted software and a registered
trademark of CGTech. Pro/PLASTIC ADVISOR is powered by Moldflow technology. Moldflow is a registered
trademark of Moldflow Corporation. The JPEG image output in the Pro/Web.Publish module is based in part on
the work of the independent JPEG Group. DFORMD.DLL is copyrighted software from Compaq Computer
Corporation and may not be distributed. METIS, developed by George Karypis and Vipin Kumar at the
University of Minnesota, can be researched at http://www.cs.umn.edu/~karypis/metis. METIS is 1997 Regents
of the University of Minnesota. LightWork Libraries are copyrighted by LightWork Design 1990-2001. Visual
Basic for Applications and Internet Explorer is copyrighted software of Microsoft Corporation. Adobe Acrobat
Reader is copyrighted software of Adobe Systems. Parasolid Electronic Data Systems (EDS). Windchill
Info*Engine Server contains IBM XML Parser for Java Edition and the IBM Lotus XSL Edition. Pop-up
calendar components Copyright 1998 Netscape Communications Corporation. All Rights Reserved.
TECHNOMATIX is copyrighted software and contains proprietary information of Technomatix Technologies
Ltd. Apache Server, Tomcat, Xalan, and Xerces are technologies developed by, and are copyrighted software of,
the Apache Software Foundation (http://www.apache.org/) - their use is subject to the terms and limitations at:
http://www.apache.org/LICENSE.txt. UnZip ( 1990-2001 Info-ZIP, All Rights Reserved) is provided "AS IS"
and WITHOUT WARRANTY OF ANY KIND. For the complete Info-ZIP license see
ftp://ftp.info-zip.org/pub/infozip/license.html. Gecko and Mozilla components are subject to the Mozilla Public
License Version 1.1 at http://www.mozilla.org/MPL/. Software distributed under the MPL is distributed on an
"AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the MPL for the
specific language governing rights and limitations. Technology "Powered by Groove" is provided by Groove
Networks, Inc. Technology "Powered by WebEx" is provided by WebEx Communications, Inc. Acrobat Reader
is Copyright 1998 Adobe Systems Inc. Oracle 8i run-time, Copyright 2000 Oracle Corporation. The Java
Telnet Applet (StatusPeer.java, TelnetIO.java, TelnetWrapper.java, TimedOutException.java), Copyright
1996, 97 Mattias L. Jugel, Marcus Meiner, is redistributed under the GNU General Public License. This license
is from the original copyright holder and the Applet is provided WITHOUT WARRANTY OF ANY KIND. You
may obtain a copy of the source code for the Applet at http://www.mud.de/se/jta (for a charge of no more than
the cost of physically performing the source distribution), by sending e-mail to [email protected] or
[email protected] are allowed to choose either distribution method. The source code is likewise provided
under the GNU General Public License. GTK+The GIMP Toolkit are licensed under the GNU LPGL. You may
obtain a copy of the source code at http://www.gtk.org/, which is likewise provided under the GNU LPGL. zlib
software Copyright 1995-2002 Jean-loup Gailly and Mark Adler.
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) (OCT'95) or DFARS 227.7202-1(a) and 227.7202-3(a) (JUN'95), is 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 (OCT'88) or Commercial
Computer Software-Restricted Rights at FAR 52.227-19(c)(1)-(2) (JUN'87), as applicable.
040103
Parametric Technology Corporation, 140 Kendrick Street, Needham, MA 02494 USA
Content
vi
Content
vii
viii
Content
ix
SearchCondition................................................................................................................ 7-14
QueryResult ...................................................................................................................... 7-15
Multiple Class Queries ...................................................................................................... 7-15
Transaction .............................................................................................................................. 7-16
Paging ............................................................................................................................... 7-17
Content
xi
xii
Content
xiii
xiv
Change Record
This table describes any major content changes or reorganizations since the last
release.
Table 1 Changes for Release 7.0
Change
Description
xv
xvi
Related Documentation
The following documentation may be helpful:
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 email if you
encounter problems using Windchill.
For complete details, refer to Contacting Technical Support in the PTC Customer
Service Guide enclosed with your shipment. This guide can also be found under
the Support Bulletins section of the PTC Web site at:
http://www.ptc.com/support/index.htm
The PTC Web site also provides a search facility that allows you to locate
Technical Support technical documentation of particular interest. To access this
page, use the following link:
http://www.ptc.com/support/support.htm
xvii
You must have a Service Contract Number (SCN) before you can receive
technical support. If you do not have an SCN, contact PTC License Management
using the instructions found in your PTC Customer Service Guide under
Contacting License Management.
Help topics
PDF books
To view and print PDF books, you must have the Adobe Acrobat Reader installed.
All Windchill documentation is included on the CD for the application. In
addition, books updated after the release (for example, to support a hardware
platform certification) are available from the Reference Documents section of the
PTC Web site at the following URL:
http://www.ptc.com/cs/doc/reference/
Comments
PTC welcomes your suggestions and comments on its documentationsend
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.
Documentation Conventions
Windchill documentation uses the following conventions:
Convention
Item
Example
Bold
Click OK.
Italic
create_<tablename>.sql
Monospace
Examples
Messages
Processing completed.
xviii
Convention
Item
Example
"Quotation
marks"
Strings
xix
xx
1
The Windchill Development
Environment
Topic
Page
1-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.
bin
Contains the wtbeans.jar file, which holds the Java bean components that
have been developed for use with Windchill clients. For more information,
see Chapter 10, Developing Client Logic.
loadFiles
1-2
The codebase directory and src directory are described in more detail in the
following subsections.
1-3
The html directory contains templates that are used to generate HTML
dynamically.
The wt directory 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 chapter 9, System Generation.
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.
1-4
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 chapter 9, System
Generation).
1-5
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 writeable, select the Write Protect <package> item. These
are menu items are both available from the same Units menu item mentioned
above.
1-6
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 % WT_HOME% \bin and JDK\bin. %
WT_HOME% 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.
WT_WORK, which specifies the top level directory where .mData files and
.cat files are located. Every wt package modeled in Rose has a corresponding
.cat file in the c:\ptc\windchill\src\wt directory.
1-7
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 Javadoc wt.util package for further 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.
db.properties
Contains properties used by Windchills database connection layer to access
the database.
tools.properties
Contains properties used by Rational Rose and the Windchill code generation
tools.
1-8
debug.properties
Contains properties used by Windchill code to control debug info capturing.
service.properties
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.
1-9
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.
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
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.
1-10
tools.properties file
The tools.properties file contains properties that are used by the System
Generation tools. The following properties within wt.tools.properties are of
interest:
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.
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
SystemAdministrator's Guide for information on the xconfmanager utility.
1-11
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:
1-12
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.
2
Getting Started With Windchill
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 chapter 1, The Windchill
Development Environment) is set up correctly.
Topic
Page
2-1
PATH
Ensure that the PATH variable includes the Oracle path. An example
follows:
% [ ]SystemRoot% [ ]\system32;% [ ]SystemRoot% [ ];
C:\ORANT\BIN;c:\jdk1.1.6\bin
SQLPATH
The SQLPATH specifies the directory in which sql scripts are generated.
It must match the value specified in the tools.properties file entry named
2-2
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 >
Start the server manager and a method server by entering the following
command:
java wt.manager.ServerLauncher
2-3
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.1 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.
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.
2-4
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.
SQL scripts that create the tables which store the Person class, and a
directory named helloWorld in c:\ptc\windchill\db\sql which contains all
the scripts.
You can verify this step by finding these files in the directories.
Create DatabaseTables
In Oracle SQL*Plus, create the tables by running the following command:
@helloWorld\make_helloWorld
2-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.
2-6
wt.util.WTException;
wt.util.WTContext;
wt.fc.PersistenceHelper;
java.lang.Integer;
java.lang.NumberFormatException;
5. Insert the following statement as the first line of the init() method in the
CreatePerson.java file:
2-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.)
2-8
3
Modeling Business Objects
Topic
Page
3-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.
3-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.
3-3
To ensure a model from which optimized code can be generated. The code
that is generated should provide for managing the state of objects,
transporting objects between the client and the server, and manipulating
objects in the database.
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.
3-4
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 chapter on server development) from which you can choose as much
3-5
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.
3-6
3-7
Foundation Hierarchy
3-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
3-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
3-10
ObjectToObjectLink
3-11
3-12
4
The Command Layer
Topic
Page
4-1
This chapter describes the classes and interfaces available in the following
packages, and guidelines on how to develop commands:
com.ptc.core.command
com.ptc.core.foundation
com.ptc.core.query.command
Note: The above packages do not contain all of the commands available in the
system. What they represent is a substantial core set of command beans, command
delegates and attribute handlers.
The command layer provides a layer of abstraction and indirection. It
encapsulates and hides from the consumer whether a command is executed
locally, remotely or a combination of both. However, the remote executability of
commands is only temporary based on a federated and type-based architecture,
and thus clients should employ webjects or Info*Engine tasks for server-side
commands to be executed in the server.
The command layer is designed such that it can be regarded as a Windchill design
pattern that can be reused by many development teams. This Windchill command
design pattern allows for commands and supporting classes to be easily reused to
support a variety of consumers (e.g., JSP, Java applet/application, Webject), and
to facilitate rapid development of new commands and execution logic.
The Windchill command design pattern supports the notion of a composite or
macro command where it is a sequence of commands to be executed. The macro
command can be executed, which then will execute each contained command in
the given order from first to last. A macro command supports the ability for
transactional blocks to be specified within the sequence of commands. This infers
that not only would the whole sequence be able to be processed in a transaction,
but also segments of commands within the sequence as well. Additionally, each
command within the sequence can be adapted for instance to feed its output to the
next commands input. The command adapters are only applicable within macro
commands and can be extended to adapt a commands execution in other ways.
Commands in the command layer exchange type instances as input and output.
They do not support heavyweight Windchill persistable types of objects.
Windchill persistable objects are neither sent nor received by consumers when
executing commands. Internally the commands transform type instances as input
to Windchill persistable objects. On output Windchill persistable objects are
transformed back into type instances.
Commands support the ability to send intermittent and completion feedback to the
client. As a part of this commands also support the logging of feedback as well as
debug information to the servers file system.
4-2
Command Beans
Design Overview
The simplest way to begin an overview of the design is to describe an example.
does this by illustrating a Create Part scenario. At the start of this scenario the
consumer makes a new CreatePersistentEntityCommand bean, sets various input
fields, most notably the source TypeInstance, filter1 and feedback specification,
and executes the command.
By design since the CreatePersistentEntityCommand is a kind of command that is
only executable in the server the corresponding command delegate is required to
run in the method servers JVM. Thus, a special type of command delegate that
forwards to the server is made anew, the target delegate by name is set2, and the
forwarder is executed causing a remote method invocation to the method server
passing itself. Once in the method server the forwarder makes a new command
delegate given the name being the CreatePersistentEntityCommandDelegate and
executes it passing along the command bean.
The CreatePersistentEntityCommandDelegate performs any pre-processing logic
that is required. It then performs the execution logic which translates the given
source TypeInstance into a Persistable, stores the Persistable using the persistence
layer, and translates the returned Persistable from the persistence layer back into
the result TypeInstance. Now the CreatePersistentEntityCommandDelegate
performs any post-processing logic that is required3.
Once the CreatePersistentEntityCommandDelegate has finished with the postprocessing it returns as a result a TypeIsntance to the consumer. The consumer at
this point is then free to do whatever with the result.
1.
2.
3.
4-3
With the simple Create Part scenario described command bean design details
can now be discussed. The Create Part Sequence Diagram shows the key part of
the overall command bean classification hierarchy.
Within this classification hierarchy there are two main types of command beans,
local and server commands. Local commands are executable in any JVM being in
either the client or server. These types of commands are useful when only local
work needs to be accomplished with a uniform and consistent set of APIs. Server
commands are only executed within the servers JVM. They currently are
remotely executable within a clients JVM. Again the remote executability of
commands is only temporary based on a federated and type-based architecture,
and thus clients should employ webjects or Info*Engine tasks for server-side
commands to be executed in the server.
The two main types of server commands are entity and repository commands.
Entity commands provide operations against business objects (i.e., a business
object is notionally an entity) like CRUD, check out, check in, revise, etc.
Repository commands provide operations against the container of persistent
business objects like performing a variety of queries on a database. A repository
represents anything that acts as a container of business objects. This container
could, instead of a typical database, alternatively be a file system or some other
mechanism that can keep business objects.
4-4
External Interface
The Command interface provides the main abstraction of a command bean. It
specifies the following key APIs that all local and server types of commands must
implement:
1. locale field: the locale to be used should any locale specific strings
need to be created. Accessors are generated for this private field.
2. execute() method: carries out the execution of the command. This
method employs the CommandDelegateFactory to get the appropriate
CommandDelegate, and then executes it passing the instance of the
Command. If for any reason there was erroneous, unrecoverable behavior then a type of CommandException is thrown.
The LocalCommand interface partitions the command bean classification
hierarchy for local types of commands. The abstract class of the LocalCommand
implements the execute() method to enforce that the command is executed within
the present JVM. The LocalCommand does not specify any more APIs.
The ServerCommand interface partitions the command bean classification
hierarchy for server types of commands. The abstract class of the
ServerCommand implements the execute() method to enforce that the command is
executed within only the servers JVM. The ServerCommand specifies the
following key APIs that all server types of commands must implement:
1. filter field: the specification of what attributes, constraints and descriptors are
to be returned in the commands result TypeInstance. Accessors are generated
for this private field.
2. getResultList() method: derives a TypeInstance list [an array] from the
underlying command bean's result type. This method is required to be
overridden by subclasses that specify a particular kind of result within a
command bean sub-classification where the result is different than what is
currently supported. For example, entity commands are required to return a
single TypeInstance, but in the case of the CheckoutFromVaultCommand it
returns both the working and reserved entities. Thus, the getResultList()
method is overridden to return an array of both of those business objects.
The AbstractServerTransaction class represents the notion of a special type of
server only command being a transaction. A transaction is not a normal command
in the sense that it is not executable. Instead its sole purpose for existing is to
enable the marking of transaction blocks within a sequence of commands in a
MacroServerCommand. Any consumer of this type of command that attempts to
execute it will get a CommandException that wraps an
UnsupportedOperationException.
The BeginServerTransaction class marks the beginning of where a transaction
block is to start in the sequence of commands within a MacroServerCommand.
This beginning of a transaction block can be placed anywhere within the sequence
provided that an EndServerTransaction follows it.
4-5
4-6
targetId field: the iteration or version identifier that is the to be the next
identifier of the iterated/versioned entity upon completion of the commands
execution. For example, the CheckinToVaultCommand can have this field
specified to be a different iteration identifier when the check in has completed
where say the checked out iteration identifier is 3, the checked in iteration
comment field: the note that is specified by a user when performing either a
check out and/or check in. This note is not applicable for an undo check out.
Accessors are generated for this private field.
Repository Commands
resultSession field: the paging session, if one has been established. A paging
session represents the concept of iterating over a collection of items in a
repository. A paging session allows for fetching results from the
resultSession over multiple command executions. Accessors are generated for
this private field.
source field: the TypeInstance representing the point at which to start at in the
iterated/versioned history. Accessors are generated for this private field.
4-7
target field: the TypeInstance representing the point at which to end at in the
iterated/versioned history. Accessors are generated for this private field.
Modeling Guidelines
PTC development practices use Rational Rose to model and develop command
beans. Although this is the practice at PTC it is not required.
All types of command beans are modeled in Common subsystems such that their
deployment is accessible to both Client and Server subsystems. This is true for
server commands since they are currently remotely executable. PTC developed
command bean classes not have any compile or run-time dependencies on
Persistable classes.
Command Infrastructure Specification Common Subsystem shows The
Command Infrastructure Specification - Common subsystem where many of the
command beans exist shown in the Command Bean Overview Class Diagram.
Other command beans more specific to Windchill services and enterprise objects
exist in similarly placed Common subsystems within the Windchill Foundation
Common and Enterprise Common subsystems.
Naming Guidelines
All command beans should be named in a manner to explicitly depict the
operation and on what they are designed for. That is to say the naming formula
verb + noun + Command should be applied. For example, if CRUD commands
didnt already exist and were to be developed, they would apply only to persistent
entities and would be named as follows:
CreatePersistentEntityCommand
RetrievePersistentEntityCommand
UpdatePersistentEntityCommand
DeletePersistentEntityCommand
And this is exactly how these pre-existing CRUD commands are named.
Declaring command bean names in this manner makes it possible for consumers
to readily know what the command does and on what. Since there is no other API
on command beans that clarify their meaning, the name is required to do so.
Serialization Guidelines
All server types of command beans are modeled and generated as Serializable
types of classes. This is true since server commands are remotely executable.
Once server commands are no longer remotely executable they would no longer
be required to be Serializable. But since they are currently remotely executable
4-8
they must be streamed from the client to the server and returned back to the client
via Java RMI.
Implementation Guidelines
All local types of commands should extend from the AbstractLocalCommand
class. All server types of commands should extend from the
AbstractServerCommand class. This will enable inheritance of common
functionality that will ensure correct behavior. Implementing LocalCommand or
ServerCommand without extending the respective abstract class is not
recommended and is not part of PTC development practices.
Javadoc Guidelines
Command beans represent the set of APIs that are to be depended on and used by
consumers. What this means is that the command beans as a whole are the formal,
type-aware APIs of the system. Because of this all of the public and protected
command beans APIs should be clearly and thoroughly documented.
Command Delegates
Design Overview
Command delegates are the realization or implementation of command beans.
Command beans are the formal API and command delegates are the
implementation details. Command delegates are a customization point where oneto-many command delegates can implement [most likely] one [and not very likely
many] command bean(s).
For example, the CreatePersistentEntityCommand bean has an OOTB default
command delegate being the CreatePersistentEntityCommandDelegate. In most
cases this command delegate will function as required. However, in the case of
some change objects they are required to be created in the repository related to
another applicable change object. Thus, based on the
CreatePersistentEntityCommand bean and type of change object a unique
command delegate can be looked up and executed as the correct implementation.
Command Delegate Overview Class Diagram shows the key part of the overall
command delegate classification hierarchy.
4-9
External Interface
The CommandDelegate interface provides the main abstraction of a command
delegate. All delegates that realize commands as their implementation will either
directly or indirectly assert that they implement this interface. The
CommandDelegate interface mandates that the following three methods be
implemented and executed in that order:
preprocess()
execute()
postprocess()
4-10
4-11
getService() method: finds the cached Windchill service from the given class
instance of the service interface. For example, passing
PersistenceManager.class will return the active persistence managers
singleton in the server.
Event Processing
As documented in the external interface of the
AbstractRemoteCommandDelegate class, it provides APIs to allow the
dispatching of any event defined by all Windchill services. Since this is only
possible for a subclass of the AbstractRemoteCommandDelegate, then these
events will only be dispatched within the server JVM.
For example, in the following code snippet the
RetrievePersistentEntityCommandDelegate dispatches either the
PREPARE_FOR_MODIFICATION or PREPARE_FOR_VIEW
PersistenceManager event depending on what the next operation is in the filter.
OperationIdentifier opid = retrieveCmd.getFilter().getNextOperation();
if (opid instanceof UpdateOperationIdentifier && !(opid instanceof CreateOperationIdentifier)) {
dispatchVetoableEvent(
PersistenceManager.class,
new PersistenceManagerEvent(
(PersistenceManager)getService( PersistenceManager.class ),
PersistenceManagerEvent.PREPARE_FOR_MODIFICATION, pers ));
}
else if (opid instanceof DisplayOperationIdentifier || opid instanceof SearchOperationIdentifier) {
dispatchVetoableEvent(
PersistenceManager.class,
4-12
new PersistenceManagerEvent(
(PersistenceManager)getService( PersistenceManager.class ),
PersistenceManagerEvent.PREPARE_FOR_VIEW, pers ));
}
Modeling Guidelines
PTC development practices do not strictly establish whether or not command
delegates should be modeled using Rational Rose. Some command delegates have
been modeled while others have not.
Local types of command delegates are developed in Common subsystems such
that their deployment is accessible to both Client and Server subsystems. Server
types of command delegates are developed in Server subsystems to limit
deployment and accessibility for server-only dependencies.
The Command Infrastructure Implementation Common and Server Subsystems
shows The Command Infrastructure Implementation - Common and Server
subsystems where many of the command delegates exist shown in The Command
Delegate Overview Class Diagram. Other command delegates more specific to
Windchill services and enterprise objects exist in similarly placed Common
subsystems within the Foundation Common and Enterprise Common subsystems.
Naming Guidelines
Command delegate naming conventions follow command bean naming
conventions with an added Delegate at the end of the class name. In most cases
where theres a one-to-one mapping between bean and delegate the command
beans name + Delegate should be used to name the command delegate.
However, in cases of one-to-many, many-to-one or many-to-many command bean
to command delegate mappings it will be necessary to be either more of less
specific in the command delegates name. The following 2 examples illustrate the
many-to-one and one-to-many mappings:
1. For all query command beans there exists only one mapped command
delegate and thus should be name more general. It is named
QueryCommandDelegate where the following command beans are mapped to
it:
AttributeContainerQueryCommand
BasicQueryCommand
FindPersistentEntityCommand
CreateWTAnalysisActivityCommandDelegate
CreateWTChangeActivity2CommandDelegate
4-13
CreateWTChangeInvestigationCommandDelegate
CreateWTChangeIssueCommandDelegate
CreateWTChangeOrder2CommandDelegate
CreateWTChangeProposalCommandDelegate
CreateWTChangeRequest2CommandDelegate
Serialization Guidelines
No command delegate should ever be Serializable. They are the implementation
details of commands where the command beans are sent across-the-wire, not the
command delegates.
Implementation Guidelines
In general, a command delegates implementation has the 3 main steps within the
doExecution() method, assuming that no customization has been done for pre-orpost-processing:
1. Given the input TypeInstance populate a new Persistable. This by-in-large is
an act of in-memory translations.
2. Perform the server-side API invocation(s) against the Persistable via
Windchill services.
3. Populate the output TypeInstance with the acted upon Persistable. This has 3
minor steps where theres an in-memory translation, derivation of server
calculated attributes and a query of all non-surface, missing attributes.
Additionally, the command delegate should be implemented where appropriate
levels of debugging and feedback messages are issued.
This type of implementation is known as a wrapper command delegate around
an existing Windchill services API matching the command. This isnt always the
case. Command delegates can also execute other commands as well. This is the
case of the MacroCommandDelegate where it iterates through the sequence of
commands and executes each one in turn.
The UpdatePersistentEntityCommandDelegate Activity Diagram shows an
activity diagram for the UpdatePersistentEntityCommandDelegate. As can be
seen within the doExecution() activity the basic 3 step pattern was applied. The
only caveat is that constraints are refreshed and enforced as well. This pattern or
slight variation of it has been applied to all wrapper command delegates.
4-14
execute()
preprocess()
initialize()
do/ populate server functions into TypeInst...
doPreprocessing()
doExecution()
populatePersistable()
do/ refresh and enforce constraints
do/ refresh Persistable from DB
do/ check Persistable's update count
do/ translate TypeInstance to Persistable
PersistenceHelper.manager.modify()
do/ PersistenceManager update of Persistable
populateTypeInstance()
do/ translate Persistable to TypeInstance
postprocess()
doPostprocessing()
finalize()
do/ populate SCAs, constraints and descriptors
do/ populate missing, non-surface content
4-15
3. Translate all changes from the input TypeInstance to the Persistable. Only
those attributes from the TypeInstance that are in a NEW, CHANGE or
DELETED state are translated to the Persistable.
4. Use the PersistenceManager to perform an update of the Persistable to the
database. For non CRUD operations, this is where other legacy APIs would
be executed to either update or retrieve Persistable objects.
5. Using the filter supplied with the command, prepare the result TypeInstance.
This processing may consist of only an in-memory translation from Persitable
to TypeInstance. It may also add any server calculated attributes to the
TypeInstance by deriving them via server functions, based on the filter. It can
as well involve an additional data base query to retrieve attributes that are
missing, again based on the filter, from the TypeInstance that were not either
translated or calculated.
But command delegates can be much more involved with their processing logic.
An example of this would be where a deferred save of an entire product
structures changes from BOM markup was needing to be done within a
transaction. Thus, the product structure represented as a single TypeInstance
could be sent to the server and processed by a special command delegate that
takes apart the TypeInstance and builds a corresponding product structure with all
of the changes. Then within a single transaction part-by-part, link-by-link would
be updated in the repository.
Attribute Handlers
Design Overview
Attribute Handlers are mechanisms for translating one of more attributes from a
Persistable to TypeInstance, or vice versa. They are translating in memory objects
only. Database hits should be avoided if at all possible. The order in which
attributes will be handled is not guaranteed or deterministic. Therefore, if
attributes require a certain order to their handling, a single Attribute Handler
should be written that handles both of them, at the same time, whenever any of the
related attributes are looked up. This handler then handles all of them
immediately, but in the proper order, then marks all of the involved attributes as
handled, so that they will not be handled multiple times.
Attribute Handlers generally do not validate arguments to make sure that business
rules are being followed. Generally, values passed to the get(...)and
set(...)methods are trusted, and if this results in an exception in a service, or a
ClassCastException, etc, then these exceptions will be passed through.
See StandardAttributeHandler for more information on when a specific
AttributeHandler must be written, and when the StandardAttributeHandler will
suffice.
4-16
External Interface
The AbstractAttributeHandler class is the main abstraction to define attribute
handlers. It provides some convenience methods for subclasses to reuse, but most
importantly it defines the following key APIs to be implemented by subclasses:
get() method: gets an attribute or attributes and their values from a Persistable,
and puts them in a TypeInstance. The source Persistable and target
TypeInstance are available via the translator command argument.
4-17
8. Attributes of these types generally must have attribute handlers that convert
the values to and from one of these "primitive" forms for storage in the
TypeInstance.
9. Attributes whose values are of type EnumeratedType or a subclass of
EnumeratedType are handled by the StandardAttributeHandler, so long as
they meet the other criteria above.
The AttributeStates class wraps two Vectors used to store
AttributeTypeIdentifiers in order to manage which have been handled and which
have not. Several methods are provided to access the state of attributes, and thus
it is important not to access them directly, but to instead use the provided methods
as follows:
1. findUnhandled() method: given an AttributeTypeIdentifier, this method
searches through the unhandled attributes for an AttributeTypeIdentifier
whose external form matches the external form of the supplied
AttributeTypeIdentifier. If a match is found, the AttributeTypeIdentifier
found with the unhandled attributes is returned, otherwise null is returned.
2. findHandled() method: given an AttributeTypeIdentifier, this method
searches through the handled attributes for an AttributeTypeIdentifier whose
external form matches the external form of the supplied
AttributeTypeIdentifier. If a match is found, the AttributeTypeIdentifier
found with the handled attributes is returned, otherwise null is returned.
3. makeHandled() method: given an AttributeTypeIdentifier, this method
searches through the handled attributes for that exact AttributeTypeIdentifier
(same actual object). If a match is found, the AttributeTypeIdentifier is
moved from the unhandled to the handled attributes, and true is returned,
otherwise false is returned.
Modeling Guidelines
PTC development practices do not strictly establish whether or not attribute
handlers should be modeled using Rational Rose. Only the
StandardAttributeHandler has been modeled while all others have not.
Since attribute handlers are purely implementation and no direct invocation is
made to them they should be packaged server.impl packages.
Naming Guidelines
Attribute handlers should be named to show the attribute being handler +
AttributeHandler. Some examples of existing attribute handlers follow:
4-18
ContentItemRoleAttributeHandler
DataFormatReferenceAttributeHandler
ContentItemCreatedByAttributeHandler
PersistInfoCreateStampAttributeHandler
PersistInfoModifyStampAttributeHandler
CabinetReferenceAttributeHandler
FolderReferenceAttributeHandler
ProjectReferenceAttributeHandler
IterationInfoCreatorAttributeHandler
MasterReferenceAttributeHandler
CheckoutInfoStateAttributeHandler
Serialization Guidelines
No attribute handler should ever be Serializable. They are the implementation
details of in-memory translations initiated by command delegates.
Implementation Guidelines
Attribute handlers can be implemented to handle one to many related attributes. In
the case of an attribute handler only handling one attribute the
CheckoutInfoStateAttributeHandler is shown to illustrate how it can be
implemented in the following code snippet:
public void get(
AttributeTypeIdentifier attr_type_id,
AbstractTranslatorCommand transl_cmd, AttributeStates
attr_states )
throws CommandException {
if (attr_states.findHandled(attr_type_id) != null)
return;
Workable work = (Workable) transl_cmd.getPersistable();
CheckoutInfo ci = work.getCheckoutInfo();
WorkInProgressState state = null;
if (ci != null)
state = ci.getState();
String value = null;
if (state != null)
value = state.toString();
putAttributeContent( attr_type_id, transl_cmd, attr_states,
value );
attr_states.makeHandled( attr_type_id );
}
public void set(
AttributeTypeIdentifier attr_type_id,
AbstractTranslatorCommand transl_cmd, AttributeStates
attr_states )
throws CommandException {
if (attr_states.findHandled(attr_type_id) != null)
return;
Workable work = (Workable) transl_cmd.getPersistable();
String value = (String) getAttributeContent( attr_type_id,
transl_cmd );
CheckoutInfo ci = work.getCheckoutInfo();
4-19
WorkInProgressState state =
WorkInProgressState.toWorkInProgressState( value );
try {
if (ci == null) {
ci = CheckoutInfo.newCheckoutInfo();
if (DEBUG) getDebugLog(transl_cmd).report("Setting
checkoutInfo = "+ci);
work.setCheckoutInfo( ci );
}
ci.setState( state );
}
catch (Exception e) {
throw new CommandException( e );
}
attr_states.makeHandled( attr_type_id );
}
For attribute handlers that are required to deal with multiple, related attributes at
the same time the VersionInfoAttributeHandler is shown to illustrate how it can
be implemnted in the following code snippet:
public void get(
AttributeTypeIdentifier attr_type_id,
AbstractTranslatorCommand transl_cmd, AttributeStates
attr_states )
throws CommandException {
AttributeTypeIdentifier versionIdATI =
getAttributeTypeIdentifier(
"versionInfo.identifier.versionId", transl_cmd );
AttributeTypeIdentifier versionLevelATI =
getAttributeTypeIdentifier(
"versionInfo.identifier.versionLevel", transl_cmd );
AttributeTypeIdentifier versionQualIdATI =
getAttributeTypeIdentifier(
"versionInfo.lineage.series.value", transl_cmd );
AttributeTypeIdentifier versionQualLevelATI =
getAttributeTypeIdentifier(
"versionInfo.lineage.series.level", transl_cmd );
AttributeTypeIdentifier[] ATIs = {
versionIdATI, versionLevelATI, versionQualIdATI,
versionQualLevelATI };
if (areHandled(ATIs, attr_states))
return;
Versioned version = (Versioned) transl_cmd.getPersistable();
try {
VersionInfo vInfo = version.getVersionInfo();
VersionIdentifier vIdentifier = null;
QualifiedIdentifier qIdentifier = null;
MultilevelSeries mSeries = null;
HarvardSeries hSeries = null;
Integer vLevel = null;
Integer qLevel = null;
String versionId = null;
Long versionLevel = null;
String qualifiedId = null;
Long qualifiedLevel = null;
if (vInfo != null) {
4-20
vIdentifier = vInfo.getIdentifier();
if (vIdentifier != null) {
mSeries = vIdentifier.getSeries();
if (mSeries != null) {
versionId = mSeries.getValue();
vLevel = mSeries.getLevel();
if (vLevel != null) {
versionLevel = new Long( vLevel.longValue() );
}
}
}
qIdentifier = vInfo.getLineage();
if (qIdentifier != null) {
hSeries = qIdentifier.getSeries();
if (hSeries != null) {
qualifiedId = hSeries.getValue();
qLevel = hSeries.getLevel();
if (qLevel != null) {
qualifiedLevel = new Long( qLevel.longValue() );
}
}
}
}
putAttributeContent( versionIdATI, transl_cmd, attr_states,
versionId );
putAttributeContent( versionLevelATI, transl_cmd,
attr_states, versionLevel );
putAttributeContent( versionQualIdATI, transl_cmd,
attr_states, qualifiedId );
putAttributeContent( versionQualLevelATI, transl_cmd,
attr_states, qualifiedLevel );
}
catch (VersionControlException vce) {
throw new CommandException( vce );
}
attr_states.makeHandled( ATIs );
}
public void set(
AttributeTypeIdentifier attr_type_id,
AbstractTranslatorCommand transl_cmd, AttributeStates
attr_states )
throws CommandException {
AttributeTypeIdentifier versionIdATI =
getAttributeTypeIdentifier(
"versionInfo.identifier.versionId", transl_cmd );
AttributeTypeIdentifier versionLevelATI =
getAttributeTypeIdentifier(
"versionInfo.identifier.versionLevel", transl_cmd );
AttributeTypeIdentifier versionQualIdATI =
getAttributeTypeIdentifier(
"versionInfo.lineage.series.value", transl_cmd );
AttributeTypeIdentifier versionQualLevelATI =
getAttributeTypeIdentifier(
"versionInfo.lineage.series.level", transl_cmd );
AttributeTypeIdentifier[] ATIs = {
versionIdATI, versionLevelATI, versionQualIdATI,
4-21
versionQualLevelATI };
if (areHandled(ATIs, attr_states))
return;
Versioned version = (Versioned) transl_cmd.getPersistable();
String versionId = (String) getAttributeContent( versionIdATI,
transl_cmd );
Long versionLevel = (Long) getAttributeContent( versionLevelATI,
transl_cmd );
try {
MultilevelSeries series =
MultilevelSeries.newMultilevelSeries(
VersionIdentifier.class.getName(), versionId, new Integer(
versionLevel.intValue() ));
if (version.getVersionInfo() == null) {
version.setVersionInfo( VersionInfo.newVersionInfo() );
}
VersionControlHelper.setVersionIdentifier( version,
VersionIdentifier.newVersionIdentifier( series ));
}
catch (Exception e) {
throw new CommandException( e );
}
attr_states.makeHandled( ATIs );
}
For attribute handlers that deal with some form of object reference
and server calculated attributes the ViewReferenceAttributeHandler
is shown to illustrate how it can be implemented in the following
code snippet:
public void get(
AttributeTypeIdentifier attr_type_id,
AbstractTranslatorCommand transl_cmd, AttributeStates
attr_states )
throws CommandException {
AttributeTypeIdentifier viewATI =
getAttributeTypeIdentifier("view.id", transl_cmd);
if (attr_states.findHandled(viewATI) != null)
return;
ViewManageable vm = (ViewManageable)
transl_cmd.getPersistable();
ViewReference viewRef = vm.getView();
TypeInstanceIdentifier viewTii = null;
if (viewRef != null)
viewTii = TypeIdentifierUtility.getTypeInstanceIdentifier(
viewRef );
putAttributeContent( viewATI, transl_cmd, attr_states, viewTii
);
attr_states.makeHandled( viewATI );
}
public void set(
AttributeTypeIdentifier attr_type_id,
AbstractTranslatorCommand transl_cmd, AttributeStates
attr_states )
throws CommandException {
AttributeTypeIdentifier viewATI =
getAttributeTypeIdentifier("view.id", transl_cmd);
4-22
AttributeTypeIdentifier viewNameATI =
getAttributeTypeIdentifier("view", transl_cmd);
AttributeTypeIdentifier[] ATIs = { viewATI, viewNameATI };
if (areHandled(ATIs, attr_states))
return;
ViewManageable vm = (ViewManageable)
transl_cmd.getPersistable();
TypeInstanceIdentifier viewTii =
(TypeInstanceIdentifier) getAttributeContent( viewATI,
transl_cmd );
String viewName =
(String) getAttributeContent( viewNameATI, transl_cmd );
try {
if (viewTii != null) {
ViewReference viewRef = ViewReference.newViewReference(
(ObjectIdentifier)TypeIdentifierUtility.getObjectReference(
viewTii ).getKey() );
vm.setView( viewRef );
}
else if (viewName != null ) {
ViewReference viewRef = ViewReference.newViewReference(
(ObjectIdentifier)TypeIdentifierUtility.getObjectReference(
ServerCommandUtility.getViewTypeInstanceIdentifier(viewName)).getK
ey() );
vm.setView( viewRef );
}
else {
vm.setView( null );
}
}
catch (Exception e) {
throw new CommandException( e );
}
attr_states.makeHandled( ATIs );
}
4-23
com.ptc.core.command.server.delegate.ServerCommandDelegate.properties
com.ptc.core.foundation.FoundationServerCommandDelegate.properties
com.ptc.core.foundation.windchill.enterprise.EnterpriseServerCommandDelegat
e.properties
wt.services/svc/default/com.ptc.core.command.common.CommandDelegate/co
m.ptc.core.command.common.bean.entity.RetrievePersistentEntityCommand
/null/0=com.ptc.core.command.server.delegate.entity.RetrievePersistentEntit
yCommandDelegate/singleton
4-24
wt.services/svc/default/com.ptc.core.command.common.CommandDelegate/co
m.ptc.core.command.common.bean.entity.CreatePersistentEntityCommand/n
ull/0=com.ptc.core.command.server.delegate.entity.CreatePersistentEntityCo
mmandDelegate/singleton
wt.services/svc/default/com.ptc.core.command.common.CommandDelegate/
com.ptc.core.command.common.bean.entity.CreatePersistentEntityComman
d/WCTYPE|
wt.change2.WTAnalysisActivity/0=com.ptc.windchill.enterprise.change2.ser
ver.CreateWTAnalysisActivityCommandDelegate/singleton
wt.services/svc/default/com.ptc.core.command.common.CommandDelegate/
com.ptc.core.command.common.bean.entity.CreatePersistentEntityComman
d/WCTYPE|
wt.change2.WTChangeActivity2/0=com.ptc.windchill.enterprise.change2.ser
ver.CreateWTChangeActivity2CommandDelegate/singleton
wt.services/svc/default/com.ptc.core.command.common.CommandDelegate/co
m.ptc.core.command.common.bean.entity.CreatePersistentEntityCommand/
WCTYPE|
wt.change2.WTChangeInvestigation/0=com.ptc.windchill.enterprise.change2
.server.CreateWTChangeInvestigationCommandDelegate/singleton
wt.services/svc/default/com.ptc.core.command.common.CommandDelegate/co
m.ptc.core.command.common.bean.entity.CreatePersistentEntityCommand/
WCTYPE|
wt.change2.WTChangeIssue/0=com.ptc.windchill.enterprise.change2.server.
CreateWTChangeIssueCommandDelegate/singleton
wt.services/svc/default/com.ptc.core.command.common.CommandDelegate/co
m.ptc.core.command.common.bean.entity.CreatePersistentEntityCommand/
WCTYPE|
wt.change2.WTChangeOrder2/0=com.ptc.windchill.enterprise.change2.serve
r.CreateWTChangeOrder2CommandDelegate/singleton
wt.services/svc/default/com.ptc.core.command.common.CommandDelegate/co
m.ptc.core.command.common.bean.entity.CreatePersistentEntityCommand/
WCTYPE|
wt.change2.WTChangeProposal/0=com.ptc.windchill.enterprise.change2.ser
ver.CreateWTChangeProposalCommandDelegate/singleton
wt.services/svc/default/com.ptc.core.command.common.CommandDelegate/co
m.ptc.core.command.common.bean.entity.CreatePersistentEntityCommand/
WCTYPE|
wt.change2.WTChangeRequest2/0=com.ptc.windchill.enterprise.change2.ser
ver.CreateWTChangeRequest2CommandDelegate/singleton
4-25
wt.services/svc/default/com.ptc.core.command.common.CommandDelegate/DE
FAULT/com.ptc.core.query.command.common.AbstractQueryCommand/0=
com.ptc.core.query.command.server.QueryCommandDelegate/singleton
The interesting aspect of this example are that the selector is nothing specific, in
particular not a command beans fully qualified class name, which is what the
requestor is. The reason for this is the algorithm for lookup is a hierarchical classbased search on the requestor. The selector is merely text. Thus, to map one
command delegate to many command beans the lookup must find a common
ancestor for each command bean that is to be mapped to the command delegate.
Further command delegate customization can be accomplished by overriding the
command delegates inherited implementation of the template methods
doPreprocessing() and doPostprocessing(). Overriding doPreprocessing() allows
the command delegate to pre-process the command before its actually executed.
Overriding doPostprocessing() allows the command delegate to post-process the
command after it has finished being executed. See also Chapter 4: The Command
Layer in the Windchill Application Developers Guide for more information on
pre-and-post-processing.
An example below illustrates how the MacroCommandDelegate overrides the
pre-processing of a command in order to validate the sequence of commands, and
then parse the segments tagged by BeginServerTransaction and
EndServerTransaction each into a transaction block. If the transactional tagging is
not well formed then an appropriate exception is thrown.
protected Command doPreprocessing( Command cmd )
throws CommandException {
CommandDelegateUtility.validateCommand(cmd,
MacroServerCommand.class);
super.doPreprocessing( cmd );
int macroCmdIndex = 0;
MacroServerCommand macroCmd = (MacroServerCommand)cmd;
TransactionalBlock trxBlock = new TransactionalBlock();
setTransactionalBlockList( new Vector() );
while (macroCmdIndex < macroCmd.getSequence().length) {
macroCmdIndex = parseCommandSequence( macroCmd.getSequence(),
macroCmdIndex, trxBlock );
getTransactionalBlockList().add( trxBlock );
}
return cmd;
}
private int parseCommandSequence( ServerCommand[] cmdList, int
cmdListIndex, TransactionalBlock trxBlock )
throws CommandException {
ServerCommand cmd = null;
try {
cmd = (ServerCommand)cmdList[cmdListIndex];
cmdListIndex++;
4-26
}
catch (ArrayIndexOutOfBoundsException ob) {
throw new InvalidTransactionTaggingException( ob );
}
if (cmd instanceof BeginServerTransaction) {
if (trxBlock.getCommandList() == null) {
trxBlock.setGuaranteed( true );
trxBlock.setCommandList( new Vector() );
}
cmdListIndex = parseCommandSequence( cmdList, cmdListIndex,
trxBlock );
}
else if (cmd instanceof EndServerTransaction) {
if (trxBlock.getCommandList() == null) {
throw new InvalidTransactionTaggingException();
}
else if (trxBlock.getCommandList() != null &&
trxBlock.getCommandList().size() == 0) {
throw new EmptyTransactionTaggingException();
}
else {
return cmdListIndex;
}
}
else {
if (trxBlock.getCommandList() == null) {
trxBlock.setGuaranteed( false );
trxBlock.setCommandList( new Vector() );
}
trxBlock.getCommandList().add( cmd );
if (cmdListIndex < cmdList.length) {
cmdListIndex = parseCommandSequence( cmdList, cmdListIndex,
trxBlock );
}
}
return cmdListIndex;
}
com.ptc.core.foundation.FoundationAttributeHandler.properties
com.ptc.windchill.enterprise.EnterpriseAttributeHandler.properties
The selector is derived from the attributes AttributeTypeIdentifier where only the
name of the attribute is used. The requestor is either null or the external form of
the type of object being represented by a TypeInstance (e.g., WCTYPE|
wt.part.WTPart).
4-27
Typically attribute handlers are only necessary when dealing with attributes that
are a form of reference to an associated attribute on another object, or when there
are nonexistent public accessors for the attribute. The StandardAttributeHandler
should handle all other cases. However, if special set/get processing is required
for an attribute an existing or new attribute handler could be implemented with
this special logic to handle the attribute. See also Chapter 4: The Command Layer
in the Windchill Application Developers Guide for more information on and
examples of attribute handlers.
The examples below show a one-to-one mapping of an attribute to its attribute
handler that can be found in the FoundationAttributeHandler.properties file where
the selector, requestor, priority triad are underlined:
wt.services/svc/default/com.ptc.core.command.server.delegate.io.AbstractAttrib
uteHandler/ownership.owner/null/0=com.ptc.core.foundation.ownership.serv
er.impl.OwnershipOwnerReferenceAttributeHandler/singleton
wt.services/svc/default/com.ptc.core.command.server.delegate.io.AbstractAtt
ributeHandler/format/WCTYPE|
wt.content.FormatContentHolder/0=com.ptc.core.foundation.content.server.i
mpl.DataFormatReferenceAttributeHandler/singleton
wt.services/svc/default/com.ptc.core.command.server.delegate.io.AbstractAttrib
uteHandler/format/WCTYPE|
wt.content.ContentItem/0=com.ptc.core.foundation.content.server.impl.Cont
entItemFormatAttributeHandler/singleton
The examples below show a many-to-one mapping from two attributes to the one
ViewReferenceAttributeHandler that can be found in the
FoundationAttributeHandler.properties file:
4-28
wt.services/svc/default/com.ptc.core.command.server.delegate.io.AbstractAttrib
uteHandler/view/null/0=com.ptc.core.foundation.vc.views.server.impl.View
ReferenceAttributeHandler/singleton
wt.services/svc/default/com.ptc.core.command.server.delegate.io.AbstractAttrib
uteHandler/view.displayIdentifier/null/0=com.ptc.core.foundation.vc.views.s
erver.impl.ViewReferenceAttributeHandler/singleton
5
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
5-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.
5-2
5-3
5-4
5-5
5-6
that version. The previous iterations are considered a history of work-inprogress activity (checkouts and checkins) for the object.
5-7
5-8
5-9
Document Abstractions
The wt.doc package provides a standard implementation of managed documents.
The model for these documents is shown in the following figure:
Doc Package
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
5-10
5-11
Windchill-provided document type. The "$$" prefix should not be used for
customer types.
Using the DocumentType resource bundle, it is possible to construct new types of
documents that users can pick from. This has the following impacts from an
administrative perspective:
Administrative rules do not recognize the new document types. Therefore, all
document types are the same from an administrative perspective; they receive
the same access control and indexing rules.
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.
5-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.
5-13
5-14
The WTPart also contains as aggregated properties a source and a type (as shown
in the following figure).
WTPart Properties
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.
5-15
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
WTPartUsageLink might not be the only IteratedUsageLink in a customization.
We recommend using the APIs in the following figure.
5-16
WTPartConfigSpec
5-17
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).
5-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.
5-19
The Part, PartMaster, and PartIteration classes modeled in the wt.part package
(see the following figure) are placeholders for future functionality.
Placeholders
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.
5-20
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.
Implement solution
5-21
<<Abstract>>
ChangeIssue
0..n
FormalizedBy
0..1
<<Abstract>>
ChangeRequest2
1
0..n <<Abstract>>
ChangeOrder2
Address edBy2
0..1
0.. n
<<Abstrac t>>
ChangeActivity2
IncludedIn2
ResearchedBy
0..n
<<Abstract>>
ChangeAnalysis
AcceptedStrategy
1
<<Abstract>>
ChangeInvestigation
<<Abstract>>
ChangeProposal
0..1
DetailedBy
For the Windchill out of
the box change process,
there can be only one
ChangeInvestigation per
ChangeRequest.
0..n
<<Abstract>>
AnalysisActivity
5-22
The following figure shows the relationship between the change item classes and
the change management process shown earlier.
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
5-23
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.
5-24
<<Interface>>
Changeable2
W TProductInstance2
(from part)
<<Abstract>>
RevisionCont rolled
(from enterprise)
WTPart
WTDocument
EPMDocument
(from part)
(from doc)
(from epm)
WTProduct
(from part)
Changeable Objects
5-25
Subject
Product
Product
Master
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 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.
5-26
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:
<<Abstract>>
Object ToObjectLink
(from fc)
AffectedActivityData
RelevantAnalysisData
<<Abstract>>
AnalysisActivity 0..n
<<Abstract>>
ChangeRequest2
WTProductMaster
(from part)
0.. n
0..n
0..n
0.. n
<<Interface>>
0..n Changeable2 0..n
0..n
0..n
<<Abstract>>
ChangeActivity2
0..n
ChangeRecord2
RelevantRequestData2
SubjectProduct
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.
<<Abstract>>
Object ToObjec tLink
(f ro m f c)
5-27
Interface layer
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
chapter 5, Windchill Services), 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
5-28
Change issue
The following figure shows the model for change issues:
<<Abstract>>
Managed
<<Interface>>
ChangeIssueIfc
<<Interface>>
ChangeItem
<<Interface>>
ContentHolder
(from enterprise)
<<Interface>>
ElectronicallySignable
(from electronicIdentity)
(f ro m co ntent )
<<Abstract>>
ChangeIss ue
<<Abstract>>
Identificat ionObjec t
(from fc)
WTChangeIssue
<<Int erface>>
Identified
number : String
name : String
description : String
requester : String
(from fc)
<<Interface>>
Typed
WTChangeIssue()
WTChangeIssue()
checkAttributes()
(from type)
WTChangeIs sueIdentity
number : String
name : String
WTChangeIssueIdentity()
assignToObject()
setToObject()
getIdentity()
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")
5-29
Change Request
The following figure shows the model for change requests:
<<Abstract>>
Managed
<<Interface>>
ChangeRequestIfc
<<Interface>>
ContentHolder
<<Interface>>
Identified
(from content)
<<Abstract>>
ChangeRequest2
<<Interface>>
ElectronicallySignable
(f ro m el ectroni cI den ti ty)
<<Interface>>
Typed
(from type)
(from fc)
0..1
WTChangeRequest2
<<Interface>>
ChangeItem
number : String
name : String
description : S tring
needDate : Timestamp
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
0..1
WTChangeRequest2()
WTChangeRequest2()
checkA ttributes()
0..1
<<Abstract>>
IdentificationObject
(from fc)
WTChangeRequest2Identity
number : String
name : String
WTChangeRequest2Identity()
assignToObject()
setToObject ()
getIdent it y()
5-30
Change Investigation
The following figure shows the model for change investigations:
<<Interface>>
ChangeAnalysisIfc
<<Interface>>
ChangeInvestigationIfc
<<Abstract>>
Cabinet Managed
<<Interface>>
Content Holder
(from enterprise)
(from content)
<<Interface>>
ChangeItem
<<Interface>>
ElectronicallySignable
(from electron icIdentity)
<<Abs tract>>
ChangeAnalysis
<<Abstract>>
ChangeInvestigation
<<Abstract>>
Ident ificat ionObject
(from fc)
<<Interface>>
Ident ified
(from fc)
WTChangeInvestigation
<<Interface>>
Typed
number : String
name : String
description : String
needDate : Timestamp
results : String
(from type)
WTChangeInvestigation()
WTChangeInvestigation()
checkAttributes()
WTChangeInvestigationIdentity
number : String
name : String
WTChangeInvestigationIdentity()
assignToObject()
setToObject()
getIdentity()
5-31
Change Proposal
The following figure shows the model for change proposals:
<<Interface>>
ChangeAnalysisIfc
<<Abstract>>
CabinetManaged
<<Interface>>
ContentHolder
(f rom en terprise)
(f rom c ontent)
<<Interface>>
ChangeProposalIfc
<<Abstract>>
ChangeAnalysis
<<Int erface>>
Ident ified
<<Abstract>>
ChangeProposal
(from type)
<<Interface>>
ElectronicallySignable
(f rom el ectroni cI denti ty)
<<Abstract>>
IdentificationObject
(from fc)
(from fc)
<<Interface>>
Ty ped
<<Interface>>
ChangeItem
WTChangeProposal
number : String
name : String
description : String
WTChangeProposal()
WTChangeProposal()
checkAttributes()
WTChangeProposalIdentity
number : String
name : String
WTChangeProposalIdentity()
assignToObject ()
setToObject()
getIdentity()
5-32
Analysis Activity
The following figure shows the model for analysis activities:
<<Interface>>
AnalysisActivityIfc
<<Abstract>>
CabinetManaged
<<Interface>>
ContentHolder
(from enterprise)
(from content)
<<Interface>>
Identified
<<Abstract>>
Analys isA ct ivit y
(f rom f c)
<<Interface>>
ChangeItem
<<Interface>>
Elect ronically Signable
(f ro m el ectroni cI dent ity )
<<Abstract>>
IdentificationObject
(f rom f c)
WTAnalysisActivity
<<Interface>>
Typed
(f rom t ype)
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()
5-33
Change Order
The following figure shows the model for change orders:
<<Abstract>>
Managed
<<Interface>>
ChangeOrderIfc
<<Int erface>>
Identified
(from type)
(from fc)
<<Interface>>
ChangeIt em
(from content)
(f rom enterprise)
<<Int erface>>
Typed
<<Interface>>
ContentHolder
<<Abstract>>
ChangeOrder2
WTChangeOrder2
number : String
name : String
description : String
needDate : Timestamp
WTChangeOrder2()
WTChangeOrder2()
checkAttributes()
<<Interface>>
ElectronicallySignable
(from electronicIdentity)
<<Abstract>>
IdentificationObjec t
(f ro m f c)
WTChangeOrder2Identity
number : String
name : String
getIdentity()
WTChangeOrder2Identity()
setToObject()
assignToObject()
5-34
Change Activity
The following figure shows the model for change activities:
<<Abstract>>
CabinetManaged
<<Interface>>
ChangeActivityIfc
(f ro m e nterp ri se )
<<Interface>>
Identified
<<Interface>>
ContentHolder
<<Interface>>
ChangeItem
(from electronicIdentity)
<<Abstrac t>>
ChangeActivity2
(from fc)
<<Interfac e>>
Typed
(from type)
W TChangeAct ivity2
number : String
name : String
description : String
needDate : Timestamp
WTChangeActivity2()
checkAttributes()
WTChangeActivity2()
<<Interface>>
ElectronicallySignable
<<Abstract>>
Ident ificationObject
(f rom f c)
WTChangeActivity2Identity
number : St ring
name : String
W TChangeAct ivity2Ident it y()
ass ignToObject()
setToObject()
getIdentit y()
5-35
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
5-36
6
Windchill Services
Topic
Page
6-1
6-2
Windchill Packages
Windchills functionality that is, its services and utilities is generally
separated into packages. These packages are available in the wt directory within
the Windchill source directory, src. You can use these packages as you build new
applications and customize existing applications. Model files are provided so you
can modify the models and then generate code from them.
This section lists a subset of the packages available and gives an overview of their
functionality. The remainder of this chapter then describes the services provided
by these packages in more detail. If not described in this chapter, the following list
refers to the chapters where they are described.
access
Functionality for access control; used to define access policies (that is, define
rules for what principals have access to what information).
admin
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.
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
Administrators Guide.
effectivity
Functionality to define and execute the vaulting algorithm for content items.
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).
Windchill Services
6-3
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.
index
Functionality to define rules and create subscriptions such that when certain
events occur to certain objects, E-mail notification is sent.
org
vc
6-4
workflow
Design Overview
An object is subject to access control if its type implements the AccessControlled
interface and implements either the DomainAdministered or the
AdHocControlled interface. The AccessControlled interface is simply a marker
interface, without any methods. Access control is enforced by access control lists
(ACLs), which associate principals to positive or negative sets of access
permissions. Permissions are defined by the AccessPermission class. When a user
attempts to perform an operation on an object, the ACLs are evaluated according
to the model set forth by the java.security.acl.Acl interface, and the access is
granted or denied.
Two types of ACLs can be associated to an object: a policy ACL, generated from
access control policy rules, and an ad hoc ACL, generated from ad hoc access
control rules. A single policy ACL applies to all objects of a specific type while
the ad hoc ACL is specific to a single object. The AccessPolicyRule class defines
policy rules and the AdHocControlled interface defines ad hoc rules. Both the
AccessPolicyRule class and the AdHocControlled interface implement the
AccessControlList interface, which associates a set of entries to a rule, and both
contain an entry set attribute (defined by the AclEntrySet class), which is a cache
of the entries. An access control rule entry is defined by the WTAclEntry class.
Windchill Services
6-5
6-6
Ad Hoc ACLs
If an object is both DomainAdministered and AdHocControlled, then both the
policy and the ad hoc ACLs determine its access, in an additive manner. In the
same way as the policy ACL, the ad hoc ACL also contains a cached set of entries.
Although ACLs can map only principals to permissions, an ad hoc ACL
specification (represented by the AdHocAclSpec class) may also map roles to
permissions. Ad hoc access control rules can be generated from the ad hoc
specification by resolving the roles into principals. Depending on the role to
principal mapping used to resolve the roles, the same specification may generate
many different ad hoc ACLs.
Windchill Services
6-7
External Interface
The functionality of this service is represented by the AccessControlManager
(accessible through the AccessControlHelper), and the AccessControlManagerSvr
(accessible through the AccessControlServerHelper).
StandardAccessControlManager defines the access control enforcement, access
control policy, and ad hoc access functionality. For enforcement, the most
important method is checkAccess, which takes a permission and either an object
or a domain and an object type as parameters and throws a
NotAuthorizedException if access is not granted to the current principal.
Business Rules
The rule for access control enforcement returns true (permission granted) if the
object is not access controlled, or if it is not ad hoc controlled and doesn't belong
to a domain. If the object belongs to a domain, the policy ACL is generated (or
retrieved if it already exists) and the ACL is evaluated. In case the object does not
belong to a domain or access is not granted by the ACL, the object is checked to
see if it is ad hoc controlled and has an ad hoc ACL. If it does, the ACL is
evaluated and access is granted accordingly. Otherwise, access is denied.
When applying access control enforcement to a DomainAdministered object, the
policy ACLs used are those associated with the domain to which the object
belongs and those associated with all ancestor domains. This allows objects to
have very different access control behavior even if they are of the same type.
6-8
Event Processing
No event is generated. The access control manager listens to domain change
events and reevaluates policy ACLs affected by any changes to the domain
hierarchy. Control is passed to the manager through explicit method calls.
The access control service now listens for the following events:
AdministrativeDomainManagerEvent.POST_CHANGE_DOMAIN
OrganizationServicesEvent.POST_DISABLE
PersistenceManagerEvent.CLEANUP_LINK
PersistenceManagerEvent.INSERT
PersistenceManagerEvent.REMOVE
Windchill Services
6-9
Design Overview
An administrative domain can be regarded as the set of all objects that have the
same administrative behavior. Administrative policies are defined for objects that
belong to a domain. For an object to belong to a domain, its class must implement
the DomainAdministered interface. A DomainAdministered object contains a
reference to the domain to which it belongs.
External Interface
Access and manipulation of the domain of an object is accomplished by the
DomainAdministeredHelper, which both defines and implements the API. The
methods in this class are static. The methods for setting domains can be used only
with objects that have not yet been stored in the database (persisted). The
functionality defined in the AdministrativeDomainManager and
AdministrativeDomainManagerSvr can be accessed through the helper classes
AdministrativeDomainHelper and AdministrativeDomainServerHelper,
respectively. Changing the domain of a persistent object causes the posting of
PRE and POST events (see Event processing later in this section).
Business Rules
Four special domains are defined in the Site container during the installation
process: the Root, the System, the Default and the User domains. These
6-10
Event Processing
This service posts two events in case a change of domain is performed on a
domain administered object that is persistent. These events are:
PRE_CHANGE_DOMAIN and POST_CHANGE_DOMAIN. The administration
service listens for the following events:
PersistenceManagerEvent.PRE_DELETE - Listen to attempts to delete
AdministrativeDomain objects, to veto deleting the pre-defined and referenced
ones.
PersistenceManagerEvent.PRE_MODIFY - Listen to attempts to modify
AdministrativeDomain objects, to veto renaming the pre-defined ones.
PersistenceManagerEvent.INSERT - Listen to attempts to create
AdministrativeDomain objects, to veto attempts to create domains in the
Windchill PDM container with the same name and parent as one of the four predefined domains in the Site container.
Windchill Services
6-11
Design Overview
The figure below is a conceptual representation of ContentHolders and how they
are represented to client developers.
ContentHolders
6-12
Windchill Services
6-13
DataFormat Class
6-14
Content Services
Windchill Services
6-15
ContentHolder holder;
holder = ContentHelper.service.getContents( holder );
Vector contents = ContentHelper.getContentList( holder );
This vector contains all the secondary ContentItems associated with the passed
ContentHolder.
The method call to get the primary content associated with a
FormatContentHolder is as follows:
ContentHolder holder;
holder = ContentHelper.service.getContents( holder );
ContentItem item = ContentHelper.getPrimary( holder );
6-16
ApplicationData applicationDataObj = . . .
String oidstr = PersistenceHelper.getObjectIdentifier(
applicationDataObj ).getStringValue( );
The content_description line should appear as follows for a new URL:
newURLLink
http://xxx.yyy.zzz
http://xxx.yyy.zzz
Business Rules
The read and modification of content is based on the access rules of the
ContentHolder.
Event Processing
At this time, the ContentService does not broadcast any events.
External Interface
The Master service has no API for developers to use.
Event processing
At this time, the Master service does not emit any events for developers to use.
Windchill Services
6-17
External Interface
The Replica service has no API for developers to use.
Event processing
At this time, the Replica service does not emit any events for developers to use.
External Interface
The InterSvrCom service has no API for developers to use.
Event processing
The InterSvrCom service does not emit any events for developers to use.
External Interface
The Shipping service has no API for developers to use.
Event processing
The Shipping service does not emit any events for developers to use.
External Interface
The Receiver service has no API for developers to use.
6-18
Event processing
The Receiver service does not emit any events for developers to use.
External Interface
The Generic Transport service has no API for developers to use.
Event processing
The Generic Transport service does not emit any events for developers to use
If the page requires user input, for example, it will have an HTML form in it,
use the TemplateProcessor subclass
wt.templateutil.processor.GenerateFormProcessor.
For detailed information about developing HTML clients, see the chapter on
customizing the HTML client in the Windchill Customizers Guide.
Design Overview
This section describes the effectivity interface, effectivity types, and configuration
item.
Windchill Services
6-19
Interface
The following figure illustrates the effectivity interface.
Effectivity Interface
6-20
Effectivity Types
The following figure illustrates effectivity types.
Effectivity Types
Effectivity is an abstract class that supports the concept that a PDM object is
effective under certain conditions. Abstract subclasses of Effectivity include
DatedEffectivity and UnitEffectivity. Effectivity contains a reference to a
ConfigurationItem (configItemRef). This ConfigurationItem reference is
necessary for UnitEffectivity subclasses, and is optional for DatedEffectivity
subclasses.
Effectivity has two mechanisms for referencing its associated
EffectivityManageable object.
Windchill Services
6-21
ConfigurationItem
The following figure illustrates the ConfigurationItem.
ConfigurationItem
6-22
External Interface
The EffectivityHelper class provides methods for setting the configuration item
and target Effectivity Manageable object (WTPart) for an Effectivity object.
When creating WTLotEffectivity and WTSerialNumbered objects, both of these
methods should be called. When creating WTDatedEffectivity objects, setting a
Configuration Item is optional.
The EffectivityManager provides methods for retrieving Effectivity objects from
the database, for retrieving configuration item objects from the database, and for
storing, modifying, or deleting Effectivity objects. These methods are accessed
through EffectivityHelper.service.
Business Rules
The following business rules apply to effectivity:
Any user who has access to modify a change order or change activity also has
permission to change the effectivity for all parts that are referenced by the
change order or change activity.
Effectivity objects are never shared. Each part has unique effectivity
information.
If the user deletes a part with effectivity, its effectivity information will be
deleted automatically from the database.
Event Processing
No events are posted by this service. This service listens for and acts upon the
following two standard Windchill events:
Windchill Services
6-23
Design Overview
The federation service is designed to be a plug and play component in the
Windchill system. The federation service is intended to be used for both client and
server development. Business objects, asserted as being federated in the object
model, are assigned a remote system information (serviceID) at creation and can
be promoted throughout the defined phases of an associated federation. The proxy
source information is held in the serviceID cookie, but instead operate on it
through the federation services external interface.
6-24
The following figure contains a representation of the object model for federation
service.
External Interface
The Federated interface provides an abstraction of a plug-and-play component.
The intent is that, in an object model, a business object would assert that is
Federated by implementing the Federated interface. With this assertion, the
business object can then be created as a proxy of remote object.
The FederationHelper provides an abstraction as the API to the
FederationService. The APIs method can be categorized as either local or remote
invocations. The local methods are getters of information, typically from cookies
that are held in the business object. The remote methods serve as wrappers to a
service that promotes server-side functionality.
Windchill Services
6-25
The FederationService provides an abstraction that specifies and promotes serverside functionality as a service that is remotely available for use by a client. The
intent is that this interface defines all the necessary server-side functionality for
federation.
The FederationServerHelper provides an abstraction of server-side API to the
federation services. These methods can be invoked only from server-side
processing.
The FederationServicesException provides an abstraction of an abnormal
occurrence or error in usage or processing of the federation service. This
exception can be localized through a given resource bundle, and other exception
can be nested with in it.
Business Rules
As defined by the standard federation service access control rules, no constraints
are placed on the access of proxy objects.
Event Processing
The federation service is an event listener. The service listener listens for and acts
upon the following standard Windchill events.
When a PRE_STORE or a PRE_MODIFY event is emitted for a proxy object,
the federation service provides the opportunity to store or update associated
objects prior to storing or updating the proxy object itself by doing:
if ( obj instanceof Federated )
((Federated)obj).prepareForStore ();
Revising a proxy object is not allowed. Proxy objects are created against
source objects from remote system. The revision is prevented to ensure that
the proxy objects are consistent with the source objects.
When a POST_STORE or a POST_MODIFY event is emitted for a proxy
object, the federation service provides the opportunity to store or update
associated objects after storing or updating the proxy object itself by doing:
if ( obj instanceof Federated )
((Federated)obj).postStore ();
6-26
Windchill Services
6-27
Design Overview
The following figure shows the essential associations and interfaces involved with
managing folder organized information.
6-28
The following figure contains a representation of the object model for foldered
information.
Folder Model
Typically, new objects that are to be foldered should extend the interfaces
provided in the wt.enterprise package. For simple foldered objects, use the
FolderResident class shown above. If additional characteristics (such as life cycle
management or versioning) are required, use the Managed or RevisionControlled
classes.
External Interface
The CabinetBased interface defines characteristics of information organized by
the foldering service. It has a name and a location that indicates the path to the
object in the cabinet and folder hierarchy.
The Foldered interface is asserted by objects that are to be organized into a folder.
An object can reside in (that is, be a member of) one and only one Folder.
The Folder interface is asserted for an object that organizes information. Both a
Cabinet and a SubFolder perform this organizing mechanism. There are two types
Windchill Services
6-29
Business Rules
The business rules for foldering are based on the access control that it enforces.
The most basic rule is that to put an object into a folder, or remove it from the
folder, you must have modify permission on that folder. This is in addition to
whatever permission you must directly have to create or delete the object. To
move an object from one folder to another, you must have modify permission on
the source and destination folders, as well as permission to delete the object from
its source folder and to create it in its destination folder. An additional rule is that
you can not move an object from a shared cabinet to a personal cabinet.
6-30
Design Overview
The file folder is the equivalent of a directory on the disk drive. Folders are
logically grouped to form vaults. Each folder has a sequence number that defines
the order in which the folders within the vault will be used for storing content
items. When a folder overflows, the vault manager makes it read-only and begins
using the next available folder in the sequence. All the folders must be mounted to
all the method server hosts in order to provide access to content items stored in
them. Depending on the domain a content holder belongs to, a class and life cycle
state content item is stored in one of the vaults or in the ORACLE BLOB.
Windchill Services
6-31
External Interface
There is no external API for customer use.
Event Processing
The service emits OVERFLOW events with the FvFolder object as a target on
folder overflow and the FvVault object as a target on vault overflow. An event is
emitted from within a transaction. Vetoing an event or throwing an exception has
no effect on the operation that caused the event to be emitted.
6-32
Object Model
The following figure shows the basic model to provide display identification
information about business objects. The following figure illustrates the basic
specification of identifiability and the identity factory mechanism.
Windchill Services
6-33
6-34
Windchill Services
6-35
Implementation
When implementing a delegate, the delegate must be a subclass of either the
DisplayIdentificationStandardDelegate or the
DisplayIdentificationVersionDelegate. The implementer must implement the
appropriate initialize methods as determined by the parent class. Typically, the
initialize() method itself is not overridden, but rather the initializeXXXX()
methods for the specific attributes of the identification object. Note that the
delegate objects should be written to be almost foolproof; that is, so that they can
always produce a DisplayIdentification object without throwing an exception.
From release 6.0, another option for subclassing delegates is the
DisplayIdentificationPersistableDeleagate. The initializeType() method in the
existing DisplayIdentificationPersistableDelegate has changed from initializing
the object using the introspection information, to dispatching the initialization
functionality to either "NonTypedDelegate" or "TypedDelegate" based on if the
object is "Typed" and let the proper delegate calculate the proper
"LocalizableMessage" for the object and set the objects type to its correspondent
"LocalizableMessage". The subclass delegate should then implement the
initializeType() method by just calling its supers initializeType() method to let
the DisplayIdentificationPersistableDelegate handle the work.
6-36
to people who wish to publish from Windchill into a different XML format.
Modifying the DTD could allow that operation.
A commented DTD for core Windchill objects is in the following location:
Windchill\codebase\registry\ixb\dtds\standard\coreobjects.dtd
Design Overview
The design of the index policy manager follows the same pattern as the other
administrative policies (see Access control and Notification service, also in this
chapter). The Indexable interface marks those classes whose objects may be
indexed in external collections. Every Indexable object holds a list of the
collections (IndexerSet) in which it is currently indexed. Access to this list is
possible through the static methods of the IndexerHelper class.
Indexing Model
For each type and state, it is possible to define the collections the object should be
in. This definition is called an index policy rule and is represented by the
IndexPolicyRule class. Indexing policy rules are enforced by indexing policy lists
(IndexPolicyLists class). The lists are derived from all of the rules that apply to a
Windchill Services
6-37
domain, type and state. The rules and lists contain a Selector object
(domain/type/state) and a set of indexers. When an event occurs to an Indexable
object, the indexer set in the policy list is the union of the collections for all the
applicable rules. Index policy lists are created on demand and for performance
reasons, stored persistently in the database and in a server cache. The set of
indexers in the policy list is used to update the objects indexer set.
Besides providing methods for managing policies, the IndexPolicyManager also
listens to events and triggers collection updates. These are not performed
immediately but queued for asynchronous execution.
The following figure shows the classes that map the attributes of Windchill
business objects to the Verity collection.
Collection Attributes
6-38
Note: Versions of Windchill prior to 5.0 used only the IndexDelegate and classes
inheriting from IndexDelegate for indexing objects. At release 5.0 the search
engine that is distributed with Windchill changed from Verity Information Server
to Excalibur RetrievalWare and there was a need to introduce the
RwareIndexDelegate class. This is so that objects can continue to be indexed to
Verity using the IndexDelegate while RetrievalWare indices are being created
using the RwareIndexDelegate class.
External Interface
The Index Policy Manager methods can be accessed through the
IndexPolicyHelper class.
Business Rules
Although the indexing mechanism can use any event posted by any service, the
implementation provided listens only to events that may cause the objects index
entry to become out of sync with the object. This list of events ensures maximum
efficiency and ensures that index entries always remain up to date.
There is no need to create a rule that removes the object from the collections in the
event that the object is deleted. The Index Policy Manager creates an implicit rule
that does that.
Event Processing
/wt.admin.AdministrativeDomainManagerEvent/POST_CHANGE_DOMAI
N
/wt.vc.wip.WorkInProgressServiceEvent/POST_CHECKIN
/wt.fc.IdentityServiceEvent/POST_CHANGE_IDENTITY
/wt.fc.PersistenceManagerEvent/POST_DELETE
/wt.fc.PersistenceManagerEvent.POST_STORE
/wt.fc.PersistenceManagerEvent/POST_MODIFY
/wt.folder.FolderServiceEvent/POST_CHANGE_FOLDER
/wt.content.ContentServiceEvent.POST_UPLOAD
/wt.lifecycle.LifeCycleServiceEvent/STATE_CHANGE
/wt.vc.sessioniteration
.SessionIterationEvent/POST_COMMIT_SESSION_ITERATION
/wt.vc.VersionControlServiceEvent/NEW_ITERATION
/wt.vc.VersionControlServiceEvent/PRE_SUPERSEDE
Windchill Services
6-39
6-40
Design Overview
Windchill Services
6-41
External Interface
The LifeCycleManaged interface provides an abstraction of a plug-and-play
component. The intent is that, in an object model, a business object would assert
that it is LifeCycleManaged by inheriting (that is, it implements) the
LifeCycleManaged interface. With this assertion, the business object can be
transitioned to successive states as defined by a life cycle definition.
The LifeCycleHelper provides an abstraction as the API to the life cycle service.
The APIs methods can be categorized as either local or remote invocations. The
local methods are getters of information, typically from cookies that are held in
the business object. The remote methods serve as wrappers to a service that
promotes server-side functionality.
The LifeCycleServerHelper provides an abstraction of the server-side API to the
life cycle services. These methods can be invoked only from server-side
processing.
The LifeCycleService provides an abstraction that specifies and promotes serverside functionality as a service that is remotely available for use by a client. This
interface is intended to define all the necessary server-side functionality for life
cycle management.
The LifeCycleServiceEvent provides an abstraction of a specialized keyed event
used by the life cycle service to signal other services that something has occurred.
This gives other services in a plug-and-play architecture the opportunity to act
accordingly upon these events. Validation, vetoing, and post-processing are
typical reactions to events.
The life cycle service emits the following events:
STATE_CHANGE
Emitted when the role participants of a role are modified. This occurs when
the object is dropped or reassigned to a different life cycle.
ENABLE_LIFECYCLE
6-42
SUBMIT
Emitted when a life cycle managed object is promoted to the next phase.
VOTE
Emitted when the life cycle managed object is demoted to the previous phase.
DENY
Emitted when a life cycle managed object is denied (that is, it is moved from
the gate back to the current phase).
DROP
Emitted when a life cycle managed object is dropped (that is, it is no longer
associated with a life cycle).
REASSIGN
Business Rules
Life cycle actions on life cycle managed objects are authorized by role
assignments. Roles are associated to principals in the definition of a life cycle
phase and a project, and are specific to a life cycle phase. Resolvable roles and
default assignments are identified in the definition of a life cycle phase. At
runtime, these roles are resolved to principals from a project specification, if the
corresponding roles are designated in the project.
There are four standard roles. The Submitter role players have authority to submit
the object for review. The Reviewer role players have authority to enter comments
and a signature designating approve or reject. The Promoter role players have
authority to promote, demote, deny, or drop the object. The Observer role players
have the right to view the object and view reviewer comments and signatures.
Additional roles can be added by updating the role resource bundle.
Windchill Services
6-43
Event Processing
The life cycle service is an event listener. The service listens for and acts upon the
following standard Windchill events:
When a PRE_STORE event is emitted for a life cycle managed object, the life
cycle service initializes the state cookie by assigning an initial state to the
object. The save of a life cycle is vetoed if the folder location is not a personal
cabinet or the System cabinet.
When a POST_STORE event is emitted for a life cycle managed object, the
life cycle service associates phase information, such as role players and access
rights, to the object.
When a PRE_DELETE event is emitted for a life cycle, and the template is in
use by a life cycle managed object, the delete is prohibited. When the object
being deleted is a WfProcessTemplate or a WfProcessTemplateMaster, and
that WfTemplate is referenced by a phase or gate of the life cycle, the delete is
prohibited.
6-44
Life cycle managed objects are project managed objects. When the
REPROJECT event is emitted for a life cycle managed object (that is, the
object is reassigned to a new project), the life cycle service updates the data
associated with this change.
service backs up the state of the object to match this old iteration. Also, the
history associated with these now obsolete iterations is also removed.
Design Overview
Windchill Services
6-45
The locking service is designed to be a plug and play component in the Windchill
system, which is by default enabled to execute.
The locking service is intended to be used for both client and server development.
Business objects, asserted as being lockable in the object model, can be locked
and unlocked through the locking services external interface. Once a business
object is lockable, its lock can be seized to prevent concurrent access. Once the
lock has been released, the business object is available to be locked again. A
lockable object is not required to be locked prior to modification but, if it is
locked, the lock is honored. The lock itself is a cookie that a lockable business
object aggregates. The business object should not interact directly with the lock
cookie, but instead operate on it through the locking services external interface.
External Interface
The Lockable interface provides an abstraction of a plug and play component. The
intent is that, in an object model, a business object would assert that it is Lockable
by inheriting (that is, it implements) the Lockable interface. With this assertion,
the business object can then be locked and unlocked.
The LockHelper provides an abstraction as the API to the locking service. The
APIs methods can be categorized as either local or remote invocations. The local
methods are getters of information, typically from cookies that are held in the
business object. The remote methods serve as wrappers to a service that promotes
server-side functionality.
The LockService provides an abstraction that specifies and promotes server-side
functionality as a service that is available remotely for use by a client. The intent
is that this interface defines all the necessary server-side functionality for locking.
The LockServiceEvent provides an abstraction of a specialized keyed event used
by the locking service to signal other services that a locking activity is about to
begin or has occurred. This gives other services the opportunity in a plug and play
architecture to act accordingly on these events. Validation, vetoing, and postprocessing are typical reactions to events.
The LockException provides an abstraction of an abnormal occurrence or error in
the usage or processing of the locking service. This exception can be localized
through a given resource bundle, and other exceptions can be nested within it. The
most common occurrence of this exception is an attempt to lock or unlock a
business object that is already locked or unlocked.
Business Rules
As specified by the locking services standard access control rules, when an
attempt is made to lock an object, if it is not already locked and the given principal
has modify access to the object, then it is locked. If an attempt is made to unlock
an object that is already locked and the given principal has administrative access,
or the given principal is the one who originally placed the lock and has modify
access to the object, then it is unlocked. Otherwise, an exception is thrown
6-46
Event Processing
Event-based processing is performed on business objects asserted as being
lockable during [preparation for] database modifications and full restorations.
When a business object is [prepared for] being modified in the database, the
locking service listens to a dispatched event indicating that the modify is about to
begin and vetoes it if the business object is locked and the current sessions
principal is not the one who originally placed the lock. Otherwise, the
modification is allowed to take place. Therefore, it is valid to modify a business
object that is lockable if it is not locked. When a business object is being fully
restored from the database, the locking service listens to a dispatched event
indicating that the full restoration is beginning and restores the principal who
holds the lock in the business objects lock cookie.
Windchill Services
6-47
Design Overview
The Notification policy design follows the pattern for the administrative policy.
The Notifiable interface is created so that it can be implemented by the classes for
which notification should be sent. This interface contains no method. A notifiable
object may hold an event set that is specific to the object.
NotificationPolicy
6-48
Ad Hoc Notification
External Interface
The Notification Manager methods can be accessed through the
NotificationHelper class.
Business Rules
The users that are the final recipients of the messages must have an e-mail
attribute defined. Additionally, for messages generated by notification policies,
the user must have read access over the object to which the event occurred.
Although the notification policy mechanism can use any event posted by any
service, in practice the notification is limited to the events listed in the
wt.admin.adminEventResource class because these are used by the administrator
Windchill Services
6-49
client to construct rules. The events must also be listed in the notify.properties
file.
Event Processing
No event is generated. However, this service listens to the events specified in the
notification policy rules.
The list of events for the notification service includes the following in addition to
events defined in notify.properties:
/wt.admin.AdministrativeDomainManagerEvent/POST_CHANGE_DOMAIN
/wt.fc.PersistenceManagerEvent/POST_DELETE
/wt.fc.PersistenceManagerEvent/PRE_DELETE
/wt.vc.VersionControlServiceEvent/NEW_ITERATION
/wt.vc.sessioniteration.SessionIterationEvent/POST_COMMIT_SESSION_ITER
ATION
/wt.vc.wip.WorkInProgressServiceEvent/POST_CHECKIN
6-50
Org Package
The three main classes that compose this model are the WTPrincipal, and its
derived classes, WTGroup, and WTUser. WTPrincipal objects contain a name
which must be unique among users, groups, and administrative domains.
WTGroup can contain zero or more users. Also, a user can be in no group or in
many.
The WTUser class has fixed and queryable attributes, and name-value pair
attributes. Fixed attributes are the name (inherited from WTPrincipal),
authenticationName, and fullName. Besides these attributes, each WTUser has a
structured attribute holder for name-value pairs: the AttributeHolder (not shown
Windchill Services
6-51
in the figure). This class is modeled after JNDIs AttributeSet and multiple values
can be associated with a given name. An attribute holder is implemented as one of
two derived classes. If the user definition comes from an LDAP server, the
LDAPAttributeHolder class is used; otherwise, the user definition is local to the
Windchill system and the StandardAttributeHolder is used.
Finally, this package hosts the WTPrincipalReference class and manages a
principal cache (not shown in the figure) through its manager (also not shown in
the figure).
Design Overview
Ownership Model
6-52
External Interface
The Ownable interface provides an abstraction of the ownership capability. The
intent is that in an object model, an object will assert that it implements the
Ownable interface, therefore allowing it to be owned.
The OwnershipHelper provides access to the API for operation on Ownable
objects. The Ownable interface can be extended to create your own business
object classes, but the Ownership package does not provide any supported API's
to directly manage those objects.
The OwnershipService defines the server-side functionality available to Ownable
objects. These operations offer complete transactions that implement the business
rules for Ownable objects.
The OwnershipServiceEvent provides the mechanism to inform other plug and
play components of the system of operations that impact Ownable objects. This
allows other services or managers to perform validation, vetoing, or other pre/post
processing related to ownership activities.
Business Rules
Ownership is typically asserted on a business object prior to being stored in the
database. For example, in the Windchill implementation, this is done for foldered
objects as part of putting the objects into folders; the owner for the folder becomes
the owner for the object. Ownership may change as an object moves from one
folder to another.ge as an object moves from one folder to another.
Event Processing
Event-based processing is performed on Ownable objects as ownership changes
take place. An event is emitted just before the ownership change takes place,
inside the transaction that makes the change, and another event is emitted just
after the change has been made to the database. These events are
PRE_CHANGEOWNER and POST_CHANGEOWNER.
Windchill Services
6-53
Design Overview
Project Model
6-54
External Interface
The ProjectManaged interface provides an abstraction of a plug-and-play
component. The intent is that, in an object model, a business object would assert
that it is ProjectManaged by inheriting (that is, it implements) the ProjectManaged
interface.
The ProjectHelper provides an abstraction as the API to the project service. The
APIs methods can be categorized as either local or remote invocations. The local
methods are getters of information, typically from cookies that are held in the
business object. The remote methods serve as wrappers to a service that promotes
server-side functionality.
The ProjectServerHelper provides an abstraction of the server-side API to the
project services. These methods can be invoked only from server-side processing.
The ProjectService provides an abstraction that specifies and promotes server-side
functionality as a service that is remotely available for use by a client. The intent
is that this interface defines all the necessary server-side functionality for project
management.
The ProjectException provides an abstraction of an abnormal occurrence or error
in the usage or processing of the life cycle service. This exception can be localized
through a given resource bundle, and other exceptions can be nested within it.
Event Processing
The LifeCycleService is an event listener. The service listens for and acts on four
standard Windchill events.
The project service emits a REPROJECT event when the project specified in a
ProjectManaged object is changed.
Windchill Services
6-55
The queues created in this service store processing requests in the form of Java
method calls. The requests are stored as queue entries and are executed following
a first-in first-out (FIFO) schedule.
Queues are named and may contain many entries. Each entry may be in one of the
following states:
READY
Executing.
COMPLETED
Executed successfully.
FAILED
Operator suspended.
The main classes in this service and their relationships are shown in the figure
above. The ProcessingQueue class represents named queues created by the
applications or other services. Processing queues can be in one of two states:
active, in which requests are executed, and inactive, in which requests arent
executed (but new entries can be added). It supports methods to add and execute
6-56
entries. The QueueEntry class holds specific information about the processing
request and its execution.
External Interface
The external interface of the QueueService can be accessed through the
QueueHelper.manager object. It provides methods to retrieve queues and
associated information, set polling intervals, change queues from active to
inactive (start/stop), create and delete queues and entries, and even execute
specific queue entries.
Business Rules
The only two requirements for an arbitrary Java method to be able to be queued
are that it be public and static. Additionally, the programmer must provide a
principal (user or group) on behalf of whom the request will be executed. If the
method returns a value, the value is lost. Finally, the methods should preferably
not require operator intervention and certainly should not depend on end user
interaction.
Event Processing
No events are posted by this service.
Windchill Services
6-57
Design Overview
Router Model
The routing service is a keyed event listener which listens for RoutingEvent
objects. The association between a routerEvent and the corresponding router
object determines how the event is handled. These elements are registered in the
wt.properties file.
A router object can operate in two modes: immediate and scheduled. Immediate
mode router objects, upon catching an event they are registered to handle,
immediately create and send an execution item to the queue. Scheduled mode
router objects, upon catching an event they are registered to handle, store the data
in a to-do list. The StandardSchedulingService invokes the static method
processToDoList defined in the scheduled mode router object. This method scans
the to-do list, creates execution items, and sends them to queues.
6-58
Windchill Services
Property Name
Description
ROUTER_NAME.immediate = false
ROUTER_NAME.NumOfQueues = 1
ROUTER_NAME.method
ROUTER_NAME.event.Y, where Y =
1,***
ROUTER_NAME.event.Y.method,
where Y = 1.*
ROUTER_NAME>event.Y.class.Z,
where Y and Z are 1*
ROUTER_NAME.event.Y.class.Z.
method
6-59
The names of all the queues started by the persistent router service are defined as
follows:
wt.router.X.Y:
wt.router.X
Example
This example shows how you can use this service by following these four steps:
1. Define an event:
Class SampleEvent extends wt.router.RoutingEvent
{
public SampleEvent(String evtType, Serializable eventTarget)
{
super(evtType, eventTarget);
}
}
4. Configure the router by placing the following five lines in the wt.properties
file:
Wt.router.1 = myRouter
myrouter.immediate=false
myRouter.NumberOfQueues=1
myRouter.method=SampleClass.aSampleMethod
myRouter.event.1=SampleEvent
6-60
Scheduler Model
The scheduling service manages the schedule items in the system. Schedule items
can be scheduled to run once or periodically, and can start immediately or be
deferred to start at a later time. Schedule items maintain a collection of their
histories and their method arguments. Method arguments can be any object. The
scheduler provides a higher-level interface to the wt.queue package. Schedule
items are executed with the same privileges as the user who created them.
The ScheduleHistory class provides the history of the execution instances. A
default CountedHistory object is supplied for use by agents that perform a number
of internal operations. The execScheduled method is provided so that when the
Windchill Services
6-61
execution fires off an autonomous agent, the agent can record its results to the
schedule history.
A running instance can be in the following states:
READY
An error has occurred in the agent session, but the agent has decided to
continue.
ERROR_COMPLETED
An error has occurred in the agent session, but the agent process continued to
completion.
ERROR_STOPPED
An error has occurred in the agent session and the agent has stopped
processing.
External Interface
There is no external API for customer use.
Event Processing
This service does not emit any events.
6-62
The classes shown below are responsible for managing the session user
(SessionManager) and setting access control ON or OFF (SessionServerHelper).
The first is a remote interface and therefore accessible from the client, while the
second is a simple interface and can only be accessed in the server.
External Interface
The SessionManager contains methods for setting and getting the current
principal. The SessionManagerSvr contains methods for setting/resetting.
Business Rules
Although it is possible to retrieve the current principal from the client, the same
cannot be said about setting the current principal. This is only possible if the
current principal is itself a member of the Administrators group. Another way is to
set the wt.clientAuthenticatedLogin property (in the wt.properties file) to false.
This, however, should be done only for development, as it can be a serious
security breach.
Event Processing
No events are posted or listened to by this service.
Windchill Services
6-63
Design Overview
The Federation Send Feedback mechanism uses the Info*Engine Web Event
Service (WES) to enable the sending of Feedback objects to clients. The
Info*Engine WES requires a Message Oriented Middleware (MOM) product to
be installed, configured and started. More information about MOM can be found
in the Info*Engine Installation and Configuration Guide.
The MOM has to be configured to recognize the "CommandDelegateFeedback"
Event. Actually the Event name only has to be the same as the EVENT parameter
value for the "Subscribe-Event" webject in the
wt/federation/StandardFederationServicesStartup Info*Engine task and the
"Emit-Event" webject in the wt/federation/CmdDelegateFeedbackEmit
Info*Engine task. These tasks are shipped with EVENT set to
"CommandDelegateFeedback". Its possible to change the value in these tasks to
something other than "CommandDelegateFeedback" although I dont know that it
is necessary to advertise this.
For sendFeedback() to work, Federation has to subscribe to receive Info*Engine
WES Events, specifically the "CommandDelegateFeedback" Event. This is done
via the wt/federation/StandardFederationServicesStartup task, which can be
executed at Federation Service startup time. For this task to execute during
Federation Service startup, the following line must be added to wt.properties:
wt.federation.task.startup=wt/federation/StandardFederationServicesStartup.xml
6-64
External Interface
This is a supported API. The corresponding UI in Windchill is the Delegate
Administrator.
Event Processing
doAction executes one or more Info*Engine tasks selected by a specific logical
action name, and the types and physical locations of a specific set of objects
passed as parameters. sendFeedback sends feedback objects to clients.
doAction
public com.infoengine.object.factory.Group
doAction(String action,
Object[][] argv)
throws WTException
Windchill Services
6-65
Example
import
import
import
import
import
import
wt.federation.FederationHelper;
wt.util.WTException;
com.infoengine.object.factory.Att;
com.infoengine.object.factory.Element;
com.infoengine.object.factory.Group;
com.ptc.core.util.feedback.common.FeedbackSpec;
import java.util.Enumeration;
public class DoActionExample {
public static void main (String[] args) {
Element testElement = new Element();
testElement.addAtt( new Att("obid",
"VR:wt.part.WTPart:73694:[email protected]") );
testElement.addAtt( new Att("name", "ENGINE") );
testElement.addAtt( new Att("number", "2623844395") );
testElement.addAtt( new Att("CLASS", "wt.part.WTPart") );
Element[] elementArray = { new Element("arrayElement1"),
new Element("arrayElement2") };
Group group1 = new Group( "group1" );
group1.addElement( group1Elem1 );
group1.addElement( group1Elem2 );
...
try {
Object[][] argv = { {"testElement", testElement },
{"group1", group1},
{"elementArray", elementArray},
{"bool1", new Boolean(true)},
{"char1", new Character(a')},'
{"int1", new Integer(100)},
{"byte1", new Byte((byte) 9)},
{"double1", new Double(10000)},
{"short1", new Short((short) 99)},
{"float1", new Float(100.25)},
{"long1", new Long(4000)},
{"string1", "argv Test String"} };
// Federation Service doAction() is accessed through
// FederationHelper
Group resultGroup =
FederationHelper.doAction( "testAction", argv );
//Example calling doAction() with a FeedbackSpec object.
Object key = TdTest.class.getName();
FeedbackSpec feedbackSpec = new DefaultFeedbackSpec(key,
true);
6-66
Group resultGroup =
FederationHelper.doAction( "testAction", argv,
feedbackSpec );
if ( resultGroup != null ) {
System.out.println( "resultGroup:" );
showIeGroup( resultGroup );
}
else {
System.out.println( "resultGroup is null." );
}
}
catch ( WTException exc ) {
...
}
...
}
private static void showIeElement(Element inElement) {
Enumeration attrs = null;
Att attr = null;
if ( inElement != null ) {
System.out.println( "Element:" );
System.out.println( " Element Name: " +
inElement.getName() );
System.out.println( " Element Attributes:" );
attrs = inElement.getAtts();
while ( attrs.hasMoreElements() ) {
attr = (com.infoengine.object.factory.Att)
attrs.nextElement();
System.out.println( " " + attr.getName() + ": " +
attr.getValue() );
}
}
}
private static void showIeGroup(Group inGroup) {
if ( inGroup != null ) {
Enumeration elements = null;
System.out.println( "Group:" );
System.out.println( "Group Name: " + inGroup.getName() );
System.out.println( "Number of Elements: " +
inGroup.getElementCount() );
System.out.println( "\nGroup Elements:" );
elements = inGroup.getElements();
while ( elements.hasMoreElements() ) {
showIeElement( (Element) elements.nextElement() );
}
}
}
Windchill Services
6-67
sendFeedback
public void
sendFeedback(MethodFeedback feedbackObject)
throws FederationServicesException
com.ptc.core.meta.type.common.TypeInstance or TypeInstance[ ],
com.infoengine.object.factory.Element or Element[ ],
com.infoengine.object.factory.Group,
At least one argument name, value pair must be specified and at least one
argument value must be of type TypeInstance (or TypeInstance[ ]), Element (or
Element[ ]), or Group.
An example of three input values would look like:
Object[][] argv = { {"arg1Name", arg1Value},
{"arg2Name", arg2Value},
{"arg3Name", arg3Value} };
Example
import wt.federation.FederationServerHelper;
import wt.federation.FederationServicesException;
import wt.feedback.StatusFeedback;
public class SendFeedbackExample {
public static void main (String[] args) {
...
try {
// Send the client a StatusFeedback type feedback object.
// Federation Service sendFeedback() is accessed through
// FederationServerHelper.service
6-68
FederationServerHelper.service.sendFeedback(
new StatusFeedback( "Test Feedback Message" );
}
catch ( FederationServicesException exc ) {
...
}
...
}
}
Windchill Services
6-69
Design Overview
6-70
Windchill Services
6-71
Versions
A business objects iteration holds the objects state and business qualifications.
These qualifications are used to form configuration specifications but in general
could be used as search criteria for ad hoc queries. Each iteration represents the
working history of a version. Incremental changes in the object, represented by
successive iterations, occur as the information is developed and changed. The
latest iteration (that is, the version) represents a development branchs current
implementation; the previous iterations are all history. Iterations are identified by
unique values within a series. Additionally, unique fully-qualified identifiers can
also identify iterations. These fully-qualified identifiers show the history of a
particular iteration as it has been changed over time. In the reference
6-72
Windchill Services
6-73
External Interface
The Mastered interface provides an abstraction of a plug-and-play component in
conjunction with the Iterated interface. The intent is that, in an object model, a
business object would assert that it is a master by inheriting (that is, it
implements) the Mastered interface. With this assertion, iterations can then be
identified by attributes in concrete masters (for example, name and number).
Note: Version control does not require Mastered objects to have any iterations,
but allows for many.
The Iterated interface provides an abstraction of a plug-and-play component in
conjunction with the Mastered interface. The intent is that, in an object model, a
business object would assert that it is an iteration by inheriting (that is, it
implements) the Iterated interface. With this assertion, the iterations can then be
incrementally superseded, rolled back, and rolled up.
Note: Version control requires Iterated objects to have one and only one master.
This is a design constraint in that foreign key associations that can be auto
navigated (that is, the association between a master and its iterations) are required
to have one side being of cardinality equal to one (1).
The Versioned interface provides an abstraction of a plug-and-play component
that is a kind of Iterated object. The intent is that, in an object model, a business
object would assert that it is a version by inheriting (that is, it implements) the
Versioned interface. With this assertion, the business object can then be revised,
branched, and copied to new versions.
The VersionHelper provides an abstraction as the API to the VC service. The
APIs methods can be categorized as either local or remote invocations. The local
methods are getters of information, typically from cookies that are held in the
business object. The remote methods serve as wrappers to a service that promotes
server-side functionality.
The VersionService provides an abstraction that specifies and promotes serverside functionality as a service that is available remotely for use by a client. The
intent is that this interface defines all the necessary server-side functionality for
VC.
The VersionServiceEvent provides an abstraction of a specialized keyed event
used by the VC service to signal other services that a VC activity is about to begin
or has occurred. This gives other services the opportunity in a plug-and-play
architecture to act accordingly on these events. Validation, vetoing, and post
processing are typical reactions to events.
The VersionException provides an abstraction of an abnormal occurrence or error
in the usage or processing of the VC service. This exception can be localized
through a given resource bundle and other exceptions can be nested within it. The
most common occurrences of this exception is when an attempt is made to use a
6-74
Business Rules
As defined by the standard VC services access control rules, no constraints are
placed on the access of versioned objects. Furthermore, no constraints are placed
on the access of either mastered or iterated objects.
Note: Direct manipulation or deletion of both masters and superseded iterations
is currently unsupported. All functions should be carried out on versions.
For additional information, see the section on updating a master through an
iteration in chapter 8, Developing Server Logic.
Event Processing
Event-based processing is performed on business objects asserted as being
Iterated during database storing, deletions, and full restorations.
When a business object is being stored in the database, the VC service listens to a
dispatched event indicating that the store is about to begin and stores the versions
master, if needed.
After a successful store, the VC service listens to a dispatched event indicating
that the store has completed and signals all other interested services that a new
version exists if the stored iteration is either the first one created or is the first in a
new branch.
When a business object is being deleted from the database, the VC service listens
to a dispatched event indicating that the deletion is about to begin and vetoes the
deletion if the version is not the latest one in that branch of development.
Otherwise, it passes on vetoing the deletion.
After a successful deletion, the VC service listens to a dispatched event indicating
that the delete has completed and deletes all of the versions iterations. If the
deleted version is the only one remaining related to a master, then it is deleted as
well.
When a business object is being fully restored from the database, the VC service
listens to a dispatched event indicating that the full restoration is beginning and
restores the iteration cookies creator/modifier, predecessor and master
references.
Windchill Services
6-75
External Interface
The Baselineable interface provides an abstraction of a plug-and-play component.
The intent is that, in an object model, a business object would assert that it is
Baselineable by inheriting (that is, it implements) the Baselineable interface. With
this assertion, the business object can then be part of a Baseline. The Baselineable
interface extends the Iterated interface and, therefore, must play the Iteration role
in the Master-Iteration (MI) pattern.
The Baseline interface is asserted for an object that can be associated with
Baselineable items. An out-of-the-box ManagedBaseline object implements the
Baseline interface and has name, number, and description attributes. It is also
Foldered and Life Cycle managed.
The Baseline service provides an abstraction that specifies and promotes serverside functionality as a service that is available remotely for use by a client. The
intent is that this interface defines all the necessary server-side functionality for
baseline. The BaselineHelper provides an abstraction as the API to the Baseline
service.
The Baseline service provides basic APIs for adding and removing Baselineable
items. There are also operations for retrieving baseline information. A
convenience operation is also provided to automatically populate a Baseline by
navigating structured data. As the structure is navigated, each Baselineable item is
added to the Baseline. This navigation is customizable and an out-of-the-box
implementation is provided for navigating a part structure via the uses
relationship.
The BaselineServiceEvent provides an abstraction of a specialized keyed event
used by the Baseline service to signal other services that a baseline activity is
about to begin or has occurred. This gives other services the opportunity in a plugand-play architecture to act accordingly on these events. Validation, vetoing, and
post-processing are typical reactions to events.
Business Rules
The following business rules apply to baseline:
6-76
could have access rights set so that any user can modify the object and be able
to add or remove items. The Released state could be set so that a normal user
does not have modify access rights. This would allow for the concept of a
frozen baseline. The baseline would be available for adding and removing
items until it was frozen by changing its state to Released.
A baseline can have zero or more Baselineable objects associated with it, and
a Baselineable object can be part of zero or more baselines. However, for a
given baseline, only a single iteration of a given master can be part of that
baseline.
Windchill Services
6-77
baseline. However, this can lead to situations that may be confusing to a user.
When viewing a baseline, only those items that the user has access to (that is,
in shared folders) are displayed. Another example is if a checked out item is
placed in a baseline and then the undo-checkout operation is performed.
Undo-checkout deletes the working copy, which will cause the Baseline
service to throw an exception (items in a baseline cannot be modified or
deleted).
Event Processing
The Baseline service is both a producer and consumer of events. Whenever an
item is added, removed, or replaced in a baseline, events are generated prior to
and after the operation. For example, adding an item generates
PRE_ADD_BASELINE and POST_ADD_BASELINE events. Developers can
use the basic event listening mechanism to perform customized actions during
baseline operations. The Baseline service listens for the pre-modify, pre-delete,
and prepare for modify events to enforce business rules for items that are part of a
baseline.
6-78
The figure below illustrates the fundamental wt.vc.config classes and methods.
Basic ConfigSpecs
Windchill Services
6-79
wt.vc.config.MultipleLatestConfigSpec
wt.part PackageConfigSpecs
wt.part.WTPartStandardConfigSpec
6-80
It combines the state a part is in and the view it may be assigned to in order to
produce a context that is based on state and view for latest iterations. If the
lifeCycleState value is assigned, the version must be in that particular state
(multiple states are not supported). If the view value is assigned, the version
must be assigned to that view (or one of its parents if no version has been
assigned to the view) or view independent. There is also a workingIncluded
that, if false, removes anything that is owned, even if it is owned by the
current principal. This ConfigSpec allows a user to state, for example, that he
works in the Engineering view and would like to see the Released product.
Note that the LatestConfigSpec is used to both append to the QuerySpec and
process to a single version per master.
wt.part.WTPartBaselineConfigSpec
This ConfigSpec (which could be used with any Baselineable Iterated class) is
the only out-of-the-box ConfigSpec to not follow VCs definition of a version
as the latest iteration. It returns only those iterations that are assigned to the
specified baseline.
wt.part.WTPartEffectivityConfigSpec
WTPartConfigSpec
Windchill Services
6-81
serve as an example only; it has not been tested and is not supported by Windchill
as code.)
ProjectConfigSpec Example
6-82
return qs;
//##end appendSearchCriteria% [ ]36484C990290.body
}
The process API is simple, although it does require some implementation. The
target class might not have been Ownable and yet may have had Ownable
children, so ownership needs to be processed. Also, this ConfigSpec should return
a single version per master, so multiple versions will need to be processed down
to one. Fortunately, the LatestConfigSpec does all of these things, so this
implementation will simply return the result of executing its process API. The
code would look similar to the following:
public QueryResult process( QueryResult results )
throws WTException {
//##begin process% [ ]353B588501C5.body preserve=yes
//We can not simply return the results, children of the target
//class may have been Ownable, even though the target
//class was not.
//Let
//LatestConfigSpec handle this case because its process API
//accounts
//for that.
return (new LatestConfigSpec()).process(results);;
//##end process% [ ]353B588501C5.body
}
ConfigHelper
Windchill Services
6-83
master so it can be displayed in place of the version or versions (to indicate that no
version matched, but there is data). This can be done via the
recoverMissingMasters API. If iterations drop out as a result of being processed,
links to those iterations can be removed by calling the removeExtraLinks API.
The Product Information Explorer navigates WTPartUsageLinks from part
versions to part versions. The WTPartUsageLink (a type of IteratedUsageLink
from wt.vc.struct) is defined between a WTPart and a WTPartMaster. No link is
defined as being between WTPart and WTPart; however, the requirement for such
a link comes primarily (as is the case for the Product Information Explorer) from
display. The buildConfigResultsFromLinks API allows iteration-to-master
associations to be represented as iteration-to-iteration associations by a client. It
does this by pairing the master (on the master role) with its corresponding version
and returning a QueryResult a Persistables. Each element, a Persistables, is of
length 2 and contains the link in the 0th position and the version in the 1st
position. The client then takes the real links information (such as Quantity) and
simply displays the version instead of the master. The following code illustrates
the use of the ConfigSpec, ConfigService, and ConfigHelper to navigate an
IteratedUsageLink to return either the other side (versions) or the links (and
versions):
public QueryResult navigateSomeIteratedUsageLinkAlongTheUsesRole(
Iterated someIteration, boolean onlyOtherSide,
ConfigSpec someConfigSpec )
throws WTException {
//Navigate the link to its masters.
QueryResult uses = PersistenceHelper.manager.navigate(someIteration,
SomeIteratedUsageLink.USES_ROLE, SomeIteratedUsageLink.class,
onlyOtherSide);
//If the navigation returns links, convert those links to masters.
QueryResult usesMasters = (onlyOtherSide) - uses :
ConfigHelper.mastersOf(uses, IteratedUsageLink.USES_ROLE);
//Get the iterations for these masters. If masters are lost because
//no matching iterations were found, recover those masters for
//display.
QueryResult iterations =
ConfigHelper.recoverMissingMasters(usesMasters,
ConfigHelper.service.filteredIterationsOf(usesMasters,
someConfigSpec));
//If the user wants only the other side objects, return the
//iterations. Otherwise, pair up the links with the versions
//for those links.
if (onlyOtherSide)
return iterations;
else
return ConfigHelper.buildConfigResultFromLinks(uses,
IteratedUsageLink.USES_ROLE, iterations);
}
6-84
The references association couples data more loosely than the uses association.
For example, the referenced data may be important to a document, but the
document can be disseminated without it. For example, a design specification that
references the requirements specification it was written for is still complete on its
own. The struct packages IteratedReferenceLink allows versioned data to
participate in references associations.
Windchill Services
6-85
structPackage APIs
The struct package provides navigate APIs for both the IteratedUsageLink and
IteratedReferenceLink for convenience and because of minor behavioral nuances.
The navigateUses and navigateReferences APIs behave exactly as would
PersistenceManagers navigate, however navigateUsedBy and
navigateReferencedBy return only versions; they filter out any iteration that is not
the latest iteration. The navigateUsesToIteration and
navigateReferencesToIteration APIs navigate the links to the masters, then
resolve the masters to their appropriate versions using the passed ConfigSpec. The
masters for which there are no appropriate versions are returned to indicate that
the association exists but has no qualifying representation given the ConfigSpec.
The return value for the navigate to iterations API, a QueryResult, consists of
those versions (and possibly masters) if onlyOtherSide is true. If it is false (that is,
the links are desired as well) a QueryResult containing Persistables as elements is
returned. Each element is an array of length 2 with the link in the 0th position and
the version (or master) in the 1st position.
6-86
Creating these links between an iteration and its own master is not allowed.
Windchill Services
6-87
the data to fit requirements. However, phantom parts are parts that the
manufacturing group might create when a group of parts are actually pre-built.
The Windchill model builds view management capabilities on top of the existing
versioning capabilities. A ViewManageable version, when assigned to a view, is
qualified by the view. When a downstream group is ready to accept and add value
to the version, it branches its own version (qualified by its view). The following
example illustrates this concept.
The Engineering group creates part 100, assigning it to the Engineering view.
The version of this part is A.
The Manufacturing group branches part 100, creating version A.A of part
100, which is assigned to the Manufacturing view.
The Manufacturing group releases version A.A and puts it into production.
6-88
View-dependent versions can not become view-independent and viewindependent versions can not become view-dependent. The first version of a
master determines that all versions of that master are view-dependent or viewindependent.
Views and their associations can be created using the LoadViews application. See
the Administrators Guide for details. Views and view associations exhibit the
following behavior:
Views can be inserted between a parent and its children at any time. However,
this is the only way to alter the structure after it has been established.
The ViewHelper and ViewService provide the functionality associated with view
management. The helper provides the client-side APIs to assign the version to a
view and get the view to which a version is assigned. The service provides APIs to
branch view-dependent versions into downstream views, and to obtain
information about the views and their associativity. When developing against this
package the following should be noted:
The ViewService does not emit an event when a new version is branched in a
downstream view. VersionServiceEvents NEW_VERSION event should be
subscribed to if you are interested in the creation of a new view-dependent
version or branch.
Windchill Services
6-89
Design Overview
6-90
series. Given the checkout example above, the checked in object would now be at
iteration 6 of version B. Mechanically, a checkin can be done from either the
original object or its working copy. The system will understand what is meant and
perform the checkin. When the checkin completes, the lock on the original object
is released and the working copy is removed from the checked out folder.
Upon an undo of a checkout, the working copy is deleted along with the link to the
original object. Additionally, whenever the checked-out original object or
working copy is deleted, the checkout is undone automatically.
External Interface
The Workable interface provides an abstraction of a plug and play component.
The intent is that, in an object model, a business object would assert that it is
Workable by inheriting (that is, to implement) the Workable interface. With this
assertion, the business object can then be checked out and checked in.
The WorkInProgressHelper provides an abstraction as the API to the WIP service.
The APIs methods can be categorized as either local or remote invocations. The
local methods are getters of information, typically from cookies that are held in
the business object. The remote methods serve as wrappers to a service that
promotes server-side functionality.
The WorkInProgressService provides an abstraction that specifies and promotes
server-side functionality as a service that is remotely available for use by a client.
The intent is that this interface defines all the necessary server-side functionality
for WIP.
The WorkInProgressServiceEvent provides an abstraction of a specialized keyed
event used by the WIP service to signal other services that a WIP activity is about
to begin or has occurred. This gives other services the opportunity in a plug-andplay architecture to act accordingly on these events. Validation, vetoing, and postprocessing are typical reactions to events.
The WorkInProgressException provides an abstraction of an abnormal occurrence
or error in the usage or processing of the WIP service. This exception can be
localized through a given resource bundle and other exceptions can be nested
within it. The most common occurrences of this exception is when an attempt is
made to check in/out a business object but it already is checked in/out, and when
used incorrectly during a database modification, deletion, and navigation.
The WorkInProgressState provides an abstraction of the valid set of work-inprogress states that a Workable object can exist within. The three supported states
are checked out, checked in, and working.
Business Rules
As defined by the standard WIP services access control rules, since a Workable
object is asserted as being Lockable, the service relies on the locking service for
applicable access control. Additionally, when an object is checked out, neither the
original checked out nor working copies can be checked out again.
Windchill Services
6-91
Event Processing
Event-based processing is performed on business objects asserted as being
workable during database storing, [preparation for] modifications, deletions, and
folder changes.
When a business object is being stored in the database, the WIP service listens to a
dispatched event indicating that the store is about to begin and initializes the state
of the object to being checked in if and only if its checkout info cookie is null.
Since a workable may also be a Foldered, the WIP service listens to a dispatched
event indicating that a store on a cabinet has successfully completed and checks if
the cabinet exists in the user domain (that is, a personal cabinet) and, if so, stores a
checkout folder in that cabinet.
When a business object is [prepared for] being modified in the database, the WIP
service listens to a dispatched event indicating that the modify is about to begin
and vetoes it if either of the following conditions are true:
The business object is checked in and not owned by the current sessions
principal.
Design Overview
The workflow package contains the following five subpackages:
engine
Directly responsible for the flow of control and data from an execution point
of view.
definer
Definition of workflow objects, that is, processes, activities, and the other
objects that compose the workflow network.
6-92
work
Responsible for the delivery and execution of assigned activities and work
list.
robots
Responsible for the execution of robot activities, that is, activities that are
executed by the system rather than assigned to a participant.
worklist
Windchill Services
6-93
WorkflowEngine Package
6-94
The mapping between local and global variables does not belong to the activity
definition. It is part of the relationship between a process and a step. They become
part of the activity execution object when it is instantiated. In this way, an activity
template can be reused independently of the process in which it will be used.
Windchill Services
6-95
dispositions made by assignees. These ballots can then be used to tally the votes
based on a voting policy to determine what routing events should fire when the
activity is completed. Both WfAssignedActivity and WfAssignment have a trip
counter attribute that is used to manage information generated as a result of loop
iterations.
6-96
Windchill Services
6-97
External Interface
With the exception of wt.workflow.robots and wt.workflow.worklist, each
workflow subpackage has its own independent service.
The wt.workflow.engine.WfEngineHelper provides an abstraction of the API
required to instantiate and initiate workflow process instances. This service also
supports the invocation of robot activities through a specification of WfActivity.
The wt.workflow.definer.WfDefinerHelper provides an abstraction of the API
required to create and edit workflow definitions.
The wt.workflow.work.WorkflowHelper provides an abstraction of the API to the
workflow service to handle work item distribution, voting, and completion.
Business Rules
Work items are created by the workflow engine and are delivered to the user
through the work list interface and optionally via e-mail. An assigned activity may
have many assignees. Each assignee receives a work item in their work list. The
completion of an activity is based on the completion policy specified at define
time. For example, an assignment to a group may declare the policy as follows: all
members must act, a single member may act on behalf of the group, or a specific
number of group members must act. Depending on the completion policy, when
an assignee "accepts" or "completes" a work item, corresponding work items on
the work list of others are removed.
LifeCycle definition allows the integration of workflows into the specification for
each phase and gate. The life cycle service will transparently launch these
workflows when the life cycle managed object enters the phase or gate.
Support the propagation of changes made to the models into the enterprise
parts
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
6-98
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.
Windchill Services
6-99
GraphicallyRepresentable
EPMDocument Model
6-100
Windchill Services
6-101
EPM Variant Link is an Iteration to Master link that denotes that an EPM
Document is a variant of another EPM Document.
6-102
Windchill Services
6-103
6-104
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.
Windchill Services
6-105
deprecated. These classes and methods will be replaced. Please refer to the
javadoc to see the deprecated classes and methods. Windchill defines a build
process, which is used to publish usage links and attributes (see the following
figure).
<<Interface>>
BuildRule
(from build)
<<Abstract>>
EPMBuildRule
uniqueID : long
<<Interface>>
EPMObject
(f rom e pm)
WTPart
(from part)
+buildTarget
n
<<Abstract>>
VersionToVersionLink
(from vc)
+buildSource
n
EPMDocument
(from epm)
Build Model
6-106
<<Abstract>>
EPMBuildRule
uniqueID : long
getApplicationTag()
initialize()
checkA ttributes()
getBuildSourc e()
setBuildSourc e()
getBuildTarget()
setBuildTarget()
EPMBuildLinksRule
EPMBuildLinksRule()
WTPart
(from part)
+buildTarget
n
+buildSource
n
EPMDocument
(from epm)
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:
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.
Windchill Services
6-107
6-108
7
Persistence Management
Topic
Page
Persistence Manager............................................................................................7-2
Query .................................................................................................................7-12
Transaction ........................................................................................................7-16
Paging................................................................................................................7-17
7-1
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 sections that follow
7-2
show the method declarations of the methods in the PersistenceManager class and
briefly describe what they do.
Persistence Manager
Persistence Management
7-3
Store
A factory method is responsible for constructing an initialized business object in
memory that the client can manipulate. The store method ensures that the state of
the business object is valid and makes it persistent in a database so it can be used
by the rest of the enterprise. The store method has the following declaration:
// Store the given object in the database
public Persistable store(Persistable wto)
throws WTException;
Uses Access Control to determine if the user is allowed to create this business
object.
Inserts the Persistable object into the database and, in so doing, assigns an
ObjectIdentifier and sets the createTimestamp and modifyTimestamp.
Dispatches a PersistenceManagerEvent.POST_STORE
7-4
Modify
The modify method has the following declaration:
// Modify the given object in the database
public Persistable modify(Persistable wto)
throws WTException;
// Modify only the specified structured attribute in the given
// object in the database
public Persistable modify( Persistable obj, String attrName,
ObjectMappable objAttr )
throws WTException;
Dispatches a PersistenceManagerEvent.PRE_MODIFY.
Updates this Persistable object in the database, ensuring that the object has not
gone stale (that is, someone else has already modified this object in the
database). Note that any attributes derived from values that exist in other
tables are not updated in the database.
Sets new values in the persistent information attributes, such as update count
and modify timestamp.
Dispatches a PersistenceManagerEvent.POST_MODIFY.
Example:
aCustomer.setPhone("555-0000");
aCustomer = (Customer)PersistenceHelper.manager.modify(aCustomer);
Note: Setting the local variable to the return value is important in programming
the client because the underlying RMI makes copies of the objects referenced by
the arguments of the method. This means that objects passed as arguments by the
client in the modify method are not changed by the operations that occur on the
method server.
Save
The save method has the following declaration:
// Save the given object in the database
public Persistable save(Persistable wto)
throws WTException;
Persistence Management
7-5
Example:
Customer c = newCustomer("Acme");
c.setPhone("555-1234");
c.setAddressUS(anAddress);
// save = store
c = (Customer)PersistenceHelper.manager.save(c);
. .
c.setPhone("555-000")
c = (Customer)PersistenceHelper.manager.save(c);
//save = modify
Note: Setting the local variable to the return value is important in programming
the client because the underlying RMI makes copies of the objects referenced by
the arguments of the method. This means that objects passed as arguments by the
client in the save method are not changed by the operations that occur on the
method server.
Delete
The delete method has the following declaration:
// Delete the given object from the database
public Persistable delete(Persistable wto)
throws WTException;
Deletes the object from the database, ensuring the object has not gone stale
(that is, someone else has already modified this object in the database) and
flagging the PersistInfo as deleted.
Example:
aCustomer =
(Customer)PersistenceHelper.manager.delete(aCustomer);
7-6
Note: Setting the local variable to the return value is important in programming
the client because the underlying RMI makes copies of the objects referenced by
the arguments of the method. This means that objects passed as arguments by the
client in the delete method are not changed by the operations that occur on the
method server.
Refresh
The refresh method ensures that neither the client nor the server has a stale
business object. The refresh method has the following declaration:
// Refreshes the given object
public Persistable refresh(Persistable wto)
throws WTException;
// Retrieves a Persistable object from the database given its object
// identifier. Object references of the target object are not refreshed.
public Persistable refresh( ObjectIdentifier objId )
throws WTException, ObjectNoLongerExistsException;
//
//
//
//
Retrieves the state for the object from the database. All persistent attributes
are retrieved, including values from autonavigated relationships.
Ensures the user is allowed to see the object, given its state.
Note: Setting the local variable to the return value is important in programming
the client because the underlying RMI makes copies of the objects referenced by
the arguments of the method. This means that objects passed as arguments by the
client in the refresh method are not changed by the operations that occur on the
method server.
Client code typically provides mechanisms that let you decide when business
information should be refreshed. Server code should refresh the business object
before performing any significant operation on that object. There is, however, one
Persistence Management
7-7
important exception to this rule: do not refresh the target object of an event in a
service event listener and then subsequently update or modify the object. Because
the refresh method actually returns a new object, the update count of the events
target object will not be incremented when the update operation is called. Then,
when any subsequent listeners are notified of the event and try to update it, they
will get an ObjectIsStaleException because the update count of the in-memory
object differs from that in the database.
The following example illustrates this point:
getManagerService().addEventListener(
new ServiceEventListenerAdapter(this.getConceptualClassname()) {
public void notifyVetoableEvent(Object event)
throws WTException {
PersistenceManagerEvent pmEvent =
(PersistenceManagerEvent)event;
Persistable target = pmEvent.getTarget();
// target now points to a new object, not the original one
// obtained from the event
target = PersistenceHelper.manager.refresh(target)
// modify target in some way...
// the update count of target is incremented when modify is
// called, causing the target object of the event to look
// stale if another
// listener were to attempt a modify.
PersistenceHelper.manager.modify(target)
}
},
PersistenceManagerEvent.generateEventKey(
PersistenceManagerEvent.POST_MODIFY));
}
Find
The find method has the following declaration:
// Queries for Persistable objects given a search criteria
public static QueryResult find(StatementSpec ss)
throws WTException;
//
//
//
//
Retrieves any and all link objects that exist between two Persistable
objects given their object identifiers. The method validates the
resulting set of link objects retrieved from the database before
returning them to the invoking method.
public QueryResult find( Class targetLinkClass, ObjectIdentifier
obj1Oid, String obj1Role, ObjectIdentifier obj2Oid )
throws WTException, InvalidRoleException;
//
//
//
//
7-8
Retrieves any and all link objects that exist between two given
Persistable objects. The method validates the resulting set of
link objects retrieved from the database before returning them
to the invoking method.
Queries the database for objects given the search criteria stored in the query
specification (described later in this chapter in the section on utility classes).
The target classes of the query specification and all of the associated
subclasses are searched.
Removes from the result set any objects the user is not allowed to view.
Example:
QuerySpec criteria = new QuerySpec(helpdesk.Product.class");
QueryResult results = PersistenceHelper.manager.find(criteria);
Product p;
while (results.hasMoreElements()) {
p = (Product) (results.nextElement());
// do something with Product p
}
In this example, the find method used an empty query specification, QuerySpec,
to retrieve all products. The target of the QuerySpec can be an abstract class,
allowing the query to span multiple subclasses. The find method returns its results
in a QueryResult object that acts like an enumeration.
Navigate
There are four navigate methods:
public QueryResult navigate(Persistable obj, String
role, Class linkClass) throws WTException
public QueryResult navigate(Persistable obj, String
role, QuerySpec criteria) throws WTException
public QueryResult navigate(Persistable obj, String
role,Class linkClass, boolean onlyOtherSide) throws WTException
public QueryResult navigate(Persistable obj, String
role, QuerySpec criteria, boolean onlyOtherSide) throws WTException
The first two methods have the same result as the last two with onlyOtherSide set
to True. When onlyOtherSide is true, the QueryResult contains the other side
objects rather than the links. When onlyOtherSide is false, the fully populated
links are returned.
The navigate method performs the following operations:
Persistence Management
Searches for objects of which the target object is a member, given the
specified role and QuerySpec.
7-9
Removes from the result set any objects the user is not allowed to view.
Example:
c = cust;
/* This QuerySpec constructor allows for a target and a link class. */
QuerySpec lqs = new QuerySpec(helpdesk.Product.class,
helpdesk.ProductRegistration.class);
lqs.appendWhere(new SearchCondition(
helpdesk.Product.class,
"name",
SearchCondition.EQUAL,
"AmazingApplets"), new int[] { 0 });
lqs.appendAnd();
lqs.appendWhere(new SearchCondition(
helpdesk.ProductRegistration.class,
"platform",
SearchCondition.EQUAL,
"NT"));
/* This will return ProductRegistrations. */
results =
PersistenceHelper.manager.navigate(c,ProductRegistration.PRODUCT_ROLE,
lqs, false);
/* This will return Products. */
results =
PersistenceHelper.manager.navigate(c,ProductRegistration.PRODUCT_ROLE, lqs);
/* this will return all Products registered for this customer. */
results =
PersistenceHelper.manager.navigate(c,ProductRegistration.PRODUCT_ROLE,
ProductRegistration.class,true);
/* this will return all objects where the role is product for this customer. */
results =
PersistenceHelper.manager.navigate(c,ProductRegistration.PRODUCT_ROLE,
Link.class);
Get LOB
The getLob method has the following declaration:
public InputStream getLob( LobLocator lob )
throws WTException;
Given the lob locator, the getLob method returns the lob as an InputStream.
7-10
Given the name of the sequence as input, the getNextSequence method returns the
next value.
Example:
String sequenceNum =
PersistenceHelper.manager.getNextSequence("SOMENAME_seq");
Note: You must create the sequence before using this. For example:
wtpk.createSequence(SOMENAME_seq,1,1)
Persistence Management
7-11
The method throws the NotAuthorizedException if the user is not allowed to view
the given object.
The prepareForView method performs the following operations:
Search
The search method queries for a persistent object using the vector of
AttributeSearchSpecifications for the criterion. If any pre-query processing of the
data is required, it performs that processing.
The search method has the following declaration:
public QueryResult search( Class classname, Vector searchSpecVector )
throws WTException;
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
7-12
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.
Persistence Management
7-13
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.
SearchCondition has constructors for each of the java primitives and their
corresponding classes, plus Enumerated and AttributeRange. AttributeRange is
used as an argument to a SearchCondition constructor to create range conditions
in the WHERE clause (for example, myInt BETWEEN 1 AND 50).
SearchCondition also defines constants to use for the operation argument on the
constructors, such as EQUAL and GREATER_THAN.
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);
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.
7-14
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.
Persistence Management
7-15
Example:
QuerySpec qs = new QuerySpec();
// 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);
Transaction
Transaction objects provide a mechanism that supports the standard concept of a
database transaction. It has the following methods:
7-16
start
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.
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
Persistence Management
7-17
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.
The Paging APIs are specified as static methods in the wt.fc.PagingSessionHelper
class (see Javadocs for full details). 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
7-18
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(
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
7-19
}
}
7-20
8
Developing Server Logic
Topic
Page
8-1
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.
8-2
The number indicates the startup order of the service. If a service depends on
other services, those services must be started first.
There are entries that are termed either a service or a manager. During the initial
stages of Windchill development, the use of the terms manager versus service was
unclear. It has been agreed that service represents the more general concept and
manager represents those services that are characterized more as managing groups
of objects. Currently the terms manager and service appear interchangeably.
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 Chapter 6, Windchill Services.
In addition to managing managers, the ManagerService provides a synchronous
event dispatch service. It could dispatch a vetoable or non-vetoable event to all
listeners for the event key. The listener may or may not object to the event. It
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
8-3
8-4
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 {
8-5
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 );
}
}
}
8-6
obj );
Transaction trx = new Transaction();
try {
trx.start();
insert(obj);
dispatchVetoableEvent( PersistenceManagerEvent.POST_STORE,
obj );
trx.commit();
trx = null;
}
finally {
if ( trx != null )
trx.rollback();
}
return obj;
}
8-7
Constraining an Attribute
8-8
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."
8-9
capable of being thrown from the setter. If an attribute is not constrained, the
setter is generated without the capability of an exception being thrown.
The properties for specifying limits on a String or numeric attribute are
LowerLimit and UpperLimit. In both cases, the value supplied is treated as a
literal or constant. This means that the validation method is code generated with
"if" statements that use Java less than or greater than operators to test against the
specified value in the LowerLimit or UpperLimit property, respectively. The
following examples illustrate the use of these two properties and the validation
code that is generated automatically:
Validation Example
8-10
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.
8-11
Persistent Attribute
8-12
8-13
8-14
if (trx != null)
trx.rollback();
}
return obj;
//##end store% [ ]3458AD98008C.body
}
if (!object.getLock().isSeized()) {
if (AccessControlHelper.manager.hasAccess( locker.getPrincipal(),
object, WTPermission.MODIFY )) {
dispatchVetoableEvent( LockServiceEvent.PRE_LOCK, object );
object.getLock().seize( locker, note );
8-15
//
//
//
//
//
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
}
8-16
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.
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:
8-17
8-18
import
import
import
import
import
import
import
java.applet.*;
java.awt.*;
java.awt.event.*;
java.lang.reflect.InvocationTargetException;
java.rmi.RemoteException;
java.io.Serializable;
java.util.Vector;
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;
Button action;
RunnerEventListener rel;
Label partNames;
TextField text;
Label queryCount;
TextField countVal;
TextArea feedback;
8-19
8-20
8-21
}
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; }
}
}
8-22
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.
8-23
set of access rules, and any changes to it would be against the master object
directly, not derived attributes on the iteration.
If this approach is taken, the client must update and persist masters and iterations
separately. There may still be derived master attributes on the iteration to facilitate
querying and/or read-only access of master attributes via the iteration. However,
these attributes would not be set via the iteration.
8-24
8-25
8-26
9
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
9-1
System Generation
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.
Classes
Operations
Attributes
Generalize relationships
Dependency relationships
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
9-2
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
code generated items is placed in the generated source code in the format of
Javadoc style comments.
System Generation
9-3
The figure below shows a class modeled in Rose that is mapped to Java.
Model of a Class
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:
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;
9-4
import
import
import
import
import
wt.pds.PersistentRetrieveIfc;
wt.pds.PersistentStoreIfc;
wt.pom.DatastoreException;
wt.util.WTException;
wt.util.WTPropertyVetoException;
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 {
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";
System Generation
9-5
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.
Stereotype:
9-6
System Generation
Deprecated if the class is obsolete and support is being phased out. (This
setting is superceded by the Deprecated property.)
Java Properties
Oracle Properties
9-7
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).
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.
Model of Operations
9-8
return null;
//##end operation1% [ ]34F19DCB01D0.body
}
}
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
generated into concrete subclasses. See the Implementing Interfaces section for
details.
System Generation
9-9
Java Properties
9-10
The class controls the integrity of the attribute by monitoring changes to the
attribute.
Model of Attributes
constants
= "a1";
= "a2";
= "a3";
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,
System Generation
9-11
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.
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.
9-12
Derived should be selected if the generated private field is not desired. Also
see the DerivedFrom property below.
System Generation
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.
9-13
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.
WriteAccess should be set if the access of the setter should be different than
that of the getter that will be generated.
9-14
Java Properties
Persistent should be set to True if the field that holds the value will be
persisted to the database.
System Generation
Oracle Properties
Unique indicates if only unique values are allowed for this attribute
(enforced at the database level).
9-15
UI Properties
9-16
System Generation
9-17
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
9-18
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;
}
System Generation
9-19
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.
9-20
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.)
Name specifies the name association that is the name of the resulting Link
class. If blank, it defaults to a role A/role B concatenation.
Role A specifies the role A name. If blank, it defaults to the name of the role
A class (in this case, the class name is prefixed with "the" to avoid a naming
conflict). The popup menu for associations provides an alternative means for
specifying role A.
Role B specifies the role B name. If blank, it defaults to the name of the role B
class (in this case, the class name is prefixed with "the" to avoid a naming
conflict). The popup menu for associations provides an alternative means for
specifying role B.
System Generation
9-21
Deprecated if the class is obsolete and support is being phased out. (This
setting is superceded by the Deprecated property.)
Java Properties
Oracle Properties
Generate should be set to False if the system generation tools should not
generate a Java class for this modeled association.
Role specifies the name of the role. (See Role A (or B) description for
General tab above.)
9-22
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.
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.
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
by this property. The constraint is enforced in the validation that is generated
for the setter.
WriteAccess should be set if the access of the setter should be different than
that of the getter that will be generated.
System Generation
Deprecated if the role is obsolete and support is being phased out. (This
setting is superceded by the Deprecated property.)
9-23
Java Properties
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.
InitialValue specifies the value to which the field will be initialized upon
declaration.
UI Properties
9-24
System Generation
9-25
Implementing Interfaces
In Rose, an interface is modeled as a class that has the stereotype <<Interface>>.
9-26
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.)
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.
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.
System Generation
9-27
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.
9-28
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
9-29
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 );
}
9-30
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 a hook (readOldVersion) for reading in previous versions of the class,
which have been externalized. Code generation detects when the externalizable
signature of a class changes, and changes its internal version UID accordingly.
System Generation
9-31
You have the ability to take control of the externalization code, but it is not highly
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( a1 );
output.writeObject( a2 );
output.writeObject( a3 );
output.writeObject( list );
output.writeObject( (size == null - null :
size.getStringValue()) );
output.writeObject( timeline );
output.writeObject( work );
//##end writeExternal% [ ]writeExternal.body
}
// Example of a readExternal method
protected boolean readVersion( MyItem thisObject,
ObjectInput input,
long readSerialVersionUID, boolean passThrough,
boolean superDone )
throws IOException, ClassNotFoundException {
//##begin readVersion% [ ]readVersion.body preserve=no
boolean success = true;
if ( readSerialVersionUID == EXTERNALIZATION_VERSION_UID ) {
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.EnumeratedType.toEnumeratedType(
size_string_value ); }
// in case old format
catch( wt.util.WTInvalidParameterException e ) {
size = MySize.toMySize( size_string_value );
}
timeline = (Timeline)input.readObject();
work = (MyAddress)input.readObject();
}
else
success = readOldVersion( input, readSerialVersionUID,
passThrough, superDone );
9-32
return success;
//##end readVersion% [ ]readVersion.body
}
Extending EnumeratedTypes
System Generation
9-33
9-34
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.
Link membership
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.)
Attributes of classes
System Generation
9-35
Derived flag
Persistent flag
Updateable flag
Required flag
Upper limit
9-36
Java Type
SQL Type
java.lang.Integer(int)
INTEGER
NUMBER
java.lang.Long (long)
BIGINT
NUMBER
java.lang.Short (short)
SMALLINT
NUMBER
java.lang.Byte (byte)
TINYINT
NUMBER
java.lang..Float (float)
REAL
NUMBER
java.lang.Double (double)
DOUBLE
NUMBER
java.lang.Boolean (boolean)
BIT
NUMBER
java.lang.Char (char)
CHAR
CHAR
java.lang.String
VARCHAR
VARCHAR
java.math.BigDecimal
NUMERIC
NUMBER
java.sql.Date
DATE
DATE
java.sql.Time
TIME
DATE
java.sql.Timestamp
TIMESTAMP
DATE
java.sql.Blob
BLOB
BLOB
wt.fc.LobLocator
BLOB
BLOB
WTTypes.SMALLBLOB
Not applicable
VARCHAR (encoded)
WTTypes.INLINEBLOB
Not applicable
WTTypes.SEQUENCE
System Generation
NUMERIC
NUMBER
9-37
Each persistable class maps to a database table. Each persistent attribute in the
class is mapped to a column name in the table. Structured attributes, like the
Address class shown earlier, are decomposed into their simple attributes.
Attributes are stored as lobs when no SQL-supported mapping is found, or if the
cardinality is greater than one (because SQL cannot allocate space for an
indefinite number of columns and rows).
Tables contain all the attributes they inherit from classes above them. Because a
class must be persistable to be in the database, all tables contain the persistInfo
attributes, including the object identifier.
The figure below shows a representation (not the actual columns) of the table that
is generated for the modeled class.
9-38
System Generation
9-39
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 sequence data types available. For simple 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) named _seq, and increment the Oracle sequence value to
set the value of the attribute when the object is inserted into the database.
If you prefer to assign the sequence number at a later time, you can use
PersistenceManager.getNextSequence() to obtain the next available sequence
number for the named sequence. That interface returns a String, so you would
either model the attribute as a String or convert it to whatever you need. You must
ensure that the sequence is created using either the Oracle CREATE SEQUENCE
command or the stored procedure provided by Windchill:
exec wtpk.createSequence(MySequence',1,1)'
9-40
The Class Localizable property is set to <Default>, and the Class implements
ObjectMappable and the Package level value is True
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>, which implies that the code generator will inspect the Class level value
to determine the value at this level. These elements will be considered Localizable
by the localizable display generator under either of the following circumstances:
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
tools.properties. For more information on creating localizations, see the
Internationalization and Localization.
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 the Customizing
Modeled Elements chapter of the Windchill Customizers Guide.
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.
Header
Each resource info file contains the following lines that define certain file level
information.
ResourceInfo.class=wt.tools.resource.MetadataResourceInfo
ResourceInfo.customizable=true
ResourceInfo.deprecated=false
System Generation
9-41
#<key.abbreviatedDisplay=
#<key.fullDisplay=
#<key.shortDescription=
#<key.longDescription=
The <key>.value is the only key that is required to have a value defined. This one,
along with the two Display values, and the two Description values are the only
ones that are localizable. The <key>.constant value is unused for these metadata
display name entries, but is used for other types of resource info files.
9-42
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:
java wt.util.resource.ResourceBundleUtil <fully.qualified.name [<locale>]
e.g. java wt.util.resource.ResourceBundleUtil wt.part.partModelRB en_GB
output goes to: $(wt.temp)part.partModelRB_en_GB.lst
System Generation
9-43
Registry Files
The classRegistry, descendentRegistry, and associationRegistry files are located
in the directory specified by the wt.generation.bin.dir entry in wt.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
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.
9-44
TimelineService.java) will have forward classes generated for the service (such as
TimelineServiceFwd.java).
All the generated Java classes are put into directories, specified by the
wt.generation.source.dir entry in wt.tools.properties, which follow the package
structure. All the classes generated for a particular package are placed in the
corresponding directory.
System Generation
9-45
The first line, which executes the dropTable procedure of the WTPK package,
drops the MyItem table if it already exists. The next line is an informational
message that is displayed within SQL*Plus as the table is being created. Then the
table is created, with a primary key constraint on the object identifier. The storage
clause indicates that an initial extent of size 20K will be allocated by Oracle. This
corresponds to a SMALL size table. The last two lines insert a comment into
Oracles data dictionary to document when and why the table was created.
These comments can be viewed using SQL*Plus by entering the following
command:
9-46
Process
Input(s)
Outputs
mData file
modelRegistry.properties
descendentRegistry.properties 1
associationRegistry.properties 1
tools.properties
wt.classRegistry.search.path
tools.properties
wt.classRegistry.search.pattern
classRegistry.properties
classRegistry.properties
modelRegistry.properties
registered mData files
.java files
modelRegistry.properties
descendentRegistry.properties
associationRegistry.properties
modelRegistry.properties
registered mData files
mData file 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.
System Generation
9-47
will be used to generate code in an integrated build environment, the mData file
must be kept synchronized with the cat file. This is best accomplished by always
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
RegistryGen
ModelInstall "<package>.*"
JavaGen "<package>.*"
ResourceBuild"<dir\sub>"
javac ...
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.
Creates a class registry from scratch, using the following two properties from
tools.properties, to determine what to include in the registry:
wt.classRegistry.search.path
wt.classRegistry.search.pattern
ModelInstall
Updates the model registries with all the modeled packages specified by
Arg1. Arg1 can be either of the following:
"<package>.*"
Registers the single package specified.
"<package>.**"
Registers the package for each mData found recursively under the
<package> directory.
9-48
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
System Generation
9-49
ResourceBuild
Verifies the existence and ability to load all classes and serialized info objects
that are referenced in the registry files. 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.
9-50
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
9-51
9-52
10
Developing Client Logic
Topic
Page
10-1
Separating the presentation and the task logic provides several benefits:
Independence
Changes made to one of the components need not have a corresponding effect
on the other component. If the logic needed to implement a task is changed,
changing the model has no effect on the presentation. For example, suppose a
change is made so the results of a database query are returned as an array of
objects rather than a QueryResult. Because this change is contained in the
implementation of the task logic, the presentation can be reused without
modification. Similarly, changes made to the user interface of a client
application do not affect the implementation of the task logic.
Reuse
Multiple implementations of the presentation can be used with the same
implementation of the model. For example, suppose a developer wants to
create a user interface to support users with a keyboard but not a mouse. By
partitioning the client application, the developer need only create another user
interface to support keyboard input. The same model can be used for both
applications.
Extensibility
The model can be extended to support evolving business logic.
10-2
Presentation Logic
The presentation is the portion of the client application that implements its look
and feel and provides the mechanism through which the end user interacts with
the application. As a result of your GUI design process (the process used at
Windchill is described in Appendix E, GUI Design Process), you should have
identified how the application should look as well as some degree of how the user
interacts with the application.
When considering the layout of your application, consider how the application
will respond to resizing the window. Many visual development environments
provide a default layout that makes creating user interfaces very straightforward.
However, these default layouts often result in user interfaces in which the
locations of the various widgets are hard-coded. Consequently, these user
interfaces do not adjust appropriately when the window is resized.
Similarly, consider layout when you create applications that must be
internationalized. The layout must support the changes that result from changing
the locale of the application (for example, labels can become significantly longer,
text could use fonts that are larger, and so on).
Another issue you must be conscious of is that of programming with threads.
Event-handlers, which are invoked in response to the end user interacting with the
application, are often run in a separate thread, allowing the end user to continue
interacting with the application while the process is going on (printing, for
example).
Task Logic
The task logic implements the model. The model represents how the objects in the
application domain interact with each other to perform tasks, completely
independent of how the application looks or how the end user interacts with the
application. The objects and tasks are expected to have been identified as the
result of a design process (for example, the design process used to develop
Windchill applications is described in appendix E, GUI Design Process).
Implementing the task logic that has been defined involves three activities:
Providing an API (that is, a set of methods) that can be used by the
presentation portion of the application to retrieve information.
10-3
Client-side validation.
The following example shows how you can use a task scenario (a typical result
from a design process) to decide how to create the task logic.
The second sentence implies that the task will involve client-side validation of
certain pieces of data.
The third sentence implies that the task will involve communication with the
method server, which will ultimately result in the incident report being saved
in the database.
10-4
Client-Side Validation
The following example shows client-side validation. In this example, validation is
performed to ensure that the user has completed both the incident summary and
the incident detail. If the incident summary or incident detail is null or an empty
string, an InvalidAttributeException is thrown.
while( ( i < products.size() ) &&
( !found ) ) {
current_product = (Product) products.elementAt(i);
if( ( current_product.getName().equals( product_name ) ) &&
( current_product.getVersionLevel().equals( product_version ) ) &&
( current_product.getReleaseLevel().equals( product_release ) ) ) {
found = true;
}
i++;
} // End of while'Loop'
if( !found ) {
Object params[] = { curCustomer.getCompanyName(),
product_name, product_version, product_release };
throw new WTException( null, RESOURCE, "productNotFound", params );
}
if( ( inc_report.getIncidentSummary().equals("") ) &&
( inc_report.getIncidentDetail().equals("") ) ) {
throw new InvalidAttributeException( null, RESOURCE,
"nullIncSummaryAndDetails", null);
10-5
10-6
You can verify that the Windchill beans have been added to your component
library by viewing the contents of the library (select the Component Library
option in the View menu in Visual Cafe). You should see a folder named wtbeans.
Once the wtbeans folder is in your component library, you can open it, and drag
and drop the individual beans onto the GUI you are creating.
Package Dependencies
The Windchill beans are dependent on the following packages which must be
installed before using the beans:
symantec.itools.awt
Windchill/codebase
WTContentHolder Bean
The WTContentHolder bean (wt.clients.contentholder.WTContentHolder)
provides support for manipulating the content of objects that implement the
wt.content.ContentHolder interface. WTContentHolder is useful for creating user
interfaces to create, view, and update such content-holding objects. This bean
provides support for the following manipulations on a ContentHolder object:
Adding URLs.
Removing URLs.
Opening a URL.
10-7
Property List
Create: supports adding and removing files and URLs, getting files and
URLs, and viewing the properties of files and URLs.
1
Update: supports adding and removing files and URLs, updating files and
URLs, getting files and URLs, and viewing the properties of files and URLs.
2
View: supports getting files and URLs, and viewing the properties of files and
URLs.
Building the GUI is complete. What remains, then, is tying in the
WTContentHolder to the task logic of updating a Report. To be able to manipulate
files and URLs with the WTContentHolder, the WTContentHolder must be
initialized with an object that implements the ContentHolder interface. Further,
this ContentHolder object must be persistent.
10-8
Notice that after invoking setReport, both the UpdateReportFrame and the
WTContentHolder used within this frame have a reference to the ContentHolder
object. The UpdateReportFrame has a reference in its local variable report
and the WTContentHolder bean has a reference which is set in the call to
setContentHolder(report). With both the frame and the bean having different
references to the same ContentHolder object, the programmer of the frame must
take care to ensure that both references remain current. For example, if a content
change is made using the WTContentHolder, and the ContentHolder is updated,
the copy of the ContentHolder maintained by the UpdateReportFrame has become
out of date.
The WTContentHolder bean provides an API that helps guard against references
to the same object getting out of sync. In addition to having an API that directly
manipulates a ContentHolder object, the WTContentHolder also has an API that
manipulates a ContentHolder via a wt.clients.util.ReferenceHolder. By
manipulating a ReferenceHolder, both the UpdateReportFrame and the contained
WTContentHolder manipulate the same ContentHolder object:
public class UpdateReportFrame extends java.awt.Frame {
...
public void setReport( Report report ) {
if( report != null ) {
this.reportHandle = new ReportHandle( report );
try {
myWTContentHolder.setContentReference(
reportHandle );
} catch (WTPropertyVetoException wtpve) {
wtpve.printStackTrace();
}
}
}
...
10-9
Essentially, these are the only two actions needed to use the WTContentHolder
bean: adding the WTContentHolder to the parenting GUI screen, and initializing
the WTContentHolder with an appropriate ContentHolder object.
The WTContentHolder provides additional methods for enhancing the interaction
between the WTContentHolder and the container in which it exists. For example,
while the WTContentHolder bean provides a Save button which, when invoked,
causes all content changes to be saved, the WTContentHolder also provides a
method to programmatically save any content changes. Consider the Report
example. If the user clicks on the Cancel button in the UpdateReportFrame, and
changes to the content have been made that have not yet been saved, you may
want to prompt the user to save these changes:
public class UpdateReportFrame extends java.awt.Frame {
...
void cancelButton_Action(java.awt.event.ActionEvent event) {
// Check for unsaved content changes
if( myWTContentHolder.isDirty() ) {
if( promptUserToSaveChanges() ) {
try {
myWTContentHolder.persistContentChanges();
} catch (PropertyVetoException pve) {
pve.printStackTrace();
} catch (WTException wte) {
wte.printStackTrace();
}
}
}
setVisible( false );
}
...
} // End class UpdateReportFrame
10-10
For more details on using WTContentHolder, see the javadoc for the
wt.clients.beans.contentholder package.
WTExplorer Bean
The WTExplorer bean is an "Explorer" type browser for displaying items and
relationships.
The WTExplorer is a composite object which contains a tree view, a list view,
several status bars, and a splitter panel. Users can select nodes in the tree view and
display information about the node in the list view. Tree nodes can be expanded to
show structures.
Nodes can be created and added to the tree with objects which implement the
wt.clients.beans.explorer.Explorable interface. A sample adapter class,
wt.clients.beans.explorer.WTBusinessObject, is provided which implements the
Explorable interface and can be easily subclassed. The WTExplorer invokes the
getUses() method on the contained object to display its children in the tree view. It
invokes the getContents() method on the object to display its contents in the list
view.
API
The WTExplorer bean has a large number of attributes and methods. Methods are
provided to perform the following functions:
Sample Code
The following code sample shows an instance of the WTExplorer bean being
created and added to a component. The instance of the WTExplorer is initialized
with the specified font and color preferences, the desired column headings, the
methods to invoke on the contained objects, and the desired toolbar buttons.
10-11
wt.clients.beans.explORER.WTExplorer;
wt.clients.beans.explorer.WTExplorerEvent;
wt.clients.beans.explorer.WTExplorerListener;
wt.clients.beans.explorer.WTNode;
wt.clients.beans.explorer.Explorable;
GridBagLayout gridBagLayout;
gridBagLayout = new GridBagLayout();
setLayout(gridBagLayout);
setSize(730,423);
myExplorer = new wt.clients.beans.explorer.WTExplorer();
// Set the column headings in the list view.
try {
java.lang.String[] tempString = new java.lang.String[8];
tempString[0] = new java.lang.String("Number");
tempString[1] = new java.lang.String("Name");
tempString[2] = new java.lang.String("Version");
tempString[3] = new java.lang.String("View");
tempString[4] = new java.lang.String("Qty");
tempString[5] = new java.lang.String("Units");
tempString[6] = new java.lang.String("Type");
tempString[7] = new java.lang.String("State");
myExplorer.setListHeadings(tempString);
}
catch(java.beans.PropertyVetoException e) { }
myExplorer.setDisplayUsesAsContents(true);
// Set the fonts to use in the Explorer
myExplorer.setTreeFont(new java.awt.Font("Dialog",
java.awt.Font.PLAIN,11));
try {
myExplorer.setListHeadingFont(new java.awt.Font("Dialog",
java.awt.Font.PLAIN,11));
}
catch(java.beans.PropertyVetoException e) { }
// Set the column alignment in the list view.
try {
java.lang.String[] tempString = new java.lang.String[8];
tempString[0] = new java.lang.String("Left");
10-12
10-13
10-14
}
}
/**
* Handle double-click events from the WTExplorer. The
* "view" task for the selectedobject will be launched.
*
* @param e the WTExplorerEvent
*/
10-15
TaskDelegate delegate =
TaskDelegateFactory.instantiateTaskDelegate(
selected_obj );
if( delegate != null )
{
delegate.setParentApplet( getApplet() );
delegate.setParentFrame( getParentFrame() );
delegate.setObject( selected_obj );
try
{
delegate.launchUpdateTask();
}
catch (TaskDelegateException tde)
{
System.out.println(tde);
}
catch (WTException wte)
{
System.out.println(wte);
}
}
else
{
System.out.println("Could not instantiate Task
Delegate for " + selected_obj);
}
}
}
}
/**
* Process the "View" command.
*
*/
public void processViewCommand()
{
try
{
Object selected_obj = getSelectedObject();
if (selected_obj != null )
{
TaskDelegate delegate =
TaskDelegateFactory.instantiateTaskDelegate(
selected_obj );
if( delegate != null )
{
delegate.setParentApplet( getApplet() );
delegate.setParentFrame( getParentFrame() );
delegate.setObject( selected_obj );
delegate.launchViewTask();
}
else
{
System.out.println("Could not instantiate Task
Delegate for " + selected_obj);
10-16
}
}
}
catch (TaskDelegateException tde)
{
System.out.println(tde.getMessage());
}
catch (WTException wte)
{
System.out.println(wte);
}
}
/**
* Get the object currently selected in the explorer.
* If a list object is selected, use that object.
* Otherwise use the selected tree node.
*
* @return the selected object or null if no object is
* selected
*/
protected Object getSelectedObject()
{
Explorable busobj = null;
Object obj = null;
WTNode node = null;
// If a list object is selected, use that object.
// Otherwise, use the selected tree node.
busobj = myExplorer.getSelectedDetail();
if (busobj == null)
{
node = myExplorer.getSelectedNode();
if ( node != null)
{
busobj = node.getObj();
}
}
if (busobj == null )
{
return null;
}
return busobj.getObject();
}
public static void main(String[] args)
{
Frame f = new Frame("PartExplorer test");
PartExplorer exp = new PartExplorer();
f.setSize(700,700);
f.setLayout(new BorderLayout());
f.add("Center",exp);
f.show();
}
10-17
PartAttributesPanel Bean
Overview
PartAttributesPanel is a Java Bean component for manipulating
wt.clients.prodmgmt.PartItem objects. It is used in the Create, Update, and View
Part windows in the Product Information Manager client, and can be used by
developers who are customizing the Product Information Management
applications. The source code for the bean is contained in the
wt.clients.prodmgmt.PartAttributesPanel.java file.
The PartAttributesPanel bean contains properties to specify the class of the object
being manipulated and the attributes to be displayed. A label, maximum length,
and edit/view can be specified for each attribute.
The PartAttributesPanel bean dynamically constructs a user interface based on the
contained class and the specified information about the attributes. Boolean
attributes are represented as check boxes, enumerated types as choice lists, and
string and integer values are shown in text fields. The bean uses a grid-bag layout
to display the attributes in a tabular format. Labels will be displayed to the left of
each attribute. The layout has two attributes on each row. The labels have a grid
width of 1 and attribute elements normally have a grid width of 3 (TextAreas and
other large components will have a larger area). The attributes will be displayed in
the order they were specified in the attributes property for the bean.
After you modify values using the constructed user interface, the program can
invoke a method on the instance of the PartAttributesPanel bean to transfer the
modified values to the contained object.
API
The PartAttributesPanel bean contains methods to specify the following items:
10-18
The maximum length for each attribute. (This property is currently used only
to determine if a string should be displayed in a TextArea instead of a
TextField element.)
For more details on using the PartAttributesPanel bean, see the Javadoc for the
wt.clients.prodmgmt package.
Many properties of the PartAttributesPanel bean can be configured at
development time. The following figure shows the Property List displayed in
Visual Cafe for the PartAttributesPanel.
An array of String values specifying the attributes to display (such as, Name,
Number, and so on).
10-19
Labels
An array of String values specifying the labels for the attributes (such as,
Name:, Number:, and so on).
Edits
Form Designer
Sample Code
The following code demonstrates a possible use of this class:
Frame f = new Frame("AttributesPanel test");
PartAttributesPanel attributeBean = new PartAttributesPanel();
f.setSize(700,600);
f.setLayout(new BorderLayout());
try
{
// Set the class name of the object to be manipulated
attributeBean.setObjectClassName("wt.clients.prodmgmt.PartItem");
// Set the attributes to display in the panel
{
java.lang.String[] tempString = new java.lang.String[4];
tempString[0] = new java.lang.String("Number");
tempString[1] = new java.lang.String("Name");
tempString[2] = new java.lang.String("Source");
tempString[3] = new java.lang.String("Type");
attributeBean.setAttributes(tempString);
}
// Set the labels for the attributes
{
java.lang.String[] tempString = new java.lang.String[4];
tempString[0] = new java.lang.String("Number:");
tempString[1] = new java.lang.String("Name:");
tempString[2] = new java.lang.String("Source:");
tempString[3] = new java.lang.String("Type:");
10-20
attributeBean.setLabels(tempString);
}
// Make all the attributes editable
{
java.lang.String[] tempString = new java.lang.String[4];
tempString[0] = "true";
tempString[1] = "true";
tempString[2] = "true";
tempString[3] = "true";
attributeBean.setEdits(tempString);
}
}
catch ( WTPropertyVetoException wte)
{
wte.printStackTrace();
}
// Add the Bean to the panel
f.add("Center",attributeBean);
f.pack();
f.show();
WTQuery Bean
WTQuery provides a tool that allows you to include in your application the ability
to search for objects in the local Windchill database. WTQuery is comprised of an
optional title, a Tab panel containing an input area for search criteria, three
required buttons, three optional buttons, a check box indicating whether to append
to or replace the search results, and a list area for displaying search results.
The search results list area presents the results of the database query. The user can
clear this area by pressing the Clear button. A check box is available to the user
that determines whether to clear the list area between invocations of pressing the
Find button. By default, the list area allows multiple objects to be selected. To
restrict the list area to allow only single selection, use the setMultipleMode()
method. To obtain the list of selected objects, use either the getSelectedDetails()
or getSelectedDetail() method, depending on whether multiple or single selection
mode is in use.
The buttons are displayed in two columns. The required column contains the Find,
Stop, and Clear buttons. The optional column contains the OK, Close, and Help
buttons. By default, you get all six buttons. The functionality for the required
buttons and the Help button is handled by WTQuery (described later in this
section). The calling application can register a listener to be notified when the OK
or Close buttons are pressed. To register a listener, create a WTQueryListener
object and call the addListener() method using the WTQueryListener object as
input.
When creating a WTQuery object, you can specify a search filter string that is
passed to the method server when performing the database query. The search filter
is used to restrict the query. For more information about the possible values for
the search filter string, see the javadoc for wt.query.SearchTask.
10-21
A WTQuery object provides the ability to search for objects of a specified class. A
WTSchema object is used to configure what attributes and classes are available to
WTQuery. When calling WTQuery, you must specify a WTSchema object.
A WTSchema object stores the class name and attributes used by a WTQuery
object. You must create this object with a properly formatted string that contains a
fully qualified class name as well as attributes that will be displayed in the Tab
panel and results list area of the WTQuery object.
The format of the string used to create a WTSchema object is broken up into
records. A one-character code followed by a colon begins each record; a semicolon and space combination are used as a separator between records. The onecharacter codes are C, G, A and D:
C
Specifies a fully qualified class name to query on. This must be the first
record in the format string.
G
Specifies text for the search criteria tabs. All attributes that follow will be
grouped on that tab until the next G record.
A
Specifies an attribute used in both the search criteria Tab panel and the results
list area. Attributes are displayed in the order they appear in the string.
D
This string designates wt.doc.WTDocument as the class that will be queried. The
tab panel will contain two tabs labeled Search Criteria and More Search Criteria.
The Search Criteria tab will contain an input field for name. The More Search
Criteria tab will contain an input field for description. The results list area will be
set up with columns for name, versionIdentity, and description.
The following example shows how to add WTQuery to a panel:
Panel queryPanel;
try {
WTQuery myQuery = new WTQuery("My Query Panel",
SearchTask.ALL_VERSIONS, false);
myQuery.setSchema(new WTSchema("C:wt.doc.WTDocument; G:Search
Criteria; A:name; D:versionIdentifier; G:More Search
Criteria; A:description;"));
myQuery.setMultipleMode(false);
myQuery.setDialogButtonsVisible(false);
this.setLayout(new BorderLayout());
this.add("Center", myQuery);
myQuery.addListener(new WTQueryListener() {
10-22
WTChooser bean
WTChooser is a subclass of WTQuery. WTChooser provides a tool that allows
you to include in your application the ability to search for objects in the local
Windchill database.
The WTChooser bean is not currently included in the wtbeans.jar file but the API
for incorporating WTChooser into an application is available.
WTChooser is comprised of an optional title, a tab panel containing an input area
for search criteria, six buttons, a check box indicating whether to append to or
replace the search results, and a list area for displaying search results.
The WTChooser object provides the ability to search for objects of a specified
class. The ChooserOptions class is distributed as source code and is used to
configure the attributes and classes available to WTChooser.
The ChooserOptions object consists of strings that associate a fully-qualified class
name with attributes to be used for restricting the query and attributes to be
displayed in the results list area. When calling WTChooser, you must specify a
fully-qualified class name that is defined appropriately in the ChooserOptions
object.
The format string is broken up into records. A one-character code followed by a
colon begins each record; a semi-colon and space combination are used as a
separator between records. The one-character codes are C, G, A and D:
C
Specifies a fully-qualified class name to query on. This must be the first
record in the format string.
G
Specifies text for the search criteria tabs. All attributes that follow will be
grouped on that tab until the next G record.
A
Specifies an attribute used in both the search criteria Tab panel and the results
list area. Attributes are displayed in the order they appear in the string.
D
10-23
Find button. By default, the list area allows multiple objects to be selected. To
restrict the list area to allow only a single selection, use the setMultipleMode()
method. To obtain the list of selected objects, use either the getSelectedDetails()
or getSelectedDetail() method, depending on whether multiple or single selection
mode is in use.
The buttons are displayed in two columns. One column contains the Find, Stop,
and Clear buttons. The other contains the OK, Close, and Help buttons. For the
most part, the functionality for these buttons is handled by WTChooser. The
calling application can register a listener to be notified when the OK or Close
buttons are pressed. To register a listener, create a WTQueryListener object and
call the addListener() method using the WTQueryListener object as input.
The WTChooser panel can either be embedded in an existing frame or you can
instruct WTChooser to create a dialog window. If a dialog window is used, you
must specify a java.awt.Component as the parent. The dialog will be centered
over the parent.
The following example shows how to create a WTChooser in a dialog:
Frame frame = getParentFrame();
WTChooser chooser = new WTChooser("wt.part.WTPartMaster",
"Find Part", frame);
chooser.addListener ( new WTQueryListener() {
public void queryEvent(WTQueryEvent e)
{
if (e.getType().equals(WTQueryEvent.COMMAND ))
{
if (e.getCommand().equals(WTQuery.OkCMD) )
{
EnumeratedChoice Bean
Overview
The EnumeratedChoice bean is a simple extension of the java.awt.Choice class. It
allows you to specify a subclass of wt.fc.EnumeratedType. The display values of
the specified EnumeratedType subclass are used to populate the list of selectable
values.
API
The EnumeratedChoice bean contains methods to perform the following
operations:
10-24
For more details on using the EnumeratedChoice bean, see the Javadoc for the
wt.clients.util package.
Many properties of the EnumeratedChoice bean can be configured at development
time. The following figure shows the Property List displayed in Visual Cafe for
the EnumeratedChoice bean.
Initially, only an empty Choice will be displayed in the Visual Cafe environment.
To populate the list of possible values, the bean must have valid values for the
following property:
EnumeratedTypeClassName
10-25
Once the preceding property for the bean has been specified, the panel should
display a form with the specified attributes in the Visual Cafe environment. The
following figure shows what should appear in the form designer for an
EnumeratedChoice with the EnumeratedTypeClassName initialized to
wt.part.source.
Sample Code
The following code demonstrates a possible use of this class:
static public void main(String args[])
{
if (args.length == 0 )
{
System.out.println("supply enumeration class");
return;
}
String classname = args[0];
class DriverFrame extends java.awt.Frame
{
EnumeratedChoice choice = null;
public DriverFrame(String title)
{
super(title);
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent event)
{
dispose(); // free the system resources
System.exit(0); // close the application
}
});
setLayout(new java.awt.BorderLayout());
setSize(300,300);
choice = new EnumeratedChoice();
add(choice, "Center");
choice.addItemListener( new java.awt.event.ItemListener() {
public void itemStateChanged(ItemEvent ie)
{
EnumeratedType value = choice.getSelectedEnumeratedType();
System.out.println("Selected value is now " + value);
}
});
}
public void setClass(String name)
10-26
{
try {
choice.setEnumeratedTypeClassName(name);
}
catch(PropertyVetoException pve)
{
pve.printStackTrace();
}
}
}
DriverFrame df;
df = new DriverFrame("EnumeratedChoice Test");
df.setClass(classname);
df.show();
}
10-27
menu item. The user can browse the system to select other templates or projects if
desired.
The LifeCycleInfo panel could be used as shown in the following example:
import wt.clients.lifecycle.beans.LifeCycleInfo
.
. // Create a dialog or frame for adding a lifecycle info panel
.
// Create the LifeCycleInfo object and add to the dialog
LifeCycleInfo myLifeCycleInfo = new LifeCycleInfo();
myDialog.add( myLifeCycleInfo );
// Set the mode to create
lifeCycleInfo1.setMode( LifeCycleInfo.CREATE_MODE );
// Set the class of the object being created
lifeCycleInfo1.setClass( wt.doc.WTDocument.class );
myDialog.show();
.
. //create a LifeCycleManaged object
.
//myObject is the lifecycle managed object being created
myLifeCycleInfo.assign( myObject );
// Optionally at this point you could switch to view mode
myLifeCycleInfo.setMode( LifeCycleInfo.VIEW_MODE );
Spinner bean
The Spinner bean (wt.clients.prodmgmt.Spinner) is a subclass of the
symantec.itools.awt.util.spinner.Spinner class. It adds a new method,
addKeyListener(), to enable listeners to detect if users have modified the value in
the text field associated with the spinner. It also adds a new property,
CurrentDoubleValue, to allow the spinner to handle double values instead of
integer values.
For more information, see the javadoc in the symantec.itools.awt.util.spinner and
the wt.clients.prodmgmt packages.
WTMultiList bean
The WTMultiList bean (wt.clients.util.WTMultiList) is a subclass of the
symantec.itools.awt.MultiList class. It overrides several methods to improve the
display appearance of the bean on UNIX clients.
WTMultiList can also be configured to display attributes of modeled Windchill
business objects, such as Parts, Documents, and so on in a multicolumn list. When
taking advantage of this feature of WTMultiList, it is necessary to specify the
10-28
For more information, see the javadoc in the symantec.itools.awt and the
wt.clients.util packages.
AssociationsPanel bean
Overview
The AssociationsPanel bean (wt.clients.beans.AssociationsPanel) has a dev time
component and a runtime component. At dev time, you can drag this component
from the component library in Visual Caf and drop it onto a container. The
properties can also be edited by using Visual Cafs Property Editor. At runtime,
this class retrieves the links of the object and displays them in a multilist.
The bean has an Edit and View mode. In edit mode, the user can add new
relationships, remove existing relationships, and update existing relationships by
editing the attributes on the link. In view mode, the user can view the relationships
and view the attributes on the link. The bean keeps track of the create, update, and
removes operations, and is able to persist the changes when save() is invoked.
10-29
This bean contains a WTMultiList that displays the results of a navigate, add, or
remove. The user can select a row in the multilist and press a button to view that
object or remove that object. The user can press the Add button to search for a
new object to create a link to. Also, when the user selects a row, the attributes on
the link of that row are displayed in an AttributesForm. If the AttributesForm is
editable, the user can edit the attributes on the link in those fields.
API
The AssociationsPanel bean contains methods to specify the following items at
dev time:
otherSideSchema - The developer can use a GUI at dev time to set the
otherSideClassName and the otherSideAttributes.
linkClassName - The class name of the BinaryLink for creating new links.
linkSchema - The developer can use a GUI at dev time to set the linkClass
name and the linkAttributes.
mode - Edit or View. Edit will have Add and Remove buttons and the
attributes form is editable.
10-30
save(Persistable myObject) - Saves the new links for that object, deletes the
removed links, and updates the links that have been modified by the user.
10-31
10-32
EffectivityPanel Bean
Overview
The EffectivityPanel bean (wt.clients.beans.EffectivityPanel) is used to create,
update, or view effectivity for an EffectivityManageable object. It has dev time
and runtime usage. At dev time, you can drag and drop the bean from the
Component Library in Visual Cafe onto a frame, applet, or panel. Properties, such
as background and mode, can be set at dev time. At run time, the user can view the
effectivity for the effectivity manageable object, or set/update the effectivity.
10-33
API
The EffectivityPanel bean contains methods to specify the following items at dev
time:
The EffectivityPanel bean contains the following methods to be used at run time:
isDirty() - Tests whether the user has modified any of the fields.
10-34
FolderPanel Bean
Overview
The FolderPanel bean provides support for objects that implement the
wt.folder.FolderEntry interface. This bean supports assigning the folder of a new
object, changing the folder of an existing object, and viewing the folder of an
existing object.
When not in view-only mode, the FolderPanel bean contains a label, a text field
for entering the location of a folder, and a "Browse..." button that launches the
WTFolderBrowserDialog to allow the user to browse for a folder.
When in view-only mode, the FolderPanel bean contains a label and text that
displays the location.
API
The FolderPanel bean has APIs that support the following actions:
Setting the list of cabinets from which the user can choose a folder.
Restricting the list of cabinets from which the user can choose a folder to the
users personal cabinet.
Restricting the list of cabinets and folders from which the user can choose to
those for which the user has a given permission.
10-35
Sample Code
The following example illustrates using the FolderPanel bean in a GUI Frame to
create a document.
import wt.clients.beans.FolderPanel;
public class CreateDocumentFrame extends java.awt.Frame implements
java.beans.PropertyChangeListener {
// Default constructor for CreateDocumentFrame
public CreateDocumentFrame() {
...
//
//
//
//
//
//
//
10-36
AttributesForm Bean
Overview
The AttributesForm is a Java bean component for manipulating modeled
Windchill objects that implement the wt.fc.Persistable interface.
The AttributesForm bean contains properties to specify the class of the object
being manipulated and the attributes to be displayed. Alternatively, the schema
property of the bean can be set. The schema property specifies both the object
class name and the list of attributes to display for the class. Windchill
introspection mechanisms are then used to obtain information about each
attribute, including the display name, the maximum length, and whether the
attribute is required or updateable.
Setting the schema property in the Visual Caf environment at design time
launches a custom property editor that allows browsing a list of all possible
Windchill modeled classes that implement the wt.fc.Persistable interface. The
developer can graphically select the class name and the attributes to display in the
form.
The AttributesForm dynamically constructs a user interface based on the
contained class and the specified information about the attributes. Boolean
attributes are represented as checkboxes; Enumerated types are represented as
choice lists; strings are shown in text fields or text areas; and integer and decimal
values are shown in Spinners. The bean uses a grid-bag layout to display the
attributes in a tabular format. Labels will be displayed to the left of each attribute.
The layout has two attributes on each row. The labels have a grid width of 1;
attribute elements normally have a grid width of 3 (TextAreas and other large
components will have a larger area). The attributes will be displayed in the order
they were specified in the attributes property for the bean.
10-37
After a user modifies values using the constructed user interface, the program can
invoke a method on the instance of the AttributesForm bean to transfer the
modified values to the contained object.
The AttributesForm depends on a Factory mechanism to construct the
components for each data type. See the wt.clients.beans.selectors package for
details. The following data types for attributes are currently supported:
int
short
long
boolean
Integer
Double
Float
String
java.sql.Timestamp
java.sql.Date
java.util.Date
wt.fc.EnumeratedType
wt.vc.views.ViewReference
wt.project.ProjectReference
wt.lifecycle.LifeCycleState
wt.folder.FolderingInfo
wt.org.WTPrincipalReference
wt.part.Quantity
API
The AttributesForm bean contains methods to specify the following items:
10-38
For more details on using the AttributesForm, see the Javadoc for the
wt.clients.beans.AttributesForm class.
Package Dependencies
The bean is dependent on base classes from the Windchill packages. Ensure that
c:\ptc\Windchill\codebase is specified in the classpath for Visual Caf.
Visual Manipulation
Many properties of the AttributesForm can be configured at development time.
See the following diagram for the Property List displayed in Visual Caf for the
AttributesForm.
AttributesForm
Initially, only a blank panel will be displayed in the Visual Cafe environment. To
construct the user interface, the bean must have valid values for the following
properties:
ObjectClassName - the fully qualified class name of the object (such as,
wt.part.WTPart)
10-39
10-40
Once the preceding properties for the bean have been specified, the panel should
display a form with the specified attributes in the Visual Cafe. The following
diagram shows what should appear in the form designer:
Clicking on the schema property in Visual Caf will launch a custom property
editor to allow the developer to visually select the class of the object and the
attributes of the class to display in the form:
10-41
initialize the AttributesForm bean, use either the Schema Editor or set the
ObjectClassName and the Attributes properties; do not use both methods to
initialize the same bean instance.
The Schema Editor displays a Class Explorer which shows all the Windchill
classes and interfaces that implement the wt.fc.Persistable interface. Selecting a
class in the treeview on the left-hand side of the Schema Editor will show the
attributes for the class in the listview in the middle of the Schema Editor.
Selecting attributes by clicking on the listview causes the attributes to appear in
the list of selected attributes in the right-hand side of the Schema Editor. Multiple
attributes can be selected by using Shift-click or Control-click. Once the selected
attributes are shown in the list on the right-hand side, they can be reordered using
the toolbar buttons at the top of the Schema Editor. The button labeled "<<"
moves an attribute to the beginning of the list. The button labeled "<" moves an
attribute up one position in the list. The button labeled ">>" moves an attribute to
the end of the list. The button labeled ">" moves an attribute down one position in
the list.
Sample Code
The following code demonstrates a possible use of this class:
final Frame f = new Frame("AttributesPanel test");
AttributesForm attributeBean = new AttributesForm();
f.setSize(700,600);
f.setLayout(new BorderLayout());
f.addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent event)
{
f.dispose(); // free the system resources
System.exit(0); // close the application
}
});
try
{
attributeBean.setObjectClassName("wt.part.WTPart");
{
java.lang.String[] tempString = new java.lang.String[5];
tempString[0] = new java.lang.String("number");
tempString[1] = new java.lang.String("name");
tempString[2] = new java.lang.String("view");
tempString[3] = new java.lang.String("partType");
tempString[4] = new java.lang.String("projectId");
attributeBean.setAttributes(tempString);
}
{
java.lang.String[] tempString = new java.lang.String[5];
tempString[0] = "true";
tempString[1] = "true";
tempString[2] = "true";
tempString[3] = "true";
tempString[4] = "true";
10-42
attributeBean.setEdits(tempString);
}
}
catch ( WTPropertyVetoException wte)
{
wte.printStackTrace();
}
f.add("Center",attributeBean);
try
{
wt.part.WTPart part = wt.part.WTPart.newWTPart("airplane", "747");
part.setPartType(wt.part.PartType.toPartType("separable"));
wt.vc.views.View view = wt.vc.views.ViewHelper.service.getView(
"Engineering");
wt.vc.views.ViewHelper.assignToView(part, view);
attributeBean.setObject(part);
}
catch (wt.util.WTException wte)
{
wte.printStackTrace();
}
f.pack();
f.show();
ViewChoice Bean
Overview
The ViewChoice bean is a simple extension of the java.awt.Choice class. It allows
specifying an instance of wt.vc.views.View. The display values of the available
Views in the Windchill database are used to populate the list of selectable values.
API
The ViewChoice bean contains methods to perform the following operations:
For more details on using the ViewChoice bean, see the Javadoc for the
wt.clients.beans package.
Package Dependencies
The bean is dependent upon base classes from the Windchill packages. Ensure
that c:\ptc\Windchill\codebase is specified in the classpath for Visual Caf.
10-43
Visual Manipulation
Several properties of the ViewChoice bean can be configured at development
time. See the following diagram for the Property List for the ViewChoice bean
displayed in Visual Caf.
ViewChoice
At design time, the Choice will show with a single possible value, "View" in the
Visual Cafe development environment. At runtime, the choice will be populate
10-44
with the actual values for all the Views stored in the database. The following
diagram shows what should appear in the form designer for a ViewChoice:
Sample Code
The following code demonstrates a possible use of this class:
static public void main(String args[])
{
class DriverFrame extends java.awt.Frame
{
ViewChoice choice = null;
public DriverFrame(String title)
{
super(title);
addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(java.awt.event.WindowEvent event)
{
dispose(); // free the system resources
System.exit(0); // close the application
}
});
setLayout(new java.awt.BorderLayout());
setSize(300,300);
choice = new ViewChoice();
choice.setBlankChoiceAllowed(true);
add(choice, "Center");
choice.addItemListener( new java.awt.event.ItemListener() {
public void itemStateChanged(ItemEvent ie)
{
View value = choice.getSelectedView();
String viewname;
if ( value == null)
10-45
{
viewname = " none selected";
}
else
{
viewname = value.getName();
}
System.out.println("Selected value is now " + viewname);
}
});
}
}
DriverFrame df;
df = new DriverFrame("ViewChoice Test");
df.show();
}
PrincipalSelectionPanel Bean
Overview
The PrincipalSelectionPanel bean allows the user to select a WTPrincipal
(WTUser or WTGroup) by either entering the name of a WTPrincipal directly or
by browsing lists of the available WTGroups or WTUsers. The bean can also
simply display a WTPrincipal. This bean contains a label, a text field, and a
browse button when used for selecting a principal. When the browse button is
clicked, a dialog box opens that allows the user to browse a list or lists for a
desired principal.
The bean has a selection mode (DISPLAY_SELECTION_MODE) and a viewonly mode (DISPLAY_VIEW_ONLY_MODE). In selection mode, the user is
allowed to select a WTPrincipal either by directly entering the name or by
browsing for it. The following figure shows the PrincipalSelectionPanel bean in
selection mode.
10-46
API
The PrincipalSelectionPanel bean contains methods to specify the following items
at dev time:
displayMode - Allows the user to set the display mode for the panel
(DISPLAY_SELECTION_MODE or DISPLAY_VIEW_ONLY_MODE).
labelMode - Allows the user to toggle between whether the principal label is
visible or not (LABEL_VISIBLE_MODE or LABEL_INVISIBLE_MODE).
principalMode - Allows the user to set the principal selection mode for the
panel (PRINCIPAL_MODE, USER_MODE, or GROUP_MODE).
10-47
10-48
addPropertyChangeListener(PropertyChangeListener l) - Adds a
PropertyChangeListener to the panel to receive a PropertyChangeEvent when
a principal is selected.
Sample Code
Following is an example using the PrincipalSelectionPanel bean:
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import wt.clients.beans.PrincipalSelectionPanel;
import wt.help.*;
import wt.org.WTPrincipal;
import symantec.itools.awt.StatusBar;
public class PSPTestFrame extends Frame
{
public PSPTestFrame()
{
// This code is automatically generated by Visual Cafe
// when you add
// components to the visual environment. It instantiates
// and initializes
// the components. To modify the code, only use code syntax
// that matches
// what Visual Cafe can generate, or Visual Cafe may be unable
// to back
// parse your Java file into its visual environment.
//{{INIT_CONTROLS
GridBagLayout gridBagLayout;
gridBagLayout = new GridBagLayout();
setLayout(gridBagLayout);
setVisible(false);
setSize(497,211);
setBackground(new Color(12632256));
psp = new wt.clients.beans.PrincipalSelectionPanel();
psp.setBounds(0,0,495,143);
psp.setBackground(new Color(12632256));
GridBagConstraints gbc;
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1.0;
gbc.weighty = 1.0;
gbc.fill = GridBagConstraints.BOTH;
gbc.insets = new Insets(0,0,0,2);
((GridBagLayout)getLayout()).setConstraints(psp, gbc);
add(psp);
testButton = new java.awt.Button();
testButton.setLabel("Test Button");
testButton.setBounds(414,143,76,23);
testButton.setBackground(new Color(12632256));
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 1;
gbc.weightx = 1.0;
gbc.anchor = GridBagConstraints.EAST;
gbc.fill = GridBagConstraints.NONE;
gbc.insets = new Insets(0,0,5,7);
((GridBagLayout)getLayout()).setConstraints(testButton, gbc);
10-49
add(testButton);
statusBar = new symantec.itools.awt.StatusBar();
try {
statusBar.setBevelStyle(
symantec.itools.awt.StatusBar.BEVEL_LOWERED);
}
catch(java.beans.PropertyVetoException e) { }
statusBar.setBounds(0,171,147,40);
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 2;
gbc.weightx = 1.0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(0,0,0,0);
((GridBagLayout)getLayout()).setConstraints(statusBar, gbc);
add(statusBar);
setTitle("PSP Test Frame");
//}}
//{{INIT_MENUS
//}}
//{{REGISTER_LISTENERS
SymWindow aSymWindow = new SymWindow();
this.addWindowListener(aSymWindow);
SymAction lSymAction = new SymAction();
testButton.addActionListener(lSymAction);
//}}
psp.setPrincipalMode(PrincipalSelectionPanel.PRINCIPAL_MODE);
psp.setDisplayMode(PrincipalSelectionPanel.DISPLAY_SELECTION_
MODE);
psp.setLabelMode(PrincipalSelectionPanel.LABEL_VISIBLE_MODE);
psp.setBrowseButtonLabel("Custom Browse...");
psp.setPrincipalLabel("Custom Principal:");
HelpListener helpListener = new HelpListener();
psp.addHelpListener(helpListener);
}
public PSPTestFrame(String title)
{
this();
setTitle(title);
}
public void setVisible(boolean b)
{
if(b)
{
setLocation(50, 50);
}
super.setVisible(b);
}
static public void main(String args[])
{
(new PSPTestFrame()).setVisible(true);
10-50
}
public void addNotify()
{
Dimension d = getSize();
super.addNotify();
if (fComponentsAdjusted)
return;
setSize(insets().left + insets().right + d.width,
insets().top + insets().bottom + d.height);
Component components[] = getComponents();
for (int i = 0; i < components.length; i++)
{
Point p = components[i].getLocation();
p.translate(insets().left, insets().top);
components[i].setLocation(p);
}
fComponentsAdjusted = true;
}
boolean fComponentsAdjusted = false;
//{{DECLARE_CONTROLS
wt.clients.beans.PrincipalSelectionPanel psp;
java.awt.Button testButton;
symantec.itools.awt.StatusBar statusBar;
//}}
//{{DECLARE_MENUS
//}}
class SymWindow extends java.awt.event.WindowAdapter
{
public void windowClosing(java.awt.event.WindowEvent event)
{
Object object = event.getSource();
if (object == PSPTestFrame.this)
Frame1_WindowClosing(event);
}
}
void Frame1_WindowClosing(java.awt.event.WindowEvent event)
{
dispose(); // free the system resources
System.exit(0); // close the application
}
class HelpListener implements PropertyChangeListener
{
public void propertyChange(PropertyChangeEvent pce)
{
try
{
if (pce.getPropertyName().equals
(HelpContext.TOOL_DESCRIPTION))
{
try
10-51
{
statusBar.setStatusText((String)
pce.getNewValue());
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
catch (Exception e) {}
}
}
class SymAction implements java.awt.event.ActionListener
{
public void actionPerformed(java.awt.event.ActionEvent event)
{
Object object = event.getSource();
if (object == testButton)
testButton_ActionPerformed(event);
}
}
void testButton_ActionPerformed(java.awt.event.ActionEvent event)
{
WTPrincipal test = psp.getSelectedParticipant();
System.out.println(test);
}
}
PrincipalSelectionBrowser Bean
Overview
The PrincipalSelectionBrowser bean allows the user to select a WTPrincipal
(WTUser or WTGroup), an Actor, or a Role. This is done by selecting one of the
tabs on the left (Groups, Users, Actors, or Roles) and then selecting the desired
participants from the list displayed on the selected tab. This bean contains a tab
panel containing lists of the available participants, an Add button, an Add All
button, a Remove button, a Remove All button, and a list to display all the
selected participants.
The bean has a multiple selection flag. If the multiple selection flag is set to true,
the user can select multiple participants, and the buttons and selected participants
10-52
list are displayed. The following figure shows the PrincipalSelectionBrowser bean
in multiple selection mode.
If the multiple selection flag is set to false, the user can select only a single
participant and only the tabs are displayed. The following figure shows the
PrincipalSelectionBrowser bean in single selection mode.
The bean allows each of the four tabs to be made invisible. For example, if you
want to allow the user to browse for only users, then the groups, actors, and roles
tabs could be made invisible and only the users tab would be displayed.
10-53
API
The PrincipalSelectionBrowser bean contains methods to specify the following
items at development time:
Visibility flags - The following flags can be set to control the visibility of
tabs: groupSelectionTabVisible, userSelectionTabVisible,
actorSelectionTabVisible, and roleSelectionTabVisible. If a flag is set to true,
its corresponding tab is displayed; if it is set to false, the tab is not displayed.
Sample Code
Following is a small example using the PrincipalSelectionBrowser bean:
//// java imports
//import
import
import
import
java.awt.*;
java.beans.PropertyChangeListener;
java.beans.PropertyChangeEvent;
java.util.Vector;
//// wt imports
//import wt.clients.beans.PrincipalSelectionBrowser;
import wt.help.*;
10-54
10-55
}
catch(java.beans.PropertyVetoException e) { }
statusBar.setBounds(2,282,769,40);
gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 2;
gbc.weightx = 1.0;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.insets = new Insets(0,2,0,2);
((GridBagLayout)getLayout()).setConstraints(statusBar,
gbc);
add(statusBar);
setTitle("PSB Test Frame");
//}}
psb.setMultipleSelection(true);
psb.setGroupSelectionTabVisible(true);
psb.setUserSelectionTabVisible(true);
psb.setActorSelectionTabVisible(true);
psb.setRoleSelectionTabVisible(true);
HelpListener helpListener = new HelpListener();
psb.addHelpListener(helpListener);
//{{INIT_MENUS
//}}
//{{REGISTER_LISTENERS
SymWindow aSymWindow = new SymWindow();
this.addWindowListener(aSymWindow);
SymAction lSymAction = new SymAction();
TestButton.addActionListener(lSymAction);
//}}
}
public PSBTestFrame(String title)
{
this();
setTitle(title);
}
public void setVisible(boolean b)
{
if(b)
{
setLocation(50, 50);
}
super.setVisible(b);
}
static public void main(String args[])
{
(new PSBTestFrame()).setVisible(true);
}
public void addNotify()
{
Dimension d = getSize();
super.addNotify();
10-56
if (fComponentsAdjusted)
return;
setSize(insets().left + insets().right + d.width,
insets().top + insets().bottom + d.height);
Component components[] = getComponents();
for (int i = 0; i < components.length; i++)
{
Point p = components[i].getLocation();
p.translate(insets().left, insets().top);
components[i].setLocation(p);
}
fComponentsAdjusted = true;
}
boolean fComponentsAdjusted = false;
//{{DECLARE_CONTROLS
wt.clients.beans.PrincipalSelectionBrowser psb;
java.awt.Button TestButton;
symantec.itools.awt.StatusBar statusBar;
//}}
//{{DECLARE_MENUS
//}}
class SymWindow extends java.awt.event.WindowAdapter
{
public void windowClosing(java.awt.event.WindowEvent event)
{
Object object = event.getSource();
if (object == PSBTestFrame.this)
Frame1_WindowClosing(event);
}
}
void Frame1_WindowClosing(java.awt.event.WindowEvent event)
{
dispose(); // free the system resources
System.exit(0); // close the application
}
class HelpListener implements PropertyChangeListener
{
public void propertyChange(PropertyChangeEvent pce)
{
try
{
if (pce.getPropertyName().equals
(HelpContext.TOOL_DESCRIPTION))
{
try
{
statusBar.setStatusText((String)
pce.getNewValue());
}
catch (Exception e)
{
10-57
e.printStackTrace();
}
}
}
catch (Exception e) {}
}
}
class SymAction implements java.awt.event.ActionListener
{
public void actionPerformed(java.awt.event.ActionEvent
event)
{
Object object = event.getSource();
if (object == TestButton)
TestButton_ActionPerformed(event);
}
}
void TestButton_ActionPerformed(java.awt.event.ActionEvent
event)
{
Vector v = new Vector();
v = psb.getSelectedParticipants();
System.out.println(v);
}
}
Primary File
10-58
When Primary URL is selected in the dropdown menu, the Browse button is
disabled and the user directly types the URL into the text field.
Primary URL
To remove a primary content item, the user can either click the Remove Primary
button or delete the contents of the text field. The Remove Primary button will
become disabled and the text field will display a localized message of "No
Primary".
No Primary
For situations where only files are valid as primary content, the
ChooseFileOrURL dropdown can be hidden.
There is also a Get button which is typically hidden when this bean is used in the
Windchill client. If displayed, the Get button is disabled when Primary File is
selected and enabled when Primary URL is selected. Clicking the Get button will
launch a browser window displaying the URL.
API
The HTTPUploadDownloadPanel bean contains methods to get/set the following
items:
The target type (File or URL), target path, default filename (used by
FileLocator), mode, and hostURL values (get/setTarget, get/setTargetType,
get/setDefaultFilename, get/setMode, get/setHostURL).
Whether or not the applet containing the bean is embedded in an HTML page
which controls the applet via Javascript (is/setEmbeddedApplet).
Once the bean is displayed, there are also methods available to:
See whether the file path entered is valid on the local system (isValidTarget).
Determine whether the file on the local system is identical to the file in the
database (checksumsMatch).
10-59
Check whether the panel values are different than the persisted values
(isDirty).
Sample Ccode
See wt.clients.doc.CreateDocumentFrame for use of this class in the Java client.
The following code demonstrates a possible use of this class within an applet
embedded in an HTML page. Initializing the HTTPUploadDownloadPanel:
/**
* Upload mode indicator
*/
public static final int UPLOAD = HTTPUploadDownloadPanel.UPLOAD;
/**
* Download mode indicator.
*/
public static final int DOWNLOAD = HTTPUploadDownloadPanel.DOWNLOAD;
public void init()
{
... other applet initializing code ...
hTTPUploadDownloadPanel1 =
new wt.clients.util.http.HTTPUploadDownloadPanel();
hTTPUploadDownloadPanel1.setLayout(null);
hTTPUploadDownloadPanel1.setBounds(0,0,998,452);
hTTPUploadDownloadPanel1.setFont(new Font("Dialog", Font.PLAIN, 11));
// Note: elsewhere in this class is a two-argument getParameter method which uses
// the second argument as a default value if there is no parameter value for the
// key given as first argument.
// set panel color from parameter, otherwise default to grey
hTTPUploadDownloadPanel1.setBackground(new Color(Integer.parseInt
(getParameter
( "bgcolor", "12632256"))));
// hide getButton
hTTPUploadDownloadPanel1.setGetButtonVisible(false);
add(hTTPUploadDownloadPanel1);
//}}
// Initialize the panel.
hTTPUploadDownloadPanel1.init( this );
// Initialize from parameters.
if ( getParameter( "debug", "FALSE" ).equalsIgnoreCase( "TRUE" ) ) {
hTTPUploadDownloadPanel1.setDebugOption( true );
hTTPUploadDownloadPanel1.setDebug( true );
}
hTTPUploadDownloadPanel1.setRemovable
( getParameter( "removable", "false" ).equalsIgnoreCase("true"));
hTTPUploadDownloadPanel1.setHostURL ( getParameter( "hosturl", "" ));
hTTPUploadDownloadPanel1.setTargetType( getParameter( "type", "FILE" ));
10-60
10-61
Clipboard Support
Windchill clipboard support provides cut, copy, and paste functionality for
Windchill applications. It is located in the wt.clients.util package and modeled
after the classes in the awt.datatransfer package.
To gain access to a clipboard, use the wt.clients.util.WTClipboard.getClipboard()
method. This is a static method that returns an instance of
awt.datatransfer.Clipboard. All Windchill applets/applications loaded from the
same codebase have access to a common clipboard. The Clipboard class contains
setContents and getContents methods to set and get information to and from the
Clipboard. The objects that are placed on the clipboard must implement the
java.awt.datatransfer.Transferable interface.
A wt.clients.WTObjectSelection class implements both the Transferable interface
and ClipboardOwner interface. This class has two constructors that allow either a
WTObject or an array of WTObject as input. The type of data being transferred is
represented by the java.awt.datatransfer.DataFlavor class. A flavor named
WT_OBJECT_ARRAY_FLAVOR has been created for Windchill objects; it is
currently being statically stored in the WTClipboard class. The
WTObjectSelection provides access to Windchill data in three different flavors
(formats): WTClipboard.WT_OBJECT_ARRAY_FLAVOR,
DataFlavor.stringFlavor and DataFlavor.plainTextFlavor. The two standard data
flavors provide a Windchill object in the form of a URL to the properties page for
the object. If the array of WTObjects being maintained in the clipboard is greater
than 1, the URLs for each object are concatenated into one string separated by a
space.
10-62
if (clipboard_contents.isDataFlavorSupported
(WTClipboard.WT_OBJECT_ARRAY_FLAVOR))
wt_object_array = clipboard_contents.getTransferData
(WTClipboard.WT_OBJECT_ARRAY_FLAVOR);
10-63
certificate (see the following figure), the browser will trust code from this
package.
Because any applet code could potentially use this package to gain access to
privileged operations, another layer of security is maintained by the security
package. This allows the user to grant or deny usage of security.jar by codebase
(see the following figure). For example, code from www.widgets.com/windchill
may be granted by the user; an new applet from www.rogueapplets.com would
prompt the user to either grant or deny privileges to the given operation.
To load the security package, the applet tag must specify the location of the signed
code. Netscape loads signed classes specified in the ARCHIVE tag while Internet
Explorer loads signed classes specified by the CABINETS parameter. The
following tag will load the security package for either browser:
<applet code="mypkg/myapplet.class"
codebase="/windchill" archive="wt/security/security.jar">
10-64
The following tag can also be used with the bootstrap loader:
<applet code="wt/boot/BootstrapApplet.class"
codebase="/windchill" archive="wt/security/security.jar">
<param name="cabinets" value="wt/security/security.cab">
<param name="boot_jar" value="wt.jar">
<param name="boot_class" value="mypkg.myapplet">
</applet>
When the security package has been loaded, the applet may use the Access classes
to perform operations outside the sandbox. Currently, the security.jar package
provides FileAccess, NetAccess, PropAccess and RuntimeAccess. The basic
template for using these operations is as follows:
File input = new File(FILENAME);
FileAccess fa = FileAccess.getFileAccess();
FileInputStream fis = fa.getFileInputStream(input);
. . .
fa.delete(input);
Threading
The following example shows a way to create a frame and populate lists within it.
This example uses threading to process database events in parallel rather than
sequentially and, thus, populates the frame more quickly. Three threads are
started: one to get user attributes, one to get group membership, and one to get all
available groups. When all three threads complete, the frame is activated.
private static final int ALL_GROUPS = 3;
private static final int MY_GROUPS = 2;
private static final int ATTRIBUTES = 1;
class ActionThread implements java.lang.Runnable {
int action;
ActionThread(int action) {
this.action = action;
}
public void run() {
try {
switch (action) {
case ATTRIBUTES:
userAttributes();
break;
case MY_GROUPS:
populateBelongsToList();
break;
case ALL_GROUPS:
populateGroupList();
break;
}
threadStatus(true,"");
}
10-65
catch (Exception e) {
threadStatus(false,e.toString());
}
}
}
private
private
private
private
/** ...threadStatus
* threadStatus is used for tracking when all the threads
* used to create & populate the user frame have completed.
* When each thread is run, it calls threadStatus to report
* its completion status and any error message it captured.
* When all the threads have completed, if no errors occurred
* the frame is activated. If something failed a msgbox shows
* the captured err message, then the frame is destroyed.
**/
private void threadStatus(boolean my_status, String ErrMsg) {
threads_complete = threads_complete + 1;
thread_status = thread_status & my_status;
if (!my_status)
//Save any error information
thread_msg = thread_msg + ErrMsg + " ";
if (threads_complete == threads_needed) {
this.setCursor(Cursor.getDefaultCursor());
if (thread_status) {
//activate
this.setEnabled(true);
}
else {
//all threads are complete but someone failed
DiaMessage m = new DiaMessage(this,
this.getTitle(),true);
thread_msg = "Action failed. The following error
occurred: " + thread_msg;
m.show(thread_msg);
this.dispose();
}
} //end if (threads_complete)
}
public synchronized void show() {
this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
move(50, 50);
super.show();
//deactivate stuff
this.setEnabled(false);
threads_needed = 3;
protectID();
setTitle("Update User");
10-66
RefreshEvent
RefreshListener
RefreshService
10-67
10-68
Online Help
Windchill provides help classes that allow you to register an application with the
online help system and create keys that are associated with the online help that is
to be displayed. The following example links frames to help classes to provide
online help for those frames. For example, under the comment line:
//Add help topics
the line:
helpContext.addComponentHelp(btnUsers,"UserAdmin");
associates the key "UserAdmin" with the Users button. The resource bundle at the
end of the example, AdminHelpResources, links the key with the help that should
be displayed for that button.
//These packages are needed for online Help
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import wt.help.*;
//End of online help imports
10-69
10-70
//{{DECLARE_CONTROLS
.
.
.
//}}
//{{DECLARE_MENUS
//}}
}
package wt.clients.administrator;
import java.util.*;
import java.lang.*;
public class AdminHelpResources extends java.util.
ListResourceBundle
{
public Object getContents()[][]
{
return contents;
}
static final Object [][] contents = {
//Localize this
//-Administrator Defaults{"Contents/Administrator", "contents.html"},
{"Help/Administrator", "BethHelp.html"},
{"Tip/Administrator//UserAdmin", "Administer user accounts"},
{"Tip/Administrator//GroupAdmin", "Administer user groups"},
{"Tip/Administrator//DomainAdmin", "Administer domains"},
{"Tip/Administrator//NotifyAdmin", "Define notification policy"},
{"Tip/Administrator//AccessAdmin", "Define access control policy"},
{"Tip/Administrator//IndexAdmin", "Define indexing policy"},
//-User Administration{"Contents/Administrator/UserAdmin", "contents.html"},
{"Help/Administrator/UserAdmin", "FAQ.html"},
{"Desc/Administrator/UserAdmin", "User Admin default"},
{"Desc/Administrator/UserAdmin/Criteria", "Specify search criteria;
press F9 for more information"},
{"Desc/Administrator/UserAdmin/Search", "Initiate search"},
{"Desc/Administrator/UserAdmin/UserList", "Use Search to populate
list of user accounts; click on entry to select it"},
{"Desc/Administrator/UserAdmin/Create", "Create a new user
account"},
{"Desc/Administrator/UserAdmin/AddToGroup", "Update group
membership for selected user"},
{"Desc/Administrator/UserAdmin/Update", "Change attributes for
selected user"},
{"Desc/Administrator/UserAdmin/View", "Examine attributes for
selected user"},
{"Desc/Administrator/UserAdmin/Delete", "Delete selected user
entry"},
{"Desc/Administrator/UserAdmin/Close", "Close this window"},
}
10-71
Preferences
The Preferences Framework is based on the principal that a unique preference
consists of the following attributes:
Preference Key
Preference Macros
The wt.prefs.WTPreferences class defines the following types of Preference
Context Macros:
10-72
Example:
PrefEntry~fileOperationType~ASK~/wt/content
Getting Preferences
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
default value. In most cases you will want to remove the user-level preference and
not clear it, giving the user the upper hierarchal preference as their default.
10-73
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");
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).
Design Overview
The batch container package is generic and does not require the target objects to
be of any particular class. Within Windchill applications, batch containers are
generally used to batch groups of Persistable objects for server-side processing.
The batch container package provides no default server-side capability. The
developer must implement the service required for their particular purpose. The
10-74
External Interface
In addition to the types already mentioned, the container.batch package includes
the following types.
The RoleBatchContainer interface is a special purpose BatchContainer used to
accumulate associative assertions. In addition to the functionality provided by
type BatchContainer, the RoleBatchContainer carries information about the
10-75
association role being manipulated. This role information includes the association
name and the role name.
The BatchContainerFactoryIfc specifies a type that manufactures
BatchContainers and TransactionContainers.
The Assertion class is the abstract base class for assertions.
There are three specializations of the Assertion class: AddAssertion,
RemoveAssertion and ReplaceAssertion. These classes represent assertions for
adding, removing and modifying target objects.
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 is meant to replace the functionality provided by the
GatewayURL class. The GatewayURL class has several drawbacks including no
support for relative HREFs, as all values returned are in the form of an URL
which must be constructed and there is no support for remapping resources. As
well, in complex SPOC configurations the hostname of the Windchill server may
not be the hostname of the machine which sends the final page to the client, and
thus currently links generated through firewalls can only work if IP masquerading
and other techniques are used to fool the servers into redirecting the request
properly.
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.
10-76
10-77
before R6.0 is released. The mappings should be key/value pairs and following
the mapping schemes defined below.
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.
10-78
be in their decoded form and stored in the appropriate HashMap. Please see the
methods parseFormData or parseQueryString in the javadoc.
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"
<jsp:setProperty name="wtcontext" property="request"
value="<% [ ]=request% [ ]>"/> </jsp:useBean>
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>
10-79
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() % [ ]>">
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");
10-80
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();
10-81
Depending on the Request Context setup above, the correct HREF String will be
returned and inserted into the output page at compile time.
Forcing a Fully Qualified Link With a URLFactory that has a Non-null Request URI
A small caveat has been discovered with usage of the URLFactory. If the
developer wants 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. How can this be
achieved- The usage of the getHREF( ) methods that include the boolean switch
will do this by optionally setting the URLFactory into fullyqualifiedmode'forthedurationofthemethod.ThisallowsasingleHREFtobegenerated
withoutaffectingtherestoftheURLFactory.LikeallgetHREF()methodsthereareform
softhemethodswhichtakequerystringsandarguments'
<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.
10-82
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" ); %
[ ]>
Note: The response content type method must be called before any call to
request.getParameter() is made.
Note: To find out more about the EncodingConverter class, please refer to the
Windchill Javadoc.
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:
10-83
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(
request.getQueryString() );
// Retrieve the (already decoded) string
from the hash map
//
String tag = query_map.get("tag");
Deprecation of WTURLEncoder
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()
10-84
10-85
<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>
Resource bundle files are Java source files, so that a single misplaced curly
bracket, missing double quote or extra comma will cause a syntax error and
break the compile and integration process. RbInfo files have much simpler
format, it is easier to localize and more difficult to introduce syntax errors.
Because of the simpler format of the rbInfo files, it is easier to handle them
with localization tools; perform change tracking, change propagation and so
on.
It is more difficult to abuse the rbInfo file format and introduce tricky
resource types. Java resource bundles can hold any type of objects, but rbInfo
files can handle strings only. (This may appear to be a limitation, but it is not.
It makes localization easier.)
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.
10-86
(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 6.0, 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.
10-87
10-88
11
Internationalization and
Localization
Topic
Page
Background .......................................................................................................11-2
The Windchill Approach ...................................................................................11-2
Localizing Text Visible to the User ..................................................................11-4
11-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.
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.
11-2
Locale class
Each locale-sensitive object maintains its own locale-specific information.
The initial default for locale is specified in the system but users can specify a
preference in the Web browser.
Resource bundles
In a resource bundle, you define pairs of keys and values, where the values are
strings and other language-dependent objects for a specific locale. Within
code, you use the key to indicate where the corresponding string or object
should be inserted. For example, Windchill uses resource bundles in its online
help and to identify button names, field names, and other elements of graphic
user interfaces. The default or preferred locale specifies which resource
bundle to use and, therefore, determines which strings and objects to display.
(An example is shown later in this chapter.)
Windchill uses a structured properties file format to manage much of the
localizable text. Unlike the java.util.PropertyResourceBundle properties files,
these resource info files are not used at runtime. They are more like
java.util.ListResourceBundle java files, where they are used to manage the
information, and runtime resource bundles are built from them. These
resource info files have a .rbInfo file extension. This format is required for
managing the localizable information for EnumeratedTypes and display
names for metadata, since these localizable resources are updated by
generation tools. The resource info format can be used for storing other
localizable text, but it is not mandatory.
Unicode
This is a 16-bit international character-encoding standard. A character
encoding is a numeric representation of alphanumeric and special text
characters. A multi-byte encoding is necessary to represent characters such as
those used in Asian countries. The intent of Unicode is to be able to represent
all written languages in the world today.
11-3
11-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"},
//{{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"));
11-5
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) {}
}
11-6
//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.
An example of resource bundles being used in online help is given in the
preceding chapter on developing client logic.
Each file must contain a header line that categorizes the file.
Each entry must exist on a single line, and the following escaped characters
are supported: \\, \n, \r, \t, \f, \".
11-7
Key cannot contain "#", since it is a comment character, but the character is
allowed in the value.
Resource Type
Source File
Run-Time File
Message Text
*RB.rbInfo
*Resource.rbInfo
*RB.class
*Resource.class
Modeled Metadata
(Display Names)
ModelRB.rbInfo
ModelRB.RB.ser
EnumertaedType Options
Definition
<EnumType>RB.rbInfo
<EnumType>RB.RB.ser
Message Text
The Message Text category most commonly contains error messages and labels
for user interface actions, but is the general category for any localizable text that
does not fall into one of the other categories. The Message Text files are
completely user maintained, while the maintenance of the entries in the other
three categories is automated via various generation tools. Since this category is
not maintained by automated tools, and since the resulting run-time bundle is the
same ListResourceBundle subclass that it would be if the information were stored
in a ListResourceBundle source code file, the use of .rbInfo file format is optional
for Message Text.
Note: The following sections describe the resource info files for Message Text.
The first line classifies the resource info and should never be changed. The values
of the second to lines can be changed by the owner of the package, if the file can
be customized, and/or the file is deprecated.
11-8
Description
<key>.value
<key>.constant
<key>.comment
<key>.argComment <n>
11-9
11-10
Resource Type
Documented
12
Import Export Framework
The Import Export Chapter describes the IX Framework and explains how to
customize and use it for various solutions.
Topic
Page
Overview ...........................................................................................................12-2
How to Write an IX Application .......................................................................12-2
Exporter Class ...................................................................................................12-4
Using the Exporter to Export Objects ...............................................................12-7
How Import Works............................................................................................12-8
Importer class ..................................................................................................12-11
Use Importer to import object from XML files...............................................12-13
Writing Export Handlers for the Export Process.............................................12-16
How to write Exp/Imp Handlers .....................................................................12-16
DTD Files ........................................................................................................12-18
How to Write Handlers for the Import Process...............................................12-21
How to Write a Class (Element) Import Handler............................................12-22
Navigating Through an Objects Structure with ObjectSet Application.........12-28
List of Existing Generators and Filters............................................................12-33
Examples .........................................................................................................12-33
Simple Export Handler Code: .........................................................................12-39
12-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.
12-2
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:
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.
12-3
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);
// -- init expActionTuner -applicationExportHandler
= _applicationExportHandler;
dtd
= targetDTD;
// -- init expActionTuner -expActionTuner = new ExportActionTuner (policyRuleFile);
}
(ApplicationDataob);
storeDocument
(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. Currently, there are two DTD
strings that are used in Windchill 6.2.2:
standard.dtd: DTD for Windchill 6.0
standard62.dtd: DTD for Windchill 6.2
12-4
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. (This
feature is available only from Windchill R6.2.2 and beyond).
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>
<tag>teamIdentity</tag>
<value>*</value>
<newValue>Change Team (/System)</newValue>
</COPY_AS>
</mappingRules>
</userSettings>
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
12-5
</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.
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl=http://www.w3.org/1999/XSL/Transform
version="1.0">
<xsl:template match='*'>
<xsl:apply-templates select='WTPart'/>
<xsl:apply-templates select='WTDocument'/>
</xsl:template>
<xsl:template match='WTPart'>
<ACTION>Checkout</ACTION>
</xsl:template>
<xsl:template match='WTDocument'>
<xsl:choose>
<xsl:when test="number='TESTDOC-1'">
<ACTION>Checkout</ACTION>
</xsl:when>
<xsl:otherwise>
<ACTION>Lock</ACTION>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
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);
12-6
12-7
Feed them to the importer one by one by calling the import process:
importer.doImport(IxbDocument Doc);
importer.finalizeImport();
12-8
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.
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.
12-9
Between <xsl:choose>, there can be many <xsl: when test ....> with different
criteria and different action names.
12-10
10. 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
_dtd,
String
_ruleFileName,
Boolean
_overrideConflicts,
Boolean
_validate
throws WTException
Parameters explanation:
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. Currently, there are two DTD strings that
are used in Windchill 6.2.2:
standard.dtd: DTD for Windchill 6.0
standard62.dtd: DTD for Windchill 6.2
ruleFileName: From windchill 6.2.6, 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
12-11
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>
12-12
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.
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);
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().
12-13
For Windchill 6.2.6, 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:
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.
12-14
12-15
For example:
<classExporter>
<class>wt.part.WTPart</class>
<dtd>standard62.dtd</dtd>
<targetTag>default</targetTag>
<handler>wt.ixb.handlers.forclasses.ExpImpForWTPart</handler>
</classExporter>
12-16
All handlers with the <dtd> tag standard.dtd are handlers for export object in
R6.0. All handlers with the <dtd> tag standard62.dtd are handlers for export
object in R6.2.
For example, to be able to export data in R6.0 legacy format, we have tags:
<classExporter>
<class>wt.part.WTPart</class>
<dtd>standard.dtd</dtd>
<targetTag>default</targetTag>
<handler>wt.ixb.handlers.forclasses.ExpImpForWTPart60</handler>
</classExporter>
and in Windchill\src\wt\ixb\registry\ixb\handlers\
core62.xml, there are tags:
<classExporter>
<class>wt.part.WTPartUsageLink</class>
<dtd>standard62.dtd</dtd>
<targetTag>default</targetTag>
<handler>
wt.ixb.handlers.forclasses.ExpImpForWTPartUsageLink
</handler>
</classExporter>
12-17
DTD Files
For backward compatible support, in the folder Windchill\src\wt\ixb\registry\ixb\
dtds, there are 2 folders:
standard.dtd contains DTD files for Windchill 6.0
standard62.dtd contains DTD files for Windchill
6.2
In each folders there is a file named coreobjects.dtd that is the DTD file for
all objects that will be exported/imported. For example, in the file
coreobjects.dtd in the folder standard.dtd, we can see the definition
for EPMDocument in R6.0:
<!ELEMENT EPMDocument (
ObjectID,
(ownerApplication , authoringApplication, description?) ,
(number, name ) , epmDocType , genericFamilyInstance? ,
(extentsValid , EPMBoxExtents)? ,
folderPath , versionInfo? , lifecycleInfo? , projectIdentity ,
contentItem*, iba* ) >
12-18
or
<classExporter>
<class>com.mycompany.MyObject</class>
<dtd>standard62.dtd</dtd>
12-19
<targetTag>default</targetTag>
<handler>wt.ixb.handlers.forclasses.ExpImpForMyObject</handler>
</classExporter>
After adding this, the export handler for class may call this method to have the
part attribute exported.
12-20
For example:
<elementImporter>
<tag>WTPart</tag>
<dtd>standard62.dtd</dtd>
<handler>wt.ixb.handlers.forclasses.ExpImpForWTPart</handler>
</elementImporter>
All handlers with the <dtd> tag standard.dtd are handlers for import
object in R6.0. All handlers with the <dtd> tag standard62.dtd are
handlers for import object in R6.2.
For example, to import parts from XML that came from R6.0, we have tags:
<elementImporter>
<tag>WTPart</tag>
<dtd>standard.dtd</dtd>
<handler>wt.ixb.handlers.forclasses.ExpImpForWTPart60</handler>
</elementImporter>
For R6.2 format we have tags:
<elementImporter>
<tag>WTPart</tag>
<dtd>standard62.dtd</dtd>
12-21
<handler>wt.ixb.handlers.forclasses.ExpImpForWTPart</handler>
</elementImporter>
It is possible that one handler can be used for import in both R6.0 and R6.2
formatted data. For example, in Windchill\codebase\registry\ixb\
handlers\core.xml, there are the following tags:
<elementImporter>
<tag>WTPartUsageLink</tag>
<dtd>standard.dtd</dtd>
<handler>
wt.ixb.handlers.forclasses.ExpImpForWTPartUsageLink
</handler>
</elementImporter>
In Windchill\codebase\registry\ixb\handlers\core62.xml, there
are the following tags:
<elementImporter>
<tag>WTPartUsageLink</tag>
<dtd>standard62.dtd</dtd>
<handler>
wt.ixb.handlers.forclasses.ExpImpForWTPartUsageLink
</handler>
</elementImporter>
formats.
The class IxbHandlersManager contains all methods to manipulate handlers.
12-22
Import handlers for non-versioned objects are quite straightforward, and any of
the following classes can be referred as example:
ExpImpForWTPartDescribeLink
ExpImpForWTPartReferenceLink
ExpImpForWTPartUsageLink
12-23
follows:
<elementImporter>
<tag>MyObject</tag>
<dtd>standard.dtd</dtd>
<handler>com.ptc.mypackage.ExpImpForMyObject</handler>
</ elementImporter >
or
<elementImporter>
<tag>MyObject</tag>
<dtd>standard62.dtd</dtd>
<handler>com.ptc.mypackage.ExpImpForMyObject</handler>
</ elementImporter >
For Windchill 6.2.6, import handlers for versioned objects dont have to
implement the method public Object storeObject () anymore. It is
implemented in the class ExpImpForVersionedObject.
12-24
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():From version 6.2.6, 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
or
<elementImporter>
<tag>MyObject</tag>
<dtd>standard62.dtd</dtd>
<handler>com.ptc.mypackage.ExpImpForMyObject</handler>
</ elementImporter >
12-25
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.
12-26
12-27
Generators are rules that are used by application to traverse through the
objects structure and get all of its objects to be exported, such as uses,
described by, reference, etc.
Combining these Generators and Filters together, the application that wants to
export object will be able to create a set of objects that will be exported based on
given top-level object.
will be displayed to the GUI for user selection. This helps to hide Generators that
you dont want the end-user to see. To hide such Generators, the XML files of
these Generators, should have the <display> tag set to false.
12-28
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>
12-29
</localizedString>
</localizedName>
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.
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, please 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>
12-30
<method>navigateFromWTPartToDescribeByDoc</method>
</byMethod>
</go>
</rule>
<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
instructs to navigate to the wt.part.WTPartDescribeLink by a navigate
method and from there using 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. Here 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>
12-31
12-32
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.
12-33
Generators list
String id
Description
Localized name
En (for GUI)
Parameters as
String
folderContent
productStructureNavi
gator
Product Structure
(built with active
Config Spec)
CAD Document
Structure (built with
active config spec)
Product Structure
with CAD documents
(built with active
Config Spec)
<class name:oid>,
like:
Document
productStructureNavi
gatorEPM
productStructureNavi
gatorWithEPM
singleDocument
wt.part.WTPart:1234
for the top-level
object. This object
must be instance of
WTPart
wt.epm.EPMDocume
nt:1234 for the toplevel object. This
object must be
instance of
EPMDocument
wt.part.WTPart:1234
for the top-level
object. This object
must be instance of
WTPart
wt.doc.WTDocument
:1234
Note: actually <class_name:oid> is object local id
12-34
Filters list
String id
Description
filterByTime
Parameters as
String
Filter based on
modification time
<timeFrom#timeTo>,
where timeFrom and
timeTo = null or
Timestamp.toString()
Without GUI:
IXBExpImpStatus status = IXBHelper.service.doExport(
boolean previewOnly,
String[ ] generatorIds,
String[ ] generatorParams,
String[ ] filterIds,
String[ ] filterParams,
IXBStreamer ruleFile,
boolean detailedLog,
String stDtd);
12-35
ObjectSetHelper.computeObjectSetForGivenGeneratorsAndFilters
(
generatorIds,
generatorParams,
filterIds,
filterParams);
12-36
Import Application
Without GUI:
IXBExpImpStatus status = IXBHelper.service.doImport(
IXBStreamer ruleFile,
IXBStreamer dataFile,
boolean overrideConflicts,
boolean isPreview,
boolean detailedLog,
String creatorName,
String stDtd);
12-37
overridden or not.
isPreview specifies whether the process should do real import, or check
Gets a list of XML files from the Jar file to be imported by calling
jar.getFileNamesByExtension ("xml");
12-38
Creates an instance of Importer, the class that does the import job.
importer.doImport(stream);
importer.doPreview(stream);
java.io.File;
java.io.PrintStream;
java.io.IOException;
java.io.InputStream;
java.io.FileOutputStream;
java.io.FileInputStream;
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;
12-39
targetDir = tmp_storeDir;
log = a_log;
}
public String storeContent (ApplicationData ob)
throws WTException{
String fileName = ob.getFileName();
String storeName = null;
try{
storeName = this.computeUniqueFileName(fileName);
Streamed sd = (Streamed)ob.getStreamData().getObject();
InputStream is = sd.retrieveStream();
jw.addEntry(is, storeName);
}
catch (IOException ioe){
throw new WTException(ioe);
}
return storeName;
}
public void storeDocument (IxbElement elem)
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, IxbHelper.STANDARD_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);
}
public void exportObjectContent (Object obj, Exporter exporter,
ContentItem item, String exportFileName)
throws WTException {
if (item instanceof ApplicationData) {
ApplicationData ad = (ApplicationData) item;
12-40
resultingJar)
throws WTException{
//init jar file
resJar = resultingJar;
try{
jw = new IXBJarWriter(resultingJar);
}
catch (IOException ioe){
throw new WTException(ioe);
}
12-41
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,
IxbHelper.STANDARD_DTD, clientSettingsElement, null, actionName );
}
else{
exporter = IxbHelper.newExporter (this,
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) {
if ( !(actionName != null &&
actionName.equals(wt.ixb.tuner.ExportActionHelper.NO_ACTION_CMD)
)){
trx.rollback();
}
12-42
trx = null;
}
}
try{
jw.finalizeJar();
}
catch(IOException ioe){
throw new WTException (ioe);
}
return resJar;
}
}
java.io.File;
java.io.PrintStream;
java.io.IOException;
java.io.InputStream;
java.io.FileOutputStream;
java.io.FileInputStream;
import java.util.HashSet;
import java.util.Set;
import java.util.Iterator;
import wt.pom.Transaction;
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;
12-43
12-44
boolean validate =
IxbHndHelper.getIxbProperty("import.parser.validate", false);
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);
12-45
12-46
13
Xconfmanager Utility
Page
13-1
associationRegistry.properties
classRegistry.properties
descendentRegistry.properties
modelRegistry.properties
The xconfmanager utility saves your changes in the site.xconf file and provides an
option to generate updated property files using the updates in the site.xconf file.
The site.xconf file contains the changes made to Windchill property files starting
with the installation and continuing with each use of the xconfmanager utility or
the System Configurator. The xconfmanager utility is located in the
<Windchill>/bin directory.
This chapter describes only the information and instructions necessary to modify
specific Windchill properties. A full description of the xconfmanger utility and
management of the Windchill property files is documented in the Windchill
System Administrators Guide in the Administering Runtime Services chapter.
Anyone with write access to the XCONF and property files under the Windchill
installation directory can successfully run the xconfmanager utility. The
xconfigmanger is executed from the command line from within a windchill shell
See About the windchill Command chapter for more information about the
windchill shell.
The syntax of xconfmanager command is as follows:
xconfmanager {-FhuwvV} {-r <product_root>} {-s <property_pair>
{-t <property_file>}} {--reset <property_names>}
{--undefine <property_names>} {-d <property_names>} {-p}
For the purposes of modifying Windchill properties, you will primarily use the set
(s), targeFile (t), and propagate (p) parameters.
13-2
set is used to define the property and new property value. See the Formatting
Property Value Guidelines section (below) for information about formatting
the <property_pair) value.
targetFile is used to specify the directory location of the property file. If the
file name or path contains spaces, you must enclose the <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.
propagate is used to propagate the changes made to the XCONF files into the
property file being modified in order to keep the XCONF and the property
files in synch with one another.
To display the current settings for a property, execute the following command
from the windchill shell:
xconfmanager -d <property_names>
On a UNIX system, you can use doubles quotes or you can escape the space
character with a backslash. For example, use the following:
-s wt.inf.container.SiteOrganization.name=ACME\ Corporation"
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 it is not interpreted by the shell or use backslash to escape the
dollar symbols. For example, use either of the following:
Xconfmanager Utility
13-3
-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
Other than escaping arguments so that the command line shell does not
misinterpret them, the values should not need to be escaped any further to be
compatible with XML or property file syntaxes. The xconfmanager escapes
property names and values automatically if necessary.
13-4
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).
Xconfmanager Utility
13-5
windchill Arguments:
Arguments (optional)
Description
- h, --help
-v, --[no]verbose
-w, --wthome=DIR
--java=JAVA_EXE
-cp, --classpath=PATH
Java classpath.
Default is the wt.java.classpath variable
value specified in the $WT_HOME/codebase/wt.properties file.
--javaargs=JAVAARGS
windchill Actions
13-6
Action
Description
shell
start
stop
status
version
Action
Description
properties
<resource>[,...][?key[&key2]...]
Displays the properties as seen by Windchill for the given resource with substitution, etc. 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]
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.
Xconfmanager Utility
13-7
13-8
A
Windchill User Authentication
Topic
Page
A-1
Each of these interfaces is described below. The wt.method package contains the
Windchill method server application main class, and it owns the basic client-toserver calling mechanism. The wt.auth package builds on the basic framework
provided by the wt.method package to add more authentication specific support
classes.
wt.method.MethodAuthenticator
The Windchill method servers provide a dynamic method invocation interface
that is accessed through a non remote class called
wt.method.RemoteMethodServer. This class exposes an invoke method but
encapsulates the details of accessing a remote method server. It hides the actual
RMI operations in order to add network failure recovery and authentication
support. The invocation target and all the call arguments are passed in an
argument container class called wt.method.MethodArgs. This argument container
contains a field for arbitrary authentication information.
The basic method invocation framework does nothing with this field. Instead, it
allows for an arbitrary server-supplied object (a wt.method.MethodAuthenticator)
to endorse outgoing calls. This object can set the extra field or wrapper the entire
wt.method.MethodArgs object such that deserialization on the server-side actually
initializes the extra field. The requirement is simply that when argument
deserialization is complete, a server-side authenticator object can use the
credentials in this extra field to reliably determine the callers user name.
The client receives a wt.method.MethodAuthenticator object inside a special
Throwable, wt.method.AuthenticationException, sent from the server when
authentication is required. The client automatically handles this exception by
initializing the received wt.method.MethodAuthenticator and using it to endorse a
retry of the failed call. Once installed, it continues to endorse all calls from that
client.
The wt.method.MethodAuthenticator interface consists of the following methods:
A-2
wt.auth.AuthenticationHandler
The method server does not hard-code what authentication scheme will be used to
securely and reliably determine user names. Instead, the wt.auth package supports
a configuration property, wt.auth.handlers, that specifies a list of classes that
implement an authentication handler interface, wt.auth.AuthenticationHandler.
The class wt.auth.Authentication is responsible for making the clients
authenticated user name available for the higher-level application layers to take
advantage of. It has a static method called getUserName that is used to access the
authenticated user name for the current thread. If the client call being processed
by the current thread did not pass any authentication information, it asks the first
A-3
wt.auth.Authenticator
In order to keep the initial (bootstrap) login authentication separate from
subsequent per-call authentication, a third interface, wt.auth.Authenticator, and
another configurable property, wt.auth.authenticator, are used to validate
endorsed calls. This allows several login techniques to share the same per-call
endorsement technique and allow them to be developed independently.
When a bootstrapping authenticator has determined the authenticated user name
of a client, the bootstrapping authenticator can be replaced by one returned by the
wt.auth.Authentication classs newMethodAuthenticator method. This method
A-4
A-5
contains a set of classes that work within the preceding framework to perform user
authentication based on HTTP Authentication.
Windchill applications are intended to be Web-based, and the Web infrastructure
already has standards to support user authentication between browsers and Web
servers. Applications deployed on the Web should be able to leverage the existing
user authentication infrastructure provided by browsers and Web servers,
allowing it to be shared across multiple Web-based applications, as well as other
resources accessed via the same Web servers.
Outsourcing user authentication to an interaction between the browser and Web
server allows sites more flexibility in administering user authentication because
they are no longer limited to solutions provided directly by Windchill. For
example, one site might deploy Windchill using Netscape Enterprise server in
conjunction with a central enterprise Certificate Server and Directory Server that
manages users. Such a configuration can support enterprise-wide, digital
certificate-based user authentication shared by all Web applications, not just
Windchill.
Another site might choose to use Microsofts Internet Information Server
combined with Windows NT Domain controllers to let users running Internet
Explorer authenticate transparently using NT Challenge/Response authentication.
Such a site achieves single sign-on support for their NT users using the same
Windchill software as the Netscape site.
The Windchill user authentication framework is used to accomplish user
authentication while allowing the actual HTTP authentication to be carried out
between the browser and Web server by implementing objects that satisfy the
interfaces expected by the Windchill framework as described next:
A-6
wt.session.SimpleSessionAuthenticator implements
wt.auth.MethodAuthenticator
The wt.session.SimpleSessionAuthenticator uses a unique session ID to
endorse each call.
Null Authentication
The wt.auth.NullAuthentication class, another authentication handler provided in
the Windchill base product class allows standalone applications running on the
same host as the Windchill method server to authenticate using their user.name
Java system property. It can be used to allow standalone administrative
applications, such as install/load tools, to execute even if the built-in
authentication schemes supported by the wt.httpgw.HTTPLogin class are not
sufficient for the local Web server environment.
It checks against the clients IP address to determine if it is a local client. If so, it
sends a wt.auth.NullLogin object to the client which accesses the user.name Java
system property. It will not access the Java system properties if a security
manager is in effect. In other words, it does not try to authenticate browser-based
clients, even if they are running on the local host. It is intended only to
authenticate stand-alone administrative applications.
A-7
A-8
B
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
B-1
B-2
B-3
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-
B-4
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.
The ServiceException abstraction provides a common definition of an exceptional
condition that may occur as a result of abnormal behavior in the service. This
B-5
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.
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
B-6
B-7
B-8
C
Advanced Query Capabilities
QuerySpec
The QuerySpec contains the following attributes and APIs for building complex
query expressions.
C-1
with zero or more classes in the From clause. See the following table to determine
the size of the a_fromIndices array based on the type of ColumnExpression. For
example, a single ClassAttribute would require one from index. A SQLFunction
with two ClassAttribute arguments and a ConstantExpression argument would
require two from indices. If no fromIndices are required, a null value can be
passed as the argument. The selectOnly parameter controls whether the column
expression should be returned as a result object. If true, the column expression is
included only in the select and is not returned as a result.
The ColumnExpression parameter specifies the query column to append to the
select clause. The following are concrete ColumnExpression implementations:
Column Expression
Description
ClassAttribute
SQLFunction
ConstantExpression
KeywordExpression
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
C-2
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 appendix), 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.
ClassViewExpression
SubSelectExpression
ExternalTableExpression
C-3
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);
ExistsExpression
CompositeWhereExpression
NegatedExpression
C-4
wt.part.WTPartMaster.NAME);
wt.part.WTPartMaster.NAME);
wt.part.WTPartMaster.NUMBER);
wt.part.WTPartMaster.NUMBER);
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)));
C-5
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
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
C-6
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);
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
C-7
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.
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
C-8
ClassAttribute
SQLFunction
SubSelectExpression
ConstantExpression
KeywordExpression
RangeExpression
DateExpression
ArrayExpression
TableColumn
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
C-9
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
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 });
C-10
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.
CompoundQuerySpec compound = new CompoundQuerySpec();
compound.setSetOperator(SetOperator.UNION);
compound.addComponent(partSelect);
compound.addComponent(altSelect);
Sub-selects (wt.query.SubSelectExpression)
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);
C-11
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)
C-12
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,
wt.part.WTPart.NAME);
partName.setColumnAlias(sortName);
partQuery.appendSelect(partName, new int[] { classIndex }, false);
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
C-13
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);
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);
C-14
D
Evolvable Classes
Topic
Page
D-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.
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
D-2
The old ID and fields must be read (removed) from the stream.
Evolvable Classes
To calculate this version UID, the code generator uses the name of the
parent class, and the names and types of all the non-transient, persistent
fields.
D-3
First, check whether the code generated into the readVersion method looks
the same as the code that is preserved in readExternal. If so, you should turn
off preservation and just let it all be generated.
Set the Serializable property on the Windchill tab of the class specification in
Rose to Evolvable.
If the class was using something other than the generated version ID
number, you must change the read/write to use the
EXTERNALIZATION_VERSION_UID constant.
In addition, OLD_FORMAT_VERSION_UID should be ignored because
it is incorrect for your class. To read in instances externalized in the old
format, reference the version UID that was actually used.
You must also add support for the old ID to readOldVersion().
D-4
Evolvable Classes
D-5
D-6
return success;
//##end readOldVersion% [ ]readOldVersion.body
}
Evolvable Classes
D-7
D-8
E
GUI Design Process
This appendix describes the GUI design process used to create the user interface
of Windchill applications. Although you are not required to follow this process to
create applications with Windchill, we recommend that you use some formal
design method. Even if you have already started design, you can use this process
to validate your work.
Topic
Page
E-1
During this phase, you determine who the users of the system are and what they
need in order to perform their work. As you progress, continually validate your
decisions by using this information about your users.
Phase 2: Analyze Tasks
Develop storyboards
During this phase, you define user tasks at a high level and prioritize them. Do not
think about design at this point. If design issues arise naturally, record them and
go back to the high-level activities.
Phase 3: Design the GUI
The last three steps of this phase (designing, prototyping, and evaluating the GUI)
are iterative steps and are typically repeated at least twice.
E-2
The first steps in the GUI design process are to define the users and their
requirements. Profiles of the users and their requirements are used as input when
modeling user tasks and GUI objects. They are also used during the GUI
evaluation step to validate the prototype.
Task structure models and task object models can be used as input to each other.
Task structure models are used to identify objects within the tasks, and the
resulting objects can be used to validate the task structure models. Both are then
used as input to the GUI design step.
A highly desirable input to the GUI design is a UI style guide, which also
addresses internationalization concerns. Use (or develop) your own corporate
style guide, use one already written for the platform for which you are designing,
or use one of the many available commercially.
The last phase, actual development of the GUI, is an iterative process of designing
the GUI, developing a prototype, evaluating the prototype, and then redesigning
E-3
based on the evaluation. These steps overlap in that they are sometimes done in
parallel and may merge with each other.
2. Group the users into types based on their patterns of use and other relevant
characteristics.
3. Write user profiles including the information given earlier in the section.
4. Determine what percentage of the total user base each type of user represents.
E-4
As an example, assume a Help Desk has two types of users: customers and
product support analysts. Following is a typical user profile of customers:
Have a wide range of expertise with Windchill products, from first-time users
to infrequent users to "power" users.
A GUI designer might look at the fourth bullet, for example, and start to think of
designing a very simple GUI for novice users while building in shortcuts and
other accelerators for expert users.
E-5
The following tables show a subset of the user requirements for the customer user
type.
For incident reports
Requirement
Priority
High
High
Medium
Low
Priority
Medium
Medium
Low
Analyze Tasks
A task is a human activity that achieves a specific goal. Examples of tasks are:
creating a document, finding a file, generating a bill of materials, or updating user
information.
Modeling user tasks starts with very simple, brief descriptions of individual tasks
and evolves to detailed descriptions of how the user interacts with the system.
Modeling tasks involves the following steps:
E-6
Develop storyboards
What is the breadth of the use case- Does it encompass more than one
user requirement
How frequently will the task described by this use case be performedHow critical is it to users work-
4. Validate the completeness of your set of use cases by going back to user
requirements.
Again, this example shows a subset of the use cases for the customer user type.
E-7
Use Case
Priority
General
Log on to Help Desk via Web
High
Incident Reports
Create an incident report via the Web
High
Medium
Low
Product Information
Make inquiry about a product
Medium
Print answers
Low
Every user requirement previously defined should be accounted for in the use
cases (although this slide is a subset and may not show every entry actually in the
use cases).
User requirements, however, do not have to map to use cases one-to-one. For
example, the two user requirements shown earlier:
E-8
influence your model. If issues come up, you can note them for future discussion,
but continue identifying high-level activities.
The process for modeling a task structure is as follows:
1. Determine which use cases are critical and should be carried forward in 4 to 8
task structure models.
2. Analyze each task into a sequence of subtasks, each with a well-defined
endpoint. Determine whether there are any dependencies among the subtasks.
3. Develop the task diagram. Decompose subtasks only to the level of logical
actions on objects in the system (for example, find a document or create a
user). Do not model details of the user interface.
4. Enrich the task structure model by considering contingencies. For example,
what happens if the user makes an error- What happens if information is
missing- Are there alternative actions- Does the task ever vary5. Validate the task structure model by getting feedback from users or domain
experts other than those who provided the input. Observe task scenarios being
performed and ensure that they map onto the task structure model. Consider
the following questions:
Is the set of task models complete- That is, have all significant user
activities been modeled-
Do the models account for errors, alternative actions, task variants, and
other contingencies-
E-9
You can model tasks in several different ways. The following figure shows an
interaction sequence model.
E-10
to interact. As a very simple example, a use case of "Create a file" could become a
scenario of "Pat wants to create a file named data1."
The purpose of task scenarios is to describe the situation or context for a task,
including the business context, the current state of the system, and values for any
user input. They also describe how a user performs the task in this scenario in
terms of a sequence of user actions. In this sense, a task scenario represents an
abstract interaction design: specific in terms of the interactions but abstract in
terms of the actual user interface. It defines how the user interacts with objects in
the system without referring to the design of the user interface.
You use information about the frequency of actions to identify how and how often
users need to navigate from one interface element to another, from one screen to
another, or from one application to another. You can use information about the
sequence of actions as input to design decisions about the order of a set of screens,
or even the layout of a set of controls, where the layout is affected by the sequence
of actions.
The process to develop task scenarios is as follows:
1. Choose which task structure models to develop as scenarios. Typically you
develop 4 to 8 scenarios. Choose those that have the highest priority,
represent the greatest breadth of user requirements, and are the most critical
and frequently used.
2. Make the task structure models more complete and realistic by adding dummy
data, such as user names and specific values.
3. Include interaction sequences; that is, add user actions and system responses.
4. Account for contingencies, such as incomplete information or an error by the
user.
This process may seem similar to modeling task structure but includes specific
values and real-world situations. If, in the interest of time, only one can be done,
task scenarios are usually preferable.
The following is an example of a task scenario for creating an incident report.
Audrey Carmen is a senior software developer in the software development
group at Acme, Inc. After repeated attempts, she was still having trouble with
the new release of their debugger, ProgramPerfector 4.0, v2. She had run her
code through ProgramPerfector five times, and it still had bugs. She decided
to file an incident report. Although some developers in Audreys organization
run ProgramPerfector on Solaris, Audrey and her team run it on Windows
NT.
Audrey logs into the Help Desk, creates an incident report, enters all required
information, and submits the report. She notes the tracking number so she can
follow the status of her report.
As demonstrated in this example, a task scenario preserves the business context of
earlier steps and adds specific values for attributes. For example, the user in this
E-11
scenario has a name (Audrey Carmen), and she has encountered a problem that
will be submitted via an incident report.
Develop Storyboards
A storyboard is based on one or more task scenarios. It is a sequence of images,
usually drawn by hand on paper, that show interactions with the system and a
sequence of screens. For example, the first image may be the action "log on" and
the next image could be a screen labeled "Initial logon screen".
The sequence of screens conveys information about structure, functionality, and
navigation. This information can be used in developing prototypes and validating
user requirements.
Typically a storyboard is done in two columns with the images in the first column
and explanatory text in the second column. The following figure is an example of
E-12
Storyboard Example
E-13
A task object model models the business objects that users perceive when they
interact through the GUI. Task object modeling helps ensure that the system
behavior is understandable and intuitive to the user.
You can use the task structure models developed earlier as input to identify task
objects, and then use the task objects to validate the task structure models.
The process to design a GUI is as follows:
1. Assess whether you need a separate user model for every user profile. For
example, in a manufacturing environment, design engineers may be
concerned with part structures while suppliers might perceive the system to be
inventory. Both models can be represented in the UI.
2. Identify objects from discussions with users, the task structure models and
scenarios created earlier, and the data model (if available). Discuss the
following questions:
Do users need to see and interact with the object to perform their tasks or
should it be invisible to users-
Does the object group related information in a way that helps the user
perform a specific task-
3. List the potential task objects. Analyze the relationships among the objects,
and diagram the objects and relationships.
4. Define attributes for each of the task objects identified by determining what
information the user can know about the object.
5. Define actions performed by the task objects.
6. Create a matrix mapping objects to the possible actions that can be performed
on them.
7. Check for dynamic behavior by asking the following questions:
Can the actions be invalid depending on the prior state of the object-
Are there any constraints on the sequence in which the actions can occur-
8. Validate the task object model using methods similar to those used in
validating the task structure model.
E-14
The objects described in the model must be represented on the screen. Creating a
task object model helps you create objects that map directly to user tasks.
Creating a task object model is also an important step in streamlining the user
interface. Following the model will result in an interface that contains every
object needed to accomplish user tasks-and nothing more.
What layout should be used- (This refers to layout guidelines such as the
position of a company logo; it is not as fine-grained as designing the layout
you would use in an IDE.)
E-15
A style guide is very useful at this point. If you have a corporate style guide, use it
or consider developing one. Otherwise, use one of those written for the platform
on which you are designing.
Results of this step are window designs (including specification of interactive
behavior) and window navigation design.
E-16
Users feel much more comfortable suggesting changes if they do not feel you
have to change code, and you can mimic sequences in the system much more
easily. Show your prototype to users as often as possible without trying to make it
perfect. This allows you to go through many iterations and make constant
improvements and adjustments before creating real screens and including some
functionality in a high fidelity prototype.
During prototyping, consider the following questions:
How can the user perform the task scenarios using the GUI-
E-17
The following figure shows the high fidelity prototype that might result from this
iterative process.
E-18
How usable is the GUI by the end users, in terms of user requirements
previously specified-
Does the GUI provide adequate support to all types of users performing their
full range of tasks-
Following evaluation, use the results as input back into the GUI design and
prototype steps.
Use the following guidelines when designing a GUI:
Does the GUI provide adequate support to all types of users performing their
full range of tasks-
Provide frequent task closure. That is, provide feedback that a task has been
completed, for example in a status bar or popup message.
Design for recognition rather than recall. Actions and objects that can be
understood intuitively are preferable to those that must be learned.
Provide error messages that tell the user what went wrong and how to
recover.
Make the user feel sufficiently safe (that is, from catastrophic failures)
and confident to explore.
E-19
E-20
Index
A
Access control
Client-side, 10-64
Property, 1-9
Access control package, 6-4
Accessor methods
Overriding, 8-9
AssociationsPanel bean, 10-29
AttributesForm bean, 10-37
Authentication, A-1
B
Background queuing package, 6-50
Batch containers, 10-73
Batch scripts, 1-2
Bean
see Java beans
bin directory, 1-2
Business classes
Revision controlled business class, 5-6
Business data types
Implementing, 8-7
Business objects
Modeling, 3-1
Business services
Implementing, 8-12
C
cat files, 1-6
For sharing code, 1-6
checkAttribute method, 8-10
Class files, 1-4
Class path environment variable, 1-7
Classes
Document, 5-10
Folder resident business class, 5-4
Windchill Foundation classes, 3-10
Item, 3-10
Link, 3-11
Managed business class, 5-5
Part, 5-13
D
Database
Access set by properties, 1-10
db.properties.file, 1-10
Default table size, 1-10
Properties file, 1-2
Property file
See db.properties file
Index-1
db directory, 1-2
db.properties file
Database access properties, 1-10
General description, 1-8
wt.pom.dbPassword property, 1-11
wt.pom.dbUser property, 1-11
wt.pom.serviceName property, 1-11
Debug tracing, 1-9
debug.properties file
General description, 1-8
Development environment
Directory structure, 1-2
Environment variables, 1-7
Files, 1-2, 1-5
Property files, 1-8
Source code control, 1-6
Directory
bin, 1-2
codebase
Details of, 1-4
Location, 1-2
codebase/wt, 1-5
db, 1-2
docs, 1-2
loadFiles, 1-2
logs, 1-2
RoseExtensions, 1-2, 1-7
search, 1-2
src
Details of, 1-5
Location, 1-2
src/wt, 1-6
Structure after installation, 1-2
Doc package, 5-10
docs directory, 1-2
Document class, 5-10
Document package, 5-10
Domain administration package, 6-7
E
EffectivityPanel bean, 10-33
Enterprise package, 5-2
EnumeratedChoice bean, 10-24
Environment variables
Class path, 1-7
Rational Rose virtual path map, 1-7
SQL path, 1-7
Events
Managing, 8-3
Examples
Development process, 2-1
Index-2
F
Federation package, 6-21
Folder resident business class, 5-4
Foldering package, 6-24
FolderPanel bean, 10-35
Windchill Foundation classes
Definitions, 3-10
G
GUI
Design process, E-1
H
HTML files
Location of, 1-5
HTTP authentication, A-5
HTTPUploadDownloadPanel bean, 10-57
I
IDEs, 10-3
Indexing package, 6-34
Integrated development environment
See IDEs
Internationalization, 11-1
Item class, 3-10
J
Java beans
AssociationsPanel, 10-29
AttributesForm, 10-37
EffectivityPanel, 10-33
EnumeratedChoice, 10-24
FolderPanel, 10-35
HTTPUploadDownloadPanel bean, 10-57
PartAttributesPanel, 10-18
PrincipalSelectionBrowser, 10-51
PrincipalSelectionPanel, 10-46
Spinner, 10-28
ViewChoice, 10-43
WTChooser, 10-23
WTContentHolder, 10-7
WTExplorer, 10-11
WTMultiList, 10-28
WTQuery, 10-21
java.rmi.server.hostname property, 1-9
JSP
Life cycle
Assigning template, 10-27
Beans, 10-27
Life cycle management package, 6-36
Link class, 3-11
loadFiles directory, 1-2
Loading
Initial data, 1-2
Localization, 11-1
Location of required files, 1-5
Localizing
Text, 11-4
Locking package, 6-41
Logging
Default location for trace logs, 1-2
Enable/disable logging, 1-9
Trace messages
From method server, 1-9
From server manager, 1-9
logs directory, 1-2
Packages
Access control, 6-4
Background queuing, 6-50
Batch container, 10-73
Configuration specification, 6-73
Content handling, 6-8
Content replication, 6-14
Control units, 1-6
Doc, 5-10
Document, 5-10
Domain administration, 6-7
Enterprise, 5-2
Federation service, 6-21
Foldering service, 6-24
Indexing, 6-34
Life cycle management, 6-36
Location of, 1-5
Locking service, 6-41
Notification, 6-43
Organization, 6-46
Overview, 6-2
Ownership, 6-47
Part, 5-13
Query, 7-12
Session management, 6-57
Version control, 6-64
Work in progress, 6-84
Workflow, 6-87
Part class, 5-13
Part package, 5-13
PartAttributesPanel bean, 10-18
PATH environment variable, 1-7
Path environment variable, 1-7
Persistence
Management, 7-1
Manager, 7-2
Query, 7-12
Presentation logic, 10-3
PrincipalSelectionBrowser bean, 10-51
PrincipalSelectionPanel bean, 10-46
Project
Assigning, 10-27
Property files
db.properties file, 1-8
debug.properties file, 1-8
Editing, 1-8
service.properties file, 1-8
System Configurator, 1-8
tools.properties file, 1-8
wt.properties file, 1-8
M
Managed business class, 5-5
Manuals
Location, 1-2
mData files, 1-6
Location, 1-10
mdl files, 1-6
Method server
Logging trace messages, 1-9
Model files, 1-6
Modeling
Business objects, 3-1
N
Notification package, 6-43
Null authentication, A-7
O
Online help, 10-68
Oracle password property, 1-11
Oracle service name property, 1-11
Oracle user name property, 1-11
Organization package, 6-46
Ownership package, 6-47
Index-3
Q
QueryResult, 7-15
QuerySpec, 7-13
R
Rational Rose, 3-2
Virtual path map, 1-7
Windchill extensions, 1-2, 1-7
WT_EXTENSIONS entry, 1-7
WT_STD_PACKAGES entry, 1-7
WT_WORK entry, 1-7, 1-10
RB.java files
Location of, 1-5
Refreshing client data, 10-66
Resource bundles
Localizing, 11-4
Location of, 1-5
Online help, 10-68
Revision control, 5-6
Revision controlled business class, 5-6
Rose model components, 1-6
RoseExtensions directory, 1-2, 1-7
Runtime environment
Files, 1-2, 1-4
S
search directory, 1-2
SearchCondition, 7-14
Server logic
Overview of developing, 8-1
Server manager
Logging trace messages, 1-9
service.properties file
General description, 1-8
Services
Access control, 6-4
Background queuing, 6-50
Batch containers, 10-73
Configuration specification, 6-73
Content handling, 6-8
Content replication, 6-14
Domain administration, 6-7
Event management, 8-3
Federation, 6-21
Foldering, 6-24
Indexing, 6-34
Life cycle management, 6-36
Locking, 6-41
Managing, 8-2
Index-4
Notification, 6-43
Organization, 6-46
Overview, 6-1
Ownership, 6-47
Query, 7-12
Session management, 6-57
Version control, 6-64
Work in progress, 6-84
Workflow, 6-87
Session management package, 6-57
Sharing code, 1-6
Signed authentication, A-7
Simple business class, 5-2
Source code management, 1-6
Source files, 1-2, 1-5, 1-6
Spinner bean, 10-28
SQL path environment variable, 1-7
SQL scripts, 1-2
Location, 1-10
SQLPATH environment variable, 1-7
src directory, 1-2
Details of, 1-5
System generation
Overview, 9-1
Using, 9-41
T
Task logic, 10-3
Threading, 10-64
tools.properties file
General description, 1-8
Use by code generator, 1-10
wt.classRegistry.search.path property, 1-10
wt.classRegistry.search.pattern property, 1-10
wt.generation.bin.dir property, 1-10
wt.generation.source.dir property, 1-10
wt.generation.sql.dir property, 1-10
wt.generation.sql.xxxTablesSize property, 1-10
ToolsSetup.bat, 1-2
Trace logs
Default location, 1-2
Trace messages
Logging
From method server, 1-9
From server manager, 1-9
Training materials
Location, 1-2
Transactions, 7-16
U
User authentication, A-1
V
Validation
Client-side, 10-5
Verity Search, 1-2
Version control
Structuring, 6-80
Viewing, 6-82
Version control package, 6-64
ViewChoice bean, 10-43
Virtual path map
Rational Rose
Purpose, 1-7
WT_EXTENSIONS entry, 1-7
WT_STD_PACKAGES entry, 1-7
WT_WORK entry, 1-7, 1-10
W
Windchill extensions, 1-2
Work in progress package, 6-84
Workflow package, 6-87
wt directory
See also Packages
wt.access.enforce property, 1-9
wt.classRegistry.search.path property, 1-10
wt.classRegistry.search.pattern property, 1-10
wt.generation.bin.dir property, 1-10
wt.generation.source.dir property, 1-10
wt.generation.sql.dir property, 1-10
wt.generation.sql.xxxtablesSize property, 1-10
wt.home property, 1-8
wt.logs.enabled property, 1-9
wt.manager.verboseClient property, 1-9
wt.manager.verboseServer property, 1-9
wt.method.verboseClient property, 1-9
wt.method.verboseServer property, 1-9
wt.pom.dbPassword property, 1-11
wt.pom.dbUser property, 1-11
wt.pom.properties property, 1-10
wt.pom.serviceName property, 1-11
wt.properties file
Double back slashes in path names, 1-8
Format of path names, 1-8
General description, 1-8
java.rmi.server.hostname property, 1-9
wt.access.enforce property, 1-9
wt.home property, 1-8
Index-5