Page tree
Skip to end of metadata
Go to start of metadata

Please see Prism Objects for a generic introduction to prism concepts.

Prism Context

Prism library maintains some long-living objects that are needed for correct operation of prism objects. This includes:

  • Parsed schemas (SchemaRegistry). Prism parses static schema when the system is initialized and keeps them in memory. Processing the schemas may be costly. Storing them in memry avoids the need for expensive re-parse of the schemas on each use.
  • Initialized instances of parsers and serializers (such as JAXB)

These instances are kept in an umbrella class PrismContext. Prism context is usually maintained as singleton. Instance of prism context is needed for vast majority of operations with prisms. However, prism objects, definitions and items keep a reference to the prism context instance. Therefore the use of prism context is often hidden.

Prism Context Initialization

MidPoint initializes prism context as a part of its normal system initialization. Prism context is exposed as a spring bean. Therefore manual initialization of prism context is usually not needed when working in midPoint environment. In case of need to manually initialize prism context a use of prism context factory is recommended. Please look for classes implementing PrismContextFactory interface as an example of prism context initialization.

Creating Objects Using Compile-Time Classes (JAXB)

Perhaps the most convenient way how to create an object is to use its generated compile-time class. These classes are generated from the static schema for all prism object types. You can directly instantiate the class and fill it with data using Java getters and setters:

// Instantiate the class
UserType userType = new UserType();

// It is good to adopt the object as soon as possible
prismContext.adopt(userType);

// Set the data: simple single-value values
userType.setDescription("blah blah");
userType.setEmployeeNumber("007");

// Set the data: complex multi-value containerAssignmentType assignmentType = new AssignmentType();
 userType.getAssignment().add(assignmentType);

The UserType is class generated by prism at compile-time. It correstponds to the UserType schema type (in XSD schema definition). It has getters and setters for prism properties and containers defined in the schema.

The UserType can be instantiated directly using a default constructor. However an object which is instantiated in this way has no connection with the prism context. It will work just fine for most basic operations. But advanced operations will fail unless the object is associated with a prism context. The association can be done in a very simple way by invoking adopt method of prism context. It is a best practice to adopt new objects as soon possible. This has two major advantages: Adopting the object immediately after instantiation means that you will not forget to adopt it later. Adoption of the object will also associate the object with its schema definition (if possible). Therefore the subsequent operations will be able to do better checks of the object content.

Instantiated (and adopted) object can be populated by data. Getters and setters are available for single-valued properties. For multi-valued attributes only getters are available. Such getters return a collection that can be changed as needed e.g. by adding a new value into the collection.

Prism Duality

Prism objects (as the name itself suggests) are multi-faceted. The same object can be inspected and modified using several interfaces:

  • Native prism interface (PrismObjectPrismProperty, ...). This is the most powerful interface but it may be slightly difficult to use. It can be used to iterate over the objects, closely inspect every item, iterate over them, inspect (or modify) their schema and do almost any kind of magic imaginable.
  • Compile-time class interface (ObjectableContainerable). This interface is using classes generated at compile time. It is very similar to JAXB (in fact it is based on JAXB) but it works for more data formats not just XML. The objects are accessed using simple getters and setters. This interface is very convenient to use. But it is only limited to the parts of the schema that was available at compile time.
  • DOM interface (W3C DOM) used to access the objects as DOM elements. The implementation of this interface is not complete yet.
  • Map interface (java.util.Map and Collection) might be able to access the prism objects as simple Java Maps and Collections. This is planned. The implementation haven't started yet.

Any prism object can be represented using any interface. At the same time. Each representation can be converted to any other representation using methods such as asObjectable and asPrismObject:

PrismObject<UserType> user = ...... // parse or instantiate it somehow

// Use prism native interface to access the "description" property
PrismProperty<String> descriptionProperty = user.findProperty(UserType.F_DESCRIPTION);
descriptionProperty.setRealValue("blah blah blah");

// switch to a compile-time-class representation
UserType userType = user.asObjectable();

// use the compile-time-class representation to access the data
String theDescription = userType.getDescription();

// ... long, looong time later .... in a galaxy far away ...  
// we have lost access to the original "user" variable but we still have userType. No problem.
PrismObject<UserType> user = userType.asPrismObject();

The important thing to remember is that these are just different representations of the same data. They are not copies. Therefore modifying the data using one representation will have immediate effect on all other representations of the same object.

Parsing and Serializing Objects

Prism context contains a set of processors to support various data formats:

  • DOM processor supports parsing of XML data structures represented in DOM form (or parsed into DOM form).
  • JAXB processor supports parsing of XML data structures represented in JAXB form (e.g. as JAXB elements). This is not a standalone processor by itself. Due to the JAXB limitations this processor usually cannot be used by itself. It cooperates with DOM processor (and vice versa). The interplay of these two processors is quite intricate. And quite fragile. We are sorry for this. But haven't found a better way how to work around the limitations of these XML libraries.
  • JSON processor supports parsing of JSON-formatted objects. This is currently in development.

The processors can be invoked to parse the objects stored in appropriate forms:

PrismObject<UserType> prismObject = prismContext.getPrismDomProcessor().parseObject(file)
// ...
PrismObject<UserType> prismObject = prismContext.getPrismDomProcessor().parseObject(domNode)
// ...
// TODO: JSON 

Parsing will process the objects in their input form (File, stream, string, ...) and it will return complete and initialized prism objects. On the other hand serialization will work on initialized prism object and it will output it in an appropriate form for storage, transmission over the network, etc. Serialization is also invoked by using processors:

String xmlString = prismContext.getPrismDomProcessor().serializeObjectToString(userType)
// ...
Element domElement = prismContext.getPrismDomProcessor().serializeToDom(userType)
// ...
// TODO: JSON 

PolyString and PolyStringType

PolyString is a special type of string that is designed to very easily support text operations in international environment. Most properties that contain human-readable names are represented as PolyString in midPoint data model. Using polystrings instead of strings may be a bit of nuisance during development but it is more than worth the trouble. As a developer you would usually only care about orig part of the polystring. This is what you will be usually displayed. You also need to set just the orig part of the polystring when setting a new value. The other polystring values (e.g. norm) will be computed transparently by prism code when polystring is added to any prism property.

Unfortunately due to implementation limitations we have two classes that represent polystrings: PolyString and PolyStringType.

ClassUsed inOriginMnemonics
PolyStringPrism native interface (PrismProperty)Manually written from scratch, part of prism core 
PolyStringTypeCompile-time classes (UserType, etc.)JAXB class (almost) generated from XSDIn UserType use PolyStringType

The reason for this confusion is mostly caused by a limitation of JAXB framework. We are using JAXB framework to parse XSD schemas and generate compile-time classes. As the origin of all generated compile-time classes are in XSD definition also all of their property types must also have XSD definition. This includes PolyString. Although we have modified and customized significant part of JAXB we haven't found a way how to avoid this confusion.

// Prism native interface: we use PolyString
PrismObject<UserType> user = ......
PrismProperty<PolyString> nameProperty = user.findProperty(UserType.F_NAME);
nameProperty.setRealValue(new PolyString("jack"));

// Compile-time class interface: we use PolyStringType
UserType userType = user.asObjectable();
userType.setName(new PolyStringType("jackie"));

Misc

As you might have already noticed native prism interface makes a heavy use of generics. Although Java generics has its limitations this approach gives us at least some compile-time type checking.

Prism object are designed to be serializable using Java IO serialization (implement interface java.io.Serializable). This is needed for GUI to store this objects in web session, etc. However, only items (PrismObject, PrismContainer, PrismProperty, ...), values (PrismPropertyValue, ...), definitions (PrismObjectDefinition, ...) and deltas (ObjectDelta, ...) are serializable. Infrastructure classes such as prism context or processors are not.

You can serialize the prism objects directly using standard java serialization. These objects contain reference to prism context but that reference is transient. This also means that you need to restore this reference after you deserialize the objects. Use adopt method of prism context to do so.

TODO

  • Components: "prism" component and "schema" component
  • Definitions
  • Dynamic schema
  • Deltas (and diff)
  • No labels