Using the COP Java API

This chapter describes how to use the COP Java API to accomplish tasks required by the UI, including the following:

Click to jump to top of pageClick to jump to parent topicClientOperations

This is the primary class you will use. It includes methods for initializing a session, creating objects to represent user choices, submitting user choices to the Configurator Engine, getting back the results in the form of displayable information, and ending a session.

Note. Several ClientOperations methods, such as getDecisionPointNames, make a distinction between “public" decision points and “all" (public and private) decision points. The current version of the Configurator does not implement this distinction; all decision points are considered public.

Click to jump to top of pageClick to jump to parent topicMethods

The following methods are contained in the ClientOperations class:

void release() void initialize(Locale appLocale, String modelName, String modelVersion, String compileID, boolean needHtmlEncoding) void initialize(Locale appLocale, String modelName, String modelVersion, boolean needHtmlEncoding) Configuration getConfiguration() String[] getDecisionPointNames(boolean allObjects) String[] getNumericDataNames() String[] getExternVarNames() ControlData getControl(String objectName) ControlData getControlData(String objectName, String[] attributes, boolean sort, ItemFilter filter) ControlData getControlData(String objectName, String attribute, boolean sort, ItemFilter filter) NumericData getNumericData(String objectName) ExternVar getExternVar(String objectName) double getTotalPrice() void processChoices(Vector choices) Violation[] getViolations() boolean verifyConfiguration(Vector choices) boolean verifyConfiguration(Configuration config) DMChoice makeSelectedChoice(String dpName, String dmName, double qty) DMChoice makeEliminatedChoice(String dpName, String dmName) EVChoice makeExternVarChoice(String name, Collection values) String getModelVersion() String getModelCompileVersion() Locale getLocale() ffBaseBillOfMaterials getBOM() String[] getCompileVersions(String modelName, String modelVersion) String getModelName() String[] getModelNames() String[] getModelVersions(String modelName) int restore(Configuration config, Locale appLocale, boolean needHtmlEncoding, int policy) void setPricingData(Map dpNamesAndAttributes) String[] getIncompleteDecisionPointNames() String[] getViolatedConstraintNames() String[] getViolatedDecisionPointNames() Date getSolveDate() void setSolveDate(Date solveDate)

Click to jump to top of pageClick to jump to parent topicInitializing the COP

Before calling any other ClientOperations methods, you must attach the COP to a particular model to initialize your session. Do this by calling the ClientOperations methods initialize or restore. There are two different forms of initialize:

void initialize(Locale appLocale, String modelName, String modelVersion, boolean needHtmlEncoding) void initialize(Locale appLocale, String modelName, String modelVersion, String compileID, boolean needHtmlEncoding) void restore(Configuration config, Locale appLocale, boolean needHtmlEncoding, int policy)

Use the first form when you have a model name and version, and wish to use the most recently compiled version of the model. In this case, you simply call the first form of initialize with the indicated parameters.

The second form is used when there is, in addition to the model name and version, a specific compilation version (indicated by compileID) of the model that you wish to use. In this case, call the second form of initialize with the indicated parameters, including the compileID.

There is one form of restore. It is used when you wish to load a previously saved configuration when initializing the COP.

To load a previously saved configuration at initialization:

  1. Create a Configuration object.

  2. Call the Configuration object’s fromXML method to read the previously saved configuration from an input stream.

    (Alternatively, if the configuration has been stored in a format other than the Configurator’s standard XML format, it may be necessary to read the saved configuration, parse it, and set the Configuration object’s values directly by using its “set" methods - setModelName, setChoices, etc.)

  3. Call restore, with the Configuration object as the config parameter. The COP will then be attached to the model identified by the model name, version, and compileID found in the config parameter, with the previously saved configuration data restored.

In all cases, you must also provide an appLocale and needHtmlEncoding parameter. appLocale specifies the language that should be used for user-readable text. needHtmlEncoding specifies whether attribute data returned by the COP should be in HTML-encoded format. When using the restore method you must also provide a policy. parameter. policy specifies how to handle the retrieval of the model to attach to before loading the configuration.

Policy options are:

Option

Description

1

Use the model version stored in the Configuration object. Fail if that version is not found.

2

Use the model version stored in Configuration object. Use the latest version if that version is not found.

3

Always use the latest model version.

4

If multiple versions exist, ask which to use. If only one version exists, automatically use it. If no versions exist, fail.

With option 4, if multiple versions exist, the restore method returns a status code indicating that there are multiple versions. The methods getModelVersions and getCompileVersions could then be used to determine available model versions. When the desired version is found, call the setModelVersion and/or setModelCompileVersion on the Configuration object. Once these initial calls are made, you can use the Configuration object in a subsequent call to restore with the policy parameter set to 1.

Additionally, you can specify the solve date for the COP to use when processing choices by calling the setSolveDate method. This method takes a java.util.Date object as a parameter. The COP constructor defaults the solve date to the current date. An example of overriding the default date is restoring a previously saved configuration. You may want to use the date that the configuration was saved as the solve date rather than the current date.

Example (without using a previously saved configuration): there are values for the model name, model version, and compileID, but if the compileID is empty (null or of zero length), we’ll initialize without it.

ClientOperations cop = new ClientOperationsImpl(); String modelName, modelVersion, compileID; { //set modelName, modelVersion, compileID here - not COP code } try { if ((compileID == null) || (compileID.length() == 0)) { cop.initialize(Locale.getDefault(), modelName, modelVersion, false); compileID = cop.getModelCompileVersion(); } else { cop.initialize(Locale.getDefault(), modelName, modelVersion, compileID, false); } catch (Exception e) { System.out.println("Error: Unable to initialize COP - " + e); }

Click to jump to top of pageClick to jump to parent topicReleasing the COP

When you are done with your session, call release. This allows the system to dispose of cached resources associated with the session. After calling release, you will not be able to make ClientOperations calls without first calling initialize again.

Click to jump to top of pageClick to jump to parent topicProcessing and Displaying a Page

Processing and displaying a page is one of the most common tasks to accomplish using the COP Java API. It consists of several subtasks.

Circumstances that require you to process and display a page are:

To process and display a page:

  1. If you want delta-pricing information for one or more domain members and/or a total price for the configuration, call setPricingData if you are running the Configurator in stand-alone mode.

    If you are running the Configurator integrated with Order Capture, setup for pricing data is handled within the Configurator schema setup pages.

    See Establishing Pricing Options.

    If you don’t want delta-pricing information, skip this step.

  2. If the user has made domain member choices (which is usually the case, except for the initial page display), call makeSelectedChoice and makeEliminatedChoice to create one DMChoice object for each user choice or elimination.

    The COP does not indicate which domain members in the UI have been selected or eliminated by the user; you must examine the UI controls and tell the COP by passing Choice objects to processChoices - see Step 4.

  3. If the user has entered extern variable choices, call makeExternVarChoice to create one EVChoice object for each extern variable choice.

  4. Call processChoices. This step is mandatory.

    If there are user choices (domain member selections or eliminations, or extern variable choices), pass them to processChoices in a vector of Choice objects. This vector can contain both DMChoice objects and EVChoice objects, since both are subclasses of Choice.

    If there are no selections, pass null to processChoices.

    The Configurator Engine creates a solution state representing the choices and their implications—which domain members are user-selected, user-eliminated, computer-selected, computer-eliminated, and so on—and the COP generates any delta-pricing information you requested in Step 2. This information is cached by the COP until the next time you call processChoices (or release), and can be retrieved by calling getControlData (and other methods), as described in Step 5.

  5. For each decision point for which you need display information, call getControlData.

    This call will return a ControlData object representing that decision point. The ControlData object contains an array of ControlItem objects, representing the decision point’s domain members. Also, the ControlData method iterator can be called to obtain iterators (objects of type ItemIterator), which are used to access the ControlItem objects.

    When you call getControlData, you specify two parameters (sort and filter) that determine how you want domain members to be sorted and filtered. The ControlData object’s iterator(s) will return the ControlItem objects in sorted order and filtered as specified. (You can further control the sort order by supplying a custom Comparator routine. )

    See Sorting and Filtering.

  6. Using the ControlData and ControlItem classes, retrieve any display data you want: domain members (sorted and filtered as desired); their attribute values; and their states (such as user-selected and computer-eliminated).

  7. If you wish to display the values of any extern variables, call the getExternVar method.

  8. Render your page with the display information from Step 6 and Step 7.

    In addition to the methods of the ControlData and ControlItem classes, you can use the ClientOperations methods getTotalPrice, getViolations, and getNumericData, and the Configuration method getAttribute for other information you might wish to display.

Click to jump to top of pageClick to jump to parent topicGetting a ControlData Object

In Step 5 of the preceding instructions for processing and displaying a page, you get one ControlData object for each decision point for which you need display information (or for whose domain members for which you need display information). You do this by calling the getControlData method.

This section describes that method in more detail. There are two forms of getControlData:

ControlData getControlData(String objectName, String attribute, boolean sort, ItemFilter filter) ControlData getControlData(String objectName, String[] attributes, boolean sort, ItemFilter filter)

Use the first form when you are only interested in obtaining values for a single attribute (one value for each domain member of the decision point). Use the second form when you are interested in the values of multiple attributes.

The call returns a ControlData object, representing a decision point. The ControlData object includes an array of ControlItem objects, representing all the domain members of that decision point. You can also obtain one or more iterators (objects of type ItemIterator) from the ControlData object, which are used to access the ControlItem objects.

In many cases, you will want the domain members in the UI to be sorted in a particular way. The sort order can be either a standard one implemented by the COP (based on the domain members’ states and elimination levels), or a custom sort order based on a Comparator routine you supply.

See Sorting and Filtering.

You may also want some domain members to be filtered out, so they don’t appear in the UI at all. For example: filter out all eliminated domain members. Specify the sort and filter as parameters to the getControlData call. The ControlData object’s iterator(s) will return the ControlItem objects (domain members) in the requested sort order, and filter out (skips over) any domain members as specified.

Note. Although you can access the ControlItem array directly using the standard array methods, you will almost never want to. The array is neither sorted nor filtered by the COP. Use the ControlData object’s iterators; they will return the ControlItem objects in the correct sort order, and filter (skip over) any ControlItem outside the specified range.

The parameters to getControlData have the following meanings:

objectName

The name of the decision point.

attribute

In the first (single-attribute) form of the call, the name of the attribute whose values you wish to obtain. After making the getControlData call, you can get ControlItem objects from the resulting ControlData object, then get the attribute value for each ControlItem (domain member) by using the ControlItem method getAttributes (which, in this case, will return a vector with one element).

attributes

In the second (multiple-attributes) form of the call, an array containing the names of all the attributes whose values you wish to obtain. After making the getControlData call, you can get ControlItem objects from the resulting ControlData object, then get the attribute values for all the attributes you specified for each ControlItem (domain member) by using the ControlItem method getAttributes.

sort

If true, the ControlItem objects returned by an iterator (object of type ItemIterator, obtained by calling the ControlData object’s iterator method) will be sorted. The sort order will either be a standard one implemented by the COP, or a custom sort order based on a Comparator object that you supply.

See Sorting and Filtering.

The standard sort order implemented by the COP is based on the state and elimination level of the ControlItem objects (domain members). The domain members are sorted as follows:

  1. Selected domain members in conflict.

  2. Selected domain members not in conflict.

  3. Selectable domain members.

  4. Eliminated domain members—high elimination level.

  5. Eliminated domain members—low elimination level.

If there is more than one domain member in a category, they will be sorted in their “default order." (This is the order in which they were originally supplied by the modeler or the data base.) In other words, within each category the default order will be preserved. This applies to eliminated domain members only if their elimination level is equal.

If sort is true and you supply a Comparator object, your Comparator routine will be used to sort the domain members.

If sort is false, the COP will do no sorting of domain members. Any iterator obtained from this ControlData object’s iterator method will return the domain members in their default order.

filter

Filters out certain ControlItem objects (domain members), based on their state and elimination level. The ControlData object’s iterator simply skips over these ControlItem objects. For example: this can be used to filter out all eliminated items (so the user doesn’t even see them), or all eliminated items with an elimination level below a certain number.

If filter is null, no filtering is done (except for “deleted" domain members).

See Handling Deleted Domain Members.

Given a decision point name (dpName) and attribute (attribute), get and display the domain members—sorted but not filtered.

ControlData ctrlData = null; ControlItem ctrlItem = null; boolean sortFlag = true; ItemFilter filter = null; ItemIterator ctrlItemIterator = null; try { ctrlData = cop.getControlData(dpName, attribute, sortFlag, filter); } catch (Exception e) { System.out.println("Error: Unable to retrieve ctrlData - " + e); ctrlData = null; } if (ctrlData != null) { crtlItemIterator = ctrlData.iterator(); } if (crtlItemIterator != null) { while (ctrlItemIterator.hasNext()) { ctrlItem = (ControlItem) ctrlItemIterator.next(); if (ctrlItem != null) { // you have ctrlItem - examine and display it here } } }

It’s important to note that the methods of ControlData and ControlItem objects return the most recent display information, which is based on the most recent calls to processChoices, getControlData, setPricingData, and so on, regardless of when the ControlData or ControlItem object was first created. They do not “remember" old values. So, for example, if you do the following:

  1. Make some user choices.

  2. Call processChoices.

  3. Call getControlData to get a ControlData object for a decision point.

  4. Make different user choices.

  5. Call processChoices again.

  6. Call getFlags on the ControlData object created in Step 3 to get the state of the decision point.

You would get the current state of the decision point, not the state it had as of Step 3. So there is no reason to save a ControlData or ControlItem object in order to hold old display information. It won’t work. (You could, of course, call getFlags immediately after Step 3 and save the value itself.)

Click to jump to top of pageClick to jump to parent topicSpecifying Delta-Pricing and Total-Pricing Requirements

The procedure to process and display a page specifies those domain members (if any) for which you need pricing-related information.

See Getting Display Information for a Domain Member.

There are two ways you can accomplish this:

Calling setPricingData describes a set of domain members for which you want pricing-related information. This information is cached by the Configurator (until you call setPricingData again, or release). The next time getControlData is called, the COP will be called to generate pricing-related information for those domain members. The delta-price value for a domain member can then be retrieved from the ControlItem representing the domain member using the ControlItem method getDeltaPrice. The total price for the configuration can also be retrieved using the ClientOperations method getTotalPrice.

There is one form of setPricingData:

void setPricingData(Map dpNamesAndAttributes)

This method takes a Map of decision point names and the corresponding price attribute for that decision point. Only the domain members in the specified decision points will be delta-priced. Also, only the specified decision points will be used when calculating the total price for the configuration.

Note. Configurator remembers only the most recent setPricingData call. Subsequent calls do not “accumulate" domain members for which to get delta-pricing data.

Click to jump to top of pageClick to jump to parent topicGetting Other Display Information

Some ClientOperations methods return information that you may wish to display, but that is not included in ControlData or ControlItem objects. These calls include:

You may also wish to display one or more configuration attributes. To obtain them, call the ClientOperations method getConfiguration to get the current configuration, and then the Configuration method getAttribute for each attribute whose value you want to display.

Click to jump to top of pageClick to jump to parent topicVerifying a Configuration

When the user wishes to finalize the configuration, as in making a purchase, you can verify the configuration by calling the ClientOperations method verifyConfiguration. This method is similar to processChoices; it takes a vector of Choice objects (representing the configuration) as input, and calls the Configurator Engine to generate a solution state. The vector can contain both DMChoice objects and EVChoice objects. verifyConfiguration also returns a boolean value: true if the configuration is complete and consistent, false if otherwise. Complete means that every required (non-optional) decision point in the configuration has a selection. Consistent means the configuration has no violations.

Note. There is an alternate version of verifyConfiguration that takes a Configuration object as a parameter. With the exception of this additional parameter, it functions the same as the other version.

Click to jump to top of pageClick to jump to parent topicConfiguration

This class represents a set of choices for the model, any configuration attributes, and the model’s name, version, and compileID.

The choices may include both DMChoice objects and EVChoice objects.

You can obtain the current configuration by calling the ClientOperations method getConfiguration. This configuration will include user, default, and computer choices.

The Configuration object can be used to write out the configuration to an external format (usually XML), or to read in a configuration that has been saved in that format. You can also directly set and get the information in the configuration: choices, configuration attributes, and the model’s name, version, and id.

You can also save and restore a configuration in other formats, but this requires a significant amount of custom code and is generally not worthwhile.

Click to jump to top of pageClick to jump to parent topicMethods

The Configuration class contains the following methods:

void convertElement(org.w3c.dom.Element elem) void fromXML(InputStream is) String getAttribute(String attribute) Map getAttributeMap() Vector getChoices() String getModelCompileVersion() String getModelName() String getModelVersion() String getTagName() Vector getUserChoices() String removeAttribute(String attribute) void setAttribute(String attribute, String value) void setChoices(Vector choices) void setModelCompileVersion(String modelCompileVersion) void setModelName(String modelName) void setModelVersion(String modelVersion) org.w3c.dom.DocumentFragment toXML(org.w3c.dom.Document doc) Object clone() DeltaConfig delta(Configuration newCfg) boolean equals(Configuration newCfg) Date getlastSavedDate() Vector getNumericDatas() boolean hasViolations() void toXML(OutputStream out) Date getSolveDate()

Click to jump to top of pageClick to jump to parent topicSaving and Restoring a Configuration

The COP can be used to save the current configuration in an external form, or to read a previously saved configuration and make it current. The COP uses a Configurator-defined XML format and standard Java input and output techniques for these operations. Provided the property calico.na.db.compression in the Advisor.properties file is set to true, it also compresses the data during the save and de-compresses it (if needed) during a restore.

To save the current configuration:

  1. Call the ClientOperations method getConfiguration to obtain a Configuration object representing the current configuration.

  2. Call that object’s toXML method to write out an XML representation of the configuration to a specified output stream.

To restore a previously saved configuration (that is, make it current):

  1. Create a Configuration object.

  2. Call that object’s fromXML method to read the previously saved configuration from a specified input stream.

  3. Call the ClientOperations method restore, with the Configuration object as its config parameter.

    Note. The Configuration methods toXML and fromXML assume the use of the Configurator’s standard XML format for configurations. It is also possible to represent a configuration in some other format, defined either by the programmer or by some other (non-Configurator) standard. In this case you can not use toXML or fromXML. Instead, to save the configuration, you would examine each item in the configuration (including all the choices, configuration attributes, and model identification information) and write it out in the desired format. To restore a saved configuration, reverse the process: create a Configuration object, read in and parse the representation of the stored configuration, and set the values of all items in the Configuration object accordingly.

    Obviously, using a non-standard format to represent a configuration entails much more work than using the Configurator’s XML representation. It is generally not worthwhile.

Click to jump to top of pageClick to jump to parent topicControlData

This class represents a decision point. You create a ControlData object for a decision point by calling the ClientOperations method getControlData. The ControlData object contains an array of ControlItem objects, representing all its domain members. It also enables you to obtain one or more iterators (objects of type ItemIterator) for accessing the ControlItem objects.

If you set the sort parameter of the getControlData call to true, then an iterator obtained from the ControlData object will return the ControlItem objects in a sort order determined by the software.

See Sorting and Filtering.

Iterators can also filter out (skip over) certain domain members, such as all eliminated domain members. Specify the filtering you want by using the filter parameter of getControlData.

See Sorting and Filtering.

Note. Although you can access the ControlItem array directly using the standard array methods, you will almost never want to. The array is neither sorted nor filtered by the COP. Use an iterator obtained from the ControlData object; the iterator will return the ControlItem objects sorted, and filter them as specified.

See Handling Deleted Domain Members.

Note. Each optional decision point has a special domain member with the reserved name “$NADA", representing a choice of “none." This domain member is supplied by the Configurator Engine; it does not come from the modeler or an external source. It does not appear in either the ControlData object’s ControlItem array or in the ControlItem objects returned by the ItemIterator. Instead, it can only be obtained by calling the ControlData method getControlItem, with a String parameter that has been set to $NADA.

If, for a given optional decision point, you want to give your users the option of “none" (including displaying the option, displaying its state, and so on), you need to handle it specially, using the $NADA domain member and the getControlItem call.

Note. The ControlData method isPublic indicates whether a decision point is public or private. However, the current version of the Configurator does not implement this distinction; all decision points are considered public.

Click to jump to top of pageClick to jump to parent topicMethods

The following methods are contained in the ControlData class:

Object[] getAllItems() Choice[] getChoices() String getClassID() ControlItem getControlItem(String domainName) long getFlags() String getName() double getQty() Violation[] getViolations() boolean hasDeletedItems() boolean isMultiSelect() boolean isOptional() boolean qtySupported() boolean isPublic() ItemIterator iterator() ItemIterator iterator(Comparator comp) int getMinChoices() int getMaxChoices() String[] getAttributeNames() String getAttributeValue(String name) String[] getAttributeValues(String[] names)

Click to jump to top of pageClick to jump to parent topicGetting Display Information for a Decision Point and Its Domain Members

Most of the display information is associated with the decision point’s domain members, rather than the decision point. To get at this information, call the ControlData method iterator to get an iterator, and use it to access the ControlItem objects. They will be sorted and filtered as specified by the software.

You can also call getAllItems, which returns the ControlItem array directly. But this array is not sorted or filtered by the COP, regardless of the getControlData parameters. It contains all of the decision point’s domain members, in whatever order they were supplied by the Visual Modeler or an external source.

For each ControlItem, use the ControlItem methods to retrieve its display information.

See ControlItem.

There is some information that you may wish to display that applies to the decision point as a whole. Methods that return such information include:

getQty

Returns the total of all the quantities for all the selected domain members of this decision point. Only some decision points, determined by the modeler, permit their domain members to have quantities. You can determine if a decision point permits quantities by using the ControlData method qtySupported.

 

getState

Returns the state of the decision point.

See Getting the State of a Domain Member.

 

getViolations

Returns all violations associated with this decision point.

 

int getMinChoices

Returns the minimum selection quantity value for this decision point.

 

int getMaxChoices

Returns the maximum selection quantity value for this decision point.

 

String[] getAttributeNames()

Returns the names of the selection point attributes for this decision point.

String getAttributeValue(String name)

Returns the value of the specified attribute.

String[] getAttributeValues(String[] names)

Returns the specified attribute values.

Click to jump to top of pageClick to jump to parent topicGetting the State of a Decision Point

Based on the configuration and solution state at any given time, a decision point has one or more states, which can be obtained by calling the ControlData method getFlags. The state of a decision point depends completely on the state of its domain members.

See Getting the State of a Domain Member.

There are four decision point states:

selectable

If one or more of the domain members is selectable.

 

selected

If one or more of the domain members is selected.

 

conflicted

If one or more of the domain members is conflicted

 

undefined

Neither selectable, selected, nor conflicted.

Combinations are certainly possible. For example, a decision point can be simultaneously selected (because at least one of its domain members is selected) and selectable (because some other of its domain members are selectable).

All of a decision point’s domain members are used in determining the domain member’s state, not just the domain members that have not been filtered out by the ControlData object’s iterator(s).

The ControlData interface defines three different state bits, which can be used to test a selection point (decision point’s state flags:

Decision point state flags

Bits

SELECTABLE

0x01

SELECTED

0x02

CONFLICTED

0x04

Note. The particular values of the state bits are not important, and are only included for illustration. They might be changed in a later release. It is important that they are single, distinct bits. The bit values are not the same as the bit values for the similarly named field constants in the ControlItem interface.

The ControlData interface also defines:

Decision point state

Bits

UNDEFINED

0x00

You can use these field constants with the value returned by the ControlData method getFlags to determine the decision point’s current state or states.

Click to jump to top of pageClick to jump to parent topicSorting and Filtering

A ControlData object contains an array of ControlItem objects, representing its domain members. This array is not sorted or filtered by the COP. All the ControlData object’s ControlItem objects (domain members) appear in the array. The ControlItem objects are arranged in the order that the corresponding domain members were loaded into the engine at model load time. For external domain members, this is the order specified by the SQL statement for the domain member query. For internal domain members, it is the order they were entered into the class by the modeler. This is called the domain member’s default order.

However, the COP does permit you to sort and filter the ControlItem objects in certain ways. This is not implemented through the ControlItem array, but through objects of type ItemIterator, which can be obtained by calling the ControlData method iterator.

A ControlData object is created by a call to the ClientOperation method getControlData. If the getControlData parameter sort is set to true, then iterators (objects of type ItemIterator) obtained from the ControlData object’s iterator method will return the ControlItem objects in a sorted order. This sort order will either be a standard one implemented by the COP, or a custom sort order based on a Comparator object that you supply, depending on which form of the ControlData method iterator you use.

You can also have multiple iterators at the same time, for simultaneous access to standard sorting, custom sorting (one or more), and multiple traverses of the ControlData object’s domain members. But this will not usually be necessary.

Standard Sorting

The first form of the ControlData method iterator takes no parameters: iterator( ). If you call this form, the resulting iterator returns the ControlItem objects sorted in a standard manner implemented by the COP. The sort order, one that many User Interfaces prefer, is as follows:

  1. Selected domain members in conflict (that is, both selected and eliminated).

  2. Selected domain members not in conflict.

  3. Selectable domain members (neither selected nor eliminated).

  4. Eliminated (but not conflicted) domain members—sorted from highest elimination value to lowest elimination value.

Within each category (for 1, 2, and 3), if the category has more than one domain member, its domain members are arranged in the same order in which they appear in the ControlItem array. That is, the original (default) order is maintained within each category.

Similarly, for category 4, multiple domain members with the same elimination value will be arranged in their original (default) order.

Every eliminated domain member has an elimination value. If it’s not determined by constraints for which the modeler has defined elimination levels, it defaults to 1.

Custom Sorting

The second form of the ControlData method iterator takes a Comparator object as its parameter: iterator(Comparator comp). If you call this form, the resulting iterator returns the ControlItem objects sorted in the order determined by your Comparator object. This enables you to create a completely customized sort order by writing your own Comparator object. Your Comparator will have access to all the methods of the ControlItem objects it is comparing, enabling you to sort on attribute values, states, and other domain member aspects.

Note. A Comparator is a Java object that is used to impose a sort order on a collection of objects by comparing pairs of objects and returning a result indicating which object is “greater” and which is “lesser?” (or that the two are to be considered “equal” in the sort order). In this case the objects are the ControlItem objects of a given ControlData object. Comparators implement the java.util.Comparator interface.

No Sorting

If you call the ClientOperations method getControlData with the sort parameter set to false, then the ControlItem objects of the resulting ControlData object will not be sorted. Any iterator returned by that ControlData object’s iterator method will return ControlItem objects in their original (default) order—exactly as they appear in the ControlItem array—with no sorting by the COP. This is true regardless of which form of the iterator method you call. However, filtering may still occur.

See Sorting and Filtering.

Filtering

If the getControlData call has a non-null filter parameter, then iterators obtained from the resulting ControlData object will filter out (skip over) certain ControlItem objects, and only return the ones that are not filtered. This makes it easier for the UI to conceal from the user a certain class of domain members (commonly, all eliminated domain members, or eliminated domain members whose elimination value is below a certain number). The filtering depends on the filter parameter, as follows:

Click to jump to top of pageClick to jump to parent topicHandling Deleted Domain Members

In systems that load domain members from external databases, it is sometimes possible to have “deleted" domain members—that is, an external domain member that has been removed from its database after the model was compiled. It might be necessary to inform the user that a domain member has been deleted, especially if it had been user-selected.

A ControlData object’s iterators automatically filter out (skips over) any deleted domain members, so they are not helpful in handling them. But the deleted domain members are still present in the ControlData object’s ControlItem array. Use the ControlData method hasDeletedItem to see if the decision point has a deleted domain member. If it does, you can use getAllItems to get the ControlItem array, then use the standard array operators to look at all the ControlItem objects in the ControlItem array. The ControlItem method isValid (false for deleted domain members, true otherwise) will tell you if a given domain member is deleted. If it is, you can then check the domain member’s state to determine if the user needs to be notified.

Click to jump to top of pageClick to jump to parent topicControlItem

This class represents a domain member. It contains display information for that domain member.

Note. A ControlItem always comes from a ControlData object, which was originally obtained from a call to the ClientOperations method getControlData. So every ControlItem can be traced back to a particular getControlData call. The attributes parameter to the getControlData (or attribute parameter, for the other version of the call) determines which attribute values can be obtained from the ControlItem.

Click to jump to top of pageClick to jump to parent topicMethods

The ControlItem class contains the following methods:

Vector getAttributes() String getAttributeValue(String attribute) String getClassID() double getDeltaPrice() long getEliminationLevel() long getFlags() String getName() double getQty() Violation[] getViolations() boolean hasEliminationLevel() boolean isValid() public double getMaxQty() public double getMinQty() void setDeltaPrice(double newDelta)

Click to jump to top of pageClick to jump to parent topicGetting Display Information for a Domain Member

You can use these ControlItem class methods to get display information for a domain member:

Method

Description

getAttributes

Returns a vector of attribute values for the domain member represented by this ControlItem. The attributes whose values will be returned are those that were included in the attributes input to the getControlData call that this ControlItem can be traced back to. The order of the values will be the same as the order of the attributes in that parameter. The UI could display these values in whatever format you decide.

getFlags

Returns the current state flags for the domain member. This tells you whether the domain member is user-selected, user-eliminated, computer-selected, computer-eliminated, and so on. The UI should mark the domain member appropriately.

See Getting the State of a Decision Point.

getQty

Returns the quantity of this domain member. Only some decision points, determined by the modeler, permit their domain members to have quantities. You can determine if a decision point permits quantities by calling the ControlData method qtySupported on the associated ControlData object.

getDeltaPrice

Returns the delta price for this domain member. This information will only be available if the decision point this domain member belongs to was specified in the pricing definition setup.

getViolations

Returns an array of all the violations (if any) associated with this domain member.

isValid r

Returns false for a deleted domain member, true otherwise.

See Handling Deleted Domain Members.

hasEliminationLevel

Returns the elimination level for an eliminated domain member. Every eliminated domain member has an elimination value. If it’s not determined by constraints for which the modeler has defined elimination levels, it defaults to 1.

double getMinQty

Returns the minimum quantity value for this domain member.

double getMaxQty

Returns the maximum quantity value for this domain member.

Click to jump to top of pageClick to jump to parent topicGetting the State of a Domain Member

Based on the configuration and solution state at any given time, each domain member has one or more states, indicating whether the domain member is user-selected, computer-selected, user-eliminated, and so on. Multiple states are certainly possible. For example, a domain member can be both user-selected and computer-selected.

A domain member that is both selected and eliminated (for example, user-selected but computer-eliminated) is called conflicted. A domain member that is neither selected nor eliminated is called selectable.

The possible states for a domain member are: eliminated, selected, conflicted, selectable, computer-selected, default-selected, user-selected, computer-eliminated, default-eliminated, user-eliminated.

Note. The Configurator engine does not support “default-eliminated."

The ControlItem interface defines five different state bits, which can be used to test a domain member’s state flags:

Domain member state flag

Bits

ELIMINATED

0x01

SELECTED

0x02

COMPUTER

0x10

DEFAULT

0x20

USER

0x40

Note. The particular values of the state bits are not important, and are only included to make some of the examples clearer. It is important that they are single, distinct bits

These bits do not occur in isolation; you would not expect to find a domain member state with only one of these bits set. In fact, you would expect at least one from ELIMINATED and SELECTED, and at least one from COMPUTER, DEFAULT, and USER. These combinations define other states in the ControlItem interface:

Domain member state

Bits

COMPUTER_ELIMINATED

0x11

DEFAULT_ELIMINATED

0x21

USER_ELIMINATED

0x41

COMPUTER_SELECTED

0x12

DEFAULT_SELECTED

0x22

USER_SELECTED

0x42

The fields can be combined by the bitwise OR operation into a number that represents the domain member’s state or states. This number is called the domain member’s state flags (or just flags). You can use the ControlItem method getFlags to get the state flags for a domain member, and then use these field constants to determine the precise state or states of the domain member—and thus how to display it in your UI.

Note. If a domain member is conflicted, then it is both eliminated and selected. But it may be difficult or impossible to get more detailed information from the state flags—such as whether the domain member is computer-selected, user-selected, computer-eliminated, and so on. For example, a domain member that is user-selected and computer-eliminated has exactly the same state bits set as a domain member that is user-eliminated and computer-selected (namely, USER, COMPUTER, SELECTED, ELIMINATED). So there’s no way to tell from the state flags if the domain member is, for example, computer-selected or computer-eliminated. The convention, in this case, is to say that the domain member is conflicted, selected, and eliminated—and not try to go into any more detail than that.

It’s up to you to decide how to use the states for display purposes in your UI. For example, most User Interfaces will display a domain member that is simply user-selected (0x42) the same way they will display one that is user-selected and computer-selected (0x52)—with an icon indicating it is user-selected. In this case user selection is considered more important than computer selection, and the UI doesn’t bother to indicate both states. However, other User Interfaces may be required to display more information depending on the model needs.

The mapping from state flags to states is not always obvious, and you need to be careful. This is particularly true when dealing with conflicted domain members. For example, suppose you want to see if a domain member is computer-selected. When you examine the COMPUTER bit and the SELECTED bit, they are both 1.

It is possible that the domain member is computer-eliminated and user-selected—a conflicted combination. This combination (0x53) has the COMPUTER and SELECTED bits set, but the domain member is not computer-selected. You need to check the SELECTED bit to rule out this and similar possibilities.

The following two examples illustrate the use of the state flags to determine the state or states of a domain member.

Example 1: Check to see if a domain member is computer-selected (a conflicted item is not considered computer-eliminated, regardless of the other state bits that are set).

long stateFlags = 0; stateFlags = ctrlItem.getFlags(); if ((stateFlags & ControlItem.COMPUTER_SELECTED) == ControlItem.COMPUTER_SELECTED) && ((stateFlags & ControlItem.CONFLICTED) != ControlItem.CONFLICTED)) { // domain member is computer-selected } else { //domain member is not computer-selected }

Example 2: Classifying a domain member as conflicted, selected, selectable, or eliminated.

long stateFlags = 0; stateFlags = ctrlItem.getFlags(); if (stateFlags & ControlItem.CONFLICTED) == ControlItem.CONFLICTED) { // domain member is conflicted } else if ((stateFlags & ControlItem.SELECTED) == ControlItem.SELECTED) { //domain member is selected (and not conflicted) else if ((stateFlags & ControlItem.ELIMINATED) != ControlItem.ELIMINATED) { //not selected, not eliminated - domain member is selectable } else { //domain member is eliminated }

Click to jump to top of pageClick to jump to parent topicChoice

This class is the superclass for DMChoice and EVChoice. Several important methods in the COP Java API (such as the ClientOperations methods processChoices and verifyConfiguration) either accept or return a vector of objects of type Choice. These vectors can include both objects of type DMChoice and objects of type EVChoice, since, by inheritance, both are objects of type Choice.

In this version of the Configurator, many Choice class methods are deprecated and reintroduced in DMChoice because they apply only to domain member choices and not extern variables. For this reason there are very few Choice methods that are actually called; instead, the appropriate DMChoice methods and EVChoice methods are called.

The Choice class contains the following methods:

String getDecisionPointName() String getDomainMemberName() //Deprecated. Use DMChoice.getDomainMemberName double getQuantity() //Deprecated. Use DMChoice.getQuantity long getState() //Deprecated. Use DMChoice.getState abstract String getTagName() boolean isSelection() //Deprecated. Use DMChoice.isSelection boolean isUserChoice() void setDecisionPointName(String dpName) void setState(long newState) //Deprecated. Use DMChoice.setState Object clone() boolean isDMChoice() void toXML(StringBuffer buffer)

When called on an object of type EVChoice:

Click to jump to top of pageClick to jump to parent topicDMChoice

This class is a subclass of Choice. Objects of type DMChoice represent a domain member choice, that is, a selection or elimination. You create DMChoice objects by calling the ClientOperations methods makeSelectedChoice and makeEliminatedChoice. These DMChoice objects (along with EVChoice objects) can be passed in a vector to the ClientOperations method processChoices. No DMChoice or Choice class methods are required for this.

The DMChoice objects created by makeSelectedChoice and makedEliminatedChoice represent, by default, user domain member choices. However, by using the DMChoice method setState, you can change them to represent computer or default domain member choices (or various combinations). This may be necessary when you are creating DMChoice objects to include in a Configuration object that represents a configuration containing user, computer, and default domain member choices.

Click to jump to top of pageClick to jump to parent topicMethods

The following methods are contained in the DMChoice class:

String getDomainMemberName() double getQuantity() long getState() String getTagName() boolean isSelection() boolean isUserChoice() void setState(long newState) boolean equals(Object newChoice) void toXML(OutputStream out)

Click to jump to top of pageClick to jump to parent topicExamining a DMChoice

Given an object of type DMChoice, you can determine what domain member choice it represents in the following manner:

Click to jump to top of pageClick to jump to parent topicEVChoice

This class is a subclass of Choice. Objects of type EVChoice represent extern variables. The value of an extern variable is a collection of floating-point numbers, strings, dates, boolean values, or integers.

You create EVChoice objects by calling the ClientOperations method makeExternVarChoice. These EVChoice objects (along with DMChoice objects) can be passed in a vector to the ClientOperations method processChoices. No EVChoice or Choice methods are required for this.

Click to jump to top of pageClick to jump to parent topicMethods

The following methods are contained in the EVChoice class:

String getTagName() int getValueCount() Collection getValues() void setValues(Collection values) boolean equals(Object newChoice) void toXML(OutputStream out) Object clone() boolean isUserChoice()

Click to jump to top of pageClick to jump to parent topicExamining an EVChoice

By using the Choice method getDecisionPointName on an EVChoice object, you can get the name of the associated extern variable. You can then use the ClientOperations method getExternVar to get an object of class ExternVar representing the extern variable itself. Alternatively, you can bypass the ExternVar object and get the value of the extern variable associated with the EVChoice by using the EVChoice method getValues.

Click to jump to top of pageClick to jump to parent topicItemFilter

The ClientOperations method getControlData has an ItemFilter parameter that enables the method to filter out certain domain members.

The most common use of an ItemFilter parameter is to filter out all eliminated domain members, or all eliminated domain members whose elimination level is below a certain threshold. Depending on the model and the User Interface, these are domain members that the user may not be interested in.

The ItemFilter parameter to getControlData causes the ItemIterator (belonging to the ControlData object created by the getControlData call) to filter out (skip over) the specified domain members. This makes it easy for the UI not to display those domain members. Note that the filtering is done by the ItemIterator; the ControlData object’s ControlItem array still contains all the ControlItem objects (domain members) of the ControlData object (decision point).

Click to jump to top of pageClick to jump to parent topicMethods

The following methods are contained in the ItemFilter class:

void setRange(boolean filterAllEliminatedItems) void setRange(int lower, int upper)

Click to jump to top of pageClick to jump to parent topicFiltering Out Domain Members

There are two versions of the ItemFilter method setRange. One takes a boolean parameter, filterAllEliminatedItems. The other takes two integers, lower and upper. Before using a parameter of type ItemFilter do one of the following:

Click to jump to top of pageClick to jump to parent topicItemIterator

The ControlData method iterator returns an object of the ItemIterator class. The ItemIterator object, called an iterator, is used to access the ControlItem objects (domain members) of the ControlData object (decision point). The iterator returns the domain members in a specified sort order, which may either be a standard sort order implemented by the COP or a custom sort order determined by a Comparator object you supply. The iterator also filters out (skips over) any domain members specified in the filter parameter to that getControlData call, as well as any deleted domain members.

It is possible to have more than one iterator for the same ControlData object at the same time. However, this is not usually necessary.

ItemIterator implements the Java interface java.util.Iterator.

The following methods are contained in the ItemIterator class:

boolean hasNext() Object next()

Click to jump to top of pageClick to jump to parent topicExternVar

This class represents an extern variable, and can be used to get the name, type, and value of the extern variable. The value of an extern variable is a collection of floating-point numbers, strings, dates, boolean values, or integers.

The ClientOperations method getExternVarNames returns a vector of the names of all the extern variables in a model. The ClientOperations method getExternVar can then be used to retrieve the extern variable itself.

The value of an extern variable can be used as a choice in a configuration.

See Handling Deleted Domain Members.

The ExternVar class methods are:

String getName() Collection getValues() String getType() Violation[] getViolations() boolean isDefault()

Click to jump to top of pageClick to jump to parent topicNumericData

This class represents a variable in the model. Some models contain variables that you might wish to display in the UI, such as “total grams of saturated fat" or “number of video card slots remaining." These are distinct from domain member attributes, prices, and quantities. Obtain a NumericData object representing a model variable by using the ClientOperations method getNumericData. Then you can use the methods in this class to get the type and value of the variable.

Numeric data values are generated by the Configurator Engine, based on formulas specified in the model. From the point of view of the COP, they are read-only.

The NumericData class:

String getName() String getValue() String getType() boolean equals(Object obj)

Click to jump to top of pageClick to jump to parent topicViolation

This class returns information on a violation. Retrieve Violation objects associated with a configuration, a given decision point, or a given domain member by using the getViolations method of the ClientOperations, ControlData, or ControlItem classes, respectively.

The Violation class has one method, getExplanation, which returns a user-readable explanation for the violation.

The Violation method contains this method:

String getExplanation()