Merging Changes

Merging changes from one development environment into another is done by exporting the changes from the first (i.e., source) environment using ZOMExport and then importing these changed objects into the second (i.e., target) environment using ZOMImport. The import process compares the incoming objects from the source environment with the objects in the target environment. New objects are created in the target environment. Changed objects are reflected in the target environment, taking into account any existing objects and dependencies with other objects.

Returning to the master-slave development example, assume that Steve is to merge his changes into the master environment first. Also, assume Steve has ZOM configured with the default new keyword, “$new”, and the default changed keyword, “$changed”. These two keywords then identify all new and changed objects in his development environment. These are the objects to be merged into the master environment.

Note: There are several variations of how ZOMExport and ZOMImport can work together. This is the most basic.

Note: ZOMExport and ZOMImport always save/load definitions to/from a directory called port beneath the DB directory.

To merge, Steve performs the following steps:

  1. Extract the new and changed objects from the slave environment using the ZOMExport command and the new keyword and changed keyword:

ZOMExport + k $new,$changed

The “+k $new” selects all new objects, while the “+k $changed” selects all changed objects. These objects are exported in the normal manner by ZOMExport. Thus, in Steve’s case, the two forms he changed, fEmpl and fCorp, and the new form he created, fProj, are exported.

Now, Steve should remove the new and changed keywords. In this way, the next time, Steve exports only objects created or changed since the last time he exported.

ZOMSet +k $new,$changed ;k$new! ;k$changed!

  1. Move the files containing the exported objects to the master environment.

ZOMExport creates a series of files whose names are suffixed with “.z50”. To move the objects from Steve’s environment to the master environment, first delete any files with the “.z50” suffix from the master environment, then copy the “.z50” files from Steve’s directory to the master environment.

For example, if Steve is working with Windows, Novell, or MS-Net and his development environment is stored in the directory C:ZimAPPSTEVE and the master environment is store in the directory C:ZimAPPMASTER, then Steve would execute the following commands:

del c:zimappmasterport*.z50

copy c:zimappsteveport*.z50 c:zimappmasterport

Under similar circumstances in a UNIX environment, Steve would execute:

rm /zimapp/master/port/*.z50

cp /zimapp/steve/port/*.z50 /zimapp/master

  1. Import the objects from the slave environment into the master environment by invoke the ZOMImport command in the master environment:

ZOMImport

ZOMImport imports the objects from the files produced by ZOMExport. These objects are loaded into the Object Dictionary and created.

The process can be repeated for Carol.

If Steve and Carol have been working on different parts of the system, their changes merge into the master environment without conflict. If, on the other hand, there are conflicting changes, then some of Carol’s updates can overwrite Steve’s. If there is the potential for conflict, there are a number of ways to control or prevent trouble using ZOM. The most straightforward methods involve use of keywords and locks.

Note: The master-slave development scenario includes the situation where the master environment represents the current “production” application and the slave environments represent ongoing developments. This scenario also applies to single person projects as well.

Configuring ZOM for Team Development

When working on a team development project, you should first adjust the configuration of ZOM for each development environment so that objects from the various environments can be easily identified. The three configuration options of importance here are the environment code, the new keyword, and the changed keyword. You configure ZOM using the ZOMConfig command.

Each development environment should be assigned a unique ZOM environment code. This guarantees all objects are registered with object keys (i.e., ObjectKey property) that are unique across all development environments. In other words, no two objects are ever assigned the same object key even though they might have been created in different development environments.

For example, you could assign environment codes based on your initials, followed by a serial number: “NICK01”. When a developer creates a new environment, the serial number assigned in the environment code could be incremented (e.g., “NICK02”, “NICK03”, and so on.).

If you do not assign an environment code, ZOM generates a random environment code for you. The randomization is designed to make duplicate environment codes unlikely.

There are two other ZOM configuration options that are useful in team development projects. The new keyword option specifies a keyword that is automatically assigned to all newly registered objects. The changed keyword option specifies a keyword that is automatically assigned to all objects you change (e.g., re-create, rename, move, erase, delete, compile, and so on).

The new keyword and changed keyword give you a convenient way to keep track of which objects are new or changed in your environment. You can reset the value of these keywords at any time using the ZOMConfig command and easily remove them from your objects using the standard ZOM key-wording services.

For example, you assign the new keyword and changed keyword to “NewObjs” and “ChangedObjs”, respectively. You are then able to retrieve all new and changed objects in your environment using the keyword selection criteria:

ZOMList +k NewObjs

ZOMList +k ChangedObjs

If you would like to reset your environment so that no objects are flagged as new or changed, use the standard ZOM keywording services:

ZOMSet +k NewObjs ;k NewObjs!

ZOMSet +k ChangedObjs ;k ChangedObjs!

By default, ZOM is configured with the new keyword as “$new” and the changed keyword as “$changed”.

Registering an Object

For ZOM to know about an object, the object must first be registered. The registration process requires no effort on your part since registration is automatic and occurs when you use a ZOM service. Each ZOM service quickly searches for any unregistered objects and registers them in the knowledge base.

When an object is registered, it is assigned an object key that uniquely identifies it. The object key is used internally by ZOM to track the object during its lifetime, even if the object changes name or location. ZOM also uses the object key to track objects that are maintained at several separate development sites.

After registration, ZOM knows the object exists. However, at this point, ZOM knows very little about the object beyond its name, type, and object key. For ZOM to understand more about the object, you must “touch” the object.

Set-oriented Manipulation of Objects

The Zim object definition commands (e.g., CREATE, ERASE, RENAME) operate against a single object at a time. For example, an EntitySet is created using a CREATE command. If you needed to create all of the EntitySets, you need to issue a series of these commands.

ZOM, on the other hand, operates on sets of objects. ZOM enables you to select a set of objects from among the universe of objects in your application and apply an operation against that set of objects. For example, recreating all EntitySets is as simple as executing the command:

ZOMReCreate +t Ent

The “+t Ent” syntax is an example of the powerful selection criteria available for retrieving objects. In this case, “+t Ent” indicates that the Type of the object must be EntitySet. As you read in the following subsections, there are many other selection criteria, as well as operations for combining sets of objects in various ways.

Touching an Object

When you “touch” an object, ZOM performs an in-depth analysis of the object and records the resulting information in its knowledge base. Objects are “touched” using a special ZOM service, ZOMTouch. For example, the following command touches the Contracts object :

ZOMTouch Contracts

ZOMTouch determines the object’s current state and discovers any dependencies between the object and the other objects it references. The source of the dependency information is Zim’s standard dependency tracking database. Zim maintains dependency information for all objects and updates this information when an object is created or a program is parsed or compiled.

Once ZOMTouch has finished processing, ZOM has a complete picture of the object and any interdependencies with other objects. This in-depth information enriches ZOM’s knowledge base and is the foundation for the powerful object analysis and manipulation you can perform with other ZOM services.

As you make changes to your application objects, this information is updated automatically if you use ZOM services. As you edit the program code, the ZOM’s knowledge of dependencies between the program object (ie document) and the objects referenced in the program becomes out of date. To update the ZOM knowledge base, “tap” the changed document objects.

Note: For more information on Zim’s dependency tracking, see SET DEPENDENCY.

A Homogeneous View of Objects

Zim applications consist of collections of objects, each of which has a specific purpose and a set of features. These objects are described in the Object Dictionary. These various types of objects are

EntitySetsMenusRelationships
WindowsRolesSets
DocumentsVariablesForms
ConstantsDisplaysDirectories

The Object Dictionary is arranged such that all objects of the same type are grouped together. This is very convenient for working with objects of the same type, but dealing with objects in general is not so easy. A simple example illustrates this point. To see the descriptions of all EntitySets with names starting with ” Inv”, enter the following command:

list all Ents where EntName like " Inv%"

To see descriptions of all objects with names starting with ” Inv”, enter the following series of steps, one for each type of object:

list all Ents where EntName like " Inv%"
list all Rels where RelName like " Inv%"
list all Roles where RoleName like " Inv%"

and so on.

ZOM, on the other hand, treats all objects the same, regardless of type, and enables you to operate on them together. This homogenous view of objects enables, for example, all objects with names starting with ” Inv” to be retrieved in a single step:

ZOMList Inv*

ZOMList, which lists information about objects, is just one of the ZOM services. As you can see from this example, treating application objects homogeneously can lead to significant time savings and very powerful operations. ZOM provides extensive capabilities for selecting and manipulating objects that operate over the entire universe of application objects.

Note: ZOM does not deal with FormField and Field objects as independent objects, but instead works with the parent objects (e.g., Forms, EntitySets, Relationship, etc.).

Registered Object Properties

For each object registered, ZOM records several properties that identify the object and track the object’s state. Some of these properties are set automatically by ZOM, while others are designated manually by the user. These properties are then used by the ZOM services in processing objects and can be used by you to select the objects to process.

Identification Properties

The identification properties ZOM can use to identify an object are

ObjectKey

 

A globally unique identifier for the object

 

ObjectName

 

The name of the object

 

ObjectType

 

The type of the object

 

OwnerName

 

The name of the owning object

 

DirName

 

The name of the directory containing the object

 

Keywords

 

User-defined keywords that identify or classify the object

 

Status Properties

The status properties ZOM uses to record the state of an object are

Defined

 

Indicates if the object is described in the Object Dictionary

 

Exists

 

Indicates whether the object is created

 

Active

 

A user-designation indicating whether the object is available for processing by the ZOM services. Initially, the active property is set automatically for all objects.

 

Locked

 

A user-designation indicating the object’s definition cannot be changed using the ZOM services

 

Data

 

Indicates if the object can have data records (i.e., an EntitySet or relationship with fields)

 

DataSave

 

A user-designation indicating if an entity set or relationship object should preserve or discard its data records when the definition changes.

 

Selected

 

A user-designation indicating if the object is considered “selected” by the user according to some user-defined criteria.

 

Compilable

 

A user-designation indicating if a document object is a compilable program.

 

CompileStatus

 

Indicates if a compilable document object is compiled or needs to be recompiled.

 

Properties are set at different times and in different ways. The identification properties, with the exception of Keywords, are set initially by ZOM when an object is registered and maintained automatically by ZOM. Keywords are assigned to objects explicitly by the user. The status properties, with the exception of user-designated properties, are set by ZOM when an object is touched. These properties are also automatically updated by ZOM when a ZOM service changes the object’s state. The user-designated properties are explicitly set by the user.

Object Dependencies

Zim contains a number of fixed object types. The objects in any application depend on each other in various ways. These dependencies among objects form a network of interrelationships.

An EntitySet, for example, depends on its fields. If the definition of a field changes, then the definition of the EntitySet changes. A relationship object depends on the EntitySets that it is relating. A relationship object can also use constants, variables, and form fields, and so depend on those objects as well. A program can reference any object, including other programs. These references create dependencies between the program and the objects referenced.

ZOM tracks dependencies between objects. There are two basic kinds of dependencies:

  • Creation Dependency
  • Program Call Dependency

A Creation Dependency occurs when an object references another object in its definition (i.e., when the object is created).

A Program Call Dependency occurs when a document object references another object in its program code.

The diagram below shows the objects in a hypothetical application. The lines between objects illustrate dependencies between objects. This diagram is called the object dependency tree. Program that call dependencies are shown as solid black lines, while creation dependencies are shown as dotted lines.

The sample application represented here has four program objects: pMainMenu, pEditCust, pFindOrder, and pEditOrder. pEditCust and pFindOrder are called from pMainMenu. pEditOrder is called from pFindOrder. Each of these programs uses a different display object (whose names all start with “d”). The display objects, in turn, depend on form objects (whose names all start with “f”). As well, there are three EntitySets, Customers, Orders and Inventory, and two relationships, Place and Require, the latter with fields.

If we look at the object dOrder, we can see that dOrder depends on (i.e., uses) both fOrder and fFrame (via creation references). On the other hand, dOrder is depended on (i.e., used) by the program pFindOrder (via a program reference). The object fOrder depends on no other objects, but is depended on by dOrder and pFindOrder.

Example Object Dependency Tree

ZOM enables you to query the dependencies between objects and use this information to process dependent objects. You can also use this information to detect unreferenced objects that are not dependent on any other object.

There are two ways to query object dependencies:

  1. A Dependency Explosion finds the objects that depend on (i.e., use) a given object. Dependency explosion begins with an object and works up the dependency tree finding objects that use the given object. You can limit the explosion to one level up the tree (i.e., immediate ancestors) or recursively retrieve dependent objects all the way back to the root of the tree.
  2. A Dependency Implosion finds the objects that are depended on (i.e., used) by a given object. Dependency implosion begins with an object and works down the dependency tree finding objects that are used by the given object. You can limit the explosion to one level down the tree (i.e., immediate descendants) or recursively retrieve dependent objects all the way to the leaves of the tree.

The dependency information tracked by ZOM leads to some of the most powerful uses of the ZOM services in developing, maintaining, and analyzing your applications.

Unreferenced Objects

The object dependency information can also be used to select un-referenced objects that are not used by any other object. In our example, there are three un-referenced objects: pMainMenu, PlacedBy and vJunkVar. Un-referenced objects can be selected using the “u” selection criteria, as shown in the following example:

ZOMList +p u

Objects Found by Unreferenced Criteria “+p u”

Often, objects that are not referenced are no longer in use by the application and can be destroyed. This is not always the case as shown above where the unreferenced pMainMenu, which is the root of the dependency tree, is a very significant object to this application. Another object, the role PlacedBy, could have been created in the application as a convenience to users entering ad hoc queries.

Dependency Implosion

Dependency implosion is the process of finding the objects which depended on (i.e., used) by a given object, and so on down the dependency tree. There are three different kinds of implosion: immediate, creation, and program.

As an example, to list all of objects that are used by pMainMenu, enter

ZOMList pMainMenu +i

The result is the list of objects that are used by pMainMenu directly, regardless of whether the dependency is creation or program. The diagram below highlights the selected objects:

Objects Selected by “pMainMenu +i”

This selects only objects that are used by pMainMenu explicitly by means of a creation dependency or a program dependency. The objects that use these depended on objects are ignored.

Similar to dependency explosions, you can implode by either creation dependencies (using the ‘t’ option) or program dependencies (using the ‘p’ option). Now suppose we want to list only the objects that are used by pMainMenu by means of a program dependency:

ZOMList pMainMenu +i p

The diagram below highlights the selected objects:

Objects Selected by “pMainMenu +i p”

This selects only objects that are used by pMainMenu by means of a program dependency, as well as any objects that have program dependencies on these dependent objects, and so on all the way down to the leaves of the tree. Creation dependencies are ignored.

 Next suppose we want to list only the objects that are used by pMainMenu by means of either creation or program dependencies and recursively search all the way down to the leaves of the tree:

ZOMList Customers +i pt

The diagram below highlights the selected objects:

Objects Selected by “pMainMenu +i pt”

This selects objects that are used by Customers by means of any dependency, as well as any objects that have a dependency on these dependent objects, and so on all the way down to the leaves of the tree.

To list only the objects that are used by pMainMenu by means of either creation or program dependencies and recursively search all the way forward to the leaves, but not include the pMainMenu object, enter

ZOMList pMainMenu +i pth

The diagram below highlights the selected objects:

Objects Selected by “pMainMenu +i pth”

This selects only objects that are used by pMainMenu by means of any dependency, as well as any objects that are used by these dependent objects, and so on all the way down to the leaves of the tree, but not the set of objects that were used as the starting point of the implosion. This is called a hollow implosion.

In a hollow implosion, the selected object set does not contain the original objects that fed the implosion algorithm in the first place.

en_CAEnglish